@descent-vtt/spec-harness 0.9.1 → 0.10.1
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 +101 -4
- package/README.md +58 -14
- package/dist/audit.d.ts +9 -2
- package/dist/audit.js +31 -1
- package/dist/audit.js.map +1 -1
- package/dist/branch.js +2 -0
- package/dist/branch.js.map +1 -1
- package/dist/briefs.js +2 -0
- package/dist/briefs.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +7 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands.js +1 -0
- package/dist/commands.js.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/configure.d.ts +25 -2
- package/dist/configure.js +44 -4
- package/dist/configure.js.map +1 -1
- package/dist/git.d.ts +8 -6
- package/dist/git.js +11 -6
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/manifests.d.ts +31 -4
- package/dist/manifests.js +71 -24
- package/dist/manifests.js.map +1 -1
- package/dist/reader.js +4 -0
- package/dist/reader.js.map +1 -1
- package/dist/round.d.ts +3 -1
- package/dist/round.js +15 -6
- package/dist/round.js.map +1 -1
- package/dist/sandbox.d.ts +20 -1
- package/dist/sandbox.js +74 -24
- package/dist/sandbox.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/setup.d.ts +3 -1
- package/dist/setup.js +13 -14
- package/dist/setup.js.map +1 -1
- package/package.json +3 -3
- package/skills/close-round/SKILL.md +28 -10
- package/skills/draft-brief/SKILL.md +31 -7
- package/skills/run-round/SKILL.md +22 -4
- package/skills/split-goal/SKILL.md +19 -3
package/dist/branch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../src/branch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which brief a branch is working on, read from its name.\n *\n * A round runs on a branch, and naming the branch after the brief is the one\n * convention every repository that runs agents on briefs already has. Reading\n * it from there keeps the harness stateless: no file says which brief is\n * active, so no file can say it wrongly (ADR-0004).\n *\n * A template is a branch name with `{id}` where the id goes and `*` for any\n * run of characters other than `/`: `brief/{id}`, `*\\/brief-{id}`. The id is\n * the longest run of letters and digits at that point, and must be followed\n * by the end of the name or a separator - so `brief/012-rotate-tokens` names\n * 012, and `brief/012x` names 012x, never 012.\n */\n\nconst SEPARATORS = new Set(['-', '_', '/', '.']);\n\nfunction isIdChar(ch: string): boolean {\n return /^[A-Za-z0-9]$/.test(ch);\n}\n\n/**\n * The offsets in `name` at which a template prefix can end, by dynamic\n * programming over prefix and name, so a template of many stars costs their\n * product and never an exponent.\n */\nfunction prefixEnds(prefix: string, name: string): number[] {\n // reach[j]: the prefix read so far can end at name offset j.\n let reach: boolean[] = new Array<boolean>(name.length + 1).fill(false);\n reach[0] = true;\n for (const token of prefix) {\n const next = new Array<boolean>(name.length + 1).fill(false);\n if (token === '*') {\n let open = false;\n for (let j = 0; j <= name.length; j += 1) {\n if (reach[j]) open = true;\n if (open) next[j] = true;\n if (name.charAt(j) === '/') open = false;\n }\n } else {\n for (let j = 0; j < name.length; j += 1) if (reach[j] && name.charAt(j) === token) next[j + 1] = true;\n }\n reach = next;\n }\n const ends: number[] = [];\n reach.forEach((ok, j) => {\n if (ok) ends.push(j);\n });\n return ends;\n}\n\n/** Why a template cannot be used, or `null`. */\nexport function templateError(template: string): string | null {\n const count = template.split('{id}').length - 1;\n if (count !== 1) return `\"${template}\" must contain {id} exactly once`;\n if (!template.endsWith('{id}')) return `\"${template}\" must end with {id}; whatever follows the id is the branch's own`;\n return null;\n}\n\n/** The brief id a branch name carries under one template, or `null`. */\nexport function idFromBranch(template: string, name: string): string | null {\n if (templateError(template) !== null) return null;\n const prefix = template.slice(0, -'{id}'.length);\n for (const start of prefixEnds(prefix, name)) {\n let end = start;\n while (end < name.length && isIdChar(name.charAt(end))) end += 1;\n if (end === start) continue;\n if (end < name.length && !SEPARATORS.has(name.charAt(end))) continue;\n return name.slice(start, end);\n }\n return null;\n}\n\n/**\n * The branch a CI run is building, as the forge names it, for a checkout on\n * no branch: CI checks out a commit, and without the branch a round's own\n * run would name no brief. In order: a GitHub pull request's head branch; the\n * branch a GitHub push built; a GitLab merge request's source branch; the\n * branch a GitLab pipeline built. Each is set only where it names a branch -\n * GitHub's `GITHUB_REF_NAME` names a tag too, so only when `GITHUB_REF_TYPE`\n * says `branch` - and an empty one is not set. `null` outside CI.\n */\nexport function ciBranch(env: Readonly<Record<string, string | undefined>>): { readonly branch: string; readonly source: string } | null {\n const named = (name: string): { branch: string; source: string } | null => {\n const value = env[name]?.trim() ?? '';\n return value === '' ? null : { branch: value, source: name };\n };\n return (\n named('GITHUB_HEAD_REF') ??\n (env['GITHUB_REF_TYPE'] === 'branch' ? named('GITHUB_REF_NAME') : null) ??\n named('CI_MERGE_REQUEST_SOURCE_BRANCH_NAME') ??\n named('CI_COMMIT_BRANCH')\n );\n}\n\n/** The first template that yields an id, in order; `null` for a head on no branch, which names no brief. */\nexport function briefIdFromBranch(templates: readonly string[], name: string | null): string | null {\n if (name === null) return null;\n for (const template of templates) {\n const id = idFromBranch(template, name);\n if (id !== null) return id;\n }\n return null;\n}\n\n/**\n * Whether two ids name the same brief: equal as written, or equal as numbers\n * when both are all digits, since a branch says `brief/12` of a brief whose\n * file says `012`.\n */\nexport function sameId(a: string, b: string): boolean {\n if (a === b) return true;\n return /^\\d+$/.test(a) && /^\\d+$/.test(b) && BigInt(a) === BigInt(b);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../src/branch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which brief a branch is working on, read from its name.\n *\n * A round runs on a branch, and naming the branch after the brief is the one\n * convention every repository that runs agents on briefs already has. Reading\n * it from there keeps the harness stateless: no file says which brief is\n * active, so no file can say it wrongly (ADR-0004).\n *\n * A template is a branch name with `{id}` where the id goes and `*` for any\n * run of characters other than `/`: `brief/{id}`, `*\\/brief-{id}`. The id is\n * the longest run of letters and digits at that point, and must be followed\n * by the end of the name or a separator - so `brief/012-rotate-tokens` names\n * 012, and `brief/012x` names 012x, never 012.\n */\n\nconst SEPARATORS = new Set(['-', '_', '/', '.']);\n\nfunction isIdChar(ch: string): boolean {\n // Asked of one character at a time, so the mutants that drop either anchor\n // are equivalent.\n return /^[A-Za-z0-9]$/.test(ch);\n}\n\n/**\n * The offsets in `name` at which a template prefix can end, by dynamic\n * programming over prefix and name, so a template of many stars costs their\n * product and never an exponent.\n */\nfunction prefixEnds(prefix: string, name: string): number[] {\n // reach[j]: the prefix read so far can end at name offset j.\n let reach: boolean[] = new Array<boolean>(name.length + 1).fill(false);\n reach[0] = true;\n for (const token of prefix) {\n const next = new Array<boolean>(name.length + 1).fill(false);\n if (token === '*') {\n let open = false;\n for (let j = 0; j <= name.length; j += 1) {\n if (reach[j]) open = true;\n if (open) next[j] = true;\n if (name.charAt(j) === '/') open = false;\n }\n } else {\n for (let j = 0; j < name.length; j += 1) if (reach[j] && name.charAt(j) === token) next[j + 1] = true;\n }\n reach = next;\n }\n const ends: number[] = [];\n reach.forEach((ok, j) => {\n if (ok) ends.push(j);\n });\n return ends;\n}\n\n/** Why a template cannot be used, or `null`. */\nexport function templateError(template: string): string | null {\n const count = template.split('{id}').length - 1;\n if (count !== 1) return `\"${template}\" must contain {id} exactly once`;\n if (!template.endsWith('{id}')) return `\"${template}\" must end with {id}; whatever follows the id is the branch's own`;\n return null;\n}\n\n/** The brief id a branch name carries under one template, or `null`. */\nexport function idFromBranch(template: string, name: string): string | null {\n if (templateError(template) !== null) return null;\n const prefix = template.slice(0, -'{id}'.length);\n for (const start of prefixEnds(prefix, name)) {\n let end = start;\n while (end < name.length && isIdChar(name.charAt(end))) end += 1;\n if (end === start) continue;\n if (end < name.length && !SEPARATORS.has(name.charAt(end))) continue;\n return name.slice(start, end);\n }\n return null;\n}\n\n/**\n * The branch a CI run is building, as the forge names it, for a checkout on\n * no branch: CI checks out a commit, and without the branch a round's own\n * run would name no brief. In order: a GitHub pull request's head branch; the\n * branch a GitHub push built; a GitLab merge request's source branch; the\n * branch a GitLab pipeline built. Each is set only where it names a branch -\n * GitHub's `GITHUB_REF_NAME` names a tag too, so only when `GITHUB_REF_TYPE`\n * says `branch` - and an empty one is not set. `null` outside CI.\n */\nexport function ciBranch(env: Readonly<Record<string, string | undefined>>): { readonly branch: string; readonly source: string } | null {\n const named = (name: string): { branch: string; source: string } | null => {\n const value = env[name]?.trim() ?? '';\n return value === '' ? null : { branch: value, source: name };\n };\n return (\n named('GITHUB_HEAD_REF') ??\n (env['GITHUB_REF_TYPE'] === 'branch' ? named('GITHUB_REF_NAME') : null) ??\n named('CI_MERGE_REQUEST_SOURCE_BRANCH_NAME') ??\n named('CI_COMMIT_BRANCH')\n );\n}\n\n/** The first template that yields an id, in order; `null` for a head on no branch, which names no brief. */\nexport function briefIdFromBranch(templates: readonly string[], name: string | null): string | null {\n if (name === null) return null;\n for (const template of templates) {\n const id = idFromBranch(template, name);\n if (id !== null) return id;\n }\n return null;\n}\n\n/**\n * Whether two ids name the same brief: equal as written, or equal as numbers\n * when both are all digits, since a branch says `brief/12` of a brief whose\n * file says `012`.\n */\nexport function sameId(a: string, b: string): boolean {\n if (a === b) return true;\n return /^\\d+$/.test(a) && /^\\d+$/.test(b) && BigInt(a) === BigInt(b);\n}\n"]}
|
package/dist/briefs.js
CHANGED
|
@@ -42,6 +42,8 @@ export function parseBriefList(document) {
|
|
|
42
42
|
throw new SiblingOutputError('spec-brief did not print a list document');
|
|
43
43
|
}
|
|
44
44
|
const version = document['schemaVersion'];
|
|
45
|
+
// The list holds numbers alone, so `includes` refuses whatever is not one:
|
|
46
|
+
// the `typeof` is the compiler's, and the mutant without it is equivalent.
|
|
45
47
|
if (typeof version !== 'number' || !SUPPORTED_SCHEMA_VERSIONS.includes(version)) {
|
|
46
48
|
throw new SiblingOutputError(`spec-brief printed schemaVersion ${String(version)}; this harness reads ${SUPPORTED_SCHEMA_VERSIONS.join(', ')}`);
|
|
47
49
|
}
|
package/dist/briefs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"briefs.js","sourceRoot":"","sources":["../src/briefs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The briefs, as spec-brief reports them, and which one a round is working on.\n *\n * spec-brief owns the brief format and its configuration (its ADR-0003), so\n * the harness reads briefs the way spec-brief does by asking it:\n * `spec-brief list --archived --format json`. This module reads that\n * document and nothing else; a shape it does not recognise is an error, never\n * a best-effort reading of half the fields (ADR-0002).\n */\n\nimport { sameId } from './branch.js';\nimport type { BriefRow } from './types.js';\n\n/**\n * The spec-brief JSON document versions this harness reads. Version 1 is the\n * one spec-brief 0.1.0 prints; version 2 changed only `matrix`, which the\n * harness never reads, so the `list` and `archive` documents are the same.\n */\nexport const SUPPORTED_SCHEMA_VERSIONS: readonly number[] = [1, 2, 3];\n\nexport class SiblingOutputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SiblingOutputError';\n }\n}\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\nfunction strings(value: unknown, where: string): string[] {\n if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) {\n throw new SiblingOutputError(`${where} is not a list of strings`);\n }\n return value;\n}\n\nfunction nullableString(value: unknown, where: string): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value !== 'string') throw new SiblingOutputError(`${where} is not a string`);\n return value;\n}\n\n/** Reads the document `spec-brief list --format json` prints. */\nexport function parseBriefList(document: unknown): BriefRow[] {\n if (!isObject(document) || document['tool'] !== 'spec-brief' || document['command'] !== 'list') {\n throw new SiblingOutputError('spec-brief did not print a list document');\n }\n const version = document['schemaVersion'];\n if (typeof version !== 'number' || !SUPPORTED_SCHEMA_VERSIONS.includes(version)) {\n throw new SiblingOutputError(\n `spec-brief printed schemaVersion ${String(version)}; this harness reads ${SUPPORTED_SCHEMA_VERSIONS.join(', ')}`,\n );\n }\n const briefs = document['briefs'];\n if (!Array.isArray(briefs)) throw new SiblingOutputError('spec-brief list has no \"briefs\"');\n return briefs.map((row, index) => {\n const where = `briefs[${index}]`;\n if (!isObject(row)) throw new SiblingOutputError(`${where} is not an object`);\n const id = row['id'];\n const file = row['file'];\n if (typeof id !== 'string' || typeof file !== 'string') throw new SiblingOutputError(`${where} has no id or file`);\n const phase = row['phase'];\n if (phase !== 'live' && phase !== 'archived') throw new SiblingOutputError(`${where}.phase is \"${String(phase)}\"`);\n const tasks = row['tasks'];\n const wave = row['wave'];\n return {\n id,\n file,\n title: nullableString(row['title'], `${where}.title`),\n phase,\n status: nullableString(row['status'], `${where}.status`),\n type: nullableString(row['type'], `${where}.type`),\n wave: typeof wave === 'number' ? wave : null,\n dependsOn: strings(row['dependsOn'] ?? [], `${where}.dependsOn`),\n affectedFiles: strings(row['affectedFiles'] ?? [], `${where}.affectedFiles`),\n protectedFiles: strings(row['protectedFiles'] ?? [], `${where}.protectedFiles`),\n tasks: {\n total: isObject(tasks) && typeof tasks['total'] === 'number' ? tasks['total'] : 0,\n checked: isObject(tasks) && typeof tasks['checked'] === 'number' ? tasks['checked'] : 0,\n },\n ready: row['ready'] === true,\n waitingOn: strings(row['waitingOn'] ?? [], `${where}.waitingOn`),\n };\n });\n}\n\n/** How the active brief was named, for messages. */\nexport type ActiveSource = 'flag' | 'environment' | 'branch';\n\nexport type ActiveBrief =\n | { readonly kind: 'found'; readonly brief: BriefRow; readonly source: ActiveSource }\n | { readonly kind: 'none'; readonly reason: string }\n | { readonly kind: 'unknown'; readonly id: string; readonly source: ActiveSource }\n | { readonly kind: 'archived'; readonly brief: BriefRow; readonly source: ActiveSource };\n\n/**\n * The brief a round is working on: named by a flag, by `SPEC_BRIEF`, or by\n * the branch - never guessed from which brief happens to be the only active\n * one (ADR-0004).\n */\nexport function findActive(\n briefs: readonly BriefRow[],\n named: { readonly flag?: string | undefined; readonly environment?: string | undefined; readonly branch?: string | null | undefined },\n): ActiveBrief {\n const pick = (id: string, source: ActiveSource): ActiveBrief => {\n const matches = briefs.filter((brief) => sameId(brief.id, id));\n const live = matches.find((brief) => brief.phase === 'live');\n if (live !== undefined) return { kind: 'found', brief: live, source };\n const archived = matches[0];\n if (archived !== undefined) return { kind: 'archived', brief: archived, source };\n return { kind: 'unknown', id, source };\n };\n if (named.flag !== undefined && named.flag.trim() !== '') return pick(named.flag.trim(), 'flag');\n if (named.environment !== undefined && named.environment.trim() !== '') return pick(named.environment.trim(), 'environment');\n if (named.branch !== undefined && named.branch !== null) return pick(named.branch, 'branch');\n return {\n kind: 'none',\n reason: 'no brief is named: pass --brief <id>, set SPEC_BRIEF, or work on a branch named like brief/<id>-<topic>',\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"briefs.js","sourceRoot":"","sources":["../src/briefs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The briefs, as spec-brief reports them, and which one a round is working on.\n *\n * spec-brief owns the brief format and its configuration (its ADR-0003), so\n * the harness reads briefs the way spec-brief does by asking it:\n * `spec-brief list --archived --format json`. This module reads that\n * document and nothing else; a shape it does not recognise is an error, never\n * a best-effort reading of half the fields (ADR-0002).\n */\n\nimport { sameId } from './branch.js';\nimport type { BriefRow } from './types.js';\n\n/**\n * The spec-brief JSON document versions this harness reads. Version 1 is the\n * one spec-brief 0.1.0 prints; version 2 changed only `matrix`, which the\n * harness never reads, so the `list` and `archive` documents are the same.\n */\nexport const SUPPORTED_SCHEMA_VERSIONS: readonly number[] = [1, 2, 3];\n\nexport class SiblingOutputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SiblingOutputError';\n }\n}\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\nfunction strings(value: unknown, where: string): string[] {\n if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) {\n throw new SiblingOutputError(`${where} is not a list of strings`);\n }\n return value;\n}\n\nfunction nullableString(value: unknown, where: string): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value !== 'string') throw new SiblingOutputError(`${where} is not a string`);\n return value;\n}\n\n/** Reads the document `spec-brief list --format json` prints. */\nexport function parseBriefList(document: unknown): BriefRow[] {\n if (!isObject(document) || document['tool'] !== 'spec-brief' || document['command'] !== 'list') {\n throw new SiblingOutputError('spec-brief did not print a list document');\n }\n const version = document['schemaVersion'];\n // The list holds numbers alone, so `includes` refuses whatever is not one:\n // the `typeof` is the compiler's, and the mutant without it is equivalent.\n if (typeof version !== 'number' || !SUPPORTED_SCHEMA_VERSIONS.includes(version)) {\n throw new SiblingOutputError(\n `spec-brief printed schemaVersion ${String(version)}; this harness reads ${SUPPORTED_SCHEMA_VERSIONS.join(', ')}`,\n );\n }\n const briefs = document['briefs'];\n if (!Array.isArray(briefs)) throw new SiblingOutputError('spec-brief list has no \"briefs\"');\n return briefs.map((row, index) => {\n const where = `briefs[${index}]`;\n if (!isObject(row)) throw new SiblingOutputError(`${where} is not an object`);\n const id = row['id'];\n const file = row['file'];\n if (typeof id !== 'string' || typeof file !== 'string') throw new SiblingOutputError(`${where} has no id or file`);\n const phase = row['phase'];\n if (phase !== 'live' && phase !== 'archived') throw new SiblingOutputError(`${where}.phase is \"${String(phase)}\"`);\n const tasks = row['tasks'];\n const wave = row['wave'];\n return {\n id,\n file,\n title: nullableString(row['title'], `${where}.title`),\n phase,\n status: nullableString(row['status'], `${where}.status`),\n type: nullableString(row['type'], `${where}.type`),\n wave: typeof wave === 'number' ? wave : null,\n dependsOn: strings(row['dependsOn'] ?? [], `${where}.dependsOn`),\n affectedFiles: strings(row['affectedFiles'] ?? [], `${where}.affectedFiles`),\n protectedFiles: strings(row['protectedFiles'] ?? [], `${where}.protectedFiles`),\n tasks: {\n total: isObject(tasks) && typeof tasks['total'] === 'number' ? tasks['total'] : 0,\n checked: isObject(tasks) && typeof tasks['checked'] === 'number' ? tasks['checked'] : 0,\n },\n ready: row['ready'] === true,\n waitingOn: strings(row['waitingOn'] ?? [], `${where}.waitingOn`),\n };\n });\n}\n\n/** How the active brief was named, for messages. */\nexport type ActiveSource = 'flag' | 'environment' | 'branch';\n\nexport type ActiveBrief =\n | { readonly kind: 'found'; readonly brief: BriefRow; readonly source: ActiveSource }\n | { readonly kind: 'none'; readonly reason: string }\n | { readonly kind: 'unknown'; readonly id: string; readonly source: ActiveSource }\n | { readonly kind: 'archived'; readonly brief: BriefRow; readonly source: ActiveSource };\n\n/**\n * The brief a round is working on: named by a flag, by `SPEC_BRIEF`, or by\n * the branch - never guessed from which brief happens to be the only active\n * one (ADR-0004).\n */\nexport function findActive(\n briefs: readonly BriefRow[],\n named: { readonly flag?: string | undefined; readonly environment?: string | undefined; readonly branch?: string | null | undefined },\n): ActiveBrief {\n const pick = (id: string, source: ActiveSource): ActiveBrief => {\n const matches = briefs.filter((brief) => sameId(brief.id, id));\n const live = matches.find((brief) => brief.phase === 'live');\n if (live !== undefined) return { kind: 'found', brief: live, source };\n const archived = matches[0];\n if (archived !== undefined) return { kind: 'archived', brief: archived, source };\n return { kind: 'unknown', id, source };\n };\n if (named.flag !== undefined && named.flag.trim() !== '') return pick(named.flag.trim(), 'flag');\n if (named.environment !== undefined && named.environment.trim() !== '') return pick(named.environment.trim(), 'environment');\n if (named.branch !== undefined && named.branch !== null) return pick(named.branch, 'branch');\n return {\n kind: 'none',\n reason: 'no brief is named: pass --brief <id>, set SPEC_BRIEF, or work on a branch named like brief/<id>-<topic>',\n };\n}\n"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { type CliIO } from './workspace.js';
|
|
11
11
|
export { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';
|
|
12
|
-
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.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note. 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 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 --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch.\n --root <dir> Run from another directory.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n --strict Warnings fail the run.\n --help, --version\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n";
|
|
12
|
+
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.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note. 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 --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch.\n --root <dir> Run from another directory.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n --strict Warnings fail the run.\n --help, --version\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n";
|
|
13
13
|
export declare function run(argv: readonly string[], io: CliIO): Promise<number>;
|
|
14
14
|
export declare function main(argv?: readonly string[]): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -42,7 +42,8 @@ Commands:
|
|
|
42
42
|
--note. It counts once committed signed.
|
|
43
43
|
rulings [brief] The brief's rulings, and whether each one's signature verifies.
|
|
44
44
|
audit [brief] Did the round stay inside the lines: what the archive would say,
|
|
45
|
-
the brief's assertions, unverified rulings, new dependencies
|
|
45
|
+
the brief's assertions, unverified rulings, new dependencies
|
|
46
|
+
and the install scripts it allowed.
|
|
46
47
|
probe [brief] Run the brief's probes: red at the base, green at the head.
|
|
47
48
|
--at base|head|both, --id <probe>.
|
|
48
49
|
premises Do the live briefs' premises still hold? For CI: exit 1 when one
|
|
@@ -209,7 +210,9 @@ async function doctorCommand(options, io) {
|
|
|
209
210
|
// Only a Claude Code that runs the guard is asked its release: one older
|
|
210
211
|
// than the hooks need lets every write through unguarded.
|
|
211
212
|
const release = claude === 'none' ? null : checkClaudeCode(await claudeVersion(io.env));
|
|
212
|
-
|
|
213
|
+
// How the hook runs the harness is a note: one that goes through npx guards
|
|
214
|
+
// as well as one that does not, and fails nothing, --strict or not.
|
|
215
|
+
const { hook, note: hookNote } = await gitHook(workspace.root);
|
|
213
216
|
const branch = workspace.branch === null ? '(detached)' : `${workspace.branch}${workspace.branchSource === undefined ? '' : ` (detached; ${workspace.branchSource} names it)`}`;
|
|
214
217
|
if (options.format === 'json') {
|
|
215
218
|
io.stdout.write(json('doctor', {
|
|
@@ -234,7 +237,7 @@ async function doctorCommand(options, io) {
|
|
|
234
237
|
? { state: 'unchecked', version: null, minimum: CLAUDE_CODE_MINIMUM, detail: 'not asked: nothing wires Claude Code to the guard here' }
|
|
235
238
|
: { state: release.state, version: 'version' in release ? release.version : null, minimum: CLAUDE_CODE_MINIMUM, detail: describeClaudeRelease(release) },
|
|
236
239
|
},
|
|
237
|
-
gitHook: { state: hook.state, file: 'file' in hook ? hook.file : null, detail: describeGitHook(hook) },
|
|
240
|
+
gitHook: { state: hook.state, file: 'file' in hook ? hook.file : null, detail: describeGitHook(hook), note: hookNote },
|
|
238
241
|
siblings: rows,
|
|
239
242
|
}));
|
|
240
243
|
}
|
|
@@ -251,6 +254,7 @@ async function doctorCommand(options, io) {
|
|
|
251
254
|
`claude ${describeClaudeCode(wiring)}`,
|
|
252
255
|
...more(release === null ? [] : [describeClaudeRelease(release)]),
|
|
253
256
|
`git ${describeGitHook(hook)}`,
|
|
257
|
+
...more(hookNote === null ? [] : [hookNote]),
|
|
254
258
|
'',
|
|
255
259
|
'',
|
|
256
260
|
].join('\n'));
|
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, a configuration that does not\n * load, a sibling that is missing or printed something unreadable. A run that\n * 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 { show, stagedChanges } from './git.js';\nimport type { Decision } from './guard.js';\nimport { claudeResponse, gitResponse, parseClaudeHook } from './hooks.js';\nimport { claudeVersion } from './host.js';\nimport { premisesCommand } from './premises.js';\nimport { createReader } from './reader.js';\nimport { checkPaths, claudeCodeWiring, resolveBase, specBriefPlugin } 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 { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';\nimport {\n activeBrief,\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n namedId,\n openWorkspace,\n parseOptions,\n UsageError,\n version,\n type CliIO,\n type Options,\n type Workspace,\n} from './workspace.js';\n\nexport { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';\n\nexport const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work\n\nUsage:\n spec-harness <command> [options]\n\nCommands:\n context [brief] What an agent needs to start a round: the brief, its scope,\n rulings, dependencies, the rules in force, the cited documents.\n guard <path...> May the round write these paths? Exit 1 if one is refused.\n hook claude Answer a Claude Code PreToolUse or PostToolUse hook (stdin).\n hook git Answer git's pre-commit hook for the staged files.\n escalate Ask a person to rule: --path <file> (repeatable) --reason <why>\n [--option \"<label>: <cost>\"]... [--recommend <text>].\n --list shows what waits; --show <id> prints one memo.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note. 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 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 --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch.\n --root <dir> Run from another directory.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n --strict Warnings fail the run.\n --help, --version\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n`;\n\n\n/* ------------------------------------------------------------------- guard */\n\nconst reader = createReader();\n\nasync function decisionsFor(\n workspace: Workspace,\n options: Options,\n io: CliIO,\n given: readonly string[],\n cwd: string,\n): Promise<{ readonly decisions: Decision[] } | { readonly problem: string }> {\n const active = await activeBrief(workspace, options, io.env);\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) return { problem };\n return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };\n}\n\nconst SYMBOL: Record<Decision['verdict'], string> = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };\n\nasync function guardCommand(options: Options, io: CliIO): Promise<number> {\n if (options.positionals.length === 0) throw new UsageError('guard needs at least one path');\n const workspace = await openWorkspace(options, io);\n const decided = await decisionsFor(workspace, options, io, options.positionals, io.cwd);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const { decisions } = decided;\n if (options.format === 'json') {\n io.stdout.write(json('guard', { decisions }));\n } else {\n for (const decision of decisions) {\n io.stdout.write(`${SYMBOL[decision.verdict]} ${decision.message}\\n`);\n if (decision.verdict !== 'allow') io.stdout.write(` ${decision.hint}\\n`);\n }\n }\n const refused = decisions.some((d) => d.verdict === 'deny' || d.verdict === 'ask');\n const warned = decisions.some((d) => d.verdict === 'warn');\n return refused || (options.strict && warned) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------------- hook */\n\nasync function readStdin(io: CliIO): Promise<string> {\n // Only the built command line reads process.stdin, and the suite spawns it\n // from dist/, outside the sweep (tests/integration/claude-code.test.ts): the\n // lines below survive it untested in-process.\n if (io.stdin !== undefined) return io.stdin();\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n}\n\nasync function hookCommand(options: Options, io: CliIO): Promise<number> {\n const kind = options.positionals[0];\n if (kind === 'claude') {\n const request = parseClaudeHook(await readStdin(io));\n if ('error' in request) {\n // A hook that cannot read its question refuses nothing it cannot see,\n // but says so where the person reads it: a non-blocking error.\n io.stderr.write(`spec-harness: ${request.error}\\n`);\n return EXIT_FAILED;\n }\n if (request.paths.length === 0) return EXIT_OK;\n const cwd = request.cwd ?? io.cwd;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ ...options, root: options.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\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 = namedId(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 const base = 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 const { hook } = 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,\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) },\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 ?? '(none named)'}`,\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 '',\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 ['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]);\n\nexport async function run(argv: readonly string[], io: CliIO): Promise<number> {\n let options: Options;\n try {\n options = parseOptions(argv);\n } catch (error) {\n io.stderr.write(`spec-harness: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n if (options.version) {\n io.stdout.write(`${version()}\\n`);\n return EXIT_OK;\n }\n if (options.help || options.command === undefined) {\n io.stdout.write(HELP);\n return options.help ? EXIT_OK : EXIT_ERROR;\n }\n const command = COMMANDS.get(options.command);\n if (command === undefined) {\n io.stderr.write(`spec-harness: unknown command \"${options.command}\"; see spec-harness --help\\n`);\n return EXIT_ERROR;\n }\n try {\n return await command(options, 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.\n if (error instanceof UsageError || error instanceof ConfigError || error instanceof SiblingError || error instanceof SiblingOutputError) {\n io.stderr.write(`spec-harness: ${error.message}\\n`);\n return EXIT_ERROR;\n }\n throw 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, a configuration that does not\n * load, a sibling that is missing or printed something unreadable. A run that\n * 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 { show, stagedChanges } from './git.js';\nimport type { Decision } from './guard.js';\nimport { claudeResponse, gitResponse, parseClaudeHook } from './hooks.js';\nimport { claudeVersion } from './host.js';\nimport { premisesCommand } from './premises.js';\nimport { createReader } from './reader.js';\nimport { checkPaths, claudeCodeWiring, resolveBase, specBriefPlugin } 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 { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';\nimport {\n activeBrief,\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n namedId,\n openWorkspace,\n parseOptions,\n UsageError,\n version,\n type CliIO,\n type Options,\n type Workspace,\n} from './workspace.js';\n\nexport { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';\n\nexport const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work\n\nUsage:\n spec-harness <command> [options]\n\nCommands:\n context [brief] What an agent needs to start a round: the brief, its scope,\n rulings, dependencies, the rules in force, the cited documents.\n guard <path...> May the round write these paths? Exit 1 if one is refused.\n hook claude Answer a Claude Code PreToolUse or PostToolUse hook (stdin).\n hook git Answer git's pre-commit hook for the staged files.\n escalate Ask a person to rule: --path <file> (repeatable) --reason <why>\n [--option \"<label>: <cost>\"]... [--recommend <text>].\n --list shows what waits; --show <id> prints one memo.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note. 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 --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch.\n --root <dir> Run from another directory.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n --strict Warnings fail the run.\n --help, --version\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n`;\n\n\n/* ------------------------------------------------------------------- guard */\n\nconst reader = createReader();\n\nasync function decisionsFor(\n workspace: Workspace,\n options: Options,\n io: CliIO,\n given: readonly string[],\n cwd: string,\n): Promise<{ readonly decisions: Decision[] } | { readonly problem: string }> {\n const active = await activeBrief(workspace, options, io.env);\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) return { problem };\n return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };\n}\n\nconst SYMBOL: Record<Decision['verdict'], string> = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };\n\nasync function guardCommand(options: Options, io: CliIO): Promise<number> {\n if (options.positionals.length === 0) throw new UsageError('guard needs at least one path');\n const workspace = await openWorkspace(options, io);\n const decided = await decisionsFor(workspace, options, io, options.positionals, io.cwd);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const { decisions } = decided;\n if (options.format === 'json') {\n io.stdout.write(json('guard', { decisions }));\n } else {\n for (const decision of decisions) {\n io.stdout.write(`${SYMBOL[decision.verdict]} ${decision.message}\\n`);\n if (decision.verdict !== 'allow') io.stdout.write(` ${decision.hint}\\n`);\n }\n }\n const refused = decisions.some((d) => d.verdict === 'deny' || d.verdict === 'ask');\n const warned = decisions.some((d) => d.verdict === 'warn');\n return refused || (options.strict && warned) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------------- hook */\n\nasync function readStdin(io: CliIO): Promise<string> {\n // Only the built command line reads process.stdin, and the suite spawns it\n // from dist/, outside the sweep (tests/integration/claude-code.test.ts): the\n // lines below survive it untested in-process.\n if (io.stdin !== undefined) return io.stdin();\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n}\n\nasync function hookCommand(options: Options, io: CliIO): Promise<number> {\n const kind = options.positionals[0];\n if (kind === 'claude') {\n const request = parseClaudeHook(await readStdin(io));\n if ('error' in request) {\n // A hook that cannot read its question refuses nothing it cannot see,\n // but says so where the person reads it: a non-blocking error.\n io.stderr.write(`spec-harness: ${request.error}\\n`);\n return EXIT_FAILED;\n }\n if (request.paths.length === 0) return EXIT_OK;\n const cwd = request.cwd ?? io.cwd;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ ...options, root: options.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\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 = namedId(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 const base = 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,\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 ?? '(none named)'}`,\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 ['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]);\n\nexport async function run(argv: readonly string[], io: CliIO): Promise<number> {\n let options: Options;\n try {\n options = parseOptions(argv);\n } catch (error) {\n io.stderr.write(`spec-harness: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n if (options.version) {\n io.stdout.write(`${version()}\\n`);\n return EXIT_OK;\n }\n if (options.help || options.command === undefined) {\n io.stdout.write(HELP);\n return options.help ? EXIT_OK : EXIT_ERROR;\n }\n const command = COMMANDS.get(options.command);\n if (command === undefined) {\n io.stderr.write(`spec-harness: unknown command \"${options.command}\"; see spec-harness --help\\n`);\n return EXIT_ERROR;\n }\n try {\n return await command(options, 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.\n if (error instanceof UsageError || error instanceof ConfigError || error instanceof SiblingError || error instanceof SiblingOutputError) {\n io.stderr.write(`spec-harness: ${error.message}\\n`);\n return EXIT_ERROR;\n }\n throw error;\n }\n}\n\n// What bin/spec-harness.js runs; the suite spawns the built one, from dist/,\n// outside the sweep (tests/integration/cli.test.ts), so it survives untested\n// in-process.\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n return run(argv, { stdout: process.stdout, stderr: process.stderr, cwd: process.cwd(), env: process.env });\n}\n\n"]}
|
package/dist/commands.js
CHANGED
package/dist/commands.js.map
CHANGED
|
@@ -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, readProbes, renderEvidence, 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/** The brief a command acts on: a positional id, else the active one. A command that needs one and has none is a usage error. */\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, { flag: positional ?? options.brief, environment: io.env['SPEC_BRIEF'], branch: fromBranch });\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) throw new UsageError(problem);\n if (brief === null) throw new UsageError(note);\n return { brief, briefs };\n}\n\nconst MARK: Record<Finding['severity'], string> = { error: 'error ', warning: 'warning', note: 'note ' };\n\nfunction printFindings(io: CliIO, findings: readonly Finding[]): void {\n for (const finding of findings) {\n const where = finding.file === undefined ? '' : `${finding.file}${finding.line === undefined ? '' : `:${finding.line}`} `;\n io.stdout.write(`${MARK[finding.severity]} ${where}${finding.message} ${finding.rule}\\n ${finding.hint}\\n`);\n }\n}\n\n/* ----------------------------------------------------------------- context */\n\nexport async function contextCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief, briefs } = await targetBrief(workspace, options, io, options.positionals[0]);\n const packet = await buildContext(workspace, brief, briefs, reader, options.base);\n if (options.format === 'json') {\n io.stdout.write(\n json('context', {\n brief: brief.id,\n markdown: packet.markdown,\n included: packet.included,\n omitted: packet.omitted,\n unresolved: packet.unresolved,\n unclosedFrontMatter: packet.unclosedFrontMatter,\n unreadableFrontMatter: packet.unreadableFrontMatter,\n unreadableScope: packet.unreadableScope,\n unreadableProtections: packet.unreadableProtections,\n unreadableRulingPaths: packet.unreadableRulingPaths,\n }),\n );\n } else {\n io.stdout.write(packet.markdown);\n }\n return EXIT_OK;\n}\n\n/* ------------------------------------------------------------------- audit */\n\nexport async function auditCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const result = await runAudit(workspace, brief, reader, options.base);\n const { counts, findings, measured } = result.report;\n if (options.format === 'json') {\n io.stdout.write(\n json('audit', {\n ok: counts.error === 0 && (!options.strict || counts.warning === 0),\n brief: brief.id,\n base: result.base.kind === 'resolved' ? { ref: result.base.ref, mergeBase: result.base.mergeBase, head: result.base.head } : null,\n counts,\n measured,\n findings,\n dependencies: result.dependencies,\n }),\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 return colon < 0 ? { label: raw.trim(), consequence: '' } : { label: raw.slice(0, colon).trim(), consequence: raw.slice(colon + 1).trim() };\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 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: options.options.map(parseOption),\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\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 classified.push(classify(probe, { exitCode: run.exitCode, output: run.output, junit }));\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 run = await runCommand(setup, directory, workspace.config.probes.timeout);\n if (run.exitCode !== 0) throw new UsageError(`the probe setup \"${setup}\" failed at ${label}:\\n${run.output.slice(-2000)}`);\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 }\n return failed.length === 0 ? EXIT_OK : EXIT_FAILED;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The commands that read a round: context, audit, escalate, rule, rulings\n * and probe. Each resolves the brief, asks `round.ts` for the facts and\n * prints them; exit codes follow the family contract.\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport { describeMeasured } from './audit.js';\nimport { briefIdFromBranch } from './branch.js';\nimport { findActive } from './briefs.js';\nimport { formatFindings } from './formats.js';\nimport { readJUnit } from './junit.js';\nimport { classify, readProbes, renderEvidence, 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/** The brief a command acts on: a positional id, else the active one. A command that needs one and has none is a usage error. */\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, { flag: positional ?? options.brief, environment: io.env['SPEC_BRIEF'], branch: fromBranch });\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) throw new UsageError(problem);\n if (brief === null) throw new UsageError(note);\n return { brief, briefs };\n}\n\nconst MARK: Record<Finding['severity'], string> = { error: 'error ', warning: 'warning', note: 'note ' };\n\nfunction printFindings(io: CliIO, findings: readonly Finding[]): void {\n for (const finding of findings) {\n const where = finding.file === undefined ? '' : `${finding.file}${finding.line === undefined ? '' : `:${finding.line}`} `;\n io.stdout.write(`${MARK[finding.severity]} ${where}${finding.message} ${finding.rule}\\n ${finding.hint}\\n`);\n }\n}\n\n/* ----------------------------------------------------------------- context */\n\nexport async function contextCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief, briefs } = await targetBrief(workspace, options, io, options.positionals[0]);\n const packet = await buildContext(workspace, brief, briefs, reader, options.base);\n if (options.format === 'json') {\n io.stdout.write(\n json('context', {\n brief: brief.id,\n markdown: packet.markdown,\n included: packet.included,\n omitted: packet.omitted,\n unresolved: packet.unresolved,\n unclosedFrontMatter: packet.unclosedFrontMatter,\n unreadableFrontMatter: packet.unreadableFrontMatter,\n unreadableScope: packet.unreadableScope,\n unreadableProtections: packet.unreadableProtections,\n unreadableRulingPaths: packet.unreadableRulingPaths,\n }),\n );\n } else {\n io.stdout.write(packet.markdown);\n }\n return EXIT_OK;\n}\n\n/* ------------------------------------------------------------------- audit */\n\nexport async function auditCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const { brief } = await targetBrief(workspace, options, io, options.positionals[0]);\n const result = await runAudit(workspace, brief, reader, options.base);\n const { counts, findings, measured } = result.report;\n if (options.format === 'json') {\n io.stdout.write(\n json('audit', {\n ok: counts.error === 0 && (!options.strict || counts.warning === 0),\n brief: brief.id,\n base: result.base.kind === 'resolved' ? { ref: result.base.ref, mergeBase: result.base.mergeBase, head: result.base.head } : null,\n counts,\n measured,\n findings,\n dependencies: result.dependencies,\n installScripts: result.installScripts,\n }),\n );\n } else if (options.format === 'pretty') {\n io.stdout.write(`audit of brief ${brief.id}${result.base.kind === 'resolved' ? ` from ${result.base.ref} (${result.base.mergeBase.slice(0, 12)})` : ''}\\n\\n`);\n printFindings(io, findings);\n // The counts stay the last line, where a script reads them.\n io.stdout.write(`\\n${describeMeasured(measured)}\\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)\\n`);\n } else {\n io.stdout.write(formatFindings(options.format, findings, { file: brief.file, version: version(), summary: describeMeasured(measured) }));\n }\n return counts.error > 0 || (options.strict && counts.warning > 0) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------- escalation */\n\nfunction parseOption(raw: string): EscalationOption {\n const colon = raw.indexOf(':');\n return colon < 0 ? { label: raw.trim(), consequence: '' } : { label: raw.slice(0, colon).trim(), consequence: raw.slice(colon + 1).trim() };\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 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: options.options.map(parseOption),\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\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 classified.push(classify(probe, { exitCode: run.exitCode, output: run.output, junit }));\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 run = await runCommand(setup, directory, workspace.config.probes.timeout);\n if (run.exitCode !== 0) throw new UsageError(`the probe setup \"${setup}\" failed at ${label}:\\n${run.output.slice(-2000)}`);\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 }\n return failed.length === 0 ? EXIT_OK : EXIT_FAILED;\n}\n"]}
|
package/dist/config.js
CHANGED
|
@@ -156,6 +156,8 @@ export function parseConfig(raw, file = CONFIG_FILE) {
|
|
|
156
156
|
const command = value[name];
|
|
157
157
|
if (command === undefined || command === null)
|
|
158
158
|
continue;
|
|
159
|
+
// A list that is not empty has a first entry: the `?.` is the
|
|
160
|
+
// compiler's, and the mutant without it is equivalent.
|
|
159
161
|
if (!isStringList(command) || command.length === 0 || command[0]?.trim() === '') {
|
|
160
162
|
// A sibling runs without a shell, so the example is node and the
|
|
161
163
|
// script: npx is a shim Windows cannot start without one.
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What `.spec-harness.json` may say, the defaults, and validation.\n *\n * Every key has a default, so a repository without the file works; a file\n * that says something this version does not understand stops the run with\n * exit 2, because a guard that silently ignored a misspelt key would be\n * guarding something other than what its owner wrote.\n */\n\nimport { templateError } from './branch.js';\n\nexport type OutOfScope = 'warn' | 'ask' | 'deny';\n\nexport interface HarnessConfig {\n /** Branch-name templates that carry the active brief's id (ADR-0004). */\n readonly branches: readonly string[];\n /** What a write outside the brief's `affectedFiles` gets: a warning, a question to the person, or a refusal. */\n readonly outOfScope: OutOfScope;\n /** The branch rounds merge into, which audits and rulings are measured against. `null`: the remote's default branch. */\n readonly base: string | null;\n readonly rulings: {\n /** The brief section whose table holds the rulings. */\n readonly section: string;\n /** The allowed-signers file, read from the base branch, never from the round's own tree. */\n readonly allowedSigners: string;\n };\n readonly dependencies: {\n /** Manifest file names whose added dependencies an audit reports. */\n readonly manifests: readonly string[];\n };\n readonly context: {\n /** The most a context packet may hold, in characters. Cited documents fill what the rest leaves; those that do not fit are named by path. */\n readonly budget: number;\n };\n readonly assertions: {\n /**\n * Brief sections whose assertions state what was true before the round -\n * the defect, measured - and are expected to stop holding when it ends.\n * Every other assertion in a brief is a goal.\n */\n readonly premises: readonly string[];\n };\n readonly probes: {\n /** How many times a probe runs; every run must agree. */\n readonly runs: number;\n /** Seconds one run may take. */\n readonly timeout: number;\n };\n /** The command for each sibling tool, or `null` to find it (ADR-0002). */\n readonly tools: Readonly<Record<SiblingName, readonly string[] | null>>;\n}\n\nexport type SiblingName = 'spec-brief' | 'spec-graph' | 'spec-guard';\nexport const SIBLINGS: readonly SiblingName[] = ['spec-brief', 'spec-graph', 'spec-guard'];\n\nexport const CONFIG_FILE = '.spec-harness.json';\n\nexport const DEFAULT_MANIFESTS: readonly string[] = [\n 'package.json',\n 'Cargo.toml',\n 'go.mod',\n 'pyproject.toml',\n 'requirements*.txt',\n 'Directory.Packages.props',\n '*.csproj',\n '*.fsproj',\n '*.vbproj',\n 'Gemfile',\n];\n\nexport const DEFAULT_CONFIG: HarnessConfig = {\n branches: ['brief/{id}', 'brief-{id}', '*/brief/{id}', '*/brief-{id}'],\n outOfScope: 'warn',\n base: null,\n rulings: { section: 'Rulings', allowedSigners: '.github/allowed_signers' },\n dependencies: { manifests: DEFAULT_MANIFESTS },\n context: { budget: 60_000 },\n assertions: { premises: ['The Defect, Measured', 'Premises', 'Preconditions'] },\n probes: { runs: 2, timeout: 600 },\n tools: { 'spec-brief': null, 'spec-graph': null, 'spec-guard': null },\n};\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\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\nfunction isStringList(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\nfunction checkKeys(value: Json, allowed: readonly string[], where: string): void {\n for (const key of Object.keys(value)) {\n if (!allowed.includes(key)) {\n throw new ConfigError(`${where}: unknown key \"${key}\"; the keys are ${allowed.join(', ')}`);\n }\n }\n}\n\nfunction positive(value: unknown, where: string): number {\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new ConfigError(`${where} must be a whole number of at least 1`);\n }\n return value;\n}\n\nfunction nonEmpty(value: unknown, where: string): string {\n if (typeof value !== 'string' || value.trim() === '') throw new ConfigError(`${where} must be a non-empty string`);\n return value;\n}\n\n/** Validates a parsed configuration and fills in every default. */\nexport function parseConfig(raw: unknown, file = CONFIG_FILE): HarnessConfig {\n if (!isObject(raw)) throw new ConfigError(`${file} must hold a JSON object`);\n checkKeys(raw, ['$schema', 'branches', 'outOfScope', 'base', 'rulings', 'dependencies', 'context', 'assertions', 'probes', 'tools'], file);\n\n let branches = DEFAULT_CONFIG.branches;\n if (raw['branches'] !== undefined) {\n if (!isStringList(raw['branches']) || raw['branches'].length === 0) {\n throw new ConfigError(`${file}: \"branches\" must be a non-empty list of templates`);\n }\n for (const template of raw['branches']) {\n const error = templateError(template);\n if (error !== null) throw new ConfigError(`${file}: \"branches\": ${error}`);\n }\n branches = raw['branches'];\n }\n\n let outOfScope = DEFAULT_CONFIG.outOfScope;\n if (raw['outOfScope'] !== undefined) {\n if (raw['outOfScope'] !== 'warn' && raw['outOfScope'] !== 'ask' && raw['outOfScope'] !== 'deny') {\n throw new ConfigError(`${file}: \"outOfScope\" must be \"warn\", \"ask\" or \"deny\"`);\n }\n outOfScope = raw['outOfScope'];\n }\n\n let base = DEFAULT_CONFIG.base;\n if (raw['base'] !== undefined && raw['base'] !== null) base = nonEmpty(raw['base'], `${file}: \"base\"`);\n\n let rulings = DEFAULT_CONFIG.rulings;\n if (raw['rulings'] !== undefined) {\n const value = raw['rulings'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"rulings\" must be an object`);\n checkKeys(value, ['section', 'allowedSigners'], `${file}: \"rulings\"`);\n rulings = {\n section: value['section'] === undefined ? rulings.section : nonEmpty(value['section'], `${file}: \"rulings.section\"`),\n allowedSigners:\n value['allowedSigners'] === undefined\n ? rulings.allowedSigners\n : nonEmpty(value['allowedSigners'], `${file}: \"rulings.allowedSigners\"`),\n };\n }\n\n let dependencies = DEFAULT_CONFIG.dependencies;\n if (raw['dependencies'] !== undefined) {\n const value = raw['dependencies'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"dependencies\" must be an object`);\n checkKeys(value, ['manifests'], `${file}: \"dependencies\"`);\n if (value['manifests'] !== undefined) {\n if (!isStringList(value['manifests'])) throw new ConfigError(`${file}: \"dependencies.manifests\" must be a list of file names`);\n dependencies = { manifests: value['manifests'] };\n }\n }\n\n let context = DEFAULT_CONFIG.context;\n if (raw['context'] !== undefined) {\n const value = raw['context'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"context\" must be an object`);\n checkKeys(value, ['budget'], `${file}: \"context\"`);\n if (value['budget'] !== undefined) context = { budget: positive(value['budget'], `${file}: \"context.budget\"`) };\n }\n\n let assertions = DEFAULT_CONFIG.assertions;\n if (raw['assertions'] !== undefined) {\n const value = raw['assertions'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"assertions\" must be an object`);\n checkKeys(value, ['premises'], `${file}: \"assertions\"`);\n if (value['premises'] !== undefined) {\n if (!isStringList(value['premises'])) throw new ConfigError(`${file}: \"assertions.premises\" must be a list of section names`);\n assertions = { premises: value['premises'] };\n }\n }\n\n let probes = DEFAULT_CONFIG.probes;\n if (raw['probes'] !== undefined) {\n const value = raw['probes'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"probes\" must be an object`);\n checkKeys(value, ['runs', 'timeout'], `${file}: \"probes\"`);\n probes = {\n runs: value['runs'] === undefined ? probes.runs : positive(value['runs'], `${file}: \"probes.runs\"`),\n timeout: value['timeout'] === undefined ? probes.timeout : positive(value['timeout'], `${file}: \"probes.timeout\"`),\n };\n }\n\n const tools: Record<SiblingName, readonly string[] | null> = { ...DEFAULT_CONFIG.tools };\n if (raw['tools'] !== undefined) {\n const value = raw['tools'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"tools\" must be an object`);\n checkKeys(value, SIBLINGS, `${file}: \"tools\"`);\n for (const name of SIBLINGS) {\n const command = value[name];\n if (command === undefined || command === null) continue;\n if (!isStringList(command) || command.length === 0 || command[0]?.trim() === '') {\n // A sibling runs without a shell, so the example is node and the\n // script: npx is a shim Windows cannot start without one.\n throw new ConfigError(`${file}: \"tools.${name}\" must be a command as a list, such as [\"node\", \"node_modules/@descent-vtt/${name}/bin/${name}.js\"], or null`);\n }\n tools[name] = command;\n }\n }\n\n return { branches, outOfScope, base, rulings, dependencies, context, assertions, probes, tools };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What `.spec-harness.json` may say, the defaults, and validation.\n *\n * Every key has a default, so a repository without the file works; a file\n * that says something this version does not understand stops the run with\n * exit 2, because a guard that silently ignored a misspelt key would be\n * guarding something other than what its owner wrote.\n */\n\nimport { templateError } from './branch.js';\n\nexport type OutOfScope = 'warn' | 'ask' | 'deny';\n\nexport interface HarnessConfig {\n /** Branch-name templates that carry the active brief's id (ADR-0004). */\n readonly branches: readonly string[];\n /** What a write outside the brief's `affectedFiles` gets: a warning, a question to the person, or a refusal. */\n readonly outOfScope: OutOfScope;\n /** The branch rounds merge into, which audits and rulings are measured against. `null`: the remote's default branch. */\n readonly base: string | null;\n readonly rulings: {\n /** The brief section whose table holds the rulings. */\n readonly section: string;\n /** The allowed-signers file, read from the base branch, never from the round's own tree. */\n readonly allowedSigners: string;\n };\n readonly dependencies: {\n /** Manifest file names whose added dependencies an audit reports. */\n readonly manifests: readonly string[];\n };\n readonly context: {\n /** The most a context packet may hold, in characters. Cited documents fill what the rest leaves; those that do not fit are named by path. */\n readonly budget: number;\n };\n readonly assertions: {\n /**\n * Brief sections whose assertions state what was true before the round -\n * the defect, measured - and are expected to stop holding when it ends.\n * Every other assertion in a brief is a goal.\n */\n readonly premises: readonly string[];\n };\n readonly probes: {\n /** How many times a probe runs; every run must agree. */\n readonly runs: number;\n /** Seconds one run may take. */\n readonly timeout: number;\n };\n /** The command for each sibling tool, or `null` to find it (ADR-0002). */\n readonly tools: Readonly<Record<SiblingName, readonly string[] | null>>;\n}\n\nexport type SiblingName = 'spec-brief' | 'spec-graph' | 'spec-guard';\nexport const SIBLINGS: readonly SiblingName[] = ['spec-brief', 'spec-graph', 'spec-guard'];\n\nexport const CONFIG_FILE = '.spec-harness.json';\n\nexport const DEFAULT_MANIFESTS: readonly string[] = [\n 'package.json',\n 'Cargo.toml',\n 'go.mod',\n 'pyproject.toml',\n 'requirements*.txt',\n 'Directory.Packages.props',\n '*.csproj',\n '*.fsproj',\n '*.vbproj',\n 'Gemfile',\n];\n\nexport const DEFAULT_CONFIG: HarnessConfig = {\n branches: ['brief/{id}', 'brief-{id}', '*/brief/{id}', '*/brief-{id}'],\n outOfScope: 'warn',\n base: null,\n rulings: { section: 'Rulings', allowedSigners: '.github/allowed_signers' },\n dependencies: { manifests: DEFAULT_MANIFESTS },\n context: { budget: 60_000 },\n assertions: { premises: ['The Defect, Measured', 'Premises', 'Preconditions'] },\n probes: { runs: 2, timeout: 600 },\n tools: { 'spec-brief': null, 'spec-graph': null, 'spec-guard': null },\n};\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\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\nfunction isStringList(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\nfunction checkKeys(value: Json, allowed: readonly string[], where: string): void {\n for (const key of Object.keys(value)) {\n if (!allowed.includes(key)) {\n throw new ConfigError(`${where}: unknown key \"${key}\"; the keys are ${allowed.join(', ')}`);\n }\n }\n}\n\nfunction positive(value: unknown, where: string): number {\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new ConfigError(`${where} must be a whole number of at least 1`);\n }\n return value;\n}\n\nfunction nonEmpty(value: unknown, where: string): string {\n if (typeof value !== 'string' || value.trim() === '') throw new ConfigError(`${where} must be a non-empty string`);\n return value;\n}\n\n/** Validates a parsed configuration and fills in every default. */\nexport function parseConfig(raw: unknown, file = CONFIG_FILE): HarnessConfig {\n if (!isObject(raw)) throw new ConfigError(`${file} must hold a JSON object`);\n checkKeys(raw, ['$schema', 'branches', 'outOfScope', 'base', 'rulings', 'dependencies', 'context', 'assertions', 'probes', 'tools'], file);\n\n let branches = DEFAULT_CONFIG.branches;\n if (raw['branches'] !== undefined) {\n if (!isStringList(raw['branches']) || raw['branches'].length === 0) {\n throw new ConfigError(`${file}: \"branches\" must be a non-empty list of templates`);\n }\n for (const template of raw['branches']) {\n const error = templateError(template);\n if (error !== null) throw new ConfigError(`${file}: \"branches\": ${error}`);\n }\n branches = raw['branches'];\n }\n\n let outOfScope = DEFAULT_CONFIG.outOfScope;\n if (raw['outOfScope'] !== undefined) {\n if (raw['outOfScope'] !== 'warn' && raw['outOfScope'] !== 'ask' && raw['outOfScope'] !== 'deny') {\n throw new ConfigError(`${file}: \"outOfScope\" must be \"warn\", \"ask\" or \"deny\"`);\n }\n outOfScope = raw['outOfScope'];\n }\n\n let base = DEFAULT_CONFIG.base;\n if (raw['base'] !== undefined && raw['base'] !== null) base = nonEmpty(raw['base'], `${file}: \"base\"`);\n\n let rulings = DEFAULT_CONFIG.rulings;\n if (raw['rulings'] !== undefined) {\n const value = raw['rulings'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"rulings\" must be an object`);\n checkKeys(value, ['section', 'allowedSigners'], `${file}: \"rulings\"`);\n rulings = {\n section: value['section'] === undefined ? rulings.section : nonEmpty(value['section'], `${file}: \"rulings.section\"`),\n allowedSigners:\n value['allowedSigners'] === undefined\n ? rulings.allowedSigners\n : nonEmpty(value['allowedSigners'], `${file}: \"rulings.allowedSigners\"`),\n };\n }\n\n let dependencies = DEFAULT_CONFIG.dependencies;\n if (raw['dependencies'] !== undefined) {\n const value = raw['dependencies'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"dependencies\" must be an object`);\n checkKeys(value, ['manifests'], `${file}: \"dependencies\"`);\n if (value['manifests'] !== undefined) {\n if (!isStringList(value['manifests'])) throw new ConfigError(`${file}: \"dependencies.manifests\" must be a list of file names`);\n dependencies = { manifests: value['manifests'] };\n }\n }\n\n let context = DEFAULT_CONFIG.context;\n if (raw['context'] !== undefined) {\n const value = raw['context'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"context\" must be an object`);\n checkKeys(value, ['budget'], `${file}: \"context\"`);\n if (value['budget'] !== undefined) context = { budget: positive(value['budget'], `${file}: \"context.budget\"`) };\n }\n\n let assertions = DEFAULT_CONFIG.assertions;\n if (raw['assertions'] !== undefined) {\n const value = raw['assertions'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"assertions\" must be an object`);\n checkKeys(value, ['premises'], `${file}: \"assertions\"`);\n if (value['premises'] !== undefined) {\n if (!isStringList(value['premises'])) throw new ConfigError(`${file}: \"assertions.premises\" must be a list of section names`);\n assertions = { premises: value['premises'] };\n }\n }\n\n let probes = DEFAULT_CONFIG.probes;\n if (raw['probes'] !== undefined) {\n const value = raw['probes'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"probes\" must be an object`);\n checkKeys(value, ['runs', 'timeout'], `${file}: \"probes\"`);\n probes = {\n runs: value['runs'] === undefined ? probes.runs : positive(value['runs'], `${file}: \"probes.runs\"`),\n timeout: value['timeout'] === undefined ? probes.timeout : positive(value['timeout'], `${file}: \"probes.timeout\"`),\n };\n }\n\n const tools: Record<SiblingName, readonly string[] | null> = { ...DEFAULT_CONFIG.tools };\n if (raw['tools'] !== undefined) {\n const value = raw['tools'];\n if (!isObject(value)) throw new ConfigError(`${file}: \"tools\" must be an object`);\n checkKeys(value, SIBLINGS, `${file}: \"tools\"`);\n for (const name of SIBLINGS) {\n const command = value[name];\n if (command === undefined || command === null) continue;\n // A list that is not empty has a first entry: the `?.` is the\n // compiler's, and the mutant without it is equivalent.\n if (!isStringList(command) || command.length === 0 || command[0]?.trim() === '') {\n // A sibling runs without a shell, so the example is node and the\n // script: npx is a shim Windows cannot start without one.\n throw new ConfigError(`${file}: \"tools.${name}\" must be a command as a list, such as [\"node\", \"node_modules/@descent-vtt/${name}/bin/${name}.js\"], or null`);\n }\n tools[name] = command;\n }\n }\n\n return { branches, outOfScope, base, rulings, dependencies, context, assertions, probes, tools };\n}\n"]}
|