@descent-vtt/spec-harness 0.14.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +34 -0
- package/README.md +8 -1
- package/dist/answers.js +2 -1
- package/dist/answers.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +26 -23
- package/dist/cli.js.map +1 -1
- package/dist/configure.d.ts +58 -2
- package/dist/configure.js +116 -3
- package/dist/configure.js.map +1 -1
- package/dist/context.js +2 -1
- package/dist/context.js.map +1 -1
- package/dist/fs.js +1 -0
- package/dist/fs.js.map +1 -1
- package/dist/git.js +2 -1
- package/dist/git.js.map +1 -1
- package/dist/hooks.js.map +1 -1
- package/dist/host.js.map +1 -1
- package/dist/literal.d.ts +18 -0
- package/dist/literal.js +21 -0
- package/dist/literal.js.map +1 -0
- package/dist/probe.js +1 -1
- package/dist/probe.js.map +1 -1
- package/dist/reader.js +2 -0
- package/dist/reader.js.map +1 -1
- package/dist/round.d.ts +12 -1
- package/dist/round.js +23 -7
- package/dist/round.js.map +1 -1
- package/dist/sandbox.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/setup.js +2 -1
- package/dist/setup.js.map +1 -1
- package/dist/siblings.js +2 -1
- package/dist/siblings.js.map +1 -1
- package/dist/signers.js +5 -0
- package/dist/signers.js.map +1 -1
- package/dist/usage.d.ts +73 -27
- package/dist/usage.js +51 -7
- package/dist/usage.js.map +1 -1
- package/dist/versions.js +3 -0
- package/dist/versions.js.map +1 -1
- package/dist/workspace.js +3 -1
- package/dist/workspace.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Rounds of agent work under a brief: context, a guard on every write, escalations a person signs, an audit at the end. Needs Claude Code 2.1.139 or later, and @descent-vtt/spec-harness and @descent-vtt/spec-brief 0.2.0 or later installed in the project.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "DescentVTT",
|
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,40 @@ only fixes, reports less or documents, so `^0.7.0` takes only releases that
|
|
|
9
9
|
cannot turn a run red. The family's policy is
|
|
10
10
|
[spec-core's ADR-0009](https://github.com/DescentVTT/spec-core/blob/main/docs/adr/0009-versions-before-1-0.md).
|
|
11
11
|
|
|
12
|
+
## 0.15.0
|
|
13
|
+
|
|
14
|
+
`doctor` reads the line of Claude Code's hook as the hook itself reads it:
|
|
15
|
+
a line with more on it than `init` writes is said to guard where it does,
|
|
16
|
+
and a line the hook cannot read, or whose `--root` is no directory, is said
|
|
17
|
+
as a guard that is off, exit 1, where each was reported as no guard at all
|
|
18
|
+
or not reported.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **`doctor` reads the line of Claude Code's hook as the hook reads it.** It
|
|
23
|
+
knew the hook only where its command and arguments were exactly what
|
|
24
|
+
`init` writes, or what 0.1 wrote: a line with `--root
|
|
25
|
+
${CLAUDE_PROJECT_DIR}` added by hand, which guards, was reported as
|
|
26
|
+
`neither the spec-harness plugin nor the hooks init writes, so Claude Code
|
|
27
|
+
guards no write`, and a line that turns the guard off was reported the
|
|
28
|
+
same way, with exit 0. It now knows the hook by its command and the words
|
|
29
|
+
`hook claude`, whatever else is on the line, and reads the rest through
|
|
30
|
+
the code the hook reads it with. A line that guards with more on it than
|
|
31
|
+
`init` writes is said as it is and fails nothing. A line the hook cannot
|
|
32
|
+
read, and a `--root` that is not a directory, are said in the hook's own
|
|
33
|
+
words, as a guard that is off, and `doctor` exits 1. A line with no
|
|
34
|
+
`args`, which a shell reads first, is *cannot tell* where the shell would
|
|
35
|
+
change what follows the command: said, and a failure under `--strict`.
|
|
36
|
+
`"onFailure": "block"` on the entry is said in a note, with what it
|
|
37
|
+
changes. `--format json` has each line as `claudeCode.lines`
|
|
38
|
+
([ADR-0005](https://github.com/DescentVTT/spec-harness/blob/main/docs/adr/0005-a-guard-is-a-guardrail.md)).
|
|
39
|
+
Upgrading: a hook's line changed by hand is now the guard to `doctor`, so
|
|
40
|
+
it asks Claude Code its release for it, and beside the plugin it is the
|
|
41
|
+
double install it always was, exit 1. Where `doctor` now exits 1 for a
|
|
42
|
+
line, the guard was off already: mend the line it names, or write
|
|
43
|
+
`hook claude` and nothing after it, as `init` does. The lines `init` and
|
|
44
|
+
the plugin wrote are reported as before.
|
|
45
|
+
|
|
12
46
|
## 0.14.0
|
|
13
47
|
|
|
14
48
|
`hook claude` says a line of its own that it cannot read with exit 1 and
|
package/README.md
CHANGED
|
@@ -374,6 +374,13 @@ The first thing to run when a hook refuses something unexpectedly. It reports:
|
|
|
374
374
|
- A `cert-authority` line is a certificate authority's key, not a person's, and is left out.
|
|
375
375
|
- A line OpenSSH refuses is named as no signer, with why. Its quotes are read as OpenSSH reads them: in the principals, the first double quote, wherever it opens, is taken out with the next, which ends the field; an option's value is always in double quotes, `\"` a quote inside it. And its options are OpenSSH's: `cert-authority`, `namespaces`, `valid-after` and `valid-before`, separated by commas.
|
|
376
376
|
- **How Claude Code runs the guard**: the Claude Code plugin, with the settings file that turns it on; `init`'s hooks and server; both, which guards every write twice and exits 1, with how to keep one; or neither.
|
|
377
|
+
- A hook in Claude Code's settings is the guard by its command, `spec-harness` or its script, and the words `hook claude`, whatever else is on its line. `doctor` reads the line as the hook reads it, through the same code, with the project in place of `${CLAUDE_PROJECT_DIR}`, and says what the hook does with it.
|
|
378
|
+
- A line that holds more than `init` writes, such as `--root ${CLAUDE_PROJECT_DIR}` or `--brief 012`, is said as it is and fails nothing: `"hook claude --root ${CLAUDE_PROJECT_DIR}" in .claude/settings.json is more than init writes, and guards: the hook reads the line, and its root, /work/app, is a directory`.
|
|
379
|
+
- A line the hook cannot read, and a `--root` that is a file or is not there, are a guard that is off. Each is said in the words the hook itself says before a write, and exits 1.
|
|
380
|
+
- A line with no `args` is one Claude Code hands to a shell. Where it holds a quote, a variable or anything else a shell rewrites after its command, what the hook is handed is *cannot tell*, never fine; `--strict` fails it. Written with `args`, each word reaches the hook as it stands, and `doctor` reads it.
|
|
381
|
+
- `"onFailure": "block"` on the hook's entry is said in a note. Claude Code 2.1.295 or later then holds a write when the hook fails, where without the field the write goes ahead: by the hook's exit 1 for a question it cannot read, by a hook that does not start, or by one that runs past its timeout. With a line that turns the guard off, that is every write, the one that mends the line among them.
|
|
382
|
+
- `--format json` has each line under `claudeCode.lines`: its `file`, `events`, the `line` as written, its `state` (`guards`, `off` or `unknown`), `onFailure`, and what is said of it as `detail` and `note`, `null` where there is nothing to say.
|
|
383
|
+
- The plugin's own hooks are not read: they are a release's files, and no release wrote more than `hook claude` on the line.
|
|
377
384
|
- **Which Claude Code**, when Claude Code runs the guard: `claude --version`, found on `PATH` and run without a shell.
|
|
378
385
|
- Older than 2.1.139 exits 1. An older release ignores a hook's `args` and runs a bare `node`, which reads the hook's input as a script and fails, and a PreToolUse hook that fails with anything but exit 2 blocks nothing: every write passes unguarded.
|
|
379
386
|
- On Windows, npm installs Claude Code as a `claude.cmd` shim, which cannot be run without a shell, so it is read instead: the `node_modules\@anthropic-ai\claude-code` it runs, as npm's shim or pnpm's names it, and that package.json's `version`, which doctor says it read. Nothing is run.
|
|
@@ -417,7 +424,7 @@ An option, an argument or a value that is given and names nothing is refused: ex
|
|
|
417
424
|
- **A `--root` that is a file, or is not there.** It read as a session outside a git work tree, exit 0 and no word, and the guard was off. It is `--root is "nowhere", which is not a directory, so the guard is off and this write is not checked`, with what to do. An empty `--root` is the directory the hook was started in, and guards there, as before.
|
|
418
425
|
- **A line the parser cannot read**: an option no command has, as in `hook claude --nope`; an option left without its value, as `--root $DIR` is in a shell where the variable is not set; a `--format` or an `--at` that is none. Each was exit 2, as it is from every other command, and Claude Code blocks the tool call on a PreToolUse hook's exit 2: every write of the session waited on a line only a write can mend. It is `the hook's line cannot be read (Option '--root <value>' argument missing), so the guard is off and this write is not checked`, with what to do. The parser's own words stand between the brackets, on one line.
|
|
419
426
|
|
|
420
|
-
Exit 2 from `hook claude` is kept for a write it could not check: a configuration that does not load, briefs that cannot be read, a brief that is named and is not one, an error nothing expected. `hook git` is not read this way. It stops one commit, exit 2, on a line a person reads, who can then mend the hook. Nor is a line that does not say `hook claude`, such as `hook` alone: the harness cannot tell whose it is. A hook entry that sets `"onFailure": "block"`, which Claude Code 2.1.295 and later read, has Claude Code hold the action when the hook fails, and exit 1 is a failure to it; neither `init` nor the plugin writes that field.
|
|
427
|
+
Exit 2 from `hook claude` is kept for a write it could not check: a configuration that does not load, briefs that cannot be read, a brief that is named and is not one, an error nothing expected. `hook git` is not read this way. It stops one commit, exit 2, on a line a person reads, who can then mend the hook. Nor is a line that does not say `hook claude`, such as `hook` alone: the harness cannot tell whose it is. A hook entry that sets `"onFailure": "block"`, which Claude Code 2.1.295 and later read, has Claude Code hold the action when the hook fails, and exit 1 is a failure to it; neither `init` nor the plugin writes that field. [`doctor`](#doctor) says each of these of a line it finds in Claude Code's settings, before any write meets it.
|
|
421
428
|
- **`doctor` says an empty `--brief` or `--base` in its report**, as it says a brief spec-brief does not know: a diagnosis is what a person runs when something is wrong, and it reports what is wrong with what it was given.
|
|
422
429
|
- **`SPEC_BRIEF` set and empty is as unset**, since what sets it sets it whether or not there is a round ([Which brief](#which-brief)).
|
|
423
430
|
|
package/dist/answers.js
CHANGED
|
@@ -134,7 +134,7 @@ export function readArchivePlan(document) {
|
|
|
134
134
|
const file = read.optionalText(reason['file'], `${where}.file`);
|
|
135
135
|
const line = read.optionalNumber(reason['line'], `${where}.line`);
|
|
136
136
|
const path = read.optionalText(reason['path'], `${where}.path`);
|
|
137
|
-
|
|
137
|
+
const carried = {
|
|
138
138
|
rule: read.text(reason['rule'], `${where}.rule`),
|
|
139
139
|
severity: severity,
|
|
140
140
|
message: read.text(reason['message'], `${where}.message`),
|
|
@@ -143,6 +143,7 @@ export function readArchivePlan(document) {
|
|
|
143
143
|
line,
|
|
144
144
|
path,
|
|
145
145
|
};
|
|
146
|
+
return carried;
|
|
146
147
|
});
|
|
147
148
|
return { blocking: reasons('blocking'), warnings: reasons('warnings') };
|
|
148
149
|
}
|
package/dist/answers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"answers.js","sourceRoot":"","sources":["../src/answers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What spec-guard and spec-brief answer in JSON, besides the brief list\n * briefs.ts reads: a query's rules, a run's results and errors, and an\n * archive's plan. Each is checked for the fields the harness reads, with the\n * types it reads them as, and a document of another shape is an error that\n * names the tool and the field (ADR-0002): the command that asked stops with\n * exit 2, as for any sibling that printed something it cannot read, rather\n * than crash halfway through the document or count what it could not read as\n * clean. Fields the harness does not read are not checked, so a sibling may\n * add to its documents freely.\n */\n\nimport type { ArchiveReason } from './audit.js';\nimport { SiblingOutputError } from './briefs.js';\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Reads fields of one document, naming the tool, its command and the field in every refusal. */\nfunction reader(printer: string) {\n const refuse = (where: string, expected: string): never => {\n throw new SiblingOutputError(`${printer} printed ${where} that is not ${expected}`);\n };\n return {\n object(value: unknown, where: string): Json {\n return isObject(value) ? value : refuse(where, 'an object');\n },\n /** A list that is absent is an empty one. */\n list(value: unknown, where: string): unknown[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? (value as unknown[]) : refuse(where, 'a list');\n },\n text(value: unknown, where: string): string {\n return typeof value === 'string' ? value : refuse(where, 'text');\n },\n optionalText(value: unknown, where: string): string | undefined {\n return value === undefined ? undefined : typeof value === 'string' ? value : refuse(where, 'text');\n },\n number(value: unknown, where: string): number {\n return typeof value === 'number' ? value : refuse(where, 'a number');\n },\n optionalNumber(value: unknown, where: string): number | undefined {\n return value === undefined ? undefined : typeof value === 'number' ? value : refuse(where, 'a number');\n },\n flag(value: unknown, where: string): boolean {\n return typeof value === 'boolean' ? value : refuse(where, 'true or false');\n },\n refuse,\n };\n}\n\n/** Where spec-guard places a directive. */\nexport interface Spec {\n readonly file: string;\n readonly line: number;\n}\n\nexport interface QueryRule {\n readonly document: string;\n readonly line: number;\n readonly kind: string;\n readonly description: string;\n readonly reason: string | null;\n /** Absent from a document that says nothing of it, which is in force. */\n readonly inForce: boolean;\n}\n\n/** The rules in each of the results of `spec-guard query --json`, in order. */\nexport function readQueryRules(document: unknown): QueryRule[][] {\n const read = reader('spec-guard query');\n const top = read.object(document, 'a document');\n return read.list(top['results'], 'results').map((value, index) => {\n const result = read.object(value, `results[${index}]`);\n return read.list(result['rules'], `results[${index}].rules`).map((ruleValue, at) => {\n const where = `results[${index}].rules[${at}]`;\n const rule = read.object(ruleValue, where);\n const reason = rule['reason'];\n if (reason !== undefined && reason !== null && typeof reason !== 'string') read.refuse(`${where}.reason`, 'text or null');\n const inForce = rule['inForce'];\n return {\n document: read.text(rule['document'], `${where}.document`),\n line: read.number(rule['line'], `${where}.line`),\n kind: read.text(rule['kind'], `${where}.kind`),\n description: read.text(rule['description'], `${where}.description`),\n reason: typeof reason === 'string' ? reason : null,\n inForce: inForce === undefined ? true : read.flag(inForce, `${where}.inForce`),\n };\n });\n });\n}\n\n/**\n * The spec patterns `spec-guard query --json` says matched no file, as\n * written. A document that says nothing of them names none: spec-guard has\n * written the field since 0.22.0, and only where there is such a pattern.\n */\nexport function readQueryUnmatched(document: unknown): string[] {\n const read = reader('spec-guard query');\n const top = read.object(document, 'a document');\n return read.list(top['unmatchedSpecs'], 'unmatchedSpecs').map((value, index) => read.text(value, `unmatchedSpecs[${index}]`));\n}\n\nexport interface GuardResult {\n readonly ok: boolean;\n readonly description: string;\n readonly message: string;\n readonly spec?: Spec | undefined;\n}\n\nexport interface GuardError {\n readonly message: string;\n readonly raw: string;\n readonly spec?: Spec | undefined;\n}\n\n/** The results and the unreadable directives of a spec-guard run over briefs, `--json`. */\nexport function readGuardRun(document: unknown): { results: GuardResult[]; errors: GuardError[] } {\n const read = reader('spec-guard');\n const top = read.object(document, 'a document');\n const spec = (value: unknown, where: string): Spec | undefined => {\n if (value === undefined) return undefined;\n const placed = read.object(value, where);\n return { file: read.text(placed['file'], `${where}.file`), line: read.number(placed['line'], `${where}.line`) };\n };\n const results = read.list(top['results'], 'results').map((value, index) => {\n const where = `results[${index}]`;\n const result = read.object(value, where);\n return {\n ok: read.flag(result['ok'], `${where}.ok`),\n description: read.text(result['description'], `${where}.description`),\n message: read.text(result['message'], `${where}.message`),\n spec: spec(result['spec'], `${where}.spec`),\n };\n });\n const errors = read.list(top['errors'], 'errors').map((value, index) => {\n const where = `errors[${index}]`;\n const error = read.object(value, where);\n return {\n message: read.text(error['message'], `${where}.message`),\n raw: read.optionalText(error['raw'], `${where}.raw`) ?? '',\n spec: spec(error['spec'], `${where}.spec`),\n };\n });\n return { results, errors };\n}\n\nconst SEVERITIES: readonly string[] = ['error', 'warning', 'note'];\n\n/**\n * What `spec-brief archive --dry-run --format json` would refuse and warn\n * about. A document with no plan plans nothing to refuse. spec-brief gives a\n * reason without a hint where it has no next step, and the reason is carried\n * as it gave it: a field it left out is undefined, which JSON leaves out too.\n */\nexport function readArchivePlan(document: unknown): { blocking: ArchiveReason[]; warnings: ArchiveReason[] } {\n const read = reader('spec-brief archive');\n const top = read.object(document, 'a document');\n if (top['plan'] === undefined) return { blocking: [], warnings: [] };\n const plan = read.object(top['plan'], 'plan');\n const reasons = (key: 'blocking' | 'warnings'): ArchiveReason[] =>\n read.list(plan[key], `plan.${key}`).map((value, index) => {\n const where = `plan.${key}[${index}]`;\n const reason = read.object(value, where);\n const severity = read.text(reason['severity'], `${where}.severity`);\n if (!SEVERITIES.includes(severity)) read.refuse(`${where}.severity`, 'error, warning or note');\n const hint = read.optionalText(reason['hint'], `${where}.hint`);\n const file = read.optionalText(reason['file'], `${where}.file`);\n const line = read.optionalNumber(reason['line'], `${where}.line`);\n const path = read.optionalText(reason['path'], `${where}.path`);\n return {\n rule: read.text(reason['rule'], `${where}.rule`),\n severity: severity as ArchiveReason['severity'],\n message: read.text(reason['message'], `${where}.message`),\n hint,\n file,\n line,\n path,\n } as ArchiveReason;\n });\n return { blocking: reasons('blocking'), warnings: reasons('warnings') };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"answers.js","sourceRoot":"","sources":["../src/answers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What spec-guard and spec-brief answer in JSON, besides the brief list\n * briefs.ts reads: a query's rules, a run's results and errors, and an\n * archive's plan. Each is checked for the fields the harness reads, with the\n * types it reads them as, and a document of another shape is an error that\n * names the tool and the field (ADR-0002): the command that asked stops with\n * exit 2, as for any sibling that printed something it cannot read, rather\n * than crash halfway through the document or count what it could not read as\n * clean. Fields the harness does not read are not checked, so a sibling may\n * add to its documents freely.\n */\n\nimport type { ArchiveReason } from './audit.js';\nimport { SiblingOutputError } from './briefs.js';\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Reads fields of one document, naming the tool, its command and the field in every refusal. */\nfunction reader(printer: string) {\n const refuse = (where: string, expected: string): never => {\n throw new SiblingOutputError(`${printer} printed ${where} that is not ${expected}`);\n };\n return {\n object(value: unknown, where: string): Json {\n return isObject(value) ? value : refuse(where, 'an object');\n },\n /** A list that is absent is an empty one. */\n list(value: unknown, where: string): unknown[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? (value as unknown[]) : refuse(where, 'a list');\n },\n text(value: unknown, where: string): string {\n return typeof value === 'string' ? value : refuse(where, 'text');\n },\n optionalText(value: unknown, where: string): string | undefined {\n return value === undefined ? undefined : typeof value === 'string' ? value : refuse(where, 'text');\n },\n number(value: unknown, where: string): number {\n return typeof value === 'number' ? value : refuse(where, 'a number');\n },\n optionalNumber(value: unknown, where: string): number | undefined {\n return value === undefined ? undefined : typeof value === 'number' ? value : refuse(where, 'a number');\n },\n flag(value: unknown, where: string): boolean {\n return typeof value === 'boolean' ? value : refuse(where, 'true or false');\n },\n refuse,\n };\n}\n\n/** Where spec-guard places a directive. */\nexport interface Spec {\n readonly file: string;\n readonly line: number;\n}\n\nexport interface QueryRule {\n readonly document: string;\n readonly line: number;\n readonly kind: string;\n readonly description: string;\n readonly reason: string | null;\n /** Absent from a document that says nothing of it, which is in force. */\n readonly inForce: boolean;\n}\n\n/** The rules in each of the results of `spec-guard query --json`, in order. */\nexport function readQueryRules(document: unknown): QueryRule[][] {\n const read = reader('spec-guard query');\n const top = read.object(document, 'a document');\n return read.list(top['results'], 'results').map((value, index) => {\n const result = read.object(value, `results[${index}]`);\n return read.list(result['rules'], `results[${index}].rules`).map((ruleValue, at) => {\n const where = `results[${index}].rules[${at}]`;\n const rule = read.object(ruleValue, where);\n const reason = rule['reason'];\n if (reason !== undefined && reason !== null && typeof reason !== 'string') read.refuse(`${where}.reason`, 'text or null');\n const inForce = rule['inForce'];\n return {\n document: read.text(rule['document'], `${where}.document`),\n line: read.number(rule['line'], `${where}.line`),\n kind: read.text(rule['kind'], `${where}.kind`),\n description: read.text(rule['description'], `${where}.description`),\n reason: typeof reason === 'string' ? reason : null,\n inForce: inForce === undefined ? true : read.flag(inForce, `${where}.inForce`),\n };\n });\n });\n}\n\n/**\n * The spec patterns `spec-guard query --json` says matched no file, as\n * written. A document that says nothing of them names none: spec-guard has\n * written the field since 0.22.0, and only where there is such a pattern.\n */\nexport function readQueryUnmatched(document: unknown): string[] {\n const read = reader('spec-guard query');\n const top = read.object(document, 'a document');\n return read.list(top['unmatchedSpecs'], 'unmatchedSpecs').map((value, index) => read.text(value, `unmatchedSpecs[${index}]`));\n}\n\nexport interface GuardResult {\n readonly ok: boolean;\n readonly description: string;\n readonly message: string;\n readonly spec?: Spec | undefined;\n}\n\nexport interface GuardError {\n readonly message: string;\n readonly raw: string;\n readonly spec?: Spec | undefined;\n}\n\n/** The results and the unreadable directives of a spec-guard run over briefs, `--json`. */\nexport function readGuardRun(document: unknown): { results: GuardResult[]; errors: GuardError[] } {\n const read = reader('spec-guard');\n const top = read.object(document, 'a document');\n const spec = (value: unknown, where: string): Spec | undefined => {\n if (value === undefined) return undefined;\n const placed = read.object(value, where);\n return { file: read.text(placed['file'], `${where}.file`), line: read.number(placed['line'], `${where}.line`) };\n };\n const results = read.list(top['results'], 'results').map((value, index) => {\n const where = `results[${index}]`;\n const result = read.object(value, where);\n return {\n ok: read.flag(result['ok'], `${where}.ok`),\n description: read.text(result['description'], `${where}.description`),\n message: read.text(result['message'], `${where}.message`),\n spec: spec(result['spec'], `${where}.spec`),\n };\n });\n const errors = read.list(top['errors'], 'errors').map((value, index) => {\n const where = `errors[${index}]`;\n const error = read.object(value, where);\n return {\n message: read.text(error['message'], `${where}.message`),\n raw: read.optionalText(error['raw'], `${where}.raw`) ?? '',\n spec: spec(error['spec'], `${where}.spec`),\n };\n });\n return { results, errors };\n}\n\nconst SEVERITIES: readonly string[] = ['error', 'warning', 'note'];\n\n/**\n * What `spec-brief archive --dry-run --format json` would refuse and warn\n * about. A document with no plan plans nothing to refuse. spec-brief gives a\n * reason without a hint where it has no next step, and the reason is carried\n * as it gave it: a field it left out is undefined, which JSON leaves out too.\n */\nexport function readArchivePlan(document: unknown): { blocking: ArchiveReason[]; warnings: ArchiveReason[] } {\n const read = reader('spec-brief archive');\n const top = read.object(document, 'a document');\n if (top['plan'] === undefined) return { blocking: [], warnings: [] };\n const plan = read.object(top['plan'], 'plan');\n const reasons = (key: 'blocking' | 'warnings'): ArchiveReason[] =>\n read.list(plan[key], `plan.${key}`).map((value, index) => {\n const where = `plan.${key}[${index}]`;\n const reason = read.object(value, where);\n const severity = read.text(reason['severity'], `${where}.severity`);\n if (!SEVERITIES.includes(severity)) read.refuse(`${where}.severity`, 'error, warning or note');\n const hint = read.optionalText(reason['hint'], `${where}.hint`);\n const file = read.optionalText(reason['file'], `${where}.file`);\n const line = read.optionalNumber(reason['line'], `${where}.line`);\n const path = read.optionalText(reason['path'], `${where}.path`);\n const carried = {\n rule: read.text(reason['rule'], `${where}.rule`),\n severity: severity as ArchiveReason['severity'],\n message: read.text(reason['message'], `${where}.message`),\n hint,\n file,\n line,\n path,\n };\n return carried as ArchiveReason;\n });\n return { blocking: reasons('blocking'), warnings: reasons('warnings') };\n}\n"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { type CliIO } from './workspace.js';
|
|
13
13
|
export { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';
|
|
14
|
-
export declare 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
|
|
14
|
+
export declare 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";
|
|
15
15
|
/**
|
|
16
16
|
* Runs the command line and resolves to the exit code, for an error nothing
|
|
17
17
|
* below expected too.
|
package/dist/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ import { mcpCommand } from './server.js';
|
|
|
24
24
|
import { gitHook, initCommand } from './setup.js';
|
|
25
25
|
import { notFido2, readAllowedSigners } from './signers.js';
|
|
26
26
|
import { SiblingError } from './siblings.js';
|
|
27
|
-
import { emptyValue, isBlank, isClaudeHook,
|
|
27
|
+
import { emptyValue, isBlank, isClaudeHook, readHookLine, refusal, unreadHookLine } from './usage.js';
|
|
28
28
|
import { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';
|
|
29
29
|
import { activeBrief, describeActive, EXIT_ERROR, EXIT_FAILED, EXIT_OK, json, namedId, openWorkspace, parseOptions, UsageError, version, } from './workspace.js';
|
|
30
30
|
export { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version } from './workspace.js';
|
|
@@ -60,7 +60,8 @@ Commands:
|
|
|
60
60
|
doctor Which siblings are installed, at which versions, which brief is
|
|
61
61
|
named, how Claude Code runs the guard, and git's hook. Exit 1
|
|
62
62
|
when a sibling is older than this release needs, the guard is
|
|
63
|
-
installed twice
|
|
63
|
+
installed twice or its hook's line turns it off, or Claude Code
|
|
64
|
+
is too old to run its hooks.
|
|
64
65
|
|
|
65
66
|
Options:
|
|
66
67
|
--brief <id> The brief the round works on. Otherwise SPEC_BRIEF, then the branch.
|
|
@@ -162,7 +163,7 @@ async function writeAsked(io) {
|
|
|
162
163
|
* that exits 1 and goes on with the write, where exit 2 would hold every
|
|
163
164
|
* write of the session, the one that mends the line among them (ADR-0005).
|
|
164
165
|
*/
|
|
165
|
-
function guardOff(io, wrong, mend) {
|
|
166
|
+
function guardOff(io, { wrong, mend }) {
|
|
166
167
|
io.stderr.write(`spec-harness: ${wrong}, so the guard is off and this write is not checked; ${mend}\n`);
|
|
167
168
|
return EXIT_FAILED;
|
|
168
169
|
}
|
|
@@ -170,14 +171,14 @@ function guardOff(io, wrong, mend) {
|
|
|
170
171
|
* Claude Code's hook on a line the parser refused: an option no command has,
|
|
171
172
|
* an option left without its value, a --format or an --at that is none. It
|
|
172
173
|
* was exit 2 before the question was read, for the line a settings file
|
|
173
|
-
* holds as for one typed at a terminal.
|
|
174
|
-
*
|
|
174
|
+
* holds as for one typed at a terminal. What is said of it is `doctor`'s
|
|
175
|
+
* to say as well, of a line it finds in a settings file (usage.ts).
|
|
175
176
|
*/
|
|
176
|
-
async function
|
|
177
|
+
async function unreadLine(said, io) {
|
|
177
178
|
const request = await writeAsked(io);
|
|
178
179
|
if (typeof request === 'number')
|
|
179
180
|
return request;
|
|
180
|
-
return guardOff(io,
|
|
181
|
+
return guardOff(io, unreadHookLine(said).fault);
|
|
181
182
|
}
|
|
182
183
|
async function hookCommand(options, io) {
|
|
183
184
|
const kind = options.positionals[0];
|
|
@@ -185,20 +186,15 @@ async function hookCommand(options, io) {
|
|
|
185
186
|
const request = await writeAsked(io);
|
|
186
187
|
if (typeof request === 'number')
|
|
187
188
|
return request;
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
// starts in neither, which read as a session outside a work tree, exit 0
|
|
194
|
-
// and no word, and the guard someone had configured was off.
|
|
195
|
-
if (root !== undefined && !isDirectory(root)) {
|
|
196
|
-
return guardOff(io, noDirectory(root), "give the hook's line a directory that exists, or leave --root out for the project Claude Code names");
|
|
197
|
-
}
|
|
189
|
+
// The root the line gives, or what is wrong with it: read as `doctor`
|
|
190
|
+
// reads the line where it finds it in a settings file (usage.ts).
|
|
191
|
+
const line = readHookLine(options.root, io.cwd, isDirectory);
|
|
192
|
+
if (line.state === 'off')
|
|
193
|
+
return guardOff(io, line.fault);
|
|
198
194
|
const cwd = request.cwd ?? io.cwd;
|
|
199
195
|
let workspace;
|
|
200
196
|
try {
|
|
201
|
-
workspace = await openWorkspace({ ...options, root: root ?? io.env['CLAUDE_PROJECT_DIR'] ?? cwd }, io);
|
|
197
|
+
workspace = await openWorkspace({ ...options, root: line.root ?? io.env['CLAUDE_PROJECT_DIR'] ?? cwd }, io);
|
|
202
198
|
}
|
|
203
199
|
catch (error) {
|
|
204
200
|
if (error instanceof UsageError)
|
|
@@ -307,6 +303,10 @@ async function doctorCommand(options, io) {
|
|
|
307
303
|
// and registers the server twice (ADR-0012).
|
|
308
304
|
const wiring = await claudeCodeWiring(workspace.root, io.env);
|
|
309
305
|
const claude = wiringState(wiring);
|
|
306
|
+
// What the hook does with each line the settings hold for it, where there
|
|
307
|
+
// is something to say: more on it than init writes, a line that turns the
|
|
308
|
+
// guard off, one only a shell can read, and what onFailure changes.
|
|
309
|
+
const lineNotes = wiring.lines.flatMap((line) => [line.detail, line.note]).filter((note) => note !== null);
|
|
310
310
|
// Only a Claude Code that runs the guard is asked its release: one older
|
|
311
311
|
// than the hooks need lets every write through unguarded.
|
|
312
312
|
const release = claude === 'none' ? null : checkClaudeCode(await claudeVersion(io.env));
|
|
@@ -353,6 +353,7 @@ async function doctorCommand(options, io) {
|
|
|
353
353
|
...more(signerNotes),
|
|
354
354
|
`plugin ${describePlugin(plugin)}`,
|
|
355
355
|
`claude ${describeClaudeCode(wiring)}`,
|
|
356
|
+
...more(lineNotes),
|
|
356
357
|
...more(release === null ? [] : [describeClaudeRelease(release)]),
|
|
357
358
|
`git ${describeGitHook(hook)}`,
|
|
358
359
|
...more(hookNote === null ? [] : [hookNote]),
|
|
@@ -365,13 +366,15 @@ async function doctorCommand(options, io) {
|
|
|
365
366
|
// An outdated sibling is a problem to fix, where a missing optional one is
|
|
366
367
|
// a choice; with none installed, the harness can check nothing. A double
|
|
367
368
|
// install is a problem too, where no Claude Code wiring at all is a choice,
|
|
368
|
-
// and so
|
|
369
|
-
// cannot be told is not fine
|
|
369
|
+
// and so are a hook whose own line turns the guard off and a Claude Code
|
|
370
|
+
// too old to run the hooks. A release that cannot be told is not fine
|
|
371
|
+
// either, nor a line only a shell can read: --strict fails both.
|
|
370
372
|
const outdated = rows.some((row) => row.state === 'outdated');
|
|
371
373
|
const usable = rows.some((row) => row.state === 'found');
|
|
374
|
+
const off = wiring.lines.some((line) => line.state === 'off');
|
|
372
375
|
const tooOld = release?.state === 'outdated';
|
|
373
|
-
const untold = options.strict && release?.state === 'unknown';
|
|
374
|
-
return outdated || !usable || claude === 'both' || tooOld || untold ? EXIT_FAILED : EXIT_OK;
|
|
376
|
+
const untold = options.strict && (release?.state === 'unknown' || wiring.lines.some((line) => line.state === 'unknown'));
|
|
377
|
+
return outdated || !usable || claude === 'both' || off || tooOld || untold ? EXIT_FAILED : EXIT_OK;
|
|
375
378
|
}
|
|
376
379
|
/* ---------------------------------------------------------------- dispatch */
|
|
377
380
|
/**
|
|
@@ -407,7 +410,7 @@ async function dispatch(argv, io) {
|
|
|
407
410
|
// write for it.
|
|
408
411
|
const refused = error;
|
|
409
412
|
if (isClaudeHook(refused.words[0], refused.words[1]))
|
|
410
|
-
return
|
|
413
|
+
return unreadLine(refused.message, io);
|
|
411
414
|
io.stderr.write(`spec-harness: ${refused.message}\n`);
|
|
412
415
|
return EXIT_ERROR;
|
|
413
416
|
}
|
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, 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, 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 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 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\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: string, mend: string): 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. The parser's words are kept, on one\n * line: what node says of an option that may have lost its value is three.\n */\nasync function unreadHookLine(said: string, io: CliIO): Promise<number> {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n return guardOff(io, `the hook's line cannot be read (${said.split('\\n').join(' ')})`, 'mend it in Claude Code\\'s settings, where init writes \"hook claude\" and nothing after it');\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 // 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.\n if (root !== undefined && !isDirectory(root)) {\n return guardOff(io, noDirectory(root), \"give the hook's line a directory that exists, or leave --root out for the project Claude Code names\");\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 // 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 unreadHookLine(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"]}
|
|
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, 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"]}
|