feat(cli): implement iterate agents list — detect installed AI CLIs#465
feat(cli): implement iterate agents list — detect installed AI CLIs#465forgou37 wants to merge 1 commit into
iterate agents list — detect installed AI CLIs#465Conversation
Replaces the hardcoded stub in `sh1pt iterate agents list` with real binary detection: - Runs `<binary> --version` for each known agent (claude, codex, qwen) via exec() - Reports installed status and version, or install hint if missing - Supports --json flag for scripting Closes profullstack#464.
Greptile SummaryThis PR replaces the hardcoded stub in
Confidence Score: 3/5The change adds no destructive side-effects, but the core feature — displaying the installed version — will produce visually broken output for every agent because the raw CLI version string is re-prefixed with The version string captured from stdout is the full, unparsed output of packages/cli/src/commands/agents.ts — version parsing and exit-code handling in Important Files Changed
Reviews (1): Last reviewed commit: "feat(cli): implement iterate agents list..." | Re-trigger Greptile |
| return { | ||
| id: agent.id, | ||
| installed: true, | ||
| version: result.stdout.trim() || undefined, | ||
| installHint: agent.installHint, | ||
| authHint: agent.authHint, | ||
| }; |
There was a problem hiding this comment.
The
v prefix is prepended to the raw, un-parsed stdout of --version. In practice claude --version outputs something like "Claude Code 1.2.3" (the full tool name), so the displayed string becomes vClaude Code 1.2.3 — not the clean v1.2.3 the PR description promises. The JSON output has the same issue: version contains the entire first-line dump rather than just the semver. A simple regex extracts the version number regardless of the prefix the CLI adds.
| return { | |
| id: agent.id, | |
| installed: true, | |
| version: result.stdout.trim() || undefined, | |
| installHint: agent.installHint, | |
| authHint: agent.authHint, | |
| }; | |
| const rawOut = result.stdout.trim() || result.stderr.trim(); | |
| const semverMatch = rawOut.match(/\d+\.\d+\.\d+[\w.-]*/); | |
| return { | |
| id: agent.id, | |
| installed: true, | |
| version: semverMatch ? semverMatch[0] : rawOut || undefined, | |
| installHint: agent.installHint, | |
| authHint: agent.authHint, | |
| }; |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| if (result.exitCode === 0) { | ||
| return { | ||
| id: agent.id, | ||
| installed: true, | ||
| version: result.stdout.trim() || undefined, | ||
| installHint: agent.installHint, | ||
| authHint: agent.authHint, | ||
| }; | ||
| } | ||
| } catch { | ||
| // binary not found | ||
| } |
There was a problem hiding this comment.
When a binary exists on PATH but
--version exits with a non-zero code, the function falls through the if (result.exitCode === 0) guard and returns installed: false. A handful of real CLIs (including some versions of codex) exit non-zero for --version. Treating any successful resolution (i.e., the process started at all) as installed would be more robust, since ENOENT is already handled by the outer catch.
| if (result.exitCode === 0) { | |
| return { | |
| id: agent.id, | |
| installed: true, | |
| version: result.stdout.trim() || undefined, | |
| installHint: agent.installHint, | |
| authHint: agent.authHint, | |
| }; | |
| } | |
| } catch { | |
| // binary not found | |
| } | |
| // Binary was found (spawn succeeded); non-zero exit for --version is still "installed". | |
| const rawOut = (result.stdout.trim() || result.stderr.trim()); | |
| const semverMatch = rawOut.match(/\d+\.\d+\.\d+[\w.-]*/); | |
| return { | |
| id: agent.id, | |
| installed: true, | |
| version: semverMatch ? semverMatch[0] : rawOut || undefined, | |
| installHint: agent.installHint, | |
| authHint: agent.authHint, | |
| }; | |
| } catch { | |
| // binary not found (ENOENT) or other spawn error | |
| } |
Closes #464.
Summary
Replaces the hardcoded stub in
sh1pt iterate agents listwith real binary detection.Before
After
Changes
<binary> --versionviaexec()from@profullstack/sh1pt-corefor each known agent--jsonflag output now contains real data, not placeholder stubs