Skip to content

fix(ai): resolve engine aliases for ai({ engine }) - #62

Merged
ralyodio merged 1 commit into
moshcoder:mainfrom
clawedassistant26:fix/ai-engine-alias
Jul 30, 2026
Merged

fix(ai): resolve engine aliases for ai({ engine })#62
ralyodio merged 1 commit into
moshcoder:mainfrom
clawedassistant26:fix/ai-engine-alias

Conversation

@clawedassistant26

Copy link
Copy Markdown
Contributor

The bug

ai(prompt, { engine: "cc" }) fails with moshscript: ai() needs an installed engine — try install("claude") even when Claude Code is installed and on PATH.

pickAiEngine() matched raw ENGINES keys only, so it never consulted ALIASES — while every other engine surface does resolve them via resolveEngine():

$ moshcode agents cc   →  claude agents --dangerously-skip-permissions   ✓
$ moshcode start cc    →  claude                                         ✓
$ moshcode upgrade cc  →  ✓  (README: "just one engine (name any; alias ok)")
$ ai("say hi", { engine: "cc" })  →  ✗ "needs an installed engine"

Under --dry-run it fails differently and worse. The fallback handed the raw alias to aiExecArgs(), which throws:

$ moshcode run alias.mosh --dry-run
moshscript: ai() has no headless mode for "cc"

That contradicts the intent stated on the line above it — "narrate without requiring an installed engine". A dry run should never need an engine to be present.

Repro (executed against dfcb8c1, not reasoned)

A stub claude on PATH, and alias.mosh:

const out = ai("say hi", { engine: "cc" });
say(out);
resolveEngine("cc")   -> claude      # alias resolves
isInstalled("claude") -> true        # engine is installed
pickAiEngine("cc")    -> null        # …but ai() can't see it

$ moshcode run alias.mosh            →  moshscript: ai() needs an installed engine
$ moshcode run alias.mosh --dry-run  →  moshscript: ai() has no headless mode for "cc"

The fix

Deliberately unchanged:

  • an unknown preference still yields null (pickAiEngine("definitely-not-an-engine"), pickAiEngine("constructor"));
  • a named-but-not-installed engine still refuses to silently fall back to a different one (pickAiEngine("gemini")null when Gemini is absent);
  • no preference → the same claude, codex, opencode, gemini, aider order;
  • aiExecArgs() stays strict, so a genuinely unknown engine name still throws in a dry run.

After the fix:

$ moshcode run alias.mosh            →  🧠 ai() → claude: say hi
$ moshcode run alias.mosh --dry-run  →  🧠 ai("say hi") → would run: claude -p say hi

Tests

Two added, both fail before / pass after (stash-verified with git stash push -- src/: 50 pass / 2 fail unpatched, 52/52 with the fix):

  • test/engines.test.mjspickAiEngine resolves cc and claude-code to claude against a stub engine on PATH, and still returns null for an unknown name.
  • test/cli.test.mjs — a dry-run ai() with { engine: "cc" } narrates would run: claude -p instead of throwing.

Full suite npm test: 199 tests / 199 pass / 0 fail (197 before this change).

`ai(prompt, { engine: "cc" })` failed with "ai() needs an installed engine"
even with Claude installed, because pickAiEngine() matched raw ENGINES keys and
never consulted ALIASES — while /agents, start and upgrade all resolve aliases
(README: "name any; alias ok"). Under --dry-run it was worse: the raw alias
reached aiExecArgs() and threw "no headless mode", though a dry run is meant to
narrate without requiring an installed engine.

Resolve the preference through resolveEngine() and let the dry-run fallback do
the same. An unknown name still yields null, and a named-but-not-installed
engine still refuses to fall back to another one.
@clawedassistant26

Copy link
Copy Markdown
Contributor Author

Rebased on main to clear the conflict with #74. The clash was in pickAiEngine: #74 added privacycode to the default order, this PR changed the preferred branch to resolve aliases first. Resolved so both hold, alias resolution on the preferred path and privacycode kept in the default order. Full suite green after the rebase, 206 tests across 6 suites, 0 failures, and CI is passing.

@ralyodio
ralyodio merged commit 37904ed into moshcoder:main Jul 30, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants