Skip to content

Spawn the detected absolute CLI path instead of the bare binary name #104

@chorus-codes

Description

@chorus-codes

Background

Surfaced during the #98 (Kimi Code detection) review series. Two independent reviewers (codex, gemini) flagged it.

runHeadless spawns CLIs by bare name (command: 'kimi', 'opencode', 'grok', …), resolved against the daemon's merged spawn PATH. Detection (cli-detect.ts), however, resolves a concrete absolute path (PATH lookup, then a fallback-dir scan). These two resolutions can disagree:

  1. ENOENT — a CLI detected only via the fallback-dir scan (its install dir isn't on the spawn PATH) can't be spawned by bare name. (Mitigated for known dot-dirs by keeping runtime-path.ts:KNOWN_INSTALL_DIRS in sync with fallbackPathsfix(runtime-path): add ~/.kimi-code/bin + ~/.grok/bin to spawn PATH (#98) #102 — but that's a manual sync, not a guarantee.)
  2. Split-brain / shadowing — when two same-named binaries exist (e.g. legacy Python ~/.kimi/bin/kimi on the interactive PATH and native ~/.kimi-code/bin/kimi), detection may resolve one while bare-name spawn resolves the other based on PATH order. The transport decision now keys on the detected path (fix(kimi): key transport on the resolved binary, not ~/.kimi-code existence #101), but the actual spawn still uses the bare name — so the binary that runs may differ from the one the decision was made about.

Proposed fix

Thread the detected absolute path (already available from detectAllClis() / the cli_paths cache) into runHeadless and spawn that instead of the bare name. This makes detection and execution share one source of truth and eliminates both the ENOENT and shadowing classes. Needs care for: Windows .cmd/.bat resolution (see buildVersionSpawn), the existing PATH-prepend logic, and per-shim spawn sites.

Why separate

Larger than the #98 fixes (touches the spawn layer + every shim) and benefits from its own test pass. The #98 follow-ups (#101 transport decision, #102 spawn-PATH coverage) make the common cases correct; this is the structural fix.

Refs: #98, PR #101, PR #102.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions