mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 05:59:43 +02:00
fix(pi): align the doctor with the pi resolver, correct the strip rationale, update the skill
Second review pass on #282, the three items left open after f4dcfbe.
1. `codeman doctor` and the run mode disagreed about pi. The registry entry
accepted a bare `which pi` hit while pi-cli-resolver demanded semver-shaped
`--version` output, so the Dependencies panel could report an installed Pi CLI
on a box where Run Pi stays hidden, which reads as a broken mode rather than a
missing install. Both sides now share one exported PI_VERSION_REGEX, and
PathResolver gains an opt-in `requireVersionMatch` so a binary that fails the
shape check is reported MISSING instead of installed-with-unknown-version.
Only pi sets it; every other tool keeps its current behaviour.
2. The isAltScreenStripMode comment justified excluding pi with "the alt screen
is load-bearing for its fullscreen TUI". That is not what exclusion does: pi
is tmux-backed, so it falls through to isMuxAltScreenOnlyStripMode, which
strips the alt-screen toggles anyway. What exclusion actually preserves is
`\x1b[3J` and the mouse DECSETs, which is the real reason (pi renders into the
main screen and is mouse-aware). Comment and changeset now say that, and state
the consequence: fullscreen pi paints into the main buffer, like vim in a tmux
shell session.
3. skills/codeman still enumerated the five pre-pi modes in nine places, telling
agents a backend does not exist and understating class-wide caveats by one
mode. All updated, plus stale session.ts line references refreshed.
Tests: a new static guard derives the mode set from the Zod schema (not a copy)
and fails when a skill enumeration lists a partial set of external CLIs, verified
by mutation. It also documents the one legitimate exception it found: the "writes
no transcript" lists drop codex, which does write a rollout Codeman reads back.
Plus doctor cases for an unrelated `pi` on PATH and registry/resolver regex parity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -94,12 +94,17 @@ export function checkTool(tool: ToolDependency, host: ProbeHost): ToolResult {
|
||||
if (!spec) return { ...base, status: 'skipped', reason: `not applicable on ${host.environment}` };
|
||||
|
||||
if (spec.resolver.kind === 'path') {
|
||||
const { bins, versionArg, versionRegex } = spec.resolver;
|
||||
const { bins, versionArg, versionRegex, requireVersionMatch } = spec.resolver;
|
||||
for (const bin of bins) {
|
||||
const resolved = host.which(bin);
|
||||
if (resolved) {
|
||||
const out = host.runVersion(bin, [versionArg ?? '--version']);
|
||||
const version = out ? extractVersion(out, versionRegex) : undefined;
|
||||
// A generic binary name that prints the wrong thing is some OTHER program (see
|
||||
// PathResolver.requireVersionMatch). Keep looking, then report MISSING; the
|
||||
// alternative is claiming a tool is installed that the feature's own resolver
|
||||
// rejects, which reads as "the mode is broken" rather than "install it".
|
||||
if (requireVersionMatch && !version) continue;
|
||||
return finalize(base, tool, resolved, version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,20 @@ const PI_SEARCH_DIRS = [
|
||||
join(homedir(), 'bin'),
|
||||
];
|
||||
|
||||
/** A real `pi --version` prints a semver-shaped string (e.g. `0.84.1`). */
|
||||
const PI_VERSION_PATTERN = /^\d+\.\d+\.\d+/;
|
||||
/**
|
||||
* A real `pi --version` prints a semver-shaped string (e.g. `0.84.1`).
|
||||
*
|
||||
* Exported and SHARED with the `pi` entry in `config/dependency-registry.ts`, so
|
||||
* `codeman doctor` and the run mode cannot disagree about what counts as an installed
|
||||
* pi: two copies of this rule would let the Dependencies panel report "Pi CLI ✓" on a
|
||||
* box where `resolvePiDir()` rejects the same binary and Run Pi stays hidden.
|
||||
*
|
||||
* Shape is dictated by the doctor's `extractVersion()`, which returns the first CAPTURE
|
||||
* GROUP and scans the whole output: hence a capturing group, and a leading boundary
|
||||
* instead of `^` so `pi 0.84.1` matches while `v0.84.1` (some other program) does not.
|
||||
* No `g` flag, so there is no shared `lastIndex` to reset.
|
||||
*/
|
||||
export const PI_VERSION_REGEX = /(?:^|\s)(\d+\.\d+\.\d+)/;
|
||||
|
||||
/** Cached directory containing the pi binary (empty string = searched but not found) */
|
||||
let _piDir: string | null = null;
|
||||
@@ -56,7 +68,7 @@ function probePiVersion(binPath: string): string | null {
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
}).trim();
|
||||
// Upstream prints a bare version today; tolerate a `pi 0.84.1` style prefix too.
|
||||
const candidate = out.split(/\s+/).find((token) => PI_VERSION_PATTERN.test(token));
|
||||
const candidate = PI_VERSION_REGEX.exec(out)?.[1];
|
||||
if (candidate) return candidate;
|
||||
console.warn(`[PiResolver] Ignoring ${binPath}: "pi --version" printed ${JSON.stringify(out.slice(0, 80))}`);
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user