Skip to content

feat(cli): implement iterate agents list — detect installed AI CLIs#465

Open
forgou37 wants to merge 1 commit into
profullstack:masterfrom
forgou37:feat/agents-list-detect-v2
Open

feat(cli): implement iterate agents list — detect installed AI CLIs#465
forgou37 wants to merge 1 commit into
profullstack:masterfrom
forgou37:feat/agents-list-detect-v2

Conversation

@forgou37
Copy link
Copy Markdown
Contributor

Closes #464.

Summary

Replaces the hardcoded stub in sh1pt iterate agents list with real binary detection.

Before

$ sh1pt iterate agents list
  ○ claude  run `sh1pt agents setup --agent claude`
  ○ codex   run `sh1pt agents setup --agent codex`
  ○ qwen    run `sh1pt agents setup --agent qwen`

After

$ sh1pt iterate agents list
  ● claude  v1.2.3
  ○ codex   not installed — npm install -g @openai/codex
  ○ qwen    not installed — pip install qwen-agent

1/3 agent(s) installed. Run `sh1pt agents setup` to install missing agents.

$ sh1pt iterate agents list --json
[
  { "id": "claude", "installed": true, "version": "1.2.3", ... },
  ...
]

Changes

  • Runs <binary> --version via exec() from @profullstack/sh1pt-core for each known agent
  • Returns real installation status with version string when available
  • Falls back to install hint + setup command when not found
  • --json flag output now contains real data, not placeholder stubs

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-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 29, 2026

Greptile Summary

This PR replaces the hardcoded stub in sh1pt iterate agents list with real binary detection, running <binary> --version via exec() for each known agent and reporting installation status with version and install hints.

  • checkAgent now spawns each CLI binary and captures stdout to populate installed and version fields, with --json output reflecting real data.
  • The raw stdout from --version (e.g. \"Claude Code 1.2.3\") is used as-is for the version field and then prefixed with v in the display, producing output like vClaude Code 1.2.3 instead of the intended v1.2.3; this affects both the human-readable output and the JSON payload.
  • A binary that exits non-zero from --version (even though it is on PATH) is silently treated as not installed, which can produce a false negative.

Confidence Score: 3/5

The 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 v.

The version string captured from stdout is the full, unparsed output of --version (e.g. "Claude Code 1.2.3"), yet the display code prepends another v, yielding vClaude Code 1.2.3. This means the primary new capability of the feature — showing the installed version cleanly — does not work correctly for any of the three listed agents. Additionally, a binary that returns a non-zero exit code for --version will be incorrectly listed as not installed.

packages/cli/src/commands/agents.ts — version parsing and exit-code handling in checkAgent

Important Files Changed

Filename Overview
packages/cli/src/commands/agents.ts Replaces hardcoded stub with real binary detection via exec(); version string is taken directly from raw stdout and prefixed with v, producing malformed output like vClaude Code 1.2.3; non-zero --version exit codes also incorrectly mark a binary as not installed.

Reviews (1): Last reviewed commit: "feat(cli): implement iterate agents list..." | Re-trigger Greptile

Comment on lines +53 to +59
return {
id: agent.id,
installed: true,
version: result.stdout.trim() || undefined,
installHint: agent.installHint,
authHint: agent.authHint,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Suggested change
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!

Comment on lines +52 to +63
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
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Suggested change
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
}

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.

feat(cli): implement iterate agents list — detect installed AI agent CLIs

1 participant