@descent-vtt/spec-harness 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +75 -0
  4. package/README.md +18 -3
  5. package/dist/answers.d.ts +6 -0
  6. package/dist/answers.js +12 -1
  7. package/dist/answers.js.map +1 -1
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.js +81 -43
  10. package/dist/cli.js.map +1 -1
  11. package/dist/commands.js +1 -0
  12. package/dist/commands.js.map +1 -1
  13. package/dist/configure.d.ts +58 -2
  14. package/dist/configure.js +116 -3
  15. package/dist/configure.js.map +1 -1
  16. package/dist/context.d.ts +16 -7
  17. package/dist/context.js +36 -11
  18. package/dist/context.js.map +1 -1
  19. package/dist/fs.js +1 -0
  20. package/dist/fs.js.map +1 -1
  21. package/dist/git.js +2 -1
  22. package/dist/git.js.map +1 -1
  23. package/dist/hooks.js.map +1 -1
  24. package/dist/host.js.map +1 -1
  25. package/dist/literal.d.ts +18 -0
  26. package/dist/literal.js +21 -0
  27. package/dist/literal.js.map +1 -0
  28. package/dist/probe.js +1 -1
  29. package/dist/probe.js.map +1 -1
  30. package/dist/reader.js +2 -0
  31. package/dist/reader.js.map +1 -1
  32. package/dist/round.d.ts +12 -1
  33. package/dist/round.js +23 -7
  34. package/dist/round.js.map +1 -1
  35. package/dist/sandbox.js.map +1 -1
  36. package/dist/server.js +2 -1
  37. package/dist/server.js.map +1 -1
  38. package/dist/setup.js +2 -1
  39. package/dist/setup.js.map +1 -1
  40. package/dist/siblings.js +2 -1
  41. package/dist/siblings.js.map +1 -1
  42. package/dist/signers.js +5 -0
  43. package/dist/signers.js.map +1 -1
  44. package/dist/usage.d.ts +83 -27
  45. package/dist/usage.js +61 -16
  46. package/dist/usage.js.map +1 -1
  47. package/dist/versions.js +3 -0
  48. package/dist/versions.js.map +1 -1
  49. package/dist/workspace.d.ts +9 -0
  50. package/dist/workspace.js +48 -32
  51. package/dist/workspace.js.map +1 -1
  52. package/package.json +3 -3
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The command line: arguments, dispatch, output and exit codes.\n *\n * Exit 0: done, nothing refused. Exit 1: something refused or found. Exit 2:\n * the answer cannot be trusted - a bad flag, an option, an argument or a\n * value that names nothing, a configuration that does not load, a sibling\n * that is missing or printed something unreadable, a git command that\n * failed, an output its reader closed, an error nothing here expected. A run\n * that could not look must never exit as though it looked and found nothing\n * (spec-core ADR-0005).\n */\n\nimport { SiblingOutputError } from './briefs.js';\nimport { auditCommand, contextCommand, escalateCommand, probeCommand, ruleCommand, rulingsCommand } from './commands.js';\nimport { ConfigError, SIBLINGS } from './config.js';\nimport {\n describeBase,\n describeClaudeCode,\n describeClaudeRelease,\n describeGitHook,\n describePlugin,\n describeSignerKeys,\n describeSignerProblem,\n describeSigners,\n wiringState,\n} from './configure.js';\nimport { isDirectory } from './fs.js';\nimport { GitError, show, stagedChanges } from './git.js';\nimport type { Decision } from './guard.js';\nimport { claudeResponse, gitResponse, parseClaudeHook } from './hooks.js';\nimport { claudeVersion } from './host.js';\nimport { premisesCommand } from './premises.js';\nimport { createReader } from './reader.js';\nimport { checkPaths, claudeCodeWiring, resolveBase, specBriefPlugin, type Base } from './round.js';\nimport { mcpCommand } from './server.js';\nimport { gitHook, initCommand } from './setup.js';\nimport { notFido2, readAllowedSigners } from './signers.js';\nimport { SiblingError } from './siblings.js';\nimport { emptyValue, isBlank, noDirectory, refusal, type Command } from './usage.js';\nimport { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';\nimport {\n activeBrief,\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n namedId,\n openWorkspace,\n parseOptions,\n UsageError,\n version,\n type CliIO,\n type Options,\n type Workspace,\n} from './workspace.js';\n\nexport { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';\n\nexport const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work\n\nUsage:\n spec-harness <command> [options]\n\nCommands:\n context [brief] What an agent needs to start a round: the brief, its scope,\n rulings, dependencies, the rules in force, the cited documents.\n guard <path...> May the round write these paths? Exit 1 if one is refused.\n hook claude Answer a Claude Code PreToolUse or PostToolUse hook (stdin).\n hook git Answer git's pre-commit hook for the staged files.\n escalate Ask a person to rule: --path <file> (repeatable) --reason <why>\n [--option \"<label>: <cost>\"]... [--recommend <text>].\n --list shows what waits; --show <id> prints one memo. Neither\n raises a request: beside one, only --root and --format are read.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note <text>. It counts once committed signed.\n rulings [brief] The brief's rulings, and whether each one's signature verifies.\n audit [brief] Did the round stay inside the lines: what the archive would say,\n the brief's assertions, unverified rulings, new dependencies\n and the install scripts it allowed.\n probe [brief] Run the brief's probes: red at the base, green at the head.\n --at <base|head|both>, --id <probe>.\n premises Do the live briefs' premises still hold? For CI: exit 1 when one\n is stale, or, with --strict, when spec-guard cannot read one.\n init Configure the spec-* tools to agree. Prints the plan; --write\n applies it; --git-hook adds a pre-commit hook.\n mcp Serve start_round, check_path, request_escalation, audit_round,\n list_rounds and the workflow prompts over MCP on stdio.\n doctor Which siblings are installed, at which versions, which brief is\n named, how Claude Code runs the guard, and git's hook. Exit 1\n when a sibling is older than this release needs, the guard is\n installed twice, or Claude Code is too old to run its hooks.\n\nOptions:\n --brief <id> The brief the round works on. Otherwise SPEC_BRIEF, then the branch.\n For context, guard, hook, escalate, rulings, audit, probe, premises\n and doctor.\n --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch. For context,\n guard, hook, rulings, audit, probe and doctor.\n --root <dir> Run from another directory, which must exist. For every command.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n For every command but hook and mcp.\n --strict Warnings fail the run. For guard, audit, premises and doctor.\n --help, --version\n\nAn option a command does not read, an argument it does not take, an option or an\nargument given an empty value, and a brief given both as the argument and as --brief\nare refused, exit 2, not read as if they were not there. doctor says an empty --brief\nor --base in its report. hook claude reads its line as every release has, and says a\n--root that is not a directory with exit 1, refusing nothing.\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n`;\n\n\n/* ------------------------------------------------------------------- guard */\n\nconst reader = createReader();\n\nasync function decisionsFor(\n workspace: Workspace,\n options: Options,\n io: CliIO,\n given: readonly string[],\n cwd: string,\n): Promise<{ readonly decisions: Decision[] } | { readonly problem: string }> {\n const active = await activeBrief(workspace, options, io.env);\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) return { problem };\n return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };\n}\n\nconst SYMBOL: Record<Decision['verdict'], string> = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };\n\nasync function guardCommand(options: Options, io: CliIO): Promise<number> {\n if (options.positionals.length === 0) throw new UsageError('guard needs at least one path');\n const workspace = await openWorkspace(options, io);\n const decided = await decisionsFor(workspace, options, io, options.positionals, io.cwd);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const { decisions } = decided;\n if (options.format === 'json') {\n io.stdout.write(json('guard', { decisions }));\n } else {\n for (const decision of decisions) {\n io.stdout.write(`${SYMBOL[decision.verdict]} ${decision.message}\\n`);\n if (decision.verdict !== 'allow') io.stdout.write(` ${decision.hint}\\n`);\n }\n }\n const refused = decisions.some((d) => d.verdict === 'deny' || d.verdict === 'ask');\n const warned = decisions.some((d) => d.verdict === 'warn');\n return refused || (options.strict && warned) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------------- hook */\n\nasync function readStdin(io: CliIO): Promise<string> {\n // Only the built command line reads process.stdin, and the suite spawns it\n // from dist/, outside the sweep (tests/integration/claude-code.test.ts): the\n // lines below survive it untested in-process.\n if (io.stdin !== undefined) return io.stdin();\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n}\n\nasync function hookCommand(options: Options, io: CliIO): Promise<number> {\n const kind = options.positionals[0];\n if (kind === 'claude') {\n let question: string;\n try {\n question = await readStdin(io);\n } catch (error) {\n // A question that could not be read is one the hook cannot see, as one\n // it cannot parse is, below: it has no event to hold a write by.\n io.stderr.write(`spec-harness: the hook input could not be read: ${(error as Error).message}\\n`);\n return EXIT_FAILED;\n }\n const request = parseClaudeHook(question);\n if ('error' in request) {\n // A hook that cannot read its question refuses nothing it cannot see,\n // but says so where the person reads it: a non-blocking error.\n io.stderr.write(`spec-harness: ${request.error}\\n`);\n return EXIT_FAILED;\n }\n if (request.paths.length === 0) return EXIT_OK;\n // An empty root is the directory the hook was started in: git starts\n // there when it is handed no directory, so the hook has guarded there\n // for an empty root in every release.\n const root = options.root === '' ? io.cwd : options.root;\n // A root written on the hook's line that is a file, or is not there: git\n // starts in neither, which read as a session outside a work tree, exit 0\n // and no word, and the guard someone had configured was off. It is said,\n // and refuses nothing: exit 1 is to Claude Code an error that does not\n // block, whose first line of stderr it shows the person, where exit 2\n // would hold every write of the session, the one that mends the line\n // among them (ADR-0005).\n if (root !== undefined && !isDirectory(root)) {\n io.stderr.write(\n `spec-harness: ${noDirectory(root)}, so the guard is off and this write is not checked; give the hook's line a directory that exists, or leave --root out for the project Claude Code names\\n`,\n );\n return EXIT_FAILED;\n }\n const cwd = request.cwd ?? io.cwd;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ ...options, root: root ?? io.env['CLAUDE_PROJECT_DIR'] ?? cwd }, io);\n } catch (error) {\n if (error instanceof UsageError) return EXIT_OK;\n throw error;\n }\n try {\n const decided = await decisionsFor(workspace, options, io, request.paths, cwd);\n if ('problem' in decided) {\n // Exit 2 blocks the tool call, and its stderr reaches the model.\n io.stderr.write(`spec-harness: ${decided.problem}. Fix the brief or the branch before writing.\\n`);\n return EXIT_ERROR;\n }\n const response = claudeResponse(request.event, decided.decisions);\n io.stdout.write(response.stdout);\n return response.exitCode;\n } catch (error) {\n if (request.event !== 'PreToolUse') throw error;\n // A round is named and its briefs cannot be read: the guard cannot\n // tell a protected file from any other, so the write waits.\n io.stderr.write(`spec-harness: cannot check this write: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n }\n if (kind === 'git') {\n const workspace = await openWorkspace(options, io);\n const staged = await stagedChanges(workspace.root);\n const paths = staged.flatMap((change) => (change.from === undefined ? [change.path] : [change.from, change.path]));\n if (paths.length === 0) return EXIT_OK;\n const decided = await decisionsFor(workspace, options, io, paths, workspace.root);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const response = gitResponse(decided.decisions);\n io.stderr.write(response.text);\n return response.exitCode;\n }\n throw new UsageError('hook takes \"claude\" or \"git\"');\n}\n\n/* ------------------------------------------------------------------ doctor */\n\n/**\n * The brief a round here works on, as doctor reports it: its id, and what is\n * wrong with the name when no round can work under it. Every other command\n * stops there. A diagnosis says it, being what a person runs when the guard\n * holds a write they expected it to pass.\n */\nasync function diagnoseBrief(workspace: Workspace, options: Options, env: CliIO['env']): Promise<{ readonly id: string | null; readonly problem: string | null }> {\n if (options.brief !== undefined && isBlank(options.brief)) return { id: null, problem: emptyValue('--brief', 'brief', options.brief) };\n const id = namedId(workspace, options, env);\n // A spec-brief that cannot be run is a row of the report, with the reason.\n if (workspace.siblings.locate('spec-brief').kind !== 'found') return { id, problem: null };\n try {\n // Where nothing names a brief, spec-brief is not asked (ADR-0004), and\n // there is no problem to state.\n return { id, problem: describeActive(await activeBrief(workspace, options, env)).problem };\n } catch (error) {\n // Asking spec-brief throws nothing but this, so the check is equivalent\n // to its mutant; it keeps any other error the stack it needs.\n if (!(error instanceof SiblingError)) throw error;\n return { id, problem: `spec-brief could not say whether it knows brief ${id}: ${error.message}` };\n }\n}\n\nasync function doctorCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const rows = SIBLINGS.map((name) => {\n const sibling = workspace.siblings.locate(name);\n const row = { tool: name, state: sibling.kind, minimum: MINIMUM_VERSIONS[name] };\n if (sibling.kind === 'absent') return { ...row, version: null, detail: sibling.reason };\n if (sibling.kind === 'outdated') return { ...row, version: sibling.version, detail: sibling.reason };\n const command = sibling.command.join(' ');\n const detail = sibling.version === null ? `${command} (named in .spec-harness.json; its version is not checked)` : `${command} (${sibling.version})`;\n return { ...row, version: sibling.version, detail };\n });\n const named = await diagnoseBrief(workspace, options, io.env);\n // A ruling counts only by a signature checked against the allowed signers\n // on the base, and only once spec-brief's archive asks the plugin about it.\n // A --base given nothing is no base, said as the brief's is, in the report.\n // Nothing below asks what kind a base is but whether it is resolved, so the\n // mutant that names this one otherwise is equivalent.\n const base: Base =\n options.base !== undefined && isBlank(options.base)\n ? { kind: 'unresolved', reason: emptyValue('--base', 'base', options.base) }\n : await resolveBase(workspace, options.base);\n const signersFile = workspace.config.rulings.allowedSigners;\n // An unresolved base has no commit: git shows nothing for one, so asking\n // anyway reads as no file, and that mutant is equivalent.\n const signersText = base.kind === 'resolved' ? await show(base.sha, signersFile, workspace.root) : null;\n const onBase = base.kind === 'resolved' ? signersText !== null : null;\n const signers = describeSigners(signersFile, base.kind === 'resolved' ? base.ref : null, onBase === true);\n // Which keys sign, as notes: a key that is not FIDO2 can still be one the\n // agent cannot use, and a PIV key reads as a plain one (ADR-0006).\n const read = readAllowedSigners(signersText ?? '');\n const plain = notFido2(read.signers);\n const signerNotes = [describeSignerKeys(plain), ...read.problems.map(describeSignerProblem)].filter((note): note is string => note !== null);\n const plugin = await specBriefPlugin(workspace.root);\n // The plugin and init's entries both on: Claude Code runs every guard twice\n // and registers the server twice (ADR-0012).\n const wiring = await claudeCodeWiring(workspace.root, io.env);\n const claude = wiringState(wiring);\n // Only a Claude Code that runs the guard is asked its release: one older\n // than the hooks need lets every write through unguarded.\n const release = claude === 'none' ? null : checkClaudeCode(await claudeVersion(io.env));\n // How the hook runs the harness is a note: one that goes through npx guards\n // as well as one that does not, and fails nothing, --strict or not.\n const { hook, note: hookNote } = await gitHook(workspace.root);\n const branch = workspace.branch === null ? '(detached)' : `${workspace.branch}${workspace.branchSource === undefined ? '' : ` (detached; ${workspace.branchSource} names it)`}`;\n if (options.format === 'json') {\n io.stdout.write(\n json('doctor', {\n root: workspace.root,\n branch: workspace.branch,\n branchSource: workspace.branchSource ?? null,\n brief: named.id,\n briefProblem: named.problem,\n base: base.kind === 'resolved' ? { ref: base.ref, source: base.source, mergeBase: base.mergeBase } : { unresolved: base.reason },\n allowedSigners: {\n file: signersFile,\n onBase,\n detail: signers,\n notFido2: plain.map(({ line, principals, keyType }) => ({ line, principals, keyType })),\n problems: read.problems,\n },\n plugin: { state: plugin.kind, file: 'file' in plugin ? plugin.file : null, detail: describePlugin(plugin) },\n claudeCode: {\n state: claude,\n ...wiring,\n detail: describeClaudeCode(wiring),\n release:\n release === null\n ? { state: 'unchecked', version: null, minimum: CLAUDE_CODE_MINIMUM, detail: 'not asked: nothing wires Claude Code to the guard here' }\n : { state: release.state, version: 'version' in release ? release.version : null, minimum: CLAUDE_CODE_MINIMUM, detail: describeClaudeRelease(release) },\n },\n gitHook: { state: hook.state, file: 'file' in hook ? hook.file : null, detail: describeGitHook(hook), note: hookNote },\n siblings: rows,\n }),\n );\n } else {\n const more = (notes: readonly string[]): string[] => notes.map((note) => ` ${note}`);\n io.stdout.write(\n [\n `root ${workspace.root}`,\n `branch ${branch}`,\n `brief ${named.problem === null ? (named.id ?? '(none named)') : `none: ${named.problem}`}`,\n `base ${describeBase(base)}`,\n `signers ${signers}`,\n ...more(signerNotes),\n `plugin ${describePlugin(plugin)}`,\n `claude ${describeClaudeCode(wiring)}`,\n ...more(release === null ? [] : [describeClaudeRelease(release)]),\n `git ${describeGitHook(hook)}`,\n ...more(hookNote === null ? [] : [hookNote]),\n '',\n '',\n ].join('\\n'),\n );\n for (const row of rows) io.stdout.write(`${row.state.padEnd(8)} ${row.tool.padEnd(10)} ${row.detail}\\n`);\n }\n // An outdated sibling is a problem to fix, where a missing optional one is\n // a choice; with none installed, the harness can check nothing. A double\n // install is a problem too, where no Claude Code wiring at all is a choice,\n // and so is a Claude Code too old to run the hooks. One whose release\n // cannot be told is not fine either: --strict fails it.\n const outdated = rows.some((row) => row.state === 'outdated');\n const usable = rows.some((row) => row.state === 'found');\n const tooOld = release?.state === 'outdated';\n const untold = options.strict && release?.state === 'unknown';\n return outdated || !usable || claude === 'both' || tooOld || untold ? EXIT_FAILED : EXIT_OK;\n}\n\n/* ---------------------------------------------------------------- dispatch */\n\n/**\n * A map, because the command is the first word a person types and an object\n * answers to more names than it was given: `spec-harness constructor` ran\n * `Object` as a command and ended on a stack trace, where `spec-harness\n * construct` is an unknown command with exit 2.\n */\nconst COMMANDS: ReadonlyMap<string, (options: Options, io: CliIO) => Promise<number>> = new Map(\n // One for every command that has a shape (usage.ts), which the compiler holds.\n Object.entries({\n guard: guardCommand,\n hook: hookCommand,\n context: contextCommand,\n audit: auditCommand,\n escalate: escalateCommand,\n rule: ruleCommand,\n rulings: rulingsCommand,\n probe: probeCommand,\n premises: premisesCommand,\n init: initCommand,\n mcp: mcpCommand,\n doctor: doctorCommand,\n } satisfies Record<Command, (options: Options, io: CliIO) => Promise<number>>),\n);\n\nasync function dispatch(argv: readonly string[], io: CliIO): Promise<number> {\n let options: Options;\n try {\n options = parseOptions(argv);\n } catch (error) {\n io.stderr.write(`spec-harness: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n if (options.version) {\n io.stdout.write(`${version()}\\n`);\n return EXIT_OK;\n }\n if (options.help || options.command === undefined) {\n io.stdout.write(HELP);\n return options.help ? EXIT_OK : EXIT_ERROR;\n }\n const command = COMMANDS.get(options.command);\n if (command === undefined) {\n io.stderr.write(`spec-harness: unknown command \"${options.command}\"; see spec-harness --help\\n`);\n return EXIT_ERROR;\n }\n // What parsed and names nothing, before anything is read or written for it.\n const refused = refusal(options, isDirectory);\n if (refused !== null) {\n io.stderr.write(`spec-harness: ${refused}\\n`);\n return EXIT_ERROR;\n }\n return command(options, io);\n}\n\n/**\n * Runs the command line and resolves to the exit code, for an error nothing\n * below expected too.\n *\n * Such an error is neither a refusal nor a finding: the answer cannot be\n * trusted, which is exit 2 (spec-core ADR-0005). Rejected instead, it reached\n * the launcher as Node's uncaught error, exit 1, \"refused or found something\"\n * to a script, and to Claude Code a hook that failed without blocking: the\n * write the guard could not check went ahead. The stack is what makes a\n * report of it something to act on, and it goes to stderr alone: a script\n * that reads a document from stdout is handed no part of one.\n *\n * A write its reader had closed the pipe for is not such an error: the answer\n * was not delivered, which is still 2, and nothing in the harness is at\n * fault, so it is said in a line and no stack sends a person looking for a\n * defect. The process's own streams report it as an event, which the\n * launcher answers in the same words; here it is a caller's stream that\n * throws it. It is read by its code: stdout and stderr are the only pipes\n * the harness writes to.\n */\nexport async function run(argv: readonly string[], io: CliIO): Promise<number> {\n try {\n return await dispatch(argv, io);\n } catch (error) {\n // A sibling's document of a shape the harness does not read is a sibling\n // that printed something it cannot read (answers.ts): exit 2. A git\n // command that failed is what git said, and no line of the harness's.\n if (\n error instanceof UsageError ||\n error instanceof ConfigError ||\n error instanceof SiblingError ||\n error instanceof SiblingOutputError ||\n error instanceof GitError\n ) {\n io.stderr.write(`spec-harness: ${error.message}\\n`);\n return EXIT_ERROR;\n }\n if (!(error instanceof Error)) io.stderr.write(`spec-harness: unexpected error: ${String(error)}\\n`);\n else if ((error as NodeJS.ErrnoException).code === 'EPIPE') io.stderr.write('spec-harness: stdout was closed before all of the output was written\\n');\n else io.stderr.write(`spec-harness: unexpected error: ${error.stack ?? error.message}\\n`);\n return EXIT_ERROR;\n }\n}\n\n// What bin/spec-harness.js runs; the suite spawns the built one, from dist/,\n// outside the sweep (tests/integration/cli.test.ts), so it survives untested\n// in-process.\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n return run(argv, { stdout: process.stdout, stderr: process.stderr, cwd: process.cwd(), env: process.env });\n}\n\n"]}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACzH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAoB,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,eAAe,EAAa,MAAM,YAAY,CAAC;AACnG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAgC,MAAM,YAAY,CAAC;AACpI,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EACL,WAAW,EACX,cAAc,EACd,UAAU,EACV,WAAW,EACX,OAAO,EACP,IAAI,EACJ,OAAO,EACP,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,GAKR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAc,MAAM,gBAAgB,CAAC;AAEnG,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDnB,CAAC;AAGF,+EAA+E;AAE/E,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAE9B,KAAK,UAAU,YAAY,CACzB,SAAoB,EACpB,OAAgB,EAChB,EAAS,EACT,KAAwB,EACxB,GAAW;IAEX,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACzC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;AACnG,CAAC;AAED,MAAM,MAAM,GAAwC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAE3H,KAAK,UAAU,YAAY,CAAC,OAAgB,EAAE,EAAS;IACrD,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;IAC5F,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IACxF,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QACtD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;YACtE,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO;gBAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;IAC3D,OAAO,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;AACvE,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,SAAS,CAAC,EAAS;IAChC,2EAA2E;IAC3E,6EAA6E;IAC7E,8CAA8C;IAC9C,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IACtE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,UAAU,CAAC,EAAS;IACjC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uEAAuE;QACvE,iEAAiE;QACjE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,mDAAoD,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QACjG,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,sEAAsE;QACtE,+DAA+D;QAC/D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QACpD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,EAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAa;IACrD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,wDAAwD,IAAI,IAAI,CAAC,CAAC;IACxG,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,EAAS;IAC/C,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,OAAO,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,OAAgB,EAAE,EAAS;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC;QAChD,sEAAsE;QACtE,kEAAkE;QAClE,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC7D,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC;QAClC,IAAI,SAAoB,CAAC;QACzB,IAAI,CAAC;YACH,SAAS,GAAG,MAAM,aAAa,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9G,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,UAAU;gBAAE,OAAO,OAAO,CAAC;YAChD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC/E,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;gBACzB,iEAAiE;gBACjE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,iDAAiD,CAAC,CAAC;gBACnG,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YAClE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjC,OAAO,QAAQ,CAAC,QAAQ,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,KAAK,KAAK,YAAY;gBAAE,MAAM,KAAK,CAAC;YAChD,mEAAmE;YACnE,4DAA4D;YAC5D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA2C,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;YACxF,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAClF,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;YACtD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC3B,CAAC;IACD,MAAM,IAAI,UAAU,CAAC,8BAA8B,CAAC,CAAC;AACvD,CAAC;AAED,+EAA+E;AAE/E;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAAC,SAAoB,EAAE,OAAgB,EAAE,GAAiB;IACpF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACvI,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAC5C,2EAA2E;IAC3E,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3F,IAAI,CAAC;QACH,uEAAuE;QACvE,gCAAgC;QAChC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC7F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wEAAwE;QACxE,8DAA8D;QAC9D,IAAI,CAAC,CAAC,KAAK,YAAY,YAAY,CAAC;YAAE,MAAM,KAAK,CAAC;QAClD,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,mDAAmD,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IACpG,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,OAAgB,EAAE,EAAS;IACtD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QACjF,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACxF,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACrG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,4DAA4D,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,CAAC;QACrJ,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC9D,0EAA0E;IAC1E,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,sDAAsD;IACtD,MAAM,IAAI,GACR,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QACjD,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;QAC5E,CAAC,CAAC,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;IAC5D,yEAAyE;IACzE,0DAA0D;IAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxG,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC;IAC1G,0EAA0E;IAC1E,mEAAmE;IACnE,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC7I,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrD,4EAA4E;IAC5E,6CAA6C;IAC7C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,0EAA0E;IAC1E,0EAA0E;IAC1E,oEAAoE;IACpE,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC3H,yEAAyE;IACzE,0DAA0D;IAC1D,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxF,4EAA4E;IAC5E,oEAAoE;IACpE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,SAAS,CAAC,YAAY,YAAY,EAAE,CAAC;IAChL,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,EAAE,CAAC,MAAM,CAAC,KAAK,CACb,IAAI,CAAC,QAAQ,EAAE;YACb,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,IAAI;YAC5C,KAAK,EAAE,KAAK,CAAC,EAAE;YACf,YAAY,EAAE,KAAK,CAAC,OAAO;YAC3B,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE;YAChI,cAAc,EAAE;gBACd,IAAI,EAAE,WAAW;gBACjB,MAAM;gBACN,MAAM,EAAE,OAAO;gBACf,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;gBACvF,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB;YACD,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE;YAC3G,UAAU,EAAE;gBACV,KAAK,EAAE,MAAM;gBACb,GAAG,MAAM;gBACT,MAAM,EAAE,kBAAkB,CAAC,MAAM,CAAC;gBAClC,OAAO,EACL,OAAO,KAAK,IAAI;oBACd,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,wDAAwD,EAAE;oBACvI,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE;aAC7J;YACD,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE;YACtH,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,CAAC,KAAwB,EAAY,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QAC5F,EAAE,CAAC,MAAM,CAAC,KAAK,CACb;YACE,WAAW,SAAS,CAAC,IAAI,EAAE;YAC3B,WAAW,MAAM,EAAE;YACnB,WAAW,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,EAAE,EAAE;YAC7F,WAAW,YAAY,CAAC,IAAI,CAAC,EAAE;YAC/B,WAAW,OAAO,EAAE;YACpB,GAAG,IAAI,CAAC,WAAW,CAAC;YACpB,WAAW,cAAc,CAAC,MAAM,CAAC,EAAE;YACnC,WAAW,kBAAkB,CAAC,MAAM,CAAC,EAAE;YACvC,GAAG,IAAI,CAAC,SAAS,CAAC;YAClB,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;YACjE,WAAW,eAAe,CAAC,IAAI,CAAC,EAAE;YAClC,GAAG,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC5C,EAAE;YACF,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7G,CAAC;IACD,2EAA2E;IAC3E,yEAAyE;IACzE,4EAA4E;IAC5E,yEAAyE;IACzE,sEAAsE;IACtE,iEAAiE;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,OAAO,EAAE,KAAK,KAAK,UAAU,CAAC;IAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC;IACzH,OAAO,QAAQ,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;AACrG,CAAC;AAED,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,QAAQ,GAA0E,IAAI,GAAG;AAC7F,+EAA+E;AAC/E,MAAM,CAAC,OAAO,CAAC;IACb,KAAK,EAAE,YAAY;IACnB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,aAAa;CACsD,CAAC,CAC/E,CAAC;AAEF,KAAK,UAAU,QAAQ,CAAC,IAAuB,EAAE,EAAS;IACxD,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qEAAqE;QACrE,mEAAmE;QACnE,gBAAgB;QAChB,MAAM,OAAO,GAAG,KAAuB,CAAC;QACxC,IAAI,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7F,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QACtD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7C,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,OAAO,CAAC,OAAO,8BAA8B,CAAC,CAAC;QACjG,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,4EAA4E;IAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAuB,EAAE,EAAS;IAC1D,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,oEAAoE;QACpE,sEAAsE;QACtE,IACE,KAAK,YAAY,UAAU;YAC3B,KAAK,YAAY,WAAW;YAC5B,KAAK,YAAY,YAAY;YAC7B,KAAK,YAAY,kBAAkB;YACnC,KAAK,YAAY,QAAQ,EACzB,CAAC;YACD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;YACpD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAChG,IAAK,KAA+B,CAAC,IAAI,KAAK,OAAO;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;;YACjJ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;QAC1F,OAAO,UAAU,CAAC;IACpB,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,6EAA6E;AAC7E,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAI,GAAsB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAC7G,CAAC","sourcesContent":["/**\n * The command line: arguments, dispatch, output and exit codes.\n *\n * Exit 0: done, nothing refused. Exit 1: something refused or found. Exit 2:\n * the answer cannot be trusted - a bad flag, an option, an argument or a\n * value that names nothing, a configuration that does not load, a sibling\n * that is missing or printed something unreadable, a git command that\n * failed, an output its reader closed, an error nothing here expected. A run\n * that could not look must never exit as though it looked and found nothing\n * (spec-core ADR-0005).\n */\n\nimport { SiblingOutputError } from './briefs.js';\nimport { auditCommand, contextCommand, escalateCommand, probeCommand, ruleCommand, rulingsCommand } from './commands.js';\nimport { ConfigError, SIBLINGS } from './config.js';\nimport {\n describeBase,\n describeClaudeCode,\n describeClaudeRelease,\n describeGitHook,\n describePlugin,\n describeSignerKeys,\n describeSignerProblem,\n describeSigners,\n wiringState,\n} from './configure.js';\nimport { isDirectory } from './fs.js';\nimport { GitError, show, stagedChanges } from './git.js';\nimport type { Decision } from './guard.js';\nimport { claudeResponse, gitResponse, parseClaudeHook, type HookRequest } from './hooks.js';\nimport { claudeVersion } from './host.js';\nimport { premisesCommand } from './premises.js';\nimport { createReader } from './reader.js';\nimport { checkPaths, claudeCodeWiring, resolveBase, specBriefPlugin, type Base } from './round.js';\nimport { mcpCommand } from './server.js';\nimport { gitHook, initCommand } from './setup.js';\nimport { notFido2, readAllowedSigners } from './signers.js';\nimport { SiblingError } from './siblings.js';\nimport { emptyValue, isBlank, isClaudeHook, readHookLine, refusal, unreadHookLine, type Command, type LineFault } from './usage.js';\nimport { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';\nimport {\n activeBrief,\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n namedId,\n openWorkspace,\n parseOptions,\n UsageError,\n version,\n type CliIO,\n type Options,\n type UnreadableLine,\n type Workspace,\n} from './workspace.js';\n\nexport { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';\n\nexport const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work\n\nUsage:\n spec-harness <command> [options]\n\nCommands:\n context [brief] What an agent needs to start a round: the brief, its scope,\n rulings, dependencies, the rules in force, the cited documents.\n guard <path...> May the round write these paths? Exit 1 if one is refused.\n hook claude Answer a Claude Code PreToolUse or PostToolUse hook (stdin).\n hook git Answer git's pre-commit hook for the staged files.\n escalate Ask a person to rule: --path <file> (repeatable) --reason <why>\n [--option \"<label>: <cost>\"]... [--recommend <text>].\n --list shows what waits; --show <id> prints one memo. Neither\n raises a request: beside one, only --root and --format are read.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note <text>. It counts once committed signed.\n rulings [brief] The brief's rulings, and whether each one's signature verifies.\n audit [brief] Did the round stay inside the lines: what the archive would say,\n the brief's assertions, unverified rulings, new dependencies\n and the install scripts it allowed.\n probe [brief] Run the brief's probes: red at the base, green at the head.\n --at <base|head|both>, --id <probe>.\n premises Do the live briefs' premises still hold? For CI: exit 1 when one\n is stale, or, with --strict, when spec-guard cannot read one.\n init Configure the spec-* tools to agree. Prints the plan; --write\n applies it; --git-hook adds a pre-commit hook.\n mcp Serve start_round, check_path, request_escalation, audit_round,\n list_rounds and the workflow prompts over MCP on stdio.\n doctor Which siblings are installed, at which versions, which brief is\n named, how Claude Code runs the guard, and git's hook. Exit 1\n when a sibling is older than this release needs, the guard is\n installed twice or its hook's line turns it off, or Claude Code\n is too old to run its hooks.\n\nOptions:\n --brief <id> The brief the round works on. Otherwise SPEC_BRIEF, then the branch.\n For context, guard, hook, escalate, rulings, audit, probe, premises\n and doctor.\n --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch. For context,\n guard, hook, rulings, audit, probe and doctor.\n --root <dir> Run from another directory, which must exist. For every command.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n For every command but hook and mcp.\n --strict Warnings fail the run. For guard, audit, premises and doctor.\n --help, --version\n\nAn option a command does not read, an argument it does not take, an option or an\nargument given an empty value, and a brief given both as the argument and as --brief\nare refused, exit 2, not read as if they were not there. doctor says an empty --brief\nor --base in its report. hook claude reads its line as every release has, and says a\nline it cannot read, and a --root that is not a directory, with exit 1: it refuses\nnothing for either.\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n`;\n\n\n/* ------------------------------------------------------------------- guard */\n\nconst reader = createReader();\n\nasync function decisionsFor(\n workspace: Workspace,\n options: Options,\n io: CliIO,\n given: readonly string[],\n cwd: string,\n): Promise<{ readonly decisions: Decision[] } | { readonly problem: string }> {\n const active = await activeBrief(workspace, options, io.env);\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) return { problem };\n return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };\n}\n\nconst SYMBOL: Record<Decision['verdict'], string> = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };\n\nasync function guardCommand(options: Options, io: CliIO): Promise<number> {\n if (options.positionals.length === 0) throw new UsageError('guard needs at least one path');\n const workspace = await openWorkspace(options, io);\n const decided = await decisionsFor(workspace, options, io, options.positionals, io.cwd);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const { decisions } = decided;\n if (options.format === 'json') {\n io.stdout.write(json('guard', { decisions }));\n } else {\n for (const decision of decisions) {\n io.stdout.write(`${SYMBOL[decision.verdict]} ${decision.message}\\n`);\n if (decision.verdict !== 'allow') io.stdout.write(` ${decision.hint}\\n`);\n }\n }\n const refused = decisions.some((d) => d.verdict === 'deny' || d.verdict === 'ask');\n const warned = decisions.some((d) => d.verdict === 'warn');\n return refused || (options.strict && warned) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------------- hook */\n\nasync function readStdin(io: CliIO): Promise<string> {\n // Only the built command line reads process.stdin, and the suite spawns it\n // from dist/, outside the sweep (tests/integration/claude-code.test.ts): the\n // lines below survive it untested in-process.\n if (io.stdin !== undefined) return io.stdin();\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n}\n\n/**\n * The write Claude Code asks the hook about, or the exit code that answers\n * already: 1 for a question that cannot be read, 0 for a tool that writes\n * no file. Asked before anything on the hook's own line is, so that a line\n * that is wrong is said where there is a write it leaves unchecked.\n */\nasync function writeAsked(io: CliIO): Promise<HookRequest | number> {\n let question: string;\n try {\n question = await readStdin(io);\n } catch (error) {\n // A question that could not be read is one the hook cannot see, as one\n // it cannot parse is, below: it has no event to hold a write by.\n io.stderr.write(`spec-harness: the hook input could not be read: ${(error as Error).message}\\n`);\n return EXIT_FAILED;\n }\n const request = parseClaudeHook(question);\n if ('error' in request) {\n // A hook that cannot read its question refuses nothing it cannot see,\n // but says so where the person reads it: a non-blocking error.\n io.stderr.write(`spec-harness: ${request.error}\\n`);\n return EXIT_FAILED;\n }\n return request.paths.length === 0 ? EXIT_OK : request;\n}\n\n/**\n * What is wrong with the hook's own line, said and nothing refused for it:\n * one line, since Claude Code shows the first line of the stderr of a hook\n * that exits 1 and goes on with the write, where exit 2 would hold every\n * write of the session, the one that mends the line among them (ADR-0005).\n */\nfunction guardOff(io: CliIO, { wrong, mend }: LineFault): number {\n io.stderr.write(`spec-harness: ${wrong}, so the guard is off and this write is not checked; ${mend}\\n`);\n return EXIT_FAILED;\n}\n\n/**\n * Claude Code's hook on a line the parser refused: an option no command has,\n * an option left without its value, a --format or an --at that is none. It\n * was exit 2 before the question was read, for the line a settings file\n * holds as for one typed at a terminal. What is said of it is `doctor`'s\n * to say as well, of a line it finds in a settings file (usage.ts).\n */\nasync function unreadLine(said: string, io: CliIO): Promise<number> {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n return guardOff(io, unreadHookLine(said).fault);\n}\n\nasync function hookCommand(options: Options, io: CliIO): Promise<number> {\n const kind = options.positionals[0];\n if (kind === 'claude') {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n // The root the line gives, or what is wrong with it: read as `doctor`\n // reads the line where it finds it in a settings file (usage.ts).\n const line = readHookLine(options.root, io.cwd, isDirectory);\n if (line.state === 'off') return guardOff(io, line.fault);\n const cwd = request.cwd ?? io.cwd;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ ...options, root: line.root ?? io.env['CLAUDE_PROJECT_DIR'] ?? cwd }, io);\n } catch (error) {\n if (error instanceof UsageError) return EXIT_OK;\n throw error;\n }\n try {\n const decided = await decisionsFor(workspace, options, io, request.paths, cwd);\n if ('problem' in decided) {\n // Exit 2 blocks the tool call, and its stderr reaches the model.\n io.stderr.write(`spec-harness: ${decided.problem}. Fix the brief or the branch before writing.\\n`);\n return EXIT_ERROR;\n }\n const response = claudeResponse(request.event, decided.decisions);\n io.stdout.write(response.stdout);\n return response.exitCode;\n } catch (error) {\n if (request.event !== 'PreToolUse') throw error;\n // A round is named and its briefs cannot be read: the guard cannot\n // tell a protected file from any other, so the write waits.\n io.stderr.write(`spec-harness: cannot check this write: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n }\n if (kind === 'git') {\n const workspace = await openWorkspace(options, io);\n const staged = await stagedChanges(workspace.root);\n const paths = staged.flatMap((change) => (change.from === undefined ? [change.path] : [change.from, change.path]));\n if (paths.length === 0) return EXIT_OK;\n const decided = await decisionsFor(workspace, options, io, paths, workspace.root);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const response = gitResponse(decided.decisions);\n io.stderr.write(response.text);\n return response.exitCode;\n }\n throw new UsageError('hook takes \"claude\" or \"git\"');\n}\n\n/* ------------------------------------------------------------------ doctor */\n\n/**\n * The brief a round here works on, as doctor reports it: its id, and what is\n * wrong with the name when no round can work under it. Every other command\n * stops there. A diagnosis says it, being what a person runs when the guard\n * holds a write they expected it to pass.\n */\nasync function diagnoseBrief(workspace: Workspace, options: Options, env: CliIO['env']): Promise<{ readonly id: string | null; readonly problem: string | null }> {\n if (options.brief !== undefined && isBlank(options.brief)) return { id: null, problem: emptyValue('--brief', 'brief', options.brief) };\n const id = namedId(workspace, options, env);\n // A spec-brief that cannot be run is a row of the report, with the reason.\n if (workspace.siblings.locate('spec-brief').kind !== 'found') return { id, problem: null };\n try {\n // Where nothing names a brief, spec-brief is not asked (ADR-0004), and\n // there is no problem to state.\n return { id, problem: describeActive(await activeBrief(workspace, options, env)).problem };\n } catch (error) {\n // Asking spec-brief throws nothing but this, so the check is equivalent\n // to its mutant; it keeps any other error the stack it needs.\n if (!(error instanceof SiblingError)) throw error;\n return { id, problem: `spec-brief could not say whether it knows brief ${id}: ${error.message}` };\n }\n}\n\nasync function doctorCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const rows = SIBLINGS.map((name) => {\n const sibling = workspace.siblings.locate(name);\n const row = { tool: name, state: sibling.kind, minimum: MINIMUM_VERSIONS[name] };\n if (sibling.kind === 'absent') return { ...row, version: null, detail: sibling.reason };\n if (sibling.kind === 'outdated') return { ...row, version: sibling.version, detail: sibling.reason };\n const command = sibling.command.join(' ');\n const detail = sibling.version === null ? `${command} (named in .spec-harness.json; its version is not checked)` : `${command} (${sibling.version})`;\n return { ...row, version: sibling.version, detail };\n });\n const named = await diagnoseBrief(workspace, options, io.env);\n // A ruling counts only by a signature checked against the allowed signers\n // on the base, and only once spec-brief's archive asks the plugin about it.\n // A --base given nothing is no base, said as the brief's is, in the report.\n // Nothing below asks what kind a base is but whether it is resolved, so the\n // mutant that names this one otherwise is equivalent.\n const base: Base =\n options.base !== undefined && isBlank(options.base)\n ? { kind: 'unresolved', reason: emptyValue('--base', 'base', options.base) }\n : await resolveBase(workspace, options.base);\n const signersFile = workspace.config.rulings.allowedSigners;\n // An unresolved base has no commit: git shows nothing for one, so asking\n // anyway reads as no file, and that mutant is equivalent.\n const signersText = base.kind === 'resolved' ? await show(base.sha, signersFile, workspace.root) : null;\n const onBase = base.kind === 'resolved' ? signersText !== null : null;\n const signers = describeSigners(signersFile, base.kind === 'resolved' ? base.ref : null, onBase === true);\n // Which keys sign, as notes: a key that is not FIDO2 can still be one the\n // agent cannot use, and a PIV key reads as a plain one (ADR-0006).\n const read = readAllowedSigners(signersText ?? '');\n const plain = notFido2(read.signers);\n const signerNotes = [describeSignerKeys(plain), ...read.problems.map(describeSignerProblem)].filter((note): note is string => note !== null);\n const plugin = await specBriefPlugin(workspace.root);\n // The plugin and init's entries both on: Claude Code runs every guard twice\n // and registers the server twice (ADR-0012).\n const wiring = await claudeCodeWiring(workspace.root, io.env);\n const claude = wiringState(wiring);\n // What the hook does with each line the settings hold for it, where there\n // is something to say: more on it than init writes, a line that turns the\n // guard off, one only a shell can read, and what onFailure changes.\n const lineNotes = wiring.lines.flatMap((line) => [line.detail, line.note]).filter((note): note is string => note !== null);\n // Only a Claude Code that runs the guard is asked its release: one older\n // than the hooks need lets every write through unguarded.\n const release = claude === 'none' ? null : checkClaudeCode(await claudeVersion(io.env));\n // How the hook runs the harness is a note: one that goes through npx guards\n // as well as one that does not, and fails nothing, --strict or not.\n const { hook, note: hookNote } = await gitHook(workspace.root);\n const branch = workspace.branch === null ? '(detached)' : `${workspace.branch}${workspace.branchSource === undefined ? '' : ` (detached; ${workspace.branchSource} names it)`}`;\n if (options.format === 'json') {\n io.stdout.write(\n json('doctor', {\n root: workspace.root,\n branch: workspace.branch,\n branchSource: workspace.branchSource ?? null,\n brief: named.id,\n briefProblem: named.problem,\n base: base.kind === 'resolved' ? { ref: base.ref, source: base.source, mergeBase: base.mergeBase } : { unresolved: base.reason },\n allowedSigners: {\n file: signersFile,\n onBase,\n detail: signers,\n notFido2: plain.map(({ line, principals, keyType }) => ({ line, principals, keyType })),\n problems: read.problems,\n },\n plugin: { state: plugin.kind, file: 'file' in plugin ? plugin.file : null, detail: describePlugin(plugin) },\n claudeCode: {\n state: claude,\n ...wiring,\n detail: describeClaudeCode(wiring),\n release:\n release === null\n ? { state: 'unchecked', version: null, minimum: CLAUDE_CODE_MINIMUM, detail: 'not asked: nothing wires Claude Code to the guard here' }\n : { state: release.state, version: 'version' in release ? release.version : null, minimum: CLAUDE_CODE_MINIMUM, detail: describeClaudeRelease(release) },\n },\n gitHook: { state: hook.state, file: 'file' in hook ? hook.file : null, detail: describeGitHook(hook), note: hookNote },\n siblings: rows,\n }),\n );\n } else {\n const more = (notes: readonly string[]): string[] => notes.map((note) => ` ${note}`);\n io.stdout.write(\n [\n `root ${workspace.root}`,\n `branch ${branch}`,\n `brief ${named.problem === null ? (named.id ?? '(none named)') : `none: ${named.problem}`}`,\n `base ${describeBase(base)}`,\n `signers ${signers}`,\n ...more(signerNotes),\n `plugin ${describePlugin(plugin)}`,\n `claude ${describeClaudeCode(wiring)}`,\n ...more(lineNotes),\n ...more(release === null ? [] : [describeClaudeRelease(release)]),\n `git ${describeGitHook(hook)}`,\n ...more(hookNote === null ? [] : [hookNote]),\n '',\n '',\n ].join('\\n'),\n );\n for (const row of rows) io.stdout.write(`${row.state.padEnd(8)} ${row.tool.padEnd(10)} ${row.detail}\\n`);\n }\n // An outdated sibling is a problem to fix, where a missing optional one is\n // a choice; with none installed, the harness can check nothing. A double\n // install is a problem too, where no Claude Code wiring at all is a choice,\n // and so are a hook whose own line turns the guard off and a Claude Code\n // too old to run the hooks. A release that cannot be told is not fine\n // either, nor a line only a shell can read: --strict fails both.\n const outdated = rows.some((row) => row.state === 'outdated');\n const usable = rows.some((row) => row.state === 'found');\n const off = wiring.lines.some((line) => line.state === 'off');\n const tooOld = release?.state === 'outdated';\n const untold = options.strict && (release?.state === 'unknown' || wiring.lines.some((line) => line.state === 'unknown'));\n return outdated || !usable || claude === 'both' || off || tooOld || untold ? EXIT_FAILED : EXIT_OK;\n}\n\n/* ---------------------------------------------------------------- dispatch */\n\n/**\n * A map, because the command is the first word a person types and an object\n * answers to more names than it was given: `spec-harness constructor` ran\n * `Object` as a command and ended on a stack trace, where `spec-harness\n * construct` is an unknown command with exit 2.\n */\nconst COMMANDS: ReadonlyMap<string, (options: Options, io: CliIO) => Promise<number>> = new Map(\n // One for every command that has a shape (usage.ts), which the compiler holds.\n Object.entries({\n guard: guardCommand,\n hook: hookCommand,\n context: contextCommand,\n audit: auditCommand,\n escalate: escalateCommand,\n rule: ruleCommand,\n rulings: rulingsCommand,\n probe: probeCommand,\n premises: premisesCommand,\n init: initCommand,\n mcp: mcpCommand,\n doctor: doctorCommand,\n } satisfies Record<Command, (options: Options, io: CliIO) => Promise<number>>),\n);\n\nasync function dispatch(argv: readonly string[], io: CliIO): Promise<number> {\n let options: Options;\n try {\n options = parseOptions(argv);\n } catch (error) {\n // The parser throws nothing but its refusal of the line, which holds\n // whose line it was. Claude Code's hook says its own, and holds no\n // write for it.\n const refused = error as UnreadableLine;\n if (isClaudeHook(refused.words[0], refused.words[1])) return unreadLine(refused.message, io);\n io.stderr.write(`spec-harness: ${refused.message}\\n`);\n return EXIT_ERROR;\n }\n if (options.version) {\n io.stdout.write(`${version()}\\n`);\n return EXIT_OK;\n }\n if (options.help || options.command === undefined) {\n io.stdout.write(HELP);\n return options.help ? EXIT_OK : EXIT_ERROR;\n }\n const command = COMMANDS.get(options.command);\n if (command === undefined) {\n io.stderr.write(`spec-harness: unknown command \"${options.command}\"; see spec-harness --help\\n`);\n return EXIT_ERROR;\n }\n // What parsed and names nothing, before anything is read or written for it.\n const refused = refusal(options, isDirectory);\n if (refused !== null) {\n io.stderr.write(`spec-harness: ${refused}\\n`);\n return EXIT_ERROR;\n }\n return command(options, io);\n}\n\n/**\n * Runs the command line and resolves to the exit code, for an error nothing\n * below expected too.\n *\n * Such an error is neither a refusal nor a finding: the answer cannot be\n * trusted, which is exit 2 (spec-core ADR-0005). Rejected instead, it reached\n * the launcher as Node's uncaught error, exit 1, \"refused or found something\"\n * to a script, and to Claude Code a hook that failed without blocking: the\n * write the guard could not check went ahead. The stack is what makes a\n * report of it something to act on, and it goes to stderr alone: a script\n * that reads a document from stdout is handed no part of one.\n *\n * A write its reader had closed the pipe for is not such an error: the answer\n * was not delivered, which is still 2, and nothing in the harness is at\n * fault, so it is said in a line and no stack sends a person looking for a\n * defect. The process's own streams report it as an event, which the\n * launcher answers in the same words; here it is a caller's stream that\n * throws it. It is read by its code: stdout and stderr are the only pipes\n * the harness writes to.\n */\nexport async function run(argv: readonly string[], io: CliIO): Promise<number> {\n try {\n return await dispatch(argv, io);\n } catch (error) {\n // A sibling's document of a shape the harness does not read is a sibling\n // that printed something it cannot read (answers.ts): exit 2. A git\n // command that failed is what git said, and no line of the harness's.\n if (\n error instanceof UsageError ||\n error instanceof ConfigError ||\n error instanceof SiblingError ||\n error instanceof SiblingOutputError ||\n error instanceof GitError\n ) {\n io.stderr.write(`spec-harness: ${error.message}\\n`);\n return EXIT_ERROR;\n }\n if (!(error instanceof Error)) io.stderr.write(`spec-harness: unexpected error: ${String(error)}\\n`);\n else if ((error as NodeJS.ErrnoException).code === 'EPIPE') io.stderr.write('spec-harness: stdout was closed before all of the output was written\\n');\n else io.stderr.write(`spec-harness: unexpected error: ${error.stack ?? error.message}\\n`);\n return EXIT_ERROR;\n }\n}\n\n// What bin/spec-harness.js runs; the suite spawns the built one, from dist/,\n// outside the sweep (tests/integration/cli.test.ts), so it survives untested\n// in-process.\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n return run(argv, { stdout: process.stdout, stderr: process.stderr, cwd: process.cwd(), env: process.env });\n}\n\n"]}
package/dist/commands.js CHANGED
@@ -58,6 +58,7 @@ export async function contextCommand(options, io) {
58
58
  unreadableScope: packet.unreadableScope,
59
59
  unreadableProtections: packet.unreadableProtections,
60
60
  unreadableRulingPaths: packet.unreadableRulingPaths,
61
+ unmatchedSpecs: packet.unmatchedSpecs,
61
62
  }));
62
63
  }
63
64
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The commands that read a round: context, audit, escalate, rule, rulings\n * and probe. Each resolves the brief, asks `round.ts` for the facts and\n * prints them; exit codes follow the family contract.\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport { describeMeasured } from './audit.js';\nimport { briefIdFromBranch } from './branch.js';\nimport { findActive } from './briefs.js';\nimport { formatFindings } from './formats.js';\nimport { readJUnit } from './junit.js';\nimport { classify, endOfOutput, readProbes, renderEvidence, renderUnexplained, verdictOf, type ProbeResult, type ProbeSpec } from './probe.js';\nimport { createReader } from './reader.js';\nimport {\n buildContext,\n checkRulings,\n briefText,\n listEscalations,\n raiseEscalation,\n recordRuling,\n resolveBase,\n runAudit,\n} from './round.js';\nimport { renderMemo, type EscalationOption } from './rulings.js';\nimport { runCommand, withWorktree } from './sandbox.js';\nimport type { BriefRow, Finding } from './types.js';\nimport {\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n UsageError,\n version,\n type CliIO,\n type Options,\n type Workspace,\n openWorkspace,\n} from './workspace.js';\n\nconst reader = createReader();\n\n/**\n * The brief a command acts on: a positional id, else the active one. A\n * command that needs one and has none is a usage error. The command line\n * refuses the id beside `--brief` before it gets here (usage.ts).\n */\nexport async function targetBrief(workspace: Workspace, options: Options, io: CliIO, positional: string | undefined): Promise<{ brief: BriefRow; briefs: BriefRow[] }> {\n const briefs = await workspace.siblings.briefs();\n const fromBranch = briefIdFromBranch(workspace.config.branches, workspace.branch);\n const active = findActive(briefs, { argument: positional, flag: options.brief, environment: io.env['SPEC_BRIEF'], branch: fromBranch });\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) throw new UsageError(problem);\n if (brief === null) throw new UsageError(note);\n return { brief, briefs };\n}\n\nconst MARK: Record<Finding['severity'], string> = { error: 'error ', warning: 'warning', note: 'note ' };\n\nfunction printFindings(io: CliIO, findings: readonly Finding[]): void {\n for (const finding of findings) {\n const where = finding.file === undefined ? '' : `${finding.file}${finding.line === undefined ? '' : `:${finding.line}`} `;\n io.stdout.write(`${MARK[finding.severity]} ${where}${finding.message} ${finding.rule}\\n ${finding.hint}\\n`);\n }\n}\n\n/* ----------------------------------------------------------------- context */\n\nexport async function contextCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief, briefs } = await targetBrief(workspace, options, io, options.positionals[0]);\n const packet = await buildContext(workspace, brief, briefs, reader, options.base);\n if (options.format === 'json') {\n io.stdout.write(\n json('context', {\n brief: brief.id,\n markdown: packet.markdown,\n included: packet.included,\n omitted: packet.omitted,\n unresolved: packet.unresolved,\n unclosedFrontMatter: packet.unclosedFrontMatter,\n unreadableFrontMatter: packet.unreadableFrontMatter,\n unreadableScope: packet.unreadableScope,\n unreadableProtections: packet.unreadableProtections,\n unreadableRulingPaths: packet.unreadableRulingPaths,\n }),\n );\n } else {\n io.stdout.write(packet.markdown);\n }\n return EXIT_OK;\n}\n\n/* ------------------------------------------------------------------- audit */\n\nexport async function auditCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const result = await runAudit(workspace, brief, reader, options.base);\n const { counts, findings, measured } = result.report;\n if (options.format === 'json') {\n io.stdout.write(\n json('audit', {\n ok: counts.error === 0 && (!options.strict || counts.warning === 0),\n brief: brief.id,\n base: result.base.kind === 'resolved' ? { ref: result.base.ref, mergeBase: result.base.mergeBase, head: result.base.head } : null,\n counts,\n measured,\n findings,\n dependencies: result.dependencies,\n installScripts: result.installScripts,\n }),\n );\n } else if (options.format === 'pretty') {\n io.stdout.write(`audit of brief ${brief.id}${result.base.kind === 'resolved' ? ` from ${result.base.ref} (${result.base.mergeBase.slice(0, 12)})` : ''}\\n\\n`);\n printFindings(io, findings);\n // The counts stay the last line, where a script reads them.\n io.stdout.write(`\\n${describeMeasured(measured)}\\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)\\n`);\n } else {\n io.stdout.write(formatFindings(options.format, findings, { file: brief.file, version: version(), summary: describeMeasured(measured) }));\n }\n return counts.error > 0 || (options.strict && counts.warning > 0) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------- escalation */\n\nfunction parseOption(raw: string): EscalationOption {\n const colon = raw.indexOf(':');\n const option = colon < 0 ? { label: raw.trim(), consequence: '' } : { label: raw.slice(0, colon).trim(), consequence: raw.slice(colon + 1).trim() };\n // An option given nothing was refused where the command line was read, so\n // this one has a colon and nothing before it: a cost, and no choice it is\n // the cost of. The memo would number a choice with no name.\n if (option.label === '') throw new UsageError(`--option is ${JSON.stringify(raw)}, which names no choice before its colon; give it \"<label>: <cost>\"`);\n return option;\n}\n\nexport async function escalateCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n if (options.list) {\n const waiting = await listEscalations(workspace);\n if (options.format === 'json') io.stdout.write(json('escalate', { waiting }));\n else if (waiting.length === 0) io.stdout.write('no escalation is waiting\\n');\n else for (const request of waiting) io.stdout.write(`${request.id} brief ${request.brief} ${request.paths.join(', ')} ${request.reason.split('\\n')[0]}\\n`);\n return EXIT_OK;\n }\n if (options.show !== undefined) {\n const request = (await listEscalations(workspace)).find((candidate) => candidate.id === options.show);\n if (request === undefined) throw new UsageError(`no escalation \"${options.show}\" is waiting`);\n io.stdout.write(options.format === 'json' ? json('escalate', { request }) : renderMemo(request));\n return EXIT_OK;\n }\n if (options.paths.length === 0 || options.reason === undefined) {\n throw new UsageError('escalate needs --path <file> (repeatable) and --reason <why>; or --list, or --show <id>');\n }\n // Read before spec-brief is asked anything: a request that cannot be\n // written is refused for what is wrong with it, whatever the brief.\n const choices = options.options.map(parseOption);\n const { brief } = await targetBrief(workspace, options, io, undefined);\n const { request, memo } = await raiseEscalation(workspace, brief, {\n paths: options.paths,\n reason: options.reason,\n options: choices,\n recommendation: options.recommend ?? null,\n });\n io.stdout.write(options.format === 'json' ? json('escalate', { request, memo }) : memo);\n // Exit 1: the round is waiting on a person, which a caller must not read as done.\n return EXIT_FAILED;\n}\n\nexport async function ruleCommand(options: Options, io: CliIO): Promise<number> {\n const id = options.positionals[0];\n if (id === undefined) throw new UsageError('rule needs the escalation id, such as E-012-1');\n if (options.allow === options.deny) throw new UsageError('rule needs exactly one of --allow or --deny');\n if (options.note === undefined || options.note.trim() === '') throw new UsageError('rule needs --note: what exactly is allowed, or why not');\n const workspace = await openWorkspace(options, io);\n const recorded = await recordRuling(workspace, id, options.allow ? 'allow' : 'deny', options.note, reader);\n const command = `git commit -S -m \"ruling ${recorded.id}: ${options.allow ? 'allow' : 'deny'}\" -- ${recorded.file}`;\n if (options.format === 'json') {\n io.stdout.write(json('rule', { ruling: recorded.id, file: recorded.file, row: recorded.row, commit: command }));\n } else {\n io.stdout.write(`${recorded.file} now holds ruling ${recorded.id}:\\n\\n ${recorded.row}\\n\\nIt counts once you commit it signed, with a key the base branch's allowed signers list:\\n\\n ${command}\\n`);\n }\n return EXIT_OK;\n}\n\nexport async function rulingsCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const base = await resolveBase(workspace, options.base);\n const check = await checkRulings(workspace, brief, await briefText(workspace, brief), reader, base);\n if (options.format === 'json') {\n io.stdout.write(json('rulings', { brief: brief.id, rows: check.rows, verified: check.verified, unverified: check.unverified, problems: check.problems }));\n } else {\n if (check.rows.length === 0) io.stdout.write(`brief ${brief.id} holds no ruling\\n`);\n for (const row of check.rows) {\n const verified = check.verified.find((ruling) => ruling.id === row.id);\n const unverified = check.unverified.find((ruling) => ruling.id === row.id);\n // An allow row that does not verify is among the unverified, with its\n // reason, so the fallback for none is equivalent to its mutants.\n const state = row.decision === 'deny' ? 'refused' : verified !== undefined ? `signed by ${verified.signer}` : `not verified: ${unverified?.reason ?? ''}`;\n io.stdout.write(`${row.id} ${row.decision} ${row.paths.join(', ')} ${state}\\n`);\n }\n printFindings(io, check.problems);\n }\n return check.unverified.length > 0 || check.problems.length > 0 ? EXIT_FAILED : EXIT_OK;\n}\n\n/* ------------------------------------------------------------------- probe */\n\n/**\n * What is said of a command answered with its output still held, three\n * seconds after its shell ended or after its timeout: of a run, in its\n * evidence, and of a `setup`, in why the probe stopped or, where the setup\n * passed, in a line of its own. What holds the output is no part of the\n * command and was not stopped with it. What the sandbox can reach of it is\n * stopped when the probe is done at that commit; the rest runs on until it\n * ends or a person ends it, and the person is the one who can find it\n * (ADR-0003).\n */\nconst LEFT_RUNNING = ', and something it started was left running, holding its output';\n\nasync function runProbe(directory: string, probe: ProbeSpec, runs: number, timeout: number): Promise<ProbeResult['runs']> {\n const classified = [];\n for (let i = 0; i < runs; i += 1) {\n const report = probe.junit === null ? null : join(directory, probe.junit);\n if (report !== null) await rm(report, { force: true });\n const run = await runCommand(probe.run, directory, timeout);\n // existsSync answers false for null, so the null check is there for the\n // type, and its mutant is equivalent.\n const junit = report === null || !existsSync(report) ? null : readJUnit(await readFile(report, 'utf8'));\n const judged = classify(probe, { exitCode: run.exitCode, output: run.output, junit });\n // After whatever `classify` says of the run: red, green or stopped, it\n // is judged by its shell, and what it left is said beside the verdict.\n classified.push(run.outputHeld ? { ...judged, detail: `${judged.detail}${LEFT_RUNNING}` } : judged);\n }\n return classified;\n}\n\nexport async function probeCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const text = await briefText(workspace, brief);\n const set = readProbes(reader.codeBlocks(text));\n if (set.problems.length > 0) {\n for (const problem of set.problems) io.stderr.write(`spec-harness: ${brief.file}:${problem.line}: ${problem.message}\\n`);\n return EXIT_ERROR;\n }\n const probes = set.probes.filter((probe) => options.id === undefined || probe.id === options.id);\n if (probes.length === 0) {\n io.stdout.write(`brief ${brief.id} declares no probe${options.id === undefined ? '' : ` named ${options.id}`}\\n`);\n return options.id === undefined ? EXIT_OK : EXIT_ERROR;\n }\n const base = await resolveBase(workspace, options.base);\n if (base.kind === 'unresolved') throw new UsageError(base.reason);\n const at = options.at ?? (base.mergeBase === base.head ? 'base' : 'both');\n const results: ProbeResult[] = [];\n const measure = async (label: 'base' | 'head', commit: string, expected: 'red' | 'green'): Promise<void> => {\n await withWorktree(workspace.root, commit, async (directory) => {\n for (const file of set.files) {\n await mkdir(dirname(join(directory, file.path)), { recursive: true });\n await writeFile(join(directory, file.path), file.content.endsWith('\\n') ? file.content : `${file.content}\\n`);\n }\n const setups = [...new Set(probes.map((probe) => probe.setup).filter((setup): setup is string => setup !== null))];\n for (const setup of setups) {\n const timeout = workspace.config.probes.timeout;\n const run = await runCommand(setup, directory, timeout);\n // A setup stopped at its timeout has no exit code to have failed by,\n // and may have printed nothing: how long it was given is the reason.\n const how = run.exitCode === null ? `was stopped after ${timeout} seconds` : 'failed';\n if (run.exitCode !== 0) throw new UsageError(`the probe setup \"${setup}\" ${how} at ${label}${run.outputHeld ? LEFT_RUNNING : ''}:\\n${endOfOutput(run.output)}`);\n // A setup that passed says nothing else, and the runs after it start\n // beside what it left: on the standard error, whatever the format,\n // since the document has no place for a setup.\n if (run.outputHeld) io.stderr.write(`spec-harness: the probe setup \"${setup}\" passed at ${label}${LEFT_RUNNING}\\n`);\n }\n for (const probe of probes) {\n const runs = await runProbe(directory, probe, probe.runs ?? workspace.config.probes.runs, probe.timeout ?? workspace.config.probes.timeout);\n results.push({ probe, at: label, commit, expected, runs, verdict: verdictOf(expected, runs) });\n }\n });\n };\n if (at === 'base' || at === 'both') await measure('base', base.mergeBase, 'red');\n if (at === 'head' || at === 'both') await measure('head', base.head, 'green');\n const evidence = renderEvidence(results, set.hash, new Date().toISOString().slice(0, 10));\n const failed = results.filter((result) => result.verdict !== (result.expected === 'red' ? 'measured' : 'fixed'));\n if (options.format === 'json') {\n io.stdout.write(\n json('probe', {\n ok: failed.length === 0,\n brief: brief.id,\n hash: set.hash,\n results: results.map((result) => ({ id: result.probe.id, at: result.at, commit: result.commit, expected: result.expected, verdict: result.verdict, runs: result.runs })),\n evidence,\n }),\n );\n } else {\n io.stdout.write(`${evidence}\\n`);\n // On the standard error, beside the table and never in it: the table is\n // what a brief records and a script reads. The JSON document has the\n // same as a field of each such run, and so says nothing here.\n io.stderr.write(renderUnexplained(results));\n }\n return failed.length === 0 ? EXIT_OK : EXIT_FAILED;\n}\n"]}
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The commands that read a round: context, audit, escalate, rule, rulings\n * and probe. Each resolves the brief, asks `round.ts` for the facts and\n * prints them; exit codes follow the family contract.\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport { describeMeasured } from './audit.js';\nimport { briefIdFromBranch } from './branch.js';\nimport { findActive } from './briefs.js';\nimport { formatFindings } from './formats.js';\nimport { readJUnit } from './junit.js';\nimport { classify, endOfOutput, readProbes, renderEvidence, renderUnexplained, verdictOf, type ProbeResult, type ProbeSpec } from './probe.js';\nimport { createReader } from './reader.js';\nimport {\n buildContext,\n checkRulings,\n briefText,\n listEscalations,\n raiseEscalation,\n recordRuling,\n resolveBase,\n runAudit,\n} from './round.js';\nimport { renderMemo, type EscalationOption } from './rulings.js';\nimport { runCommand, withWorktree } from './sandbox.js';\nimport type { BriefRow, Finding } from './types.js';\nimport {\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n UsageError,\n version,\n type CliIO,\n type Options,\n type Workspace,\n openWorkspace,\n} from './workspace.js';\n\nconst reader = createReader();\n\n/**\n * The brief a command acts on: a positional id, else the active one. A\n * command that needs one and has none is a usage error. The command line\n * refuses the id beside `--brief` before it gets here (usage.ts).\n */\nexport async function targetBrief(workspace: Workspace, options: Options, io: CliIO, positional: string | undefined): Promise<{ brief: BriefRow; briefs: BriefRow[] }> {\n const briefs = await workspace.siblings.briefs();\n const fromBranch = briefIdFromBranch(workspace.config.branches, workspace.branch);\n const active = findActive(briefs, { argument: positional, flag: options.brief, environment: io.env['SPEC_BRIEF'], branch: fromBranch });\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) throw new UsageError(problem);\n if (brief === null) throw new UsageError(note);\n return { brief, briefs };\n}\n\nconst MARK: Record<Finding['severity'], string> = { error: 'error ', warning: 'warning', note: 'note ' };\n\nfunction printFindings(io: CliIO, findings: readonly Finding[]): void {\n for (const finding of findings) {\n const where = finding.file === undefined ? '' : `${finding.file}${finding.line === undefined ? '' : `:${finding.line}`} `;\n io.stdout.write(`${MARK[finding.severity]} ${where}${finding.message} ${finding.rule}\\n ${finding.hint}\\n`);\n }\n}\n\n/* ----------------------------------------------------------------- context */\n\nexport async function contextCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief, briefs } = await targetBrief(workspace, options, io, options.positionals[0]);\n const packet = await buildContext(workspace, brief, briefs, reader, options.base);\n if (options.format === 'json') {\n io.stdout.write(\n json('context', {\n brief: brief.id,\n markdown: packet.markdown,\n included: packet.included,\n omitted: packet.omitted,\n unresolved: packet.unresolved,\n unclosedFrontMatter: packet.unclosedFrontMatter,\n unreadableFrontMatter: packet.unreadableFrontMatter,\n unreadableScope: packet.unreadableScope,\n unreadableProtections: packet.unreadableProtections,\n unreadableRulingPaths: packet.unreadableRulingPaths,\n unmatchedSpecs: packet.unmatchedSpecs,\n }),\n );\n } else {\n io.stdout.write(packet.markdown);\n }\n return EXIT_OK;\n}\n\n/* ------------------------------------------------------------------- audit */\n\nexport async function auditCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const result = await runAudit(workspace, brief, reader, options.base);\n const { counts, findings, measured } = result.report;\n if (options.format === 'json') {\n io.stdout.write(\n json('audit', {\n ok: counts.error === 0 && (!options.strict || counts.warning === 0),\n brief: brief.id,\n base: result.base.kind === 'resolved' ? { ref: result.base.ref, mergeBase: result.base.mergeBase, head: result.base.head } : null,\n counts,\n measured,\n findings,\n dependencies: result.dependencies,\n installScripts: result.installScripts,\n }),\n );\n } else if (options.format === 'pretty') {\n io.stdout.write(`audit of brief ${brief.id}${result.base.kind === 'resolved' ? ` from ${result.base.ref} (${result.base.mergeBase.slice(0, 12)})` : ''}\\n\\n`);\n printFindings(io, findings);\n // The counts stay the last line, where a script reads them.\n io.stdout.write(`\\n${describeMeasured(measured)}\\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)\\n`);\n } else {\n io.stdout.write(formatFindings(options.format, findings, { file: brief.file, version: version(), summary: describeMeasured(measured) }));\n }\n return counts.error > 0 || (options.strict && counts.warning > 0) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------- escalation */\n\nfunction parseOption(raw: string): EscalationOption {\n const colon = raw.indexOf(':');\n const option = colon < 0 ? { label: raw.trim(), consequence: '' } : { label: raw.slice(0, colon).trim(), consequence: raw.slice(colon + 1).trim() };\n // An option given nothing was refused where the command line was read, so\n // this one has a colon and nothing before it: a cost, and no choice it is\n // the cost of. The memo would number a choice with no name.\n if (option.label === '') throw new UsageError(`--option is ${JSON.stringify(raw)}, which names no choice before its colon; give it \"<label>: <cost>\"`);\n return option;\n}\n\nexport async function escalateCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n if (options.list) {\n const waiting = await listEscalations(workspace);\n if (options.format === 'json') io.stdout.write(json('escalate', { waiting }));\n else if (waiting.length === 0) io.stdout.write('no escalation is waiting\\n');\n else for (const request of waiting) io.stdout.write(`${request.id} brief ${request.brief} ${request.paths.join(', ')} ${request.reason.split('\\n')[0]}\\n`);\n return EXIT_OK;\n }\n if (options.show !== undefined) {\n const request = (await listEscalations(workspace)).find((candidate) => candidate.id === options.show);\n if (request === undefined) throw new UsageError(`no escalation \"${options.show}\" is waiting`);\n io.stdout.write(options.format === 'json' ? json('escalate', { request }) : renderMemo(request));\n return EXIT_OK;\n }\n if (options.paths.length === 0 || options.reason === undefined) {\n throw new UsageError('escalate needs --path <file> (repeatable) and --reason <why>; or --list, or --show <id>');\n }\n // Read before spec-brief is asked anything: a request that cannot be\n // written is refused for what is wrong with it, whatever the brief.\n const choices = options.options.map(parseOption);\n const { brief } = await targetBrief(workspace, options, io, undefined);\n const { request, memo } = await raiseEscalation(workspace, brief, {\n paths: options.paths,\n reason: options.reason,\n options: choices,\n recommendation: options.recommend ?? null,\n });\n io.stdout.write(options.format === 'json' ? json('escalate', { request, memo }) : memo);\n // Exit 1: the round is waiting on a person, which a caller must not read as done.\n return EXIT_FAILED;\n}\n\nexport async function ruleCommand(options: Options, io: CliIO): Promise<number> {\n const id = options.positionals[0];\n if (id === undefined) throw new UsageError('rule needs the escalation id, such as E-012-1');\n if (options.allow === options.deny) throw new UsageError('rule needs exactly one of --allow or --deny');\n if (options.note === undefined || options.note.trim() === '') throw new UsageError('rule needs --note: what exactly is allowed, or why not');\n const workspace = await openWorkspace(options, io);\n const recorded = await recordRuling(workspace, id, options.allow ? 'allow' : 'deny', options.note, reader);\n const command = `git commit -S -m \"ruling ${recorded.id}: ${options.allow ? 'allow' : 'deny'}\" -- ${recorded.file}`;\n if (options.format === 'json') {\n io.stdout.write(json('rule', { ruling: recorded.id, file: recorded.file, row: recorded.row, commit: command }));\n } else {\n io.stdout.write(`${recorded.file} now holds ruling ${recorded.id}:\\n\\n ${recorded.row}\\n\\nIt counts once you commit it signed, with a key the base branch's allowed signers list:\\n\\n ${command}\\n`);\n }\n return EXIT_OK;\n}\n\nexport async function rulingsCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const base = await resolveBase(workspace, options.base);\n const check = await checkRulings(workspace, brief, await briefText(workspace, brief), reader, base);\n if (options.format === 'json') {\n io.stdout.write(json('rulings', { brief: brief.id, rows: check.rows, verified: check.verified, unverified: check.unverified, problems: check.problems }));\n } else {\n if (check.rows.length === 0) io.stdout.write(`brief ${brief.id} holds no ruling\\n`);\n for (const row of check.rows) {\n const verified = check.verified.find((ruling) => ruling.id === row.id);\n const unverified = check.unverified.find((ruling) => ruling.id === row.id);\n // An allow row that does not verify is among the unverified, with its\n // reason, so the fallback for none is equivalent to its mutants.\n const state = row.decision === 'deny' ? 'refused' : verified !== undefined ? `signed by ${verified.signer}` : `not verified: ${unverified?.reason ?? ''}`;\n io.stdout.write(`${row.id} ${row.decision} ${row.paths.join(', ')} ${state}\\n`);\n }\n printFindings(io, check.problems);\n }\n return check.unverified.length > 0 || check.problems.length > 0 ? EXIT_FAILED : EXIT_OK;\n}\n\n/* ------------------------------------------------------------------- probe */\n\n/**\n * What is said of a command answered with its output still held, three\n * seconds after its shell ended or after its timeout: of a run, in its\n * evidence, and of a `setup`, in why the probe stopped or, where the setup\n * passed, in a line of its own. What holds the output is no part of the\n * command and was not stopped with it. What the sandbox can reach of it is\n * stopped when the probe is done at that commit; the rest runs on until it\n * ends or a person ends it, and the person is the one who can find it\n * (ADR-0003).\n */\nconst LEFT_RUNNING = ', and something it started was left running, holding its output';\n\nasync function runProbe(directory: string, probe: ProbeSpec, runs: number, timeout: number): Promise<ProbeResult['runs']> {\n const classified = [];\n for (let i = 0; i < runs; i += 1) {\n const report = probe.junit === null ? null : join(directory, probe.junit);\n if (report !== null) await rm(report, { force: true });\n const run = await runCommand(probe.run, directory, timeout);\n // existsSync answers false for null, so the null check is there for the\n // type, and its mutant is equivalent.\n const junit = report === null || !existsSync(report) ? null : readJUnit(await readFile(report, 'utf8'));\n const judged = classify(probe, { exitCode: run.exitCode, output: run.output, junit });\n // After whatever `classify` says of the run: red, green or stopped, it\n // is judged by its shell, and what it left is said beside the verdict.\n classified.push(run.outputHeld ? { ...judged, detail: `${judged.detail}${LEFT_RUNNING}` } : judged);\n }\n return classified;\n}\n\nexport async function probeCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const text = await briefText(workspace, brief);\n const set = readProbes(reader.codeBlocks(text));\n if (set.problems.length > 0) {\n for (const problem of set.problems) io.stderr.write(`spec-harness: ${brief.file}:${problem.line}: ${problem.message}\\n`);\n return EXIT_ERROR;\n }\n const probes = set.probes.filter((probe) => options.id === undefined || probe.id === options.id);\n if (probes.length === 0) {\n io.stdout.write(`brief ${brief.id} declares no probe${options.id === undefined ? '' : ` named ${options.id}`}\\n`);\n return options.id === undefined ? EXIT_OK : EXIT_ERROR;\n }\n const base = await resolveBase(workspace, options.base);\n if (base.kind === 'unresolved') throw new UsageError(base.reason);\n const at = options.at ?? (base.mergeBase === base.head ? 'base' : 'both');\n const results: ProbeResult[] = [];\n const measure = async (label: 'base' | 'head', commit: string, expected: 'red' | 'green'): Promise<void> => {\n await withWorktree(workspace.root, commit, async (directory) => {\n for (const file of set.files) {\n await mkdir(dirname(join(directory, file.path)), { recursive: true });\n await writeFile(join(directory, file.path), file.content.endsWith('\\n') ? file.content : `${file.content}\\n`);\n }\n const setups = [...new Set(probes.map((probe) => probe.setup).filter((setup): setup is string => setup !== null))];\n for (const setup of setups) {\n const timeout = workspace.config.probes.timeout;\n const run = await runCommand(setup, directory, timeout);\n // A setup stopped at its timeout has no exit code to have failed by,\n // and may have printed nothing: how long it was given is the reason.\n const how = run.exitCode === null ? `was stopped after ${timeout} seconds` : 'failed';\n if (run.exitCode !== 0) throw new UsageError(`the probe setup \"${setup}\" ${how} at ${label}${run.outputHeld ? LEFT_RUNNING : ''}:\\n${endOfOutput(run.output)}`);\n // A setup that passed says nothing else, and the runs after it start\n // beside what it left: on the standard error, whatever the format,\n // since the document has no place for a setup.\n if (run.outputHeld) io.stderr.write(`spec-harness: the probe setup \"${setup}\" passed at ${label}${LEFT_RUNNING}\\n`);\n }\n for (const probe of probes) {\n const runs = await runProbe(directory, probe, probe.runs ?? workspace.config.probes.runs, probe.timeout ?? workspace.config.probes.timeout);\n results.push({ probe, at: label, commit, expected, runs, verdict: verdictOf(expected, runs) });\n }\n });\n };\n if (at === 'base' || at === 'both') await measure('base', base.mergeBase, 'red');\n if (at === 'head' || at === 'both') await measure('head', base.head, 'green');\n const evidence = renderEvidence(results, set.hash, new Date().toISOString().slice(0, 10));\n const failed = results.filter((result) => result.verdict !== (result.expected === 'red' ? 'measured' : 'fixed'));\n if (options.format === 'json') {\n io.stdout.write(\n json('probe', {\n ok: failed.length === 0,\n brief: brief.id,\n hash: set.hash,\n results: results.map((result) => ({ id: result.probe.id, at: result.at, commit: result.commit, expected: result.expected, verdict: result.verdict, runs: result.runs })),\n evidence,\n }),\n );\n } else {\n io.stdout.write(`${evidence}\\n`);\n // On the standard error, beside the table and never in it: the table is\n // what a brief records and a script reads. The JSON document has the\n // same as a field of each such run, and so says nothing here.\n io.stderr.write(renderUnexplained(results));\n }\n return failed.length === 0 ? EXIT_OK : EXIT_FAILED;\n}\n"]}
@@ -8,6 +8,7 @@
8
8
  * nothing to add.
9
9
  */
10
10
  import type { AllowedSigner } from './signers.js';
11
+ import type { HookLine } from './usage.js';
11
12
  import { type ClaudeCodeCheck } from './versions.js';
12
13
  type Json = Record<string, unknown>;
13
14
  /** The project root, as Claude Code substitutes it in a hook's arguments and in a plugin server's. */
@@ -36,6 +37,59 @@ export declare function mcpServer(projectDir: string): Json;
36
37
  export declare function mergeMcp(current: Json): Json | null;
37
38
  /** Whether Claude Code settings hold the guard hooks, as this release or 0.1 wrote them. */
38
39
  export declare function holdsGuard(settings: unknown): boolean;
40
+ /** A line of the harness's in Claude Code's settings: what follows its command there. */
41
+ export interface WrittenHook {
42
+ /** The events whose hooks hold the line, of the two the guard answers. */
43
+ readonly events: readonly string[];
44
+ /** What follows the harness's command, word for word as written. */
45
+ readonly words: readonly string[];
46
+ /**
47
+ * Whether a shell reads those words first, and can change them: a line
48
+ * with no `args`, which Claude Code hands to a shell, holding a quote, a
49
+ * variable or anything else a shell rewrites. What the hook is handed is
50
+ * then the shell's to say. With `args`, Claude Code hands each word over
51
+ * as it stands.
52
+ */
53
+ readonly shell: boolean;
54
+ /** Whether the entry sets `onFailure` to `"block"`. */
55
+ readonly blocks: boolean;
56
+ }
57
+ /**
58
+ * Every line in Claude Code's settings that runs the harness, under the two
59
+ * events the guard answers: a line that stands under both, as init writes
60
+ * it, is one line. Whose line each is, the guard's or another command's, is
61
+ * the reader's to say (usage.ts): this knows the harness by its command
62
+ * alone.
63
+ */
64
+ export declare function writtenHooks(settings: unknown): WrittenHook[];
65
+ /** What doctor reports of one line of Claude Code's hook. */
66
+ export interface HookReport {
67
+ /** The settings file that holds it, as a person finds it. */
68
+ readonly file: string;
69
+ readonly events: readonly string[];
70
+ /** What follows the harness's command, as written. */
71
+ readonly line: readonly string[];
72
+ /** `unknown`: a shell reads the line before the hook does, so what the hook is handed cannot be told. */
73
+ readonly state: 'guards' | 'off' | 'unknown';
74
+ readonly onFailure: 'block' | null;
75
+ /** What there is to say of the line, or `null` for the line a release wrote, which guards. */
76
+ readonly detail: string | null;
77
+ /** What `onFailure` changes, where the entry sets it to `"block"`. */
78
+ readonly note: string | null;
79
+ }
80
+ /**
81
+ * The lines of Claude Code's hook in the settings files, each with what the
82
+ * hook does with it. `read` is the hook's own reading of the words it is
83
+ * handed (usage.ts), `null` for a line that is not its; the words are handed
84
+ * to it as Claude Code hands them to the hook, each `${CLAUDE_PROJECT_DIR}`
85
+ * filled with `project`.
86
+ *
87
+ * A line that guards and holds no more than a release wrote is reported
88
+ * with nothing to say, as it always was. One with more on it is said as it
89
+ * is, and fails nothing. One the hook cannot read, or whose root is no
90
+ * directory, is a guard that is off: a problem, and doctor exits 1 for it.
91
+ */
92
+ export declare function reportHooks(sources: readonly ClaudeSettings[], project: string, read: (words: readonly string[]) => HookLine | null): HookReport[];
39
93
  /** Whether a project's `.mcp.json` registers a server under the harness's name, however it runs it. */
40
94
  export declare function registersServer(mcp: unknown): boolean;
41
95
  /** A Claude Code settings file, named as a person finds it, and what reading it gave: an object, or nothing usable. */
@@ -69,14 +123,16 @@ export interface ClaudeCodeWiring {
69
123
  readonly plugin: EnabledPlugin | null;
70
124
  /** The settings files that hold the guard hooks. */
71
125
  readonly hooks: readonly string[];
126
+ /** Each line of the hook in those files, with what the hook does with it. */
127
+ readonly lines: readonly HookReport[];
72
128
  /** Whether `.mcp.json` registers the server. */
73
129
  readonly server: boolean;
74
130
  }
75
131
  export type WiringState = 'plugin' | 'init' | 'both' | 'none';
76
132
  /** Which of the four the wiring is. `both` is a double install, and doctor fails it; either of init's entries counts. */
77
- export declare function wiringState(wiring: ClaudeCodeWiring): WiringState;
133
+ export declare function wiringState(wiring: Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'>): WiringState;
78
134
  /** What `doctor` says of the wiring, and what to do when it is doubled or missing. */
79
- export declare function describeClaudeCode(wiring: ClaudeCodeWiring): string;
135
+ export declare function describeClaudeCode(wiring: Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'>): string;
80
136
  /** The spec-brief plugin this package ships, as spec-brief's `plugins` names it. */
81
137
  export declare const PLUGIN = "@descent-vtt/spec-harness/spec-brief-plugin";
82
138
  /** spec-brief's configuration files, in the order spec-brief looks for them in a directory. */
package/dist/configure.js CHANGED
@@ -8,6 +8,7 @@
8
8
  * nothing to add.
9
9
  */
10
10
  import { isAbsolute } from 'node:path';
11
+ import { literal } from './literal.js';
11
12
  import { parseGlobList } from './vendor/spec-core/pattern/index.js';
12
13
  import { CLAUDE_CODE_MINIMUM } from './versions.js';
13
14
  function isObject(value) {
@@ -116,6 +117,117 @@ export function holdsGuard(settings) {
116
117
  return Array.isArray(groups) && groups.some((group) => hooksOf(group).some((hook) => isGuard(hook) || isLegacyGuard(hook)));
117
118
  });
118
119
  }
120
+ /** The harness's command on a line: its script, or its name, alone or at the end of a path. */
121
+ function isLauncher(word) {
122
+ const name = word.split(/[\\/]/).at(-1);
123
+ return name === 'spec-harness' || name === 'spec-harness.js';
124
+ }
125
+ /** Anything in a word that a shell reads before the program is handed it: a quote, a variable, an operator, a pattern. */
126
+ const SHELL_READS = /[^A-Za-z0-9_./:=@%+,-]/;
127
+ function writtenHook(hook) {
128
+ if (!isObject(hook))
129
+ return null;
130
+ const { command, args } = hook;
131
+ if (typeof command !== 'string')
132
+ return null;
133
+ let line;
134
+ // Without arguments the line is a shell's, which splits it at its spaces:
135
+ // at each one here, and what stands between two of them is no word.
136
+ if (args === undefined)
137
+ line = command.split(/\s/).filter((word) => word !== '');
138
+ else if (Array.isArray(args) && args.every((arg) => typeof arg === 'string'))
139
+ line = [command, ...args];
140
+ // Arguments that are not all text are no line Claude Code can start.
141
+ else
142
+ return null;
143
+ const shell = args === undefined;
144
+ // A quote around the path of the command is the shell's, dropped to know the command by.
145
+ const at = line.findIndex((word) => isLauncher(shell ? word.replace(/["']/g, '') : word));
146
+ if (at === -1)
147
+ return null;
148
+ const words = line.slice(at + 1);
149
+ return { words, shell: shell && words.some((word) => SHELL_READS.test(word)), blocks: hook['onFailure'] === 'block' };
150
+ }
151
+ /**
152
+ * Every line in Claude Code's settings that runs the harness, under the two
153
+ * events the guard answers: a line that stands under both, as init writes
154
+ * it, is one line. Whose line each is, the guard's or another command's, is
155
+ * the reader's to say (usage.ts): this knows the harness by its command
156
+ * alone.
157
+ */
158
+ export function writtenHooks(settings) {
159
+ const hooks = field(settings, 'hooks');
160
+ if (!isObject(hooks))
161
+ return [];
162
+ const found = [];
163
+ for (const event of GUARDED_EVENTS) {
164
+ const groups = hooks[event];
165
+ if (!Array.isArray(groups))
166
+ continue;
167
+ for (const hook of groups.flatMap(hooksOf)) {
168
+ const written = writtenHook(hook);
169
+ if (written === null)
170
+ continue;
171
+ const same = found.find((other) => other.shell === written.shell && other.blocks === written.blocks && sameStrings(other.words, written.words));
172
+ if (same === undefined)
173
+ found.push({ events: [event], ...written });
174
+ else if (!same.events.includes(event))
175
+ same.events.push(event);
176
+ }
177
+ }
178
+ return found;
179
+ }
180
+ /**
181
+ * The release of Claude Code that reads `onFailure` on a hook's entry, by its
182
+ * hooks reference (https://code.claude.com/docs/en/hooks, read 2026-10-12).
183
+ */
184
+ const ON_FAILURE_SINCE = '2.1.295';
185
+ /** What `onFailure: "block"` changes for a line, named by `where` it stands, or `null` where the entry does not set it. */
186
+ function describeOnFailure(where, blocks, off) {
187
+ if (!blocks)
188
+ return null;
189
+ const holds = `${where} sets onFailure to "block", so Claude Code ${ON_FAILURE_SINCE} or later holds a write when the hook fails`;
190
+ if (off)
191
+ return `${holds}, which with this line is every write, the one that mends the line among them: mend it by hand`;
192
+ return `${holds}, where it lets the write go ahead without it: by its exit 1 for a question it cannot read, by not starting, or by running past its timeout`;
193
+ }
194
+ /**
195
+ * The lines of Claude Code's hook in the settings files, each with what the
196
+ * hook does with it. `read` is the hook's own reading of the words it is
197
+ * handed (usage.ts), `null` for a line that is not its; the words are handed
198
+ * to it as Claude Code hands them to the hook, each `${CLAUDE_PROJECT_DIR}`
199
+ * filled with `project`.
200
+ *
201
+ * A line that guards and holds no more than a release wrote is reported
202
+ * with nothing to say, as it always was. One with more on it is said as it
203
+ * is, and fails nothing. One the hook cannot read, or whose root is no
204
+ * directory, is a guard that is off: a problem, and doctor exits 1 for it.
205
+ */
206
+ export function reportHooks(sources, project, read) {
207
+ return sources.flatMap(({ file, settings }) => writtenHooks(settings).flatMap((hook) => {
208
+ const handed = read(hook.words.map((word) => word.split(PROJECT_DIR).join(project)));
209
+ if (handed === null)
210
+ return [];
211
+ const both = GUARDED_EVENTS.every((event) => hook.events.includes(event));
212
+ // An empty word is shown as a shell spells one, where joined it would not show at all.
213
+ // A line that is not under both events is under one.
214
+ const where = `"${hook.words.map((word) => (word === '' ? "''" : word)).join(' ')}" in ${file}${both ? '' : ` (under ${hook.events[0]} alone)`}`;
215
+ const written = { file, events: hook.events, line: hook.words, onFailure: hook.blocks ? 'block' : null };
216
+ if (hook.shell) {
217
+ const detail = `${where} is a shell's to read before the hook is handed it, so what the hook does with it cannot be told here: written with "args", each word reaches the hook as it stands`;
218
+ return [{ ...written, state: 'unknown', detail, note: describeOnFailure(where, hook.blocks, false) }];
219
+ }
220
+ if (handed.state === 'off') {
221
+ const detail = `${where}: ${handed.fault.wrong}, so the guard is off and no write is checked; ${handed.fault.mend}`;
222
+ return [{ ...written, state: 'off', detail, note: describeOnFailure(where, hook.blocks, true) }];
223
+ }
224
+ // What a release wrote: its hook, and nothing after it.
225
+ if (sameStrings(hook.words, ['hook', 'claude']))
226
+ return [{ ...written, state: 'guards', detail: null, note: describeOnFailure(where, hook.blocks, false) }];
227
+ const root = handed.root === undefined ? '' : `, and its root, ${handed.root}, is a directory`;
228
+ return [{ ...written, state: 'guards', detail: `${where} is more than init writes, and guards: the hook reads the line${root}`, note: describeOnFailure(where, hook.blocks, false) }];
229
+ }));
230
+ }
119
231
  /** Whether a project's `.mcp.json` registers a server under the harness's name, however it runs it. */
120
232
  export function registersServer(mcp) {
121
233
  const servers = field(mcp, 'mcpServers');
@@ -152,10 +264,10 @@ function isOn(plugin) {
152
264
  function turnOff(plugin) {
153
265
  return `turn the plugin off for this project with claude plugin disable ${plugin.id} --scope local`;
154
266
  }
155
- const PARTS = {
267
+ const PARTS = literal({
156
268
  hooks: { brings: 'the guard hooks', twice: 'every write is guarded twice', skipped: 'init writes none', entry: "spec-harness's hooks", them: 'them' },
157
269
  server: { brings: 'the server', twice: 'the server is registered twice', skipped: 'init registers none', entry: 'the spec-harness server', them: 'it' },
158
- };
270
+ });
159
271
  /**
160
272
  * What init says of a Claude Code file it leaves alone because the plugin is
161
273
  * on and brings the same `part`. A file that holds init's entry already is a
@@ -461,7 +573,8 @@ export function describeGraph(archiveGlob, briefs, reads, added) {
461
573
  }
462
574
  /** spec-graph's configuration with the archive read as history, or `null` when it already is. */
463
575
  export function mergeSpecGraph(current, archiveGlob) {
464
- const history = Array.isArray(current['historyPatterns']) ? current['historyPatterns'].filter((p) => typeof p === 'string') : [];
576
+ const patterns = current['historyPatterns'];
577
+ const history = Array.isArray(patterns) ? patterns.filter((p) => typeof p === 'string') : [];
465
578
  if (history.includes(archiveGlob))
466
579
  return null;
467
580
  return { ...current, historyPatterns: [...history, archiveGlob] };