@descent-vtt/spec-harness 0.16.0 → 0.18.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.
@@ -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 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"]}
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 { isDirectory } from './fs.js';\nimport { readJUnit, type JUnitRead } 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\n/**\n * What is read of a probe's report where a directory stands under its name,\n * as a repository can hold one: no report, said in the probe's own words\n * for one it cannot read. Taken away as a file or read as one, it ended the\n * command on Node's EISDIR and a stack.\n */\nconst A_DIRECTORY: JUnitRead = { ok: false, error: 'it is a directory, not a report' };\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 // A report an earlier run left is taken away, so that what is read\n // after this run is this run's. A directory is none, and is left.\n if (report !== null && !isDirectory(report)) 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 : isDirectory(report) ? A_DIRECTORY : 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,7 +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
+ import { type HookLine } from './usage.js';
12
12
  import { type ClaudeCodeCheck } from './versions.js';
13
13
  type Json = Record<string, unknown>;
14
14
  /** The project root, as Claude Code substitutes it in a hook's arguments and in a plugin server's. */
@@ -24,6 +24,53 @@ export declare const PROJECT_DIR_OR_HERE = "${CLAUDE_PROJECT_DIR:-.}";
24
24
  * path is one argument whatever it holds, and no shell is involved.
25
25
  */
26
26
  export declare const GUARD_HOOK: Readonly<Json>;
27
+ /**
28
+ * The release of Claude Code from which a comma in a matcher separates
29
+ * names as a `|` does. Its page on debugging a configuration (Check hooks,
30
+ * read 2026-10-14) has a comma before it fall through to the reading of a
31
+ * pattern, under which the matcher never matched, and its changelog has the
32
+ * fix under this release: hooks with comma-separated matchers no longer
33
+ * silently never firing.
34
+ */
35
+ export declare const COMMA_SINCE = "2.1.191";
36
+ /**
37
+ * How the Claude Code that runs the hooks reads a comma in a matcher of
38
+ * names: as a separator, from {@link COMMA_SINCE} on; as part of a pattern,
39
+ * in the release named, which is older; or it cannot be told, where the
40
+ * release cannot.
41
+ */
42
+ export type Commas = {
43
+ readonly as: 'separator';
44
+ } | {
45
+ readonly as: 'pattern';
46
+ readonly release: string;
47
+ } | {
48
+ readonly as: 'untold';
49
+ };
50
+ /**
51
+ * How the Claude Code doctor asked its release reads a comma. A release that
52
+ * was not asked, or could not be told, leaves the reading untold: asked or
53
+ * not, nothing says which it is.
54
+ */
55
+ export declare function commasUnder(release: ClaudeCodeCheck | null): Commas;
56
+ /** What reads a matcher that is a pattern: the writing tools it matches, or `null` where that cannot be told. */
57
+ export type PatternReader = (source: string) => readonly string[] | null;
58
+ /**
59
+ * A reader for one run: a pattern is read the first time it is asked of,
60
+ * and answered from that reading after.
61
+ *
62
+ * A reading that runs out its budget costs the whole of it, a settings file
63
+ * can hold one matcher over any number of entries, and init asks of an
64
+ * entry twice, for what doctor says of the file and for what to write into
65
+ * it. Fifty entries under one such pattern were fifty readings, five and a
66
+ * half seconds, and fifty-one for init; they are one. Nothing is spared a
67
+ * file that holds a pattern of its own for each entry.
68
+ *
69
+ * Made where a run begins and handed down, never kept by this module: a
70
+ * reading is of the clock, so one kept past its run would answer for a
71
+ * machine that is busy no longer.
72
+ */
73
+ export declare function patternReader(read?: PatternReader): PatternReader;
27
74
  /**
28
75
  * `.claude/settings.json`, or the plugin's hooks, with the guard hooks merged
29
76
  * in; `null` when they are already there.
@@ -36,8 +83,15 @@ export declare const GUARD_HOOK: Readonly<Json>;
36
83
  * init rewrites none but the one 0.1 wrote. Without `isHook`, only init's
37
84
  * own line is known: the default's `false` and an `undefined` read the same
38
85
  * in `some`, so that mutant is equivalent.
86
+ *
87
+ * `pattern` reads a matcher that is a pattern: the run's own reader, where
88
+ * the run has read the file's matchers already ({@link patternReader}).
89
+ * `commas` is how the Claude Code here reads a comma in a matcher of names,
90
+ * where the run asked its release ({@link commasUnder}): a line that
91
+ * release starts for no write is no guard, and init's own is written beside
92
+ * it.
39
93
  */
40
- export declare function mergeClaudeSettings(current: Json, isHook?: (words: readonly string[]) => boolean): Json | null;
94
+ export declare function mergeClaudeSettings(current: Json, isHook?: (words: readonly string[]) => boolean, pattern?: PatternReader, commas?: Commas): Json | null;
41
95
  /** The server's entry, reading the project at `projectDir`: {@link PROJECT_DIR} for the plugin, {@link PROJECT_DIR_OR_HERE} for a project. */
42
96
  export declare function mcpServer(projectDir: string): Json;
43
97
  /**
@@ -63,6 +117,13 @@ export interface WrittenHook {
63
117
  readonly shell: boolean;
64
118
  /** Whether the entry sets `onFailure` to `"block"`. */
65
119
  readonly blocks: boolean;
120
+ /**
121
+ * What the entry has for `type` where that is not `"command"`, as it is
122
+ * said of the line: none at all, or a word the reference does not list.
123
+ * Whether Claude Code runs such an entry cannot be told. `null` for an
124
+ * entry it runs as a command.
125
+ */
126
+ readonly untyped: string | null;
66
127
  }
67
128
  /**
68
129
  * Every line in Claude Code's settings that runs the harness, under the two
@@ -83,17 +144,20 @@ export interface HookReport {
83
144
  readonly line: readonly string[];
84
145
  /**
85
146
  * `guards`: Claude Code waits on the hook before a write, and the hook
86
- * checks it. `off`: the hook checks no write, for a line it cannot read or
87
- * a root that is no directory. `held`: the hook holds every write, for a
147
+ * checks it. `off`: the hook checks no write, for a line it cannot read, a
148
+ * root that is no directory, or a root that is a directory outside any
149
+ * work tree; or it is never started, in a file an array for a matcher
150
+ * keeps Claude Code from loading the hooks of. `held`: the hook holds every write, for a
88
151
  * brief the line names that is not one. `unstarted`: Claude Code waits on
89
152
  * the line before no write, so it is not the guard. `unknown`: what the
90
- * hook is handed, or which writes it is started for, cannot be told here.
153
+ * hook is handed, which writes it is started for, or whether Claude Code
154
+ * runs the entry at all, cannot be told here.
91
155
  */
92
156
  readonly state: 'guards' | 'off' | 'held' | 'unstarted' | 'unknown';
93
157
  readonly onFailure: 'block' | null;
94
158
  /** What there is to say of what the hook does with the line, or `null`. */
95
159
  readonly detail: string | null;
96
- /** The writing tools Claude Code waits on the line before a write by, where the hook can refuse it; `null` where that cannot be told. */
160
+ /** The writing tools Claude Code waits on the line before a write by, where the hook can refuse it, of those a supported Claude Code can call (hooks.ts); `null` where that cannot be told. */
97
161
  readonly before: readonly string[] | null;
98
162
  /** The writing tools Claude Code starts the line after a write by, where the hook can warn of it; `null` where that cannot be told. */
99
163
  readonly after: readonly string[] | null;
@@ -102,6 +166,30 @@ export interface HookReport {
102
166
  /** What `onFailure` changes, where the entry sets it to `"block"`. */
103
167
  readonly note: string | null;
104
168
  }
169
+ /** An array that stands for a matcher where it unloads a settings file's hooks: the event it stands under, and the array as written. */
170
+ export interface ArrayMatcher {
171
+ readonly event: string;
172
+ readonly matcher: string;
173
+ }
174
+ /**
175
+ * The first array that stands for a matcher under `PreToolUse` or
176
+ * `PermissionRequest` in a settings file, or `null`.
177
+ *
178
+ * Claude Code's page on debugging a configuration
179
+ * (https://code.claude.com/docs/en/debug-your-config, Check hooks, read
180
+ * 2026-10-14) has a matcher that is an array, where it must be one string,
181
+ * as an entry Claude Code lists as an invalid setting, at the start of an
182
+ * interactive session and in `claude doctor`; and where the array is under
183
+ * one of these two events, none of that file's other hooks load either. It
184
+ * names no release. So a file that holds one runs no hook at all, whoever
185
+ * wrote the entry and whatever it runs: the array's own is not loaded, and
186
+ * neither is any other.
187
+ */
188
+ export declare function arrayMatcher(settings: unknown): ArrayMatcher | null;
189
+ /** What is said of a settings file that an array for a matcher keeps Claude Code from loading the hooks of. */
190
+ export declare function describeArrayMatcher(file: string, { event, matcher }: ArrayMatcher): string;
191
+ /** How a matcher that is an array is mended. */
192
+ export declare const ONE_STRING = "write the matcher as one string, its names between \"|\"";
105
193
  /** The words handed over for every line of the harness's in the settings files, for a caller that has to ask something of each before it reports them. */
106
194
  export declare function handedLines(sources: readonly ClaudeSettings[], project: string): string[][];
107
195
  /**
@@ -114,12 +202,25 @@ export declare function handedLines(sources: readonly ClaudeSettings[], project:
114
202
  * A line that guards and holds no more than a release wrote is reported
115
203
  * with nothing to say, as it always was. One with more on it is said as it
116
204
  * is, and fails nothing. One the hook cannot read, or whose root is no
117
- * directory, is a guard that is off, and one that names a brief which is not
205
+ * directory, or is in no work tree that holds the project, is a guard that
206
+ * is off, and one that names a brief which is not
118
207
  * one holds every write: each a problem, and doctor exits 1 for it. A line
119
208
  * Claude Code waits on before no write is not the guard, whatever the hook
120
209
  * would do with it.
210
+ *
211
+ * `pattern` reads a matcher that is a pattern, once for every entry under
212
+ * it in every file: the run's own reader, where something else in the run
213
+ * reads the same files ({@link patternReader}). `commas` is how the Claude
214
+ * Code here reads a comma in a matcher of names, where its release was
215
+ * asked ({@link commasUnder}); a caller that asks none reads a comma as
216
+ * every release from {@link COMMA_SINCE} on does.
217
+ *
218
+ * A file that holds an array for a matcher under `PreToolUse` or
219
+ * `PermissionRequest` has none of its hooks loaded ({@link arrayMatcher}):
220
+ * each line of the hook there is started for no write, and one that stood
221
+ * to be started for a write is a guard that is off.
121
222
  */
122
- export declare function reportHooks(sources: readonly ClaudeSettings[], project: string, read: (words: readonly string[]) => HookLine | null): HookReport[];
223
+ export declare function reportHooks(sources: readonly ClaudeSettings[], project: string, read: (words: readonly string[]) => HookLine | null, pattern?: PatternReader, commas?: Commas): HookReport[];
123
224
  /** Whether a project's `.mcp.json` registers a server under the harness's name, however it runs it. */
124
225
  export declare function registersServer(mcp: unknown): boolean;
125
226
  /** A Claude Code settings file, named as a person finds it, and what reading it gave: an object, or nothing usable. */
@@ -141,6 +242,87 @@ export interface EnabledPlugin {
141
242
  * turns it on.
142
243
  */
143
244
  export declare function enabledPlugin(sources: readonly ClaudeSettings[]): EnabledPlugin | null;
245
+ /**
246
+ * The settings file whose `disableAllHooks` turns Claude Code's hooks off,
247
+ * or `null` where none does.
248
+ *
249
+ * By its settings reference
250
+ * (https://code.claude.com/docs/en/settings-reference, disableAllHooks, read
251
+ * 2026-10-12) the key is a Boolean any settings file may hold, and `true`
252
+ * turns hooks off. Set outside managed settings, it turns off the hooks of
253
+ * the user's, the project's and the local settings and of plugins, and the
254
+ * hooks of managed settings, of the Agent SDK and of a plugin that managed
255
+ * settings force on keep running. By its hooks reference (Disable or remove
256
+ * hooks) the value that counts is the one left after settings precedence:
257
+ * of the files given, lowest precedence first, the last that sets a Boolean
258
+ * decides. A value that is no Boolean is passed over, as the key left out.
259
+ */
260
+ export declare function hooksDisabled(sources: readonly ClaudeSettings[]): string | null;
261
+ /** The project's settings file for Claude Code, as it is named among the sources. */
262
+ export declare const PROJECT_SETTINGS = ".claude/settings.json";
263
+ /** Where Claude Code records the marketplaces it has fetched, in a directory it keeps plugins in. */
264
+ export declare const MARKETPLACE_REGISTRY = "known_marketplaces.json";
265
+ /** Where it records the marketplaces hosted on claude.ai, in a shape its reference does not give. */
266
+ export declare const HOSTED_REGISTRY = "known_marketplaces_claudeai.json";
267
+ /**
268
+ * The marketplace a plugin's id names, where it names one whose directory
269
+ * can be looked up: `null` for an origin that is no marketplace, and for
270
+ * text that names no directory.
271
+ */
272
+ export declare function pluginMarketplace(id: string): string | null;
273
+ /** What one of the directories Claude Code keeps plugins in holds of a plugin and its marketplace. */
274
+ export interface PluginsRoot {
275
+ readonly directory: string;
276
+ /** Whether its cache holds a version of the plugin that no `.orphaned_at` marks as left behind. */
277
+ readonly cached: boolean;
278
+ /** Its `known_marketplaces.json` as read: `null` where there is none. */
279
+ readonly registry: Json | null | 'unreadable';
280
+ /** Whether a record of marketplaces hosted on claude.ai stands beside it. */
281
+ readonly hosted: boolean;
282
+ }
283
+ /**
284
+ * Whether this machine has what Claude Code loads a plugin from. `detail`
285
+ * is why, where the plugin is not simply there.
286
+ */
287
+ export type PluginPresence = {
288
+ readonly state: 'present';
289
+ readonly detail: null;
290
+ } | {
291
+ readonly state: 'absent' | 'unknown';
292
+ readonly detail: string;
293
+ };
294
+ /**
295
+ * Whether the plugin that settings turn on is on this machine, by Claude
296
+ * Code's plugin loading reference
297
+ * (https://code.claude.com/docs/en/plugins/loading, read 2026-10-12), from
298
+ * the settings files and from what the directories it keeps plugins in
299
+ * hold: its plugins root, and each seed directory.
300
+ *
301
+ * `present`: a version of it is in a cache, where the reference has one
302
+ * directory for each installed version of a marketplace plugin (Find
303
+ * plugins on disk).
304
+ *
305
+ * `absent` is said only where the reference leaves the plugin no way to
306
+ * load (Enabled in project settings but not installed): its only `true` is
307
+ * in the project's `.claude/settings.json`, for which Claude Code fetches
308
+ * no plugin a machine lacks, and neither of the page's two exceptions is
309
+ * met, a marketplace that lists it by a relative path, since no marketplace
310
+ * of that name is recorded as fetched or declared in settings, and a seed
311
+ * directory that holds it.
312
+ *
313
+ * Everything else is `unknown`: an origin that is no marketplace, a record
314
+ * that is not there or cannot be read, a marketplace that is there or is
315
+ * declared, whose own list is not read here, and a `true` in a settings
316
+ * file of the person's own, for which Claude Code fetches.
317
+ */
318
+ export declare function pluginPresence(plugin: EnabledPlugin, sources: readonly ClaudeSettings[], roots: readonly PluginsRoot[]): PluginPresence;
319
+ /**
320
+ * What init says of a Claude Code file where the plugin that settings turn
321
+ * on is not on this machine. It writes nothing on that reading alone: a
322
+ * plugin that is there after all would bring the same `part` a second time.
323
+ * A file that holds init's entry already is `present`.
324
+ */
325
+ export declare function describeAbsent(plugin: EnabledPlugin, detail: string, part: 'hooks' | 'server', present: boolean): string;
144
326
  /**
145
327
  * What init says of a Claude Code file it leaves alone because the plugin is
146
328
  * on and brings the same `part`. A file that holds init's entry already is a
@@ -153,18 +335,57 @@ export declare function describeSkipped(plugin: EnabledPlugin, part: 'hooks' | '
153
335
  /** How Claude Code is wired to the harness: the plugin, init's entries, both or neither. */
154
336
  export interface ClaudeCodeWiring {
155
337
  readonly plugin: EnabledPlugin | null;
338
+ /** Whether this machine has what Claude Code loads that plugin from; `null` where no settings file turns one on. */
339
+ readonly presence: PluginPresence | null;
340
+ /** The settings file whose `disableAllHooks` turns the hooks off, or `null`. */
341
+ readonly hooksOff: string | null;
156
342
  /** The settings files that hold the guard hooks: a line of the hook that Claude Code starts for a write, before it or after. */
157
343
  readonly hooks: readonly string[];
158
344
  /** Each line of the hook in the settings files, with what the hook does with it and the writes it is started for. */
159
345
  readonly lines: readonly HookReport[];
160
346
  /** Whether `.mcp.json` registers the server. */
161
347
  readonly server: boolean;
348
+ /**
349
+ * The release of the Claude Code on `PATH`, where it was asked: a matcher
350
+ * that lists names with a comma is read as that release reads it
351
+ * ({@link commasUnder}). `null` where it was not asked.
352
+ */
353
+ readonly release: ClaudeCodeCheck | null;
162
354
  }
163
355
  export type WiringState = 'plugin' | 'init' | 'both' | 'none';
164
- /** Which of the four the wiring is. `both` is a double install, and doctor fails it; either of init's entries counts. */
165
- export declare function wiringState(wiring: Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'>): WiringState;
356
+ /** The wiring as its descriptions read it: what a caller knows of the plugin's presence, which one that does not ask leaves out. */
357
+ type Wired = Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'> & {
358
+ readonly presence?: PluginPresence | null;
359
+ };
360
+ /**
361
+ * Which of the four the wiring is. `both` is a double install, and doctor
362
+ * fails it; either of init's entries counts. A plugin that is not on this
363
+ * machine brings nothing to it, and is not counted.
364
+ */
365
+ export declare function wiringState(wiring: Wired): WiringState;
366
+ /**
367
+ * Whether hooks that would guard are switched off: `disableAllHooks` in a
368
+ * settings file, where a settings file holds the guard hooks or a plugin
369
+ * that may be on this machine brings them. A guard someone set up, which
370
+ * checks no write.
371
+ */
372
+ export declare function guardSwitchedOff(wiring: Wired & Pick<ClaudeCodeWiring, 'hooksOff'>): boolean;
373
+ /**
374
+ * What doctor and init say of `disableAllHooks` in `file`. `guarded` is
375
+ * whether there are guard hooks for it to switch off; without any it is a
376
+ * note on what the key would do to them.
377
+ */
378
+ export declare function describeHooksOff(file: string, guarded: boolean): string;
379
+ /**
380
+ * What doctor adds of the plugin settings turn on, where it is not simply on
381
+ * this machine: that it cannot be told, which is never fine, or that it is
382
+ * not, beside entries of init's. `null` where there is no more to say: no
383
+ * plugin, one that is there, and one that is not where nothing else is
384
+ * wired, which the wiring's own sentence says.
385
+ */
386
+ export declare function describePresence(wiring: Wired): string | null;
166
387
  /** What `doctor` says of the wiring, and what to do when it is doubled or missing. */
167
- export declare function describeClaudeCode(wiring: Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'>): string;
388
+ export declare function describeClaudeCode(wiring: Wired): string;
168
389
  /** The spec-brief plugin this package ships, as spec-brief's `plugins` names it. */
169
390
  export declare const PLUGIN = "@descent-vtt/spec-harness/spec-brief-plugin";
170
391
  /** spec-brief's configuration files, in the order spec-brief looks for them in a directory. */
@@ -264,6 +485,17 @@ export declare function describeClaudeRelease(check: ClaudeCodeCheck): string;
264
485
  export type GitHookState = {
265
486
  readonly state: 'runs' | 'absent' | 'other' | 'inert';
266
487
  readonly file: string;
488
+ }
489
+ /**
490
+ * What stands at the path is no file, `what` it is instead. `stops`: git
491
+ * can execute it, tries to run it as the hook, fails, and stops every
492
+ * commit. `ignored`: git cannot execute it, and skips it as it skips a
493
+ * hook that is not executable.
494
+ */
495
+ | {
496
+ readonly state: 'stops' | 'ignored';
497
+ readonly file: string;
498
+ readonly what: string;
267
499
  } | {
268
500
  readonly state: 'unknown';
269
501
  readonly reason: string;