@descent-vtt/spec-harness 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +212 -0
  4. package/README.md +30 -15
  5. package/dist/briefs.d.ts +45 -0
  6. package/dist/briefs.js +73 -0
  7. package/dist/briefs.js.map +1 -1
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.js +211 -134
  10. package/dist/cli.js.map +1 -1
  11. package/dist/commands.js +7 -2
  12. package/dist/commands.js.map +1 -1
  13. package/dist/config.d.ts +13 -1
  14. package/dist/config.js +14 -3
  15. package/dist/config.js.map +1 -1
  16. package/dist/configure.d.ts +55 -1
  17. package/dist/configure.js +130 -22
  18. package/dist/configure.js.map +1 -1
  19. package/dist/fs.d.ts +78 -1
  20. package/dist/fs.js +289 -10
  21. package/dist/fs.js.map +1 -1
  22. package/dist/git.d.ts +50 -2
  23. package/dist/git.js +98 -8
  24. package/dist/git.js.map +1 -1
  25. package/dist/hooks.d.ts +45 -0
  26. package/dist/hooks.js +62 -3
  27. package/dist/hooks.js.map +1 -1
  28. package/dist/round.d.ts +8 -0
  29. package/dist/round.js +23 -8
  30. package/dist/round.js.map +1 -1
  31. package/dist/sandbox.js +4 -3
  32. package/dist/sandbox.js.map +1 -1
  33. package/dist/server.d.ts +25 -1
  34. package/dist/server.js +194 -27
  35. package/dist/server.js.map +1 -1
  36. package/dist/setup.js +40 -10
  37. package/dist/setup.js.map +1 -1
  38. package/dist/siblings.d.ts +24 -3
  39. package/dist/siblings.js +106 -14
  40. package/dist/siblings.js.map +1 -1
  41. package/dist/usage.d.ts +42 -7
  42. package/dist/usage.js +65 -6
  43. package/dist/usage.js.map +1 -1
  44. package/dist/workspace.d.ts +45 -3
  45. package/dist/workspace.js +133 -13
  46. package/dist/workspace.js.map +1 -1
  47. package/package.json +1 -1
package/dist/round.js CHANGED
@@ -17,9 +17,9 @@ import { fileURLToPath } from 'node:url';
17
17
  import { readArchivePlan, readGuardRun } from './answers.js';
18
18
  import { SiblingOutputError } from './briefs.js';
19
19
  import { sameId } from './branch.js';
20
- import { arrayMatcher, enabledPlugin, exportedFile, handedLines, hooksDisabled, HOSTED_REGISTRY, isStarted, loadsPlugin, MARKETPLACE_REGISTRY, matchingUnder, patternReader, pluginMarketplace, pluginPresence, PROJECT_SETTINGS, registersServer, reportHooks, SPEC_BRIEF_CONFIGS, startsSessions, wiringState, } from './configure.js';
20
+ import { arrayMatcher, enabledPlugin, exportedFile, handedLines, hooksDisabled, HOSTED_REGISTRY, isStarted, loadsPlugin, MARKETPLACE_REGISTRY, matchingUnder, patternReader, pluginMarketplace, pluginPresence, PROJECT_SETTINGS, readsOnFailure, registersServer, reportHooks, SPEC_BRIEF_CONFIGS, startsSessions, wiringState, } from './configure.js';
21
21
  import { readRules, renderContext } from './context.js';
22
- import { isDirectory, readJsonObject, readText, repositoryPath, stateDirectory, writeAtomic } from './fs.js';
22
+ import { isDirectory, isFile, readJsonObject, readText, repositoryPath, stateDirectory, writeAtomic } from './fs.js';
23
23
  import { blameLine, changes, commonDirectory, isUncommitted, mergeBase, remoteDefault, revision, show, verifyCommit, workTreeRoot } from './git.js';
24
24
  import { decide } from './guard.js';
25
25
  import { diffManifest, ecosystemOf, readManifestNames } from './manifests.js';
@@ -310,7 +310,10 @@ export function pluginFile(root) {
310
310
  // or on the missing key inside this block, which the catch reads as no
311
311
  // installed copy: `exports?.` and `target !== null` are equivalent to
312
312
  // their mutants here. So is the encoding: a Buffer parses as its text.
313
- const manifest = JSON.parse(readFileSync(join(installed, 'package.json'), 'utf8'));
313
+ // Only a file is read: what stands there and is none is no installed
314
+ // copy, as a manifest with no exports is (ADR-0002).
315
+ const file = join(installed, 'package.json');
316
+ const manifest = isFile(file) ? JSON.parse(readFileSync(file, 'utf8')) : {};
314
317
  const target = exportedFile(manifest.exports?.['./spec-brief-plugin']);
315
318
  if (target !== null)
316
319
  candidates.push(join(installed, target));
@@ -456,7 +459,7 @@ export async function claudeCodeWiring(root, io, pattern = patternReader(), repo
456
459
  // init writes its hooks into the project's file alone, and none where an array unloads it.
457
460
  const unloaded = arrayMatcher(sources.find(({ file }) => file === PROJECT_SETTINGS).settings);
458
461
  const under = (release) => {
459
- const lines = reportHooks(sources, root, (words) => read.get(JSON.stringify(words)), pattern, matchingUnder(release));
462
+ const lines = reportHooks(sources, root, (words) => read.get(JSON.stringify(words)), pattern, matchingUnder(release), readsOnFailure(release));
460
463
  // A line Claude Code starts for no write, before one or after, is in no
461
464
  // one's way: it is said, and the file is not counted for it.
462
465
  const hooks = sources.map(({ file }) => file).filter((file) => lines.some((line) => line.file === file && (isStarted(line.before) || isStarted(line.after))));
@@ -524,25 +527,34 @@ async function hookLineHere(words, root, io) {
524
527
  * wrong with the name when no round can work under it. Every other command
525
528
  * stops there. A diagnosis says it, being what a person runs when the guard
526
529
  * holds a write they expected it to pass.
530
+ *
531
+ * `branch` is whether the name no round can work under is the branch's: a
532
+ * brief it names that spec-brief does not know, or has archived. The hook
533
+ * reads the same branch and holds every write under such a name, which is a
534
+ * setup that holds every write, as a hook's line naming such a brief is
535
+ * (ADR-0004). A name the flag gives is the question doctor was asked, and
536
+ * holds no write of anyone's.
527
537
  */
528
538
  export async function diagnoseBrief(workspace, options, env) {
529
539
  if (options.brief !== undefined && isBlank(options.brief))
530
- return { id: null, problem: emptyValue('--brief', 'brief', options.brief) };
540
+ return { id: null, problem: emptyValue('--brief', 'brief', options.brief), branch: false };
531
541
  const id = namedId(workspace, options, env);
532
542
  // A spec-brief that cannot be run is a row of the report, with the reason.
533
543
  if (workspace.siblings.locate('spec-brief').kind !== 'found')
534
- return { id, problem: null };
544
+ return { id, problem: null, branch: false };
535
545
  try {
536
546
  // Where nothing names a brief, spec-brief is not asked (ADR-0004), and
537
547
  // there is no problem to state.
538
- return { id, problem: describeActive(await activeBrief(workspace, options, env)).problem };
548
+ const active = await activeBrief(workspace, options, env);
549
+ const branch = (active.kind === 'unknown' || active.kind === 'archived') && active.source === 'branch';
550
+ return { id, problem: describeActive(active).problem, branch };
539
551
  }
540
552
  catch (error) {
541
553
  // Asking spec-brief throws nothing but this, so the check is equivalent
542
554
  // to its mutant; it keeps any other error the stack it needs.
543
555
  if (!(error instanceof SiblingError))
544
556
  throw error;
545
- return { id, problem: `spec-brief could not say whether it knows brief ${id}: ${error.message}` };
557
+ return { id, problem: `spec-brief could not say whether it knows brief ${id}: ${error.message}`, branch: false };
546
558
  }
547
559
  }
548
560
  async function archiveReasons(workspace, brief, base) {
@@ -619,6 +631,9 @@ export async function listEscalations(workspace) {
619
631
  const directory = await escalationDirectory(workspace);
620
632
  const out = [];
621
633
  for (const name of (await readdir(directory)).filter((n) => n.endsWith('.json')).sort()) {
634
+ // What is no file is no request, and is passed over as one that cannot be read is.
635
+ if (!isFile(join(directory, name)))
636
+ continue;
622
637
  try {
623
638
  // A Buffer parses as its text, so the encoding is equivalent to its mutant.
624
639
  const request = JSON.parse(await readFile(join(directory, name), 'utf8'));
package/dist/round.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"round.js","sourceRoot":"","sources":["../src/round.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A round, measured: the operations the command line and the MCP server\n * share. Each gathers what a pure module needs - from git, the disk and the\n * siblings - and hands it over; the decisions are made in `context.ts`,\n * `audit.ts`, `guard.ts` and `rulings.ts`.\n *\n * The hook loads this module before every write it decides, so what only\n * an audit, a verified ruling or `doctor` runs is imported where it runs:\n * the audit's judgement, which brings the Markdown scanner with it, the\n * hash a copy of the signers is named by, and what asks Claude Code its\n * release.\n */\n\nimport { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { readdir, readFile, rm } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { readArchivePlan, readGuardRun } from './answers.js';\nimport type { ArchiveReason, AssertionOutcome, AuditInput, AuditReport, UnreadableAssertion } from './audit.js';\nimport { SiblingOutputError } from './briefs.js';\nimport { sameId } from './branch.js';\nimport {\n arrayMatcher,\n enabledPlugin,\n exportedFile,\n handedLines,\n hooksDisabled,\n HOSTED_REGISTRY,\n isStarted,\n loadsPlugin,\n MARKETPLACE_REGISTRY,\n matchingUnder,\n patternReader,\n pluginMarketplace,\n pluginPresence,\n PROJECT_SETTINGS,\n registersServer,\n reportHooks,\n SPEC_BRIEF_CONFIGS,\n startsSessions,\n wiringState,\n type BaseSource,\n type ClaudeCodeWiring,\n type ClaudeSettings,\n type PatternReader,\n type PluginsRoot,\n type PluginState,\n} from './configure.js';\nimport { readRules, renderContext, type CitedDocument, type ContextPacket, type Rules } from './context.js';\nimport type { DocumentReader } from './document.js';\nimport { isDirectory, readJsonObject, readText, repositoryPath, stateDirectory, writeAtomic } from './fs.js';\nimport { blameLine, changes, commonDirectory, isUncommitted, mergeBase, remoteDefault, revision, show, verifyCommit, workTreeRoot } from './git.js';\nimport { decide, type Decision, type VerifiedRuling } from './guard.js';\nimport { diffManifest, ecosystemOf, readManifestNames, type DependencyChange, type InstallScriptChange } from './manifests.js';\nimport {\n addRulingRow,\n nextId,\n readRulings,\n renderMemo,\n renderRow,\n type EscalationOption,\n type EscalationRequest,\n type RulingRow,\n} from './rulings.js';\nimport type { BriefRow, Finding } from './types.js';\nimport { compileGlob, type LiteralReading } from './vendor/spec-core/pattern/index.js';\nimport { dirname, isRelativeReference, resolveInside, splitReference } from './vendor/spec-core/path/index.js';\nimport { SiblingError } from './siblings.js';\nimport { claudeHookLine, elsewhereHookLine, emptyValue, heldHookLine, holderHookLine, isBlank, outsideHookLine, type HookLine } from './usage.js';\nimport { checkClaudeCode, type ClaudeCodeCheck } from './versions.js';\nimport { activeBrief, describeActive, namedId, openWorkspace, parseOptions, UsageError, type CliIO, type Options, type Workspace } from './workspace.js';\n\n/* -------------------------------------------------------------------- base */\n\nexport type Base =\n | { readonly kind: 'resolved'; readonly ref: string; readonly source: BaseSource; readonly sha: string; readonly mergeBase: string; readonly head: string }\n | { readonly kind: 'unresolved'; readonly reason: string };\n\n/** What the round is measured from: the flag, the configuration, then the remote's default branch. */\nexport async function resolveBase(workspace: Workspace, flag: string | undefined): Promise<Base> {\n const source: BaseSource = flag !== undefined ? 'flag' : workspace.config.base !== null ? 'config' : 'remote';\n const ref = flag ?? workspace.config.base ?? (await remoteDefault(workspace.root));\n if (ref === null) {\n return { kind: 'unresolved', reason: 'no base is named and the remote has no default branch; pass --base <ref> or set \"base\"' };\n }\n // Neither commit waits on the other, so git is asked for both at once, and\n // they are read in the order they were asked in before: a base that names\n // no commit is said before a HEAD that names none.\n const [sha, head] = await Promise.all([revision(ref, workspace.root), revision('HEAD', workspace.root)]);\n if (sha === null) return { kind: 'unresolved', reason: `\"${ref}\" names no commit` };\n if (head === null) return { kind: 'unresolved', reason: 'HEAD names no commit: nothing is committed on this branch yet' };\n const common = await mergeBase(sha, head, workspace.root);\n if (common === null) return { kind: 'unresolved', reason: `\"${ref}\" and HEAD share no history` };\n return { kind: 'resolved', ref, source, sha, mergeBase: common, head };\n}\n\n/* ----------------------------------------------------------------- rulings */\n\nexport interface RulingCheck {\n readonly rows: readonly RulingRow[];\n readonly verified: readonly VerifiedRuling[];\n readonly unverified: readonly { readonly id: string; readonly reason: string }[];\n readonly problems: readonly Finding[];\n}\n\n/**\n * The brief's rulings, each checked against its signature: the commit that\n * last changed its row must be signed by a principal the base branch's\n * allowed-signers file lists (ADR-0006).\n */\nexport async function checkRulings(workspace: Workspace, brief: Pick<BriefRow, 'file'>, text: string, reader: DocumentReader, base: Base): Promise<RulingCheck> {\n const { rulings: rows, problems } = readRulings(reader.sectionTables(text, workspace.config.rulings.section).tables);\n const findings: Finding[] = problems.map((problem) => ({\n rule: 'ruling-unreadable',\n severity: 'warning',\n message: problem.message,\n hint: 'a ruling row is | id | `paths` | allow or deny | note |',\n file: brief.file,\n line: problem.line,\n }));\n const allows = rows.filter((row) => row.decision === 'allow');\n // Nothing below verifies a row that allows nothing, so this saves a git\n // show and is equivalent to its mutants.\n if (allows.length === 0) return { rows, verified: [], unverified: [], problems: findings };\n if (base.kind === 'unresolved') {\n return { rows, verified: [], unverified: allows.map((row) => ({ id: row.id, reason: `no base to read the allowed signers from: ${base.reason}` })), problems: findings };\n }\n const signers = await show(base.sha, workspace.config.rulings.allowedSigners, workspace.root);\n if (signers === null) {\n const reason = `${base.ref} has no ${workspace.config.rulings.allowedSigners}, so no signature can count`;\n return { rows, verified: [], unverified: allows.map((row) => ({ id: row.id, reason })), problems: findings };\n }\n // Only verify-commit below reads this copy, so where it is kept, and under\n // what name, is equivalent to its mutants. The one that reads the digest\n // with no encoding names the file by its bytes, which a path refuses when\n // one of them is NUL: a sweep counts that mutant killed now and then.\n const directory = await stateDirectory(workspace.commonDir, 'signers');\n const { createHash } = await import('node:crypto');\n const file = join(directory, `${createHash('sha256').update(signers).digest('hex').slice(0, 16)}`);\n await writeAtomic(file, signers);\n const verified: VerifiedRuling[] = [];\n const unverified: { id: string; reason: string }[] = [];\n for (const row of allows) {\n // The row's line is a line of the text on disk, so it is blamed there: at\n // HEAD the same number can be another line, one a signed commit wrote,\n // and an uncommitted row would borrow that commit's signature.\n const commit = await blameLine(null, brief.file, row.line, workspace.root);\n if (commit === null || isUncommitted(commit)) {\n unverified.push({ id: row.id, reason: 'its row is not committed' });\n continue;\n }\n const signature = await verifyCommit(commit, file, workspace.root);\n if (signature.good) verified.push({ id: row.id, paths: row.paths, signer: signature.principal });\n else unverified.push({ id: row.id, reason: `commit ${commit.slice(0, 12)} last changed its row, and ${signature.detail || 'it is not signed'}` });\n }\n return { rows, verified, unverified, problems: findings };\n}\n\n/* ------------------------------------------------------------------- guard */\n\nexport async function briefText(workspace: Workspace, brief: BriefRow): Promise<string> {\n const text = await readText(join(workspace.root, brief.file));\n if (text === null) throw new UsageError(`${brief.file} cannot be read`);\n return text;\n}\n\n/**\n * Decides paths against the brief, with the rulings verified against the\n * base `baseFlag` names, or the configured one. The reader may be given as\n * what makes one: it is asked for where a ruling is read, and a caller that\n * decides every write need not load a scanner for those that read none.\n */\nexport async function checkPaths(\n workspace: Workspace,\n brief: BriefRow | null,\n noBrief: string | undefined,\n given: readonly string[],\n cwd: string,\n reader: DocumentReader | (() => Promise<DocumentReader>),\n baseFlag: string | undefined,\n): Promise<Decision[]> {\n const resolved = given.map((path) => ({ given: path, path: repositoryPath(path, workspace.root, cwd) }));\n const decideAll = (rulings: readonly VerifiedRuling[]): Decision[] =>\n resolved.map(({ path, given: g }) => decide({ path, given: g, brief, noBrief, rulings, outOfScope: workspace.config.outOfScope }));\n const first = decideAll([]);\n // Rulings cost the reader of a brief, and a blame and a signature check\n // each, so they are read only when a write reaches a protected file. Read\n // anyway, they decide the same, since a ruling allows only a protected\n // path: what a mutant that always reads them changes is what is loaded\n // for a write no brief protects (loads.test.ts). With no brief nothing is\n // protected, so the null check is there for the type.\n if (brief === null || !first.some((decision) => decision.reason === 'protected')) return first;\n const text = await briefText(workspace, brief);\n const documents = typeof reader === 'function' ? await reader() : reader;\n // The base is where the allowed signers are read, and only a row that\n // allows something is checked against them: where none does, git is asked\n // nothing of the base, three processes of a refusal, and what was decided\n // without a ruling stands.\n const { rulings } = readRulings(documents.sectionTables(text, workspace.config.rulings.section).tables);\n if (!rulings.some((row) => row.decision === 'allow')) return first;\n const base = await resolveBase(workspace, baseFlag);\n return decideAll((await checkRulings(workspace, brief, text, documents, base)).verified);\n}\n\n/* ----------------------------------------------------------------- context */\n\n/**\n * The paths spec-guard is asked about for a scope: where its patterns can\n * match. A name with no glob syntax that exists is asked about as itself,\n * since spec-guard reads from the disk whether a path is a file or a\n * directory. One the round has yet to create may become either, and\n * spec-guard would read it as a file, leaving out the rules over a\n * directory of that name; it is asked about through the directory that will\n * hold it, the root for a name at the top, which covers both.\n */\nfunction scopeBases(root: string, patterns: readonly string[]): string[] {\n // Read as a directory, a name's base is the name itself; read any other\n // way, it is the directory holding it, so which other reading a missing\n // name gets changes nothing. The glob is compiled for its bases and never\n // matched: a file read as a directory narrows the question and nothing\n // else.\n const literal = (path: string): LiteralReading => (existsSync(join(root, path)) ? 'directory' : 'either');\n const bases = new Set<string>();\n for (const pattern of patterns) {\n try {\n // Case is read only in matching, which this compile never does: its\n // bases are the same either way, so `caseSensitive: false` is equivalent.\n for (const base of compileGlob(pattern, { dialect: 'path', caseSensitive: true, literal }).bases) {\n // A rooted alternative's base, `/docs` or `/`, is outside the\n // repository: it puts no path in the scope, and spec-guard refuses\n // the whole question for it, with the rules for every other base.\n // The packet names the pattern.\n if (base.startsWith('/')) continue;\n bases.add(base === '' ? '.' : base);\n }\n } catch {\n // The packet names a pattern the guard cannot read, with spec-core's\n // reason, and says so when it is every pattern; the rules for the rest\n // still count.\n }\n }\n return [...bases].sort();\n}\n\nasync function rulesFor(workspace: Workspace, brief: BriefRow): Promise<Rules> {\n const paths = scopeBases(workspace.root, brief.affectedFiles);\n if (paths.length === 0) return [];\n try {\n const answer = await workspace.siblings.json('spec-guard', ['query', ...paths, '--json']);\n return 'absent' in answer ? { unavailable: answer.absent } : readRules(answer);\n } catch (error) {\n // spec-guard printed no JSON, or a document of another shape: what it\n // said instead, or what was wrong, is the reason, and the rest of the\n // packet stands without the rules.\n if (error instanceof SiblingError || error instanceof SiblingOutputError) return { unavailable: error.message };\n throw error;\n }\n}\n\nasync function citedDocuments(workspace: Workspace, brief: BriefRow, text: string, reader: DocumentReader): Promise<CitedDocument[]> {\n const seen = new Set<string>();\n const out: CitedDocument[] = [];\n for (const citation of reader.citations(text)) {\n if (!isRelativeReference(citation.target)) continue;\n let target = splitReference(citation.target).path;\n try {\n target = decodeURIComponent(target);\n } catch {\n // A destination that is not valid percent-encoding is read as written.\n }\n const path = resolveInside(dirname(brief.file), target);\n if (path === null || path === brief.file || seen.has(path)) continue;\n seen.add(path);\n const document = /\\.(?:md|markdown|mdx|txt)$/i.test(path);\n // A link to code or a directory that exists is not a document to include,\n // and must not be reported as a link that resolves to nothing.\n if (!document && existsSync(join(workspace.root, path))) continue;\n const content = document ? await readText(join(workspace.root, path)) : null;\n // A document that cannot be read is listed by its path alone, so its\n // title and status are never read, and an empty object is equivalent.\n const meta = content === null ? { title: null, status: null } : reader.titleAndStatus(content);\n out.push({ path, ...meta, text: content });\n }\n return out;\n}\n\nexport async function buildContext(\n workspace: Workspace,\n brief: BriefRow,\n briefs: readonly BriefRow[],\n reader: DocumentReader,\n baseFlag: string | undefined,\n): Promise<ContextPacket> {\n const text = await briefText(workspace, brief);\n const base = await resolveBase(workspace, baseFlag);\n const [rules, cited, rulings] = await Promise.all([\n rulesFor(workspace, brief),\n citedDocuments(workspace, brief, text, reader),\n checkRulings(workspace, brief, text, reader, base),\n ]);\n return renderContext({\n brief,\n briefText: text,\n dependencies: brief.dependsOn.map(\n (id) =>\n // spec-brief reports a dependency as its front matter spells it, `7` for brief 007.\n // The context reads a dependency's id, title, status and phase, and\n // the brief copied here is live.\n briefs.find((candidate) => sameId(candidate.id, id)) ?? { ...brief, id, title: '(no such brief)', status: 'unknown' },\n ),\n cited,\n rules,\n rulings: rulings.verified,\n branch: workspace.branch,\n base: base.kind === 'resolved' ? base.ref : null,\n budget: workspace.config.context.budget,\n });\n}\n\n/* ------------------------------------------------------------------- audit */\n\nasync function dependencyChanges(workspace: Workspace, base: Base): Promise<AuditInput['dependencies'] & { readonly installScripts: readonly InstallScriptChange[] }> {\n // A name that cannot be read is reported with or without a base: it would\n // leave its manifests out of every audit measured from one.\n const names = readManifestNames(workspace.config.dependencies.manifests);\n if (base.kind === 'unresolved') return { changes: [], installScripts: [], unread: [], unreadNames: names.unread, rootedNames: names.rooted };\n const isManifest = names.match;\n const out: DependencyChange[] = [];\n const installScripts: InstallScriptChange[] = [];\n const unread: string[] = [];\n for (const change of await changes(base.mergeBase, base.head, workspace.root)) {\n if (!isManifest(change.path) && !(change.from !== undefined && isManifest(change.from))) continue;\n const ecosystem = ecosystemOf(change.path);\n if (ecosystem === null) {\n unread.push(change.path);\n continue;\n }\n // git shows nothing where a file is not: an added manifest has no before,\n // and a deleted one no after.\n const before = await show(base.mergeBase, change.from ?? change.path, workspace.root);\n const after = await show(base.head, change.path, workspace.root);\n const diff = diffManifest(change.path, ecosystem, before, after);\n if ('error' in diff) {\n unread.push(change.path);\n continue;\n }\n out.push(...diff.changes);\n installScripts.push(...diff.installScripts);\n }\n return { changes: out, installScripts, unread, unreadNames: names.unread, rootedNames: names.rooted };\n}\n\n/** A file's real path, links and the filesystem's case resolved, or `null` when there is no such file. */\nfunction realFile(path: string): string | null {\n try {\n return realpathSync.native(path);\n } catch {\n return null;\n }\n}\n\n/**\n * Whether a path spec-brief's `plugins` names, read from the root, is this\n * package's plugin: the file its `./spec-brief-plugin` export names, as the\n * project installed the package, or as this copy of it ships. spec-brief\n * loads a plugin by a path as well as by its name, and a path to the plugin\n * read as another plugin would say the archive cannot accept a ruling it can.\n */\nexport function pluginFile(root: string): (path: string) => boolean {\n const installed = join(root, 'node_modules', '@descent-vtt', 'spec-harness');\n const candidates: string[] = [fileURLToPath(new URL('../dist/plugin.js', import.meta.url))];\n try {\n // A manifest with no exports, or none for the plugin, throws in `join`\n // or on the missing key inside this block, which the catch reads as no\n // installed copy: `exports?.` and `target !== null` are equivalent to\n // their mutants here. So is the encoding: a Buffer parses as its text.\n const manifest: { exports?: Record<string, unknown> } = JSON.parse(readFileSync(join(installed, 'package.json'), 'utf8'));\n const target = exportedFile(manifest.exports?.['./spec-brief-plugin']);\n if (target !== null) candidates.push(join(installed, target));\n } catch {\n // Not installed at the root, or its manifest cannot be read: this copy's file is the one to compare.\n }\n // A candidate that names no file is `null` here, and so is a path that\n // names none, which is never the plugin.\n const files = new Set(candidates.map(realFile));\n return (path) => {\n const file = realFile(resolve(root, path));\n return file !== null && files.has(file);\n };\n}\n\n/** Whether spec-brief loads this package's plugin, as its configuration at the root says. */\nexport async function specBriefPlugin(root: string): Promise<PluginState> {\n const file = SPEC_BRIEF_CONFIGS.find((name) => existsSync(join(root, name)));\n if (file === undefined) return { kind: 'unconfigured' };\n const config = await readJsonObject(join(root, file));\n // The file was found a moment ago, so null is one removed in between, and\n // reads as the unreadable one it has become.\n if (config === null || config === 'unreadable') return { kind: 'unreadable', file };\n return { kind: loadsPlugin(config, pluginFile(root)) ? 'loaded' : 'not-loaded', file };\n}\n\n/** Claude Code's configuration directory, where it is known: `CLAUDE_CONFIG_DIR`, otherwise `.claude` under the home directory it uses. */\nfunction claudeConfigDirectory(env: CliIO['env'], platform: NodeJS.Platform): string | undefined {\n const home = (platform === 'win32' ? env['USERPROFILE'] : env['HOME']) || undefined;\n return env['CLAUDE_CONFIG_DIR'] || (home === undefined ? undefined : join(home, '.claude'));\n}\n\n/**\n * The directories Claude Code keeps plugins in, by its documentation\n * (https://code.claude.com/docs/en/env-vars, read 2026-10-12): the plugins\n * root, which is `CLAUDE_CODE_PLUGIN_CACHE_DIR` when that is set and\n * `plugins` in the configuration directory otherwise, and after it each\n * seed directory `CLAUDE_CODE_PLUGIN_SEED_DIR` names, separated by `;` on\n * Windows and `:` elsewhere. A seed has the layout of the root, by its page\n * on plugins for an organization\n * (https://code.claude.com/docs/en/plugins/org, Seed containers and CI,\n * read the same day). Read from the environment this runs in, as the\n * settings files are.\n */\nexport function pluginDirectories(env: CliIO['env'], platform: NodeJS.Platform = process.platform): string[] {\n const configDir = claudeConfigDirectory(env, platform);\n const plugins = env['CLAUDE_CODE_PLUGIN_CACHE_DIR'] || (configDir === undefined ? undefined : join(configDir, 'plugins'));\n const seeds = (env['CLAUDE_CODE_PLUGIN_SEED_DIR'] ?? '').split(platform === 'win32' ? ';' : ':').filter((seed) => seed !== '');\n return [...(plugins === undefined ? [] : [plugins]), ...seeds];\n}\n\n/**\n * What one of those directories holds of this package's plugin as\n * `marketplace` lists it: whether its cache has a version of it, one\n * directory each under the marketplace's and the plugin's names, that no\n * `.orphaned_at` marks as left behind by an update or an uninstall; the\n * record of marketplaces fetched; and whether a record of marketplaces\n * hosted on claude.ai stands beside it (the plugin loading reference, Find\n * plugins on disk, ADR-0012). Nothing else there is read.\n */\nasync function pluginsRoot(directory: string, marketplace: string): Promise<PluginsRoot> {\n const versions = join(directory, 'cache', marketplace, 'spec-harness');\n let cached = false;\n try {\n const entries = await readdir(versions, { withFileTypes: true });\n cached = entries.some((entry) => entry.isDirectory() && !existsSync(join(versions, entry.name, '.orphaned_at')));\n } catch {\n // No directory for the plugin in this cache: it holds no version of it.\n }\n return { directory, cached, registry: await readJsonObject(join(directory, MARKETPLACE_REGISTRY)), hosted: existsSync(join(directory, HOSTED_REGISTRY)) };\n}\n\n/**\n * Claude Code's settings files that can turn a plugin on or hold a hook,\n * lowest precedence first: the user's, the project's, and the person's own\n * for the project. The user's is in `CLAUDE_CONFIG_DIR` when that is set,\n * otherwise in `.claude` under the home directory Claude Code uses,\n * `USERPROFILE` on Windows and `HOME` elsewhere; with neither it is not read.\n * Managed settings and `--settings` are not files a project can see.\n */\nexport function claudeSettingsFiles(root: string, env: CliIO['env'], platform: NodeJS.Platform = process.platform): { file: string; path: string }[] {\n const configDir = claudeConfigDirectory(env, platform);\n const user = configDir === undefined ? null : join(configDir, 'settings.json');\n return [\n ...(user === null ? [] : [{ file: user, path: user }]),\n { file: PROJECT_SETTINGS, path: join(root, '.claude', 'settings.json') },\n { file: '.claude/settings.local.json', path: join(root, '.claude', 'settings.local.json') },\n ];\n}\n\n/** The settings files Claude Code reads here, as read; one that is missing or cannot be read as JSON holds nothing. */\nexport async function claudeSettings(root: string, env: CliIO['env']): Promise<ClaudeSettings[]> {\n return Promise.all(claudeSettingsFiles(root, env).map(async ({ file, path }) => ({ file, settings: await readJsonObject(path) })));\n}\n\n/**\n * Whether the plugin, init's entries, both or neither wire Claude Code to the\n * harness here, and what the hook does with each line the settings hold for\n * it.\n *\n * A line is the hook's by the hook's own reading of it, whatever else stands\n * on it, and read as a session started at `root` hands it over: the project\n * is `root`, an empty `--root` is the directory the hook is started in, and\n * a relative one is read from there. A brief on it is asked of spec-brief, as\n * the hook asks. The plugin's own hooks are not read: they are files of a\n * release, in a directory Claude Code keeps, and every release wrote the\n * hook alone on their line, under the matcher init writes (ADR-0012). What\n * is read of that directory is whether the plugin is in it at all.\n *\n * `init` reads the wiring through this too, so that it and `doctor` say\n * the same of every tree, and hands it the reader it reads the matchers of\n * the same files with, so that the two read each pattern once between them.\n *\n * A matcher that lists names with a comma is read as the Claude Code on\n * `PATH` reads it, which turns on its release (configure.ts). `doctor`\n * reports the release, and asks it wherever something wires the guard,\n * since one too old for the hooks lets every write through: the lines are\n * first read as a release that cannot be told reads them, under which a\n * line that may be started counts as wiring. `init` has no other use for\n * the release, so it says that it does not report it, and it is asked only\n * where a line turns on it: where what is read of the lines differs between\n * a release that cannot be told and the newest.\n */\nexport async function claudeCodeWiring(root: string, io: CliIO, pattern: PatternReader = patternReader(), reported = true): Promise<ClaudeCodeWiring> {\n const sources = await claudeSettings(root, io.env);\n // Each line is read once, before any is reported: what the brief on one\n // names is spec-brief's to say, and the report itself asks nothing.\n const read = new Map<string, HookLine | null>();\n for (const words of handedLines(sources, root)) read.set(JSON.stringify(words), await hookLineHere(words, root, io));\n const plugin = enabledPlugin(sources);\n // An id that names no marketplace has no directory to look in, and is said\n // as one that cannot be told whatever is on disk: pluginPresence answers\n // for it before it reads a directory, so what stands here for none is\n // equivalent to its mutant.\n const marketplace = plugin === null ? null : pluginMarketplace(plugin.id);\n const roots = marketplace === null ? [] : await Promise.all(pluginDirectories(io.env).map((directory) => pluginsRoot(directory, marketplace)));\n const presence = plugin === null ? null : pluginPresence(plugin, sources, roots);\n const server = registersServer(await readJsonObject(join(root, '.mcp.json')));\n // A line under SessionStart is the hook's by the hook's own reading of it, as any line is.\n // A root on it that is no directory is a line of the hook that is off, and\n // one all the same, so the mutant of the test for a directory is\n // equivalent.\n const isHook = (words: readonly string[]): boolean => claudeHookLine(words, parseOptions, root, (path) => isDirectory(resolve(root, path))) !== null;\n const sessionStart = sources.some(({ settings }) => startsSessions(settings, isHook));\n // init writes its hooks into the project's file alone, and none where an array unloads it.\n const unloaded = arrayMatcher(sources.find(({ file }) => file === PROJECT_SETTINGS)!.settings);\n const under = (release: ClaudeCodeCheck | null): ClaudeCodeWiring => {\n const lines = reportHooks(sources, root, (words) => read.get(JSON.stringify(words))!, pattern, matchingUnder(release));\n // A line Claude Code starts for no write, before one or after, is in no\n // one's way: it is said, and the file is not counted for it.\n const hooks = sources.map(({ file }) => file).filter((file) => lines.some((line) => line.file === file && (isStarted(line.before) || isStarted(line.after))));\n // In the order a document has them, which a script may compare by the byte.\n return { plugin, presence, hooksOff: hooksDisabled(sources), hooks, lines, server, sessionStart, release, unloaded };\n };\n const untold = under(null);\n const asked = reported ? wiringState(untold) !== 'none' : JSON.stringify(untold.lines) !== JSON.stringify(reportHooks(sources, root, (words) => read.get(JSON.stringify(words))!, pattern));\n // Read again under the release, where it was asked: what is read without\n // one is what is read under one that cannot be told. What asks it is\n // loaded here, where it is asked: the hook loads these operations for\n // every write, and asks no release.\n return under(asked ? checkClaudeCode(await (await import('./host.js')).claudeVersion(io.env)) : null);\n}\n\n/**\n * What the hook does with the words a session started at `root` hands it:\n * its own reading of the line (usage.ts), and what follows from where its\n * root is, where the line guards. The hook opens the work tree its root is\n * in. Where the root is a directory in none, it reads a session outside a\n * work tree, checks no write and says nothing (ADR-0005): git is asked here\n * as the hook asks it, and the line is one under which the guard is off.\n * Where the root is in another work tree than the project's, the hook\n * decides by that work tree's briefs, and a file outside it is none of its\n * repository's: so a work tree that does not hold the project leaves every\n * write to a file of the project unchecked, and one that holds it checks\n * them, by its own briefs. Where the line names a brief, the hook asks\n * spec-brief in the work tree it opened which brief the name is, and holds\n * every write under a name that is none (ADR-0004). So this asks the same,\n * of the same work tree, and a line that holds every write is said as that\n * wherever its root is.\n */\nasync function hookLineHere(words: readonly string[], root: string, io: CliIO): Promise<HookLine | null> {\n const line = claudeHookLine(words, parseOptions, root, (path) => isDirectory(resolve(root, path)));\n // Only a line that guards gives a root to open or names a brief, so the\n // check of its state is the compiler's, and its mutant is equivalent.\n if (line === null || line.state !== 'guards') return line;\n let told: HookLine = line;\n // With no root on its line the hook opens the project, which is the work\n // tree this runs in: git is asked only about a root the line gives.\n if (line.root !== undefined) {\n const top = await workTreeRoot(resolve(root, line.root));\n if (top === null) return outsideHookLine(line.root);\n // The project's top as the root's work tree names it: nothing where the\n // two are one work tree, which is every root in the project, and\n // `null` where the project is not in it.\n const path = repositoryPath(root, top, root);\n if (path !== '') {\n // One repository's work trees share a git directory, and no two\n // repositories do.\n const [theirs, ours] = await Promise.all([commonDirectory(top), commonDirectory(root)]);\n const tree = { top, ours: theirs === ours };\n told = path === null ? elsewhereHookLine(line.root, tree) : holderHookLine(line, tree, path);\n }\n }\n if (line.brief === undefined) return told;\n const workspace = await openWorkspace({ root: line.root === undefined ? root : resolve(root, line.root) }, io);\n const { problem } = await diagnoseBrief(workspace, { brief: line.brief }, io.env);\n return problem === null ? told : heldHookLine(problem);\n}\n\n/**\n * The brief a round works on, as doctor reports it: its id, and what is\n * wrong with the name when no round can work under it. Every other command\n * stops there. A diagnosis says it, being what a person runs when the guard\n * holds a write they expected it to pass.\n */\nexport async function diagnoseBrief(workspace: Workspace, options: Pick<Options, 'brief'>, env: CliIO['env']): Promise<{ readonly id: string | null; readonly problem: string | null }> {\n if (options.brief !== undefined && isBlank(options.brief)) return { id: null, problem: emptyValue('--brief', 'brief', options.brief) };\n const id = namedId(workspace, options, env);\n // A spec-brief that cannot be run is a row of the report, with the reason.\n if (workspace.siblings.locate('spec-brief').kind !== 'found') return { id, problem: null };\n try {\n // Where nothing names a brief, spec-brief is not asked (ADR-0004), and\n // there is no problem to state.\n return { id, problem: describeActive(await activeBrief(workspace, options, env)).problem };\n } catch (error) {\n // Asking spec-brief throws nothing but this, so the check is equivalent\n // to its mutant; it keeps any other error the stack it needs.\n if (!(error instanceof SiblingError)) throw error;\n return { id, problem: `spec-brief could not say whether it knows brief ${id}: ${error.message}` };\n }\n}\n\nasync function archiveReasons(workspace: Workspace, brief: BriefRow, base: Base): Promise<{ blocking: ArchiveReason[]; warnings: ArchiveReason[] } | { unavailable: string }> {\n const args = ['archive', brief.id, '--dry-run', '--format', 'json', '--no-color'];\n if (base.kind === 'resolved') args.push('--base', base.ref);\n const answer = await workspace.siblings.json('spec-brief', args);\n // The audit listed the briefs through spec-brief before it asks this, so\n // an absent one stopped it there; the check is for the type.\n if ('absent' in answer) return { unavailable: answer.absent };\n if (answer.code === 2) return { unavailable: 'spec-brief could not plan the archive' };\n return readArchivePlan(answer.document);\n}\n\n/** The brief's assertions as spec-guard ran them, and those it could not read, which it lists apart as `errors`. */\nasync function briefAssertions(\n workspace: Workspace,\n brief: BriefRow,\n text: string,\n reader: DocumentReader,\n): Promise<{ outcomes: AssertionOutcome[]; unreadable: UnreadableAssertion[] } | { unavailable: string }> {\n const answer = await workspace.siblings.json('spec-guard', [brief.file, '--ignore-status', '--json']);\n if ('absent' in answer) return { unavailable: answer.absent };\n if (answer.code === 2) return { unavailable: 'spec-guard could not run the brief\\'s assertions' };\n const report = readGuardRun(answer.document);\n const own = (spec: { readonly file: string } | undefined): boolean => spec === undefined || spec.file.replace(/\\\\/g, '/') === brief.file;\n const outcomes = report.results\n .filter((result) => own(result.spec))\n .map((result) => {\n const line = result.spec?.line ?? 0;\n return { ok: result.ok, description: result.description, message: result.message, line, section: reader.sectionAt(text, line), enclosing: reader.sectionsAt(text, line) };\n });\n const unreadable = report.errors.filter((error) => own(error.spec)).map((error) => ({ message: error.message, line: error.spec?.line ?? 0, raw: error.raw }));\n return { outcomes, unreadable };\n}\n\nexport interface AuditResult {\n readonly brief: BriefRow;\n readonly base: Base;\n readonly report: AuditReport;\n readonly dependencies: readonly DependencyChange[];\n /** The entries of an install-script policy the round added, removed or turned. */\n readonly installScripts: readonly InstallScriptChange[];\n}\n\nexport async function runAudit(workspace: Workspace, brief: BriefRow, reader: DocumentReader, baseFlag: string | undefined): Promise<AuditResult> {\n const { audit, tally } = await import('./audit.js');\n const base = await resolveBase(workspace, baseFlag);\n const text = await briefText(workspace, brief);\n const [dependencies, archive, assertions, rulings, plugin] = await Promise.all([\n dependencyChanges(workspace, base),\n archiveReasons(workspace, brief, base),\n briefAssertions(workspace, brief, text, reader),\n checkRulings(workspace, brief, text, reader, base),\n specBriefPlugin(workspace.root),\n ]);\n const unmeasured =\n base.kind === 'unresolved' ? base.reason : base.mergeBase === base.head ? `${base.ref} and HEAD are the same commit: there is nothing to measure` : null;\n const report = audit({\n brief,\n unmeasured,\n dependencies,\n archive,\n assertions: 'unavailable' in assertions ? assertions : assertions.outcomes,\n // The audit reads no list as an empty one, and a run spec-guard could not\n // make has none, so a mutant of this test reads the same.\n unreadableAssertions: 'unavailable' in assertions ? [] : assertions.unreadable,\n premiseSections: workspace.config.assertions.premises,\n unverifiedRulings: rulings.unverified,\n verifiedRulings: rulings.verified,\n pluginLoaded: plugin.kind === 'loaded',\n });\n const findings = [...rulings.problems, ...report.findings];\n return {\n brief,\n base,\n dependencies: dependencies.changes,\n installScripts: dependencies.installScripts,\n report: { findings, counts: tally(findings), measured: report.measured },\n };\n}\n\n/* -------------------------------------------------------------- escalation */\n\nasync function escalationDirectory(workspace: Workspace): Promise<string> {\n return stateDirectory(workspace.commonDir, 'escalations');\n}\n\nexport async function listEscalations(workspace: Workspace): Promise<EscalationRequest[]> {\n const directory = await escalationDirectory(workspace);\n const out: EscalationRequest[] = [];\n for (const name of (await readdir(directory)).filter((n) => n.endsWith('.json')).sort()) {\n try {\n // A Buffer parses as its text, so the encoding is equivalent to its mutant.\n const request: EscalationRequest = JSON.parse(await readFile(join(directory, name), 'utf8'));\n out.push(request);\n } catch {\n // A request that cannot be read is skipped; listing it would list nothing true.\n }\n }\n return out;\n}\n\nexport async function raiseEscalation(\n workspace: Workspace,\n brief: BriefRow,\n request: { paths: readonly string[]; reason: string; options: readonly EscalationOption[]; recommendation: string | null },\n): Promise<{ request: EscalationRequest; memo: string }> {\n const existing = await listEscalations(workspace);\n const id = nextId('E', brief.id, existing.map((e) => e.id));\n const full: EscalationRequest = {\n id,\n brief: brief.id,\n briefFile: brief.file,\n paths: request.paths,\n reason: request.reason,\n options: request.options,\n recommendation: request.recommendation,\n created: new Date().toISOString(),\n branch: workspace.branch,\n head: await revision('HEAD', workspace.root),\n };\n await writeAtomic(join(await escalationDirectory(workspace), `${id}.json`), `${JSON.stringify(full, null, 2)}\\n`);\n return { request: full, memo: renderMemo(full) };\n}\n\n/** Writes a person's ruling into the brief and retires the request. Never commits: the signature is the person's. */\nexport async function recordRuling(\n workspace: Workspace,\n escalationId: string,\n decision: 'allow' | 'deny',\n note: string,\n reader: DocumentReader,\n): Promise<{ id: string; file: string; row: string }> {\n const request = (await listEscalations(workspace)).find((candidate) => candidate.id === escalationId.toUpperCase() || candidate.id === escalationId);\n if (request === undefined) throw new UsageError(`no escalation \"${escalationId}\" is waiting; spec-harness escalate --list shows those that are`);\n const path = join(workspace.root, request.briefFile);\n const text = await readText(path);\n if (text === null) throw new UsageError(`${request.briefFile} cannot be read`);\n const where = reader.sectionTables(text, workspace.config.rulings.section);\n const taken = readRulings(where.tables).rulings.map((row) => row.id);\n const id = nextId('R', request.brief, taken);\n const row = renderRow(id, request.paths, decision, note);\n await writeAtomic(path, addRulingRow(text, workspace.config.rulings.section, row, where));\n // Listed a moment ago; forced, a request another process retired in\n // between is not an error, so the option is equivalent to its mutants.\n await rm(join(await escalationDirectory(workspace), `${request.id}.json`), { force: true });\n return { id, file: request.briefFile, row };\n}\n"]}
1
+ {"version":3,"file":"round.js","sourceRoot":"","sources":["../src/round.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A round, measured: the operations the command line and the MCP server\n * share. Each gathers what a pure module needs - from git, the disk and the\n * siblings - and hands it over; the decisions are made in `context.ts`,\n * `audit.ts`, `guard.ts` and `rulings.ts`.\n *\n * The hook loads this module before every write it decides, so what only\n * an audit, a verified ruling or `doctor` runs is imported where it runs:\n * the audit's judgement, which brings the Markdown scanner with it, the\n * hash a copy of the signers is named by, and what asks Claude Code its\n * release.\n */\n\nimport { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { readdir, readFile, rm } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { readArchivePlan, readGuardRun } from './answers.js';\nimport type { ArchiveReason, AssertionOutcome, AuditInput, AuditReport, UnreadableAssertion } from './audit.js';\nimport { SiblingOutputError } from './briefs.js';\nimport { sameId } from './branch.js';\nimport {\n arrayMatcher,\n enabledPlugin,\n exportedFile,\n handedLines,\n hooksDisabled,\n HOSTED_REGISTRY,\n isStarted,\n loadsPlugin,\n MARKETPLACE_REGISTRY,\n matchingUnder,\n patternReader,\n pluginMarketplace,\n pluginPresence,\n PROJECT_SETTINGS,\n readsOnFailure,\n registersServer,\n reportHooks,\n SPEC_BRIEF_CONFIGS,\n startsSessions,\n wiringState,\n type BaseSource,\n type ClaudeCodeWiring,\n type ClaudeSettings,\n type PatternReader,\n type PluginsRoot,\n type PluginState,\n} from './configure.js';\nimport { readRules, renderContext, type CitedDocument, type ContextPacket, type Rules } from './context.js';\nimport type { DocumentReader } from './document.js';\nimport { isDirectory, isFile, readJsonObject, readText, repositoryPath, stateDirectory, writeAtomic } from './fs.js';\nimport { blameLine, changes, commonDirectory, isUncommitted, mergeBase, remoteDefault, revision, show, verifyCommit, workTreeRoot } from './git.js';\nimport { decide, type Decision, type VerifiedRuling } from './guard.js';\nimport { diffManifest, ecosystemOf, readManifestNames, type DependencyChange, type InstallScriptChange } from './manifests.js';\nimport {\n addRulingRow,\n nextId,\n readRulings,\n renderMemo,\n renderRow,\n type EscalationOption,\n type EscalationRequest,\n type RulingRow,\n} from './rulings.js';\nimport type { BriefRow, Finding } from './types.js';\nimport { compileGlob, type LiteralReading } from './vendor/spec-core/pattern/index.js';\nimport { dirname, isRelativeReference, resolveInside, splitReference } from './vendor/spec-core/path/index.js';\nimport { SiblingError } from './siblings.js';\nimport { claudeHookLine, elsewhereHookLine, emptyValue, heldHookLine, holderHookLine, isBlank, outsideHookLine, type HookLine } from './usage.js';\nimport { checkClaudeCode, type ClaudeCodeCheck } from './versions.js';\nimport { activeBrief, describeActive, namedId, openWorkspace, parseOptions, UsageError, type CliIO, type Options, type Workspace } from './workspace.js';\n\n/* -------------------------------------------------------------------- base */\n\nexport type Base =\n | { readonly kind: 'resolved'; readonly ref: string; readonly source: BaseSource; readonly sha: string; readonly mergeBase: string; readonly head: string }\n | { readonly kind: 'unresolved'; readonly reason: string };\n\n/** What the round is measured from: the flag, the configuration, then the remote's default branch. */\nexport async function resolveBase(workspace: Workspace, flag: string | undefined): Promise<Base> {\n const source: BaseSource = flag !== undefined ? 'flag' : workspace.config.base !== null ? 'config' : 'remote';\n const ref = flag ?? workspace.config.base ?? (await remoteDefault(workspace.root));\n if (ref === null) {\n return { kind: 'unresolved', reason: 'no base is named and the remote has no default branch; pass --base <ref> or set \"base\"' };\n }\n // Neither commit waits on the other, so git is asked for both at once, and\n // they are read in the order they were asked in before: a base that names\n // no commit is said before a HEAD that names none.\n const [sha, head] = await Promise.all([revision(ref, workspace.root), revision('HEAD', workspace.root)]);\n if (sha === null) return { kind: 'unresolved', reason: `\"${ref}\" names no commit` };\n if (head === null) return { kind: 'unresolved', reason: 'HEAD names no commit: nothing is committed on this branch yet' };\n const common = await mergeBase(sha, head, workspace.root);\n if (common === null) return { kind: 'unresolved', reason: `\"${ref}\" and HEAD share no history` };\n return { kind: 'resolved', ref, source, sha, mergeBase: common, head };\n}\n\n/* ----------------------------------------------------------------- rulings */\n\nexport interface RulingCheck {\n readonly rows: readonly RulingRow[];\n readonly verified: readonly VerifiedRuling[];\n readonly unverified: readonly { readonly id: string; readonly reason: string }[];\n readonly problems: readonly Finding[];\n}\n\n/**\n * The brief's rulings, each checked against its signature: the commit that\n * last changed its row must be signed by a principal the base branch's\n * allowed-signers file lists (ADR-0006).\n */\nexport async function checkRulings(workspace: Workspace, brief: Pick<BriefRow, 'file'>, text: string, reader: DocumentReader, base: Base): Promise<RulingCheck> {\n const { rulings: rows, problems } = readRulings(reader.sectionTables(text, workspace.config.rulings.section).tables);\n const findings: Finding[] = problems.map((problem) => ({\n rule: 'ruling-unreadable',\n severity: 'warning',\n message: problem.message,\n hint: 'a ruling row is | id | `paths` | allow or deny | note |',\n file: brief.file,\n line: problem.line,\n }));\n const allows = rows.filter((row) => row.decision === 'allow');\n // Nothing below verifies a row that allows nothing, so this saves a git\n // show and is equivalent to its mutants.\n if (allows.length === 0) return { rows, verified: [], unverified: [], problems: findings };\n if (base.kind === 'unresolved') {\n return { rows, verified: [], unverified: allows.map((row) => ({ id: row.id, reason: `no base to read the allowed signers from: ${base.reason}` })), problems: findings };\n }\n const signers = await show(base.sha, workspace.config.rulings.allowedSigners, workspace.root);\n if (signers === null) {\n const reason = `${base.ref} has no ${workspace.config.rulings.allowedSigners}, so no signature can count`;\n return { rows, verified: [], unverified: allows.map((row) => ({ id: row.id, reason })), problems: findings };\n }\n // Only verify-commit below reads this copy, so where it is kept, and under\n // what name, is equivalent to its mutants. The one that reads the digest\n // with no encoding names the file by its bytes, which a path refuses when\n // one of them is NUL: a sweep counts that mutant killed now and then.\n const directory = await stateDirectory(workspace.commonDir, 'signers');\n const { createHash } = await import('node:crypto');\n const file = join(directory, `${createHash('sha256').update(signers).digest('hex').slice(0, 16)}`);\n await writeAtomic(file, signers);\n const verified: VerifiedRuling[] = [];\n const unverified: { id: string; reason: string }[] = [];\n for (const row of allows) {\n // The row's line is a line of the text on disk, so it is blamed there: at\n // HEAD the same number can be another line, one a signed commit wrote,\n // and an uncommitted row would borrow that commit's signature.\n const commit = await blameLine(null, brief.file, row.line, workspace.root);\n if (commit === null || isUncommitted(commit)) {\n unverified.push({ id: row.id, reason: 'its row is not committed' });\n continue;\n }\n const signature = await verifyCommit(commit, file, workspace.root);\n if (signature.good) verified.push({ id: row.id, paths: row.paths, signer: signature.principal });\n else unverified.push({ id: row.id, reason: `commit ${commit.slice(0, 12)} last changed its row, and ${signature.detail || 'it is not signed'}` });\n }\n return { rows, verified, unverified, problems: findings };\n}\n\n/* ------------------------------------------------------------------- guard */\n\nexport async function briefText(workspace: Workspace, brief: BriefRow): Promise<string> {\n const text = await readText(join(workspace.root, brief.file));\n if (text === null) throw new UsageError(`${brief.file} cannot be read`);\n return text;\n}\n\n/**\n * Decides paths against the brief, with the rulings verified against the\n * base `baseFlag` names, or the configured one. The reader may be given as\n * what makes one: it is asked for where a ruling is read, and a caller that\n * decides every write need not load a scanner for those that read none.\n */\nexport async function checkPaths(\n workspace: Workspace,\n brief: BriefRow | null,\n noBrief: string | undefined,\n given: readonly string[],\n cwd: string,\n reader: DocumentReader | (() => Promise<DocumentReader>),\n baseFlag: string | undefined,\n): Promise<Decision[]> {\n const resolved = given.map((path) => ({ given: path, path: repositoryPath(path, workspace.root, cwd) }));\n const decideAll = (rulings: readonly VerifiedRuling[]): Decision[] =>\n resolved.map(({ path, given: g }) => decide({ path, given: g, brief, noBrief, rulings, outOfScope: workspace.config.outOfScope }));\n const first = decideAll([]);\n // Rulings cost the reader of a brief, and a blame and a signature check\n // each, so they are read only when a write reaches a protected file. Read\n // anyway, they decide the same, since a ruling allows only a protected\n // path: what a mutant that always reads them changes is what is loaded\n // for a write no brief protects (loads.test.ts). With no brief nothing is\n // protected, so the null check is there for the type.\n if (brief === null || !first.some((decision) => decision.reason === 'protected')) return first;\n const text = await briefText(workspace, brief);\n const documents = typeof reader === 'function' ? await reader() : reader;\n // The base is where the allowed signers are read, and only a row that\n // allows something is checked against them: where none does, git is asked\n // nothing of the base, three processes of a refusal, and what was decided\n // without a ruling stands.\n const { rulings } = readRulings(documents.sectionTables(text, workspace.config.rulings.section).tables);\n if (!rulings.some((row) => row.decision === 'allow')) return first;\n const base = await resolveBase(workspace, baseFlag);\n return decideAll((await checkRulings(workspace, brief, text, documents, base)).verified);\n}\n\n/* ----------------------------------------------------------------- context */\n\n/**\n * The paths spec-guard is asked about for a scope: where its patterns can\n * match. A name with no glob syntax that exists is asked about as itself,\n * since spec-guard reads from the disk whether a path is a file or a\n * directory. One the round has yet to create may become either, and\n * spec-guard would read it as a file, leaving out the rules over a\n * directory of that name; it is asked about through the directory that will\n * hold it, the root for a name at the top, which covers both.\n */\nfunction scopeBases(root: string, patterns: readonly string[]): string[] {\n // Read as a directory, a name's base is the name itself; read any other\n // way, it is the directory holding it, so which other reading a missing\n // name gets changes nothing. The glob is compiled for its bases and never\n // matched: a file read as a directory narrows the question and nothing\n // else.\n const literal = (path: string): LiteralReading => (existsSync(join(root, path)) ? 'directory' : 'either');\n const bases = new Set<string>();\n for (const pattern of patterns) {\n try {\n // Case is read only in matching, which this compile never does: its\n // bases are the same either way, so `caseSensitive: false` is equivalent.\n for (const base of compileGlob(pattern, { dialect: 'path', caseSensitive: true, literal }).bases) {\n // A rooted alternative's base, `/docs` or `/`, is outside the\n // repository: it puts no path in the scope, and spec-guard refuses\n // the whole question for it, with the rules for every other base.\n // The packet names the pattern.\n if (base.startsWith('/')) continue;\n bases.add(base === '' ? '.' : base);\n }\n } catch {\n // The packet names a pattern the guard cannot read, with spec-core's\n // reason, and says so when it is every pattern; the rules for the rest\n // still count.\n }\n }\n return [...bases].sort();\n}\n\nasync function rulesFor(workspace: Workspace, brief: BriefRow): Promise<Rules> {\n const paths = scopeBases(workspace.root, brief.affectedFiles);\n if (paths.length === 0) return [];\n try {\n const answer = await workspace.siblings.json('spec-guard', ['query', ...paths, '--json']);\n return 'absent' in answer ? { unavailable: answer.absent } : readRules(answer);\n } catch (error) {\n // spec-guard printed no JSON, or a document of another shape: what it\n // said instead, or what was wrong, is the reason, and the rest of the\n // packet stands without the rules.\n if (error instanceof SiblingError || error instanceof SiblingOutputError) return { unavailable: error.message };\n throw error;\n }\n}\n\nasync function citedDocuments(workspace: Workspace, brief: BriefRow, text: string, reader: DocumentReader): Promise<CitedDocument[]> {\n const seen = new Set<string>();\n const out: CitedDocument[] = [];\n for (const citation of reader.citations(text)) {\n if (!isRelativeReference(citation.target)) continue;\n let target = splitReference(citation.target).path;\n try {\n target = decodeURIComponent(target);\n } catch {\n // A destination that is not valid percent-encoding is read as written.\n }\n const path = resolveInside(dirname(brief.file), target);\n if (path === null || path === brief.file || seen.has(path)) continue;\n seen.add(path);\n const document = /\\.(?:md|markdown|mdx|txt)$/i.test(path);\n // A link to code or a directory that exists is not a document to include,\n // and must not be reported as a link that resolves to nothing.\n if (!document && existsSync(join(workspace.root, path))) continue;\n const content = document ? await readText(join(workspace.root, path)) : null;\n // A document that cannot be read is listed by its path alone, so its\n // title and status are never read, and an empty object is equivalent.\n const meta = content === null ? { title: null, status: null } : reader.titleAndStatus(content);\n out.push({ path, ...meta, text: content });\n }\n return out;\n}\n\nexport async function buildContext(\n workspace: Workspace,\n brief: BriefRow,\n briefs: readonly BriefRow[],\n reader: DocumentReader,\n baseFlag: string | undefined,\n): Promise<ContextPacket> {\n const text = await briefText(workspace, brief);\n const base = await resolveBase(workspace, baseFlag);\n const [rules, cited, rulings] = await Promise.all([\n rulesFor(workspace, brief),\n citedDocuments(workspace, brief, text, reader),\n checkRulings(workspace, brief, text, reader, base),\n ]);\n return renderContext({\n brief,\n briefText: text,\n dependencies: brief.dependsOn.map(\n (id) =>\n // spec-brief reports a dependency as its front matter spells it, `7` for brief 007.\n // The context reads a dependency's id, title, status and phase, and\n // the brief copied here is live.\n briefs.find((candidate) => sameId(candidate.id, id)) ?? { ...brief, id, title: '(no such brief)', status: 'unknown' },\n ),\n cited,\n rules,\n rulings: rulings.verified,\n branch: workspace.branch,\n base: base.kind === 'resolved' ? base.ref : null,\n budget: workspace.config.context.budget,\n });\n}\n\n/* ------------------------------------------------------------------- audit */\n\nasync function dependencyChanges(workspace: Workspace, base: Base): Promise<AuditInput['dependencies'] & { readonly installScripts: readonly InstallScriptChange[] }> {\n // A name that cannot be read is reported with or without a base: it would\n // leave its manifests out of every audit measured from one.\n const names = readManifestNames(workspace.config.dependencies.manifests);\n if (base.kind === 'unresolved') return { changes: [], installScripts: [], unread: [], unreadNames: names.unread, rootedNames: names.rooted };\n const isManifest = names.match;\n const out: DependencyChange[] = [];\n const installScripts: InstallScriptChange[] = [];\n const unread: string[] = [];\n for (const change of await changes(base.mergeBase, base.head, workspace.root)) {\n if (!isManifest(change.path) && !(change.from !== undefined && isManifest(change.from))) continue;\n const ecosystem = ecosystemOf(change.path);\n if (ecosystem === null) {\n unread.push(change.path);\n continue;\n }\n // git shows nothing where a file is not: an added manifest has no before,\n // and a deleted one no after.\n const before = await show(base.mergeBase, change.from ?? change.path, workspace.root);\n const after = await show(base.head, change.path, workspace.root);\n const diff = diffManifest(change.path, ecosystem, before, after);\n if ('error' in diff) {\n unread.push(change.path);\n continue;\n }\n out.push(...diff.changes);\n installScripts.push(...diff.installScripts);\n }\n return { changes: out, installScripts, unread, unreadNames: names.unread, rootedNames: names.rooted };\n}\n\n/** A file's real path, links and the filesystem's case resolved, or `null` when there is no such file. */\nfunction realFile(path: string): string | null {\n try {\n return realpathSync.native(path);\n } catch {\n return null;\n }\n}\n\n/**\n * Whether a path spec-brief's `plugins` names, read from the root, is this\n * package's plugin: the file its `./spec-brief-plugin` export names, as the\n * project installed the package, or as this copy of it ships. spec-brief\n * loads a plugin by a path as well as by its name, and a path to the plugin\n * read as another plugin would say the archive cannot accept a ruling it can.\n */\nexport function pluginFile(root: string): (path: string) => boolean {\n const installed = join(root, 'node_modules', '@descent-vtt', 'spec-harness');\n const candidates: string[] = [fileURLToPath(new URL('../dist/plugin.js', import.meta.url))];\n try {\n // A manifest with no exports, or none for the plugin, throws in `join`\n // or on the missing key inside this block, which the catch reads as no\n // installed copy: `exports?.` and `target !== null` are equivalent to\n // their mutants here. So is the encoding: a Buffer parses as its text.\n // Only a file is read: what stands there and is none is no installed\n // copy, as a manifest with no exports is (ADR-0002).\n const file = join(installed, 'package.json');\n const manifest: { exports?: Record<string, unknown> } = isFile(file) ? JSON.parse(readFileSync(file, 'utf8')) : {};\n const target = exportedFile(manifest.exports?.['./spec-brief-plugin']);\n if (target !== null) candidates.push(join(installed, target));\n } catch {\n // Not installed at the root, or its manifest cannot be read: this copy's file is the one to compare.\n }\n // A candidate that names no file is `null` here, and so is a path that\n // names none, which is never the plugin.\n const files = new Set(candidates.map(realFile));\n return (path) => {\n const file = realFile(resolve(root, path));\n return file !== null && files.has(file);\n };\n}\n\n/** Whether spec-brief loads this package's plugin, as its configuration at the root says. */\nexport async function specBriefPlugin(root: string): Promise<PluginState> {\n const file = SPEC_BRIEF_CONFIGS.find((name) => existsSync(join(root, name)));\n if (file === undefined) return { kind: 'unconfigured' };\n const config = await readJsonObject(join(root, file));\n // The file was found a moment ago, so null is one removed in between, and\n // reads as the unreadable one it has become.\n if (config === null || config === 'unreadable') return { kind: 'unreadable', file };\n return { kind: loadsPlugin(config, pluginFile(root)) ? 'loaded' : 'not-loaded', file };\n}\n\n/** Claude Code's configuration directory, where it is known: `CLAUDE_CONFIG_DIR`, otherwise `.claude` under the home directory it uses. */\nfunction claudeConfigDirectory(env: CliIO['env'], platform: NodeJS.Platform): string | undefined {\n const home = (platform === 'win32' ? env['USERPROFILE'] : env['HOME']) || undefined;\n return env['CLAUDE_CONFIG_DIR'] || (home === undefined ? undefined : join(home, '.claude'));\n}\n\n/**\n * The directories Claude Code keeps plugins in, by its documentation\n * (https://code.claude.com/docs/en/env-vars, read 2026-10-12): the plugins\n * root, which is `CLAUDE_CODE_PLUGIN_CACHE_DIR` when that is set and\n * `plugins` in the configuration directory otherwise, and after it each\n * seed directory `CLAUDE_CODE_PLUGIN_SEED_DIR` names, separated by `;` on\n * Windows and `:` elsewhere. A seed has the layout of the root, by its page\n * on plugins for an organization\n * (https://code.claude.com/docs/en/plugins/org, Seed containers and CI,\n * read the same day). Read from the environment this runs in, as the\n * settings files are.\n */\nexport function pluginDirectories(env: CliIO['env'], platform: NodeJS.Platform = process.platform): string[] {\n const configDir = claudeConfigDirectory(env, platform);\n const plugins = env['CLAUDE_CODE_PLUGIN_CACHE_DIR'] || (configDir === undefined ? undefined : join(configDir, 'plugins'));\n const seeds = (env['CLAUDE_CODE_PLUGIN_SEED_DIR'] ?? '').split(platform === 'win32' ? ';' : ':').filter((seed) => seed !== '');\n return [...(plugins === undefined ? [] : [plugins]), ...seeds];\n}\n\n/**\n * What one of those directories holds of this package's plugin as\n * `marketplace` lists it: whether its cache has a version of it, one\n * directory each under the marketplace's and the plugin's names, that no\n * `.orphaned_at` marks as left behind by an update or an uninstall; the\n * record of marketplaces fetched; and whether a record of marketplaces\n * hosted on claude.ai stands beside it (the plugin loading reference, Find\n * plugins on disk, ADR-0012). Nothing else there is read.\n */\nasync function pluginsRoot(directory: string, marketplace: string): Promise<PluginsRoot> {\n const versions = join(directory, 'cache', marketplace, 'spec-harness');\n let cached = false;\n try {\n const entries = await readdir(versions, { withFileTypes: true });\n cached = entries.some((entry) => entry.isDirectory() && !existsSync(join(versions, entry.name, '.orphaned_at')));\n } catch {\n // No directory for the plugin in this cache: it holds no version of it.\n }\n return { directory, cached, registry: await readJsonObject(join(directory, MARKETPLACE_REGISTRY)), hosted: existsSync(join(directory, HOSTED_REGISTRY)) };\n}\n\n/**\n * Claude Code's settings files that can turn a plugin on or hold a hook,\n * lowest precedence first: the user's, the project's, and the person's own\n * for the project. The user's is in `CLAUDE_CONFIG_DIR` when that is set,\n * otherwise in `.claude` under the home directory Claude Code uses,\n * `USERPROFILE` on Windows and `HOME` elsewhere; with neither it is not read.\n * Managed settings and `--settings` are not files a project can see.\n */\nexport function claudeSettingsFiles(root: string, env: CliIO['env'], platform: NodeJS.Platform = process.platform): { file: string; path: string }[] {\n const configDir = claudeConfigDirectory(env, platform);\n const user = configDir === undefined ? null : join(configDir, 'settings.json');\n return [\n ...(user === null ? [] : [{ file: user, path: user }]),\n { file: PROJECT_SETTINGS, path: join(root, '.claude', 'settings.json') },\n { file: '.claude/settings.local.json', path: join(root, '.claude', 'settings.local.json') },\n ];\n}\n\n/** The settings files Claude Code reads here, as read; one that is missing or cannot be read as JSON holds nothing. */\nexport async function claudeSettings(root: string, env: CliIO['env']): Promise<ClaudeSettings[]> {\n return Promise.all(claudeSettingsFiles(root, env).map(async ({ file, path }) => ({ file, settings: await readJsonObject(path) })));\n}\n\n/**\n * Whether the plugin, init's entries, both or neither wire Claude Code to the\n * harness here, and what the hook does with each line the settings hold for\n * it.\n *\n * A line is the hook's by the hook's own reading of it, whatever else stands\n * on it, and read as a session started at `root` hands it over: the project\n * is `root`, an empty `--root` is the directory the hook is started in, and\n * a relative one is read from there. A brief on it is asked of spec-brief, as\n * the hook asks. The plugin's own hooks are not read: they are files of a\n * release, in a directory Claude Code keeps, and every release wrote the\n * hook alone on their line, under the matcher init writes (ADR-0012). What\n * is read of that directory is whether the plugin is in it at all.\n *\n * `init` reads the wiring through this too, so that it and `doctor` say\n * the same of every tree, and hands it the reader it reads the matchers of\n * the same files with, so that the two read each pattern once between them.\n *\n * A matcher that lists names with a comma is read as the Claude Code on\n * `PATH` reads it, which turns on its release (configure.ts). `doctor`\n * reports the release, and asks it wherever something wires the guard,\n * since one too old for the hooks lets every write through: the lines are\n * first read as a release that cannot be told reads them, under which a\n * line that may be started counts as wiring. `init` has no other use for\n * the release, so it says that it does not report it, and it is asked only\n * where a line turns on it: where what is read of the lines differs between\n * a release that cannot be told and the newest.\n */\nexport async function claudeCodeWiring(root: string, io: CliIO, pattern: PatternReader = patternReader(), reported = true): Promise<ClaudeCodeWiring> {\n const sources = await claudeSettings(root, io.env);\n // Each line is read once, before any is reported: what the brief on one\n // names is spec-brief's to say, and the report itself asks nothing.\n const read = new Map<string, HookLine | null>();\n for (const words of handedLines(sources, root)) read.set(JSON.stringify(words), await hookLineHere(words, root, io));\n const plugin = enabledPlugin(sources);\n // An id that names no marketplace has no directory to look in, and is said\n // as one that cannot be told whatever is on disk: pluginPresence answers\n // for it before it reads a directory, so what stands here for none is\n // equivalent to its mutant.\n const marketplace = plugin === null ? null : pluginMarketplace(plugin.id);\n const roots = marketplace === null ? [] : await Promise.all(pluginDirectories(io.env).map((directory) => pluginsRoot(directory, marketplace)));\n const presence = plugin === null ? null : pluginPresence(plugin, sources, roots);\n const server = registersServer(await readJsonObject(join(root, '.mcp.json')));\n // A line under SessionStart is the hook's by the hook's own reading of it, as any line is.\n // A root on it that is no directory is a line of the hook that is off, and\n // one all the same, so the mutant of the test for a directory is\n // equivalent.\n const isHook = (words: readonly string[]): boolean => claudeHookLine(words, parseOptions, root, (path) => isDirectory(resolve(root, path))) !== null;\n const sessionStart = sources.some(({ settings }) => startsSessions(settings, isHook));\n // init writes its hooks into the project's file alone, and none where an array unloads it.\n const unloaded = arrayMatcher(sources.find(({ file }) => file === PROJECT_SETTINGS)!.settings);\n const under = (release: ClaudeCodeCheck | null): ClaudeCodeWiring => {\n const lines = reportHooks(sources, root, (words) => read.get(JSON.stringify(words))!, pattern, matchingUnder(release), readsOnFailure(release));\n // A line Claude Code starts for no write, before one or after, is in no\n // one's way: it is said, and the file is not counted for it.\n const hooks = sources.map(({ file }) => file).filter((file) => lines.some((line) => line.file === file && (isStarted(line.before) || isStarted(line.after))));\n // In the order a document has them, which a script may compare by the byte.\n return { plugin, presence, hooksOff: hooksDisabled(sources), hooks, lines, server, sessionStart, release, unloaded };\n };\n const untold = under(null);\n const asked = reported ? wiringState(untold) !== 'none' : JSON.stringify(untold.lines) !== JSON.stringify(reportHooks(sources, root, (words) => read.get(JSON.stringify(words))!, pattern));\n // Read again under the release, where it was asked: what is read without\n // one is what is read under one that cannot be told. What asks it is\n // loaded here, where it is asked: the hook loads these operations for\n // every write, and asks no release.\n return under(asked ? checkClaudeCode(await (await import('./host.js')).claudeVersion(io.env)) : null);\n}\n\n/**\n * What the hook does with the words a session started at `root` hands it:\n * its own reading of the line (usage.ts), and what follows from where its\n * root is, where the line guards. The hook opens the work tree its root is\n * in. Where the root is a directory in none, it reads a session outside a\n * work tree, checks no write and says nothing (ADR-0005): git is asked here\n * as the hook asks it, and the line is one under which the guard is off.\n * Where the root is in another work tree than the project's, the hook\n * decides by that work tree's briefs, and a file outside it is none of its\n * repository's: so a work tree that does not hold the project leaves every\n * write to a file of the project unchecked, and one that holds it checks\n * them, by its own briefs. Where the line names a brief, the hook asks\n * spec-brief in the work tree it opened which brief the name is, and holds\n * every write under a name that is none (ADR-0004). So this asks the same,\n * of the same work tree, and a line that holds every write is said as that\n * wherever its root is.\n */\nasync function hookLineHere(words: readonly string[], root: string, io: CliIO): Promise<HookLine | null> {\n const line = claudeHookLine(words, parseOptions, root, (path) => isDirectory(resolve(root, path)));\n // Only a line that guards gives a root to open or names a brief, so the\n // check of its state is the compiler's, and its mutant is equivalent.\n if (line === null || line.state !== 'guards') return line;\n let told: HookLine = line;\n // With no root on its line the hook opens the project, which is the work\n // tree this runs in: git is asked only about a root the line gives.\n if (line.root !== undefined) {\n const top = await workTreeRoot(resolve(root, line.root));\n if (top === null) return outsideHookLine(line.root);\n // The project's top as the root's work tree names it: nothing where the\n // two are one work tree, which is every root in the project, and\n // `null` where the project is not in it.\n const path = repositoryPath(root, top, root);\n if (path !== '') {\n // One repository's work trees share a git directory, and no two\n // repositories do.\n const [theirs, ours] = await Promise.all([commonDirectory(top), commonDirectory(root)]);\n const tree = { top, ours: theirs === ours };\n told = path === null ? elsewhereHookLine(line.root, tree) : holderHookLine(line, tree, path);\n }\n }\n if (line.brief === undefined) return told;\n const workspace = await openWorkspace({ root: line.root === undefined ? root : resolve(root, line.root) }, io);\n const { problem } = await diagnoseBrief(workspace, { brief: line.brief }, io.env);\n return problem === null ? told : heldHookLine(problem);\n}\n\n/**\n * The brief a round works on, as doctor reports it: its id, and what is\n * wrong with the name when no round can work under it. Every other command\n * stops there. A diagnosis says it, being what a person runs when the guard\n * holds a write they expected it to pass.\n *\n * `branch` is whether the name no round can work under is the branch's: a\n * brief it names that spec-brief does not know, or has archived. The hook\n * reads the same branch and holds every write under such a name, which is a\n * setup that holds every write, as a hook's line naming such a brief is\n * (ADR-0004). A name the flag gives is the question doctor was asked, and\n * holds no write of anyone's.\n */\nexport async function diagnoseBrief(\n workspace: Workspace,\n options: Pick<Options, 'brief'>,\n env: CliIO['env'],\n): Promise<{ readonly id: string | null; readonly problem: string | null; readonly branch: boolean }> {\n if (options.brief !== undefined && isBlank(options.brief)) return { id: null, problem: emptyValue('--brief', 'brief', options.brief), branch: false };\n const id = namedId(workspace, options, env);\n // A spec-brief that cannot be run is a row of the report, with the reason.\n if (workspace.siblings.locate('spec-brief').kind !== 'found') return { id, problem: null, branch: false };\n try {\n // Where nothing names a brief, spec-brief is not asked (ADR-0004), and\n // there is no problem to state.\n const active = await activeBrief(workspace, options, env);\n const branch = (active.kind === 'unknown' || active.kind === 'archived') && active.source === 'branch';\n return { id, problem: describeActive(active).problem, branch };\n } catch (error) {\n // Asking spec-brief throws nothing but this, so the check is equivalent\n // to its mutant; it keeps any other error the stack it needs.\n if (!(error instanceof SiblingError)) throw error;\n return { id, problem: `spec-brief could not say whether it knows brief ${id}: ${error.message}`, branch: false };\n }\n}\n\nasync function archiveReasons(workspace: Workspace, brief: BriefRow, base: Base): Promise<{ blocking: ArchiveReason[]; warnings: ArchiveReason[] } | { unavailable: string }> {\n const args = ['archive', brief.id, '--dry-run', '--format', 'json', '--no-color'];\n if (base.kind === 'resolved') args.push('--base', base.ref);\n const answer = await workspace.siblings.json('spec-brief', args);\n // The audit listed the briefs through spec-brief before it asks this, so\n // an absent one stopped it there; the check is for the type.\n if ('absent' in answer) return { unavailable: answer.absent };\n if (answer.code === 2) return { unavailable: 'spec-brief could not plan the archive' };\n return readArchivePlan(answer.document);\n}\n\n/** The brief's assertions as spec-guard ran them, and those it could not read, which it lists apart as `errors`. */\nasync function briefAssertions(\n workspace: Workspace,\n brief: BriefRow,\n text: string,\n reader: DocumentReader,\n): Promise<{ outcomes: AssertionOutcome[]; unreadable: UnreadableAssertion[] } | { unavailable: string }> {\n const answer = await workspace.siblings.json('spec-guard', [brief.file, '--ignore-status', '--json']);\n if ('absent' in answer) return { unavailable: answer.absent };\n if (answer.code === 2) return { unavailable: 'spec-guard could not run the brief\\'s assertions' };\n const report = readGuardRun(answer.document);\n const own = (spec: { readonly file: string } | undefined): boolean => spec === undefined || spec.file.replace(/\\\\/g, '/') === brief.file;\n const outcomes = report.results\n .filter((result) => own(result.spec))\n .map((result) => {\n const line = result.spec?.line ?? 0;\n return { ok: result.ok, description: result.description, message: result.message, line, section: reader.sectionAt(text, line), enclosing: reader.sectionsAt(text, line) };\n });\n const unreadable = report.errors.filter((error) => own(error.spec)).map((error) => ({ message: error.message, line: error.spec?.line ?? 0, raw: error.raw }));\n return { outcomes, unreadable };\n}\n\nexport interface AuditResult {\n readonly brief: BriefRow;\n readonly base: Base;\n readonly report: AuditReport;\n readonly dependencies: readonly DependencyChange[];\n /** The entries of an install-script policy the round added, removed or turned. */\n readonly installScripts: readonly InstallScriptChange[];\n}\n\nexport async function runAudit(workspace: Workspace, brief: BriefRow, reader: DocumentReader, baseFlag: string | undefined): Promise<AuditResult> {\n const { audit, tally } = await import('./audit.js');\n const base = await resolveBase(workspace, baseFlag);\n const text = await briefText(workspace, brief);\n const [dependencies, archive, assertions, rulings, plugin] = await Promise.all([\n dependencyChanges(workspace, base),\n archiveReasons(workspace, brief, base),\n briefAssertions(workspace, brief, text, reader),\n checkRulings(workspace, brief, text, reader, base),\n specBriefPlugin(workspace.root),\n ]);\n const unmeasured =\n base.kind === 'unresolved' ? base.reason : base.mergeBase === base.head ? `${base.ref} and HEAD are the same commit: there is nothing to measure` : null;\n const report = audit({\n brief,\n unmeasured,\n dependencies,\n archive,\n assertions: 'unavailable' in assertions ? assertions : assertions.outcomes,\n // The audit reads no list as an empty one, and a run spec-guard could not\n // make has none, so a mutant of this test reads the same.\n unreadableAssertions: 'unavailable' in assertions ? [] : assertions.unreadable,\n premiseSections: workspace.config.assertions.premises,\n unverifiedRulings: rulings.unverified,\n verifiedRulings: rulings.verified,\n pluginLoaded: plugin.kind === 'loaded',\n });\n const findings = [...rulings.problems, ...report.findings];\n return {\n brief,\n base,\n dependencies: dependencies.changes,\n installScripts: dependencies.installScripts,\n report: { findings, counts: tally(findings), measured: report.measured },\n };\n}\n\n/* -------------------------------------------------------------- escalation */\n\nasync function escalationDirectory(workspace: Workspace): Promise<string> {\n return stateDirectory(workspace.commonDir, 'escalations');\n}\n\nexport async function listEscalations(workspace: Workspace): Promise<EscalationRequest[]> {\n const directory = await escalationDirectory(workspace);\n const out: EscalationRequest[] = [];\n for (const name of (await readdir(directory)).filter((n) => n.endsWith('.json')).sort()) {\n // What is no file is no request, and is passed over as one that cannot be read is.\n if (!isFile(join(directory, name))) continue;\n try {\n // A Buffer parses as its text, so the encoding is equivalent to its mutant.\n const request: EscalationRequest = JSON.parse(await readFile(join(directory, name), 'utf8'));\n out.push(request);\n } catch {\n // A request that cannot be read is skipped; listing it would list nothing true.\n }\n }\n return out;\n}\n\nexport async function raiseEscalation(\n workspace: Workspace,\n brief: BriefRow,\n request: { paths: readonly string[]; reason: string; options: readonly EscalationOption[]; recommendation: string | null },\n): Promise<{ request: EscalationRequest; memo: string }> {\n const existing = await listEscalations(workspace);\n const id = nextId('E', brief.id, existing.map((e) => e.id));\n const full: EscalationRequest = {\n id,\n brief: brief.id,\n briefFile: brief.file,\n paths: request.paths,\n reason: request.reason,\n options: request.options,\n recommendation: request.recommendation,\n created: new Date().toISOString(),\n branch: workspace.branch,\n head: await revision('HEAD', workspace.root),\n };\n await writeAtomic(join(await escalationDirectory(workspace), `${id}.json`), `${JSON.stringify(full, null, 2)}\\n`);\n return { request: full, memo: renderMemo(full) };\n}\n\n/** Writes a person's ruling into the brief and retires the request. Never commits: the signature is the person's. */\nexport async function recordRuling(\n workspace: Workspace,\n escalationId: string,\n decision: 'allow' | 'deny',\n note: string,\n reader: DocumentReader,\n): Promise<{ id: string; file: string; row: string }> {\n const request = (await listEscalations(workspace)).find((candidate) => candidate.id === escalationId.toUpperCase() || candidate.id === escalationId);\n if (request === undefined) throw new UsageError(`no escalation \"${escalationId}\" is waiting; spec-harness escalate --list shows those that are`);\n const path = join(workspace.root, request.briefFile);\n const text = await readText(path);\n if (text === null) throw new UsageError(`${request.briefFile} cannot be read`);\n const where = reader.sectionTables(text, workspace.config.rulings.section);\n const taken = readRulings(where.tables).rulings.map((row) => row.id);\n const id = nextId('R', request.brief, taken);\n const row = renderRow(id, request.paths, decision, note);\n await writeAtomic(path, addRulingRow(text, workspace.config.rulings.section, row, where));\n // Listed a moment ago; forced, a request another process retired in\n // between is not an error, so the option is equivalent to its mutants.\n await rm(join(await escalationDirectory(workspace), `${request.id}.json`), { force: true });\n return { id, file: request.briefFile, row };\n}\n"]}
package/dist/sandbox.js CHANGED
@@ -19,7 +19,7 @@ import { execFileSync, spawn } from 'node:child_process';
19
19
  import { mkdtempSync, rmSync } from 'node:fs';
20
20
  import { constants, tmpdir } from 'node:os';
21
21
  import { join } from 'node:path';
22
- import { addWorktree, removeWorktree } from './git.js';
22
+ import { addWorktree, ANSWER_MS, removeWorktree, WORK_MS } from './git.js';
23
23
  import { probeEnvironment } from './probe.js';
24
24
  const live = new Map();
25
25
  const running = new Set();
@@ -110,8 +110,9 @@ function stop(child) {
110
110
  // stopping the shell alone leaves node holding the output. True already
111
111
  // on Windows, so the mutant that makes it true is equivalent there;
112
112
  // elsewhere there is no taskkill, and the shell alone is stopped.
113
+ // taskkill is a question answered at once, and given the time one is (git.ts).
113
114
  if (process.platform === 'win32')
114
- execFileSync('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true });
115
+ execFileSync('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true, timeout: ANSWER_MS });
115
116
  else
116
117
  process.kill(-child.pid, 'SIGKILL');
117
118
  }
@@ -158,7 +159,7 @@ function discard(directory) {
158
159
  */
159
160
  function forget(directory, repository) {
160
161
  try {
161
- execFileSync('git', ['worktree', 'remove', '--force', directory], { cwd: repository, stdio: 'ignore', windowsHide: true });
162
+ execFileSync('git', ['worktree', 'remove', '--force', directory], { cwd: repository, stdio: 'ignore', windowsHide: true, timeout: WORK_MS });
162
163
  // Asked again about a worktree it has forgotten, git changes nothing, so
163
164
  // the mutant that answers false here is equivalent.
164
165
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Temporary worktrees: somewhere to run a command at a commit without\n * touching the person's own checkout.\n *\n * The family's tools read git and never write it (spec-core ADR-0005). The one\n * exception is this: a detached worktree under the system's temporary\n * directory, added for one job and removed after it, whether the job\n * succeeded, threw, or the process was interrupted (ADR-0003). The person's\n * branch, index, stash and working files are never touched; a failed round is\n * discarded by discarding its worktree, never by resetting theirs.\n *\n * Git forgets a worktree whatever becomes of its directory. A directory that\n * cannot be deleted, as on Windows while something a command started still\n * runs in it, costs the job nothing: its answer stands, the directory is\n * tried again as the process exits, and one still there then is named on the\n * standard error.\n */\n\nimport { execFileSync, spawn, type ChildProcess } from 'node:child_process';\nimport { mkdtempSync, rmSync } from 'node:fs';\nimport { constants, tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { addWorktree, removeWorktree } from './git.js';\nimport { probeEnvironment } from './probe.js';\n\nconst live = new Map<string, string>();\nconst running = new Set<ChildProcess>();\n/**\n * The commands whose shell has ended and left a process in its process\n * group, each with the directory it ran in: what `withWorktree` stops when\n * the job in that directory ends, and an interrupt or the exit of the process\n * whenever it comes. Linux and macOS alone have such a group; on Windows\n * nothing is kept, since nothing a command left can be reached once its\n * shell has ended (ADR-0003).\n */\nconst left = new Map<ChildProcess, string>();\nlet installed = false;\n/** Set once the process is interrupted: from then on a command's end is never answered. */\nlet ending = false;\n\n/**\n * How long the sandbox waits for the commands it stopped to let go of their\n * output and their directory. They were stopped forced, so this is only the\n * time the system takes to end them; whatever still holds either after it has\n * left the tree, and no wait would end it.\n *\n * It is also how long the output of a command whose shell ended by itself is\n * waited for: what still holds it then is something the command started and\n * did not wait for, which is no part of the command.\n */\nconst SETTLE_MS = 3_000;\n\n/**\n * Whether a process has this id now. Signal 0 asks and sends nothing, and any\n * answer but \"no such process\" says one has it: another user's process\n * answers that it may not be signalled.\n */\nfunction taken(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n}\n\n/**\n * Stops a command with what can be reached of what it started, forced:\n * SIGKILL to its process group on Linux and macOS, taskkill over its tree on\n * Windows. A process that left the group is not in it, and taskkill follows\n * a tree from parent to child while each parent runs: one whose parent has\n * ended is found under no root. Such a process runs on (ADR-0003).\n *\n * A command is stopped so at its timeout while its shell still runs, and at\n * an interrupt and at the exit of the process. One whose shell has ended is\n * answered and not stopped: what it left in its group runs on until the job\n * in its worktree ends, as what a step leaves runs on until its job ends in\n * CI, and is stopped then, by this.\n *\n * Both name the command by its id, and the id is the command's only while\n * something holds it (ADR-0003). Node holds the command's shell until it has\n * seen the shell end, and until then the system gives the id to nothing else.\n * After that the id is free on Windows, where a process started seconds later\n * can be given it: taskkill would stop that process with all it started, and\n * could not have found what the command left anyway, since it finds no tree\n * under a root that has ended. So a command whose shell has ended is not\n * stopped there. On Linux and macOS the id names the command's process group\n * as well, and stays out of use while the group has a member: what the shell\n * left in its group is still stopped, unless a process has the id now, which\n * says the group emptied and the id was given out again.\n *\n * `windowsHide` here and below only keeps a console window from opening on\n * Windows, which nothing reads, so its mutants are equivalent.\n */\nfunction stop(child: ChildProcess): void {\n // No pid means the spawn failed and nothing runs. Past the tick it failed\n // in, the kill below throws on the missing id and the fallback finds no\n // process, so the mutant that lets it through is equivalent; within that\n // tick nothing here stops a command.\n if (child.pid === undefined) return;\n // Node sets one of the two when it sees the shell end, and lets go of the\n // shell then. Windows reports no signal: there the second is set only once\n // the fallback below has stopped the shell, on the path no test takes.\n const held = child.exitCode === null && child.signalCode === null;\n // Windows is not asked whether a process has the id: one could be given it\n // between the answer and taskkill. Elsewhere `win32` is false already, so\n // the mutants that make it false are equivalent there.\n if (!held && (process.platform === 'win32' || taken(child.pid))) return;\n try {\n // False already on Linux and macOS, so the mutants that make it false\n // are equivalent there. On Windows the tests fail without taskkill:\n // stopping the shell alone leaves node holding the output. True already\n // on Windows, so the mutant that makes it true is equivalent there;\n // elsewhere there is no taskkill, and the shell alone is stopped.\n if (process.platform === 'win32') execFileSync('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true });\n else process.kill(-child.pid, 'SIGKILL');\n } catch {\n // Reached when the group is already gone, and the command's shell with\n // it, as when the command left something outside the group holding its\n // output; on Windows when the shell has only just ended, which taskkill\n // sees before Node does; and there when taskkill cannot be run, where\n // stopping the shell is what is left. No test takes that last path.\n // `kill` goes through Node's own hold on the shell, and does nothing\n // once that is gone.\n child.kill('SIGKILL');\n }\n}\n\n/**\n * Deletes a worktree's directory, trying again for up to `SETTLE_MS` while\n * something holds it, and answers `null` once it is gone, or else why it is\n * not. On Windows a command just stopped lets go of its directory a moment\n * after taskkill returns, and an exit handler, which runs synchronously, has\n * no other way to wait; elsewhere a directory in use is deleted all the same.\n */\nfunction discard(directory: string): Error | null {\n const deadline = Date.now() + SETTLE_MS;\n for (;;) {\n try {\n rmSync(directory, { recursive: true, force: true });\n return null;\n } catch (error) {\n // `>=` would differ only in the millisecond the deadline falls on, so\n // that mutant is equivalent.\n if (Date.now() > deadline) return error as Error;\n // The pause only spares the processor between attempts: without it\n // the directory is deleted, or given up on, at the same moment, so\n // that mutant is equivalent.\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);\n }\n }\n}\n\n/**\n * Has git remove the worktree at `directory` with its record of it, as\n * `removeWorktree` does and synchronously, and answers whether git did.\n */\nfunction forget(directory: string, repository: string): boolean {\n try {\n execFileSync('git', ['worktree', 'remove', '--force', directory], { cwd: repository, stdio: 'ignore', windowsHide: true });\n // Asked again about a worktree it has forgotten, git changes nothing, so\n // the mutant that answers false here is equivalent.\n return true;\n } catch {\n // Git refused a worktree its job broke, could not delete all of the\n // directory, holds nothing of it any more, or cannot be run. The answer\n // is read with `!` and nowhere else, so the mutant that answers nothing\n // here is equivalent.\n return false;\n }\n}\n\n/**\n * Stops what the commands that ran in `directory` left in their process\n * groups, and forgets those commands: the end of a job, before its worktree\n * is removed. With no directory, what every command left: an interrupt, or\n * the exit of the process. One job's end leaves what another job's commands\n * left, which that job may still be using.\n */\nfunction clear(directory?: string): void {\n for (const [child, where] of left) {\n if (directory !== undefined && where !== directory) continue;\n stop(child);\n left.delete(child);\n }\n}\n\n/**\n * Stops every command still running, then removes every live worktree:\n * synchronously, the only kind of work an exit handler may do, so at exit\n * nothing waits for the commands to end but `discard`'s retries. A directory\n * that outlasts those is named on the standard error and left: nothing\n * thrown here could be caught, and the next worktree is still to remove.\n */\nfunction sweep(): void {\n for (const child of running) stop(child);\n clear();\n for (const [directory, repository] of live) {\n // In the order a job's end takes, for the reasons `withWorktree` gives.\n const forgotten = forget(directory, repository);\n const kept = discard(directory);\n if (kept !== null) process.stderr.write(`spec-harness: the temporary worktree at ${directory} could not be deleted and is left there: ${kept.message}\\n`);\n // The mutant that always asks again is equivalent, as in `forget`.\n else if (!forgotten) forget(directory, repository);\n }\n // A signal handler ends in an exit, which sweeps again: over worktrees\n // already gone and forgotten, where keeping them would change nothing, and\n // over one that could not be deleted, which would be named a second time.\n live.clear();\n}\n\n/**\n * Stops every running command with its tree, waits a bounded time for them to\n * let go of their output, removes the worktrees, and exits as a shell reports\n * a process the signal ended: 128 and the signal's number, the same on every\n * platform Node runs on. The commands lead process groups of their own on\n * Linux and macOS, so the terminal's signal never reached them.\n */\nasync function interrupted(signal: NodeJS.Signals): Promise<void> {\n ending = true;\n const stopping = [...running];\n for (const child of stopping) stop(child);\n // A command the stop ended is answered `SETTLE_MS` after its shell ended,\n // its output let go, so every one of them closes by then and the first of\n // the two below is over as soon as the second. The second is for a shell\n // the stop did not end, which no test can make: its mutant survives.\n await Promise.race([\n Promise.all(stopping.map((child) => new Promise((resolve) => child.once('close', resolve)))),\n new Promise((resolve) => setTimeout(resolve, SETTLE_MS)),\n ]);\n sweep();\n process.exit(128 + constants.signals[signal]);\n}\n\nfunction install(): void {\n if (installed) return;\n installed = true;\n process.once('exit', sweep);\n // `on`, not `once`: a second signal while the first waits would otherwise\n // meet Node's default, which ends the process before any 'exit' handler\n // runs, with the worktrees still in place. It runs the same steps again,\n // and the first to finish exits.\n //\n // SIGBREAK is Windows' own: Ctrl+Break, which GitHub's runner sends there,\n // after Ctrl+C, where it sends SIGTERM elsewhere. Unheard, it ends the\n // process before any 'exit' handler runs, and the commands run on.\n // Elsewhere there is no such signal and nothing calls its listener, so\n // its mutants are equivalent there.\n for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGBREAK'] satisfies NodeJS.Signals[]) process.on(signal, interrupted);\n}\n\n/**\n * Runs `work` in a detached worktree of `repository` at `revision`, and\n * removes the worktree after.\n *\n * Git removes it first, while it is as the job left it: git then forgets the\n * worktree whether or not all of its directory can be deleted. What git left\n * of the directory is deleted next, which is all of it when the job broke the\n * worktree, since git refuses one whose `.git` file is gone. Only then is\n * git asked again, once the directory is gone, when it forgets what it finds\n * missing (`removeWorktree`).\n *\n * A directory that cannot be deleted stays on the list for the exit to try\n * again, and does not take the job's answer with it.\n *\n * What the job's commands left running in their process groups is stopped\n * first, so that the worktree is removed with as little running in it as the\n * sandbox can reach.\n */\nexport async function withWorktree<T>(repository: string, revision: string, work: (directory: string) => Promise<T>): Promise<T> {\n install();\n const directory = mkdtempSync(join(tmpdir(), 'spec-harness-'));\n live.set(directory, repository);\n try {\n await addWorktree(directory, revision, repository);\n return await work(directory);\n } finally {\n clear(directory);\n const forgotten = await removeWorktree(directory, repository);\n if (discard(directory) === null) {\n // Asked again about a worktree it has forgotten, git changes nothing,\n // so the mutant that always asks again is equivalent.\n if (!forgotten) await removeWorktree(directory, repository);\n live.delete(directory);\n }\n }\n}\n\nexport interface CommandRun {\n /** How the command's shell ended; `null` when the command was stopped at its timeout. */\n readonly exitCode: number | null;\n /** What the command had printed by the time it was answered. */\n readonly output: string;\n /**\n * Set on a command answered with its output still open: something it\n * started holds the output, `SETTLE_MS` after its shell ended or after its\n * timeout stopped what it could reach, and runs on (ADR-0003).\n */\n readonly outputHeld?: true;\n}\n\n/**\n * Runs a command line in a directory, output and errors interleaved, until\n * its shell ends. A command is its shell: it is answered with the shell's\n * exit code and what was printed, once the shell has ended and its output\n * has closed. A command whose shell outlives `timeoutSeconds` is stopped\n * with what `stop` reaches of it, as is one still running when the process\n * is interrupted or exits. Once the process is interrupted it never answers:\n * the job waiting on it would otherwise carry on in a worktree being removed.\n *\n * The wait for the output is bounded, after the shell's own end as after the\n * timeout. A shell that ends leaves its output open only where something it\n * started still holds it, and that is no part of the command: the answer is\n * the shell's, as a step's is in CI, where GitHub's runner waits five seconds\n * for such an output and goes on. Here the bound is `SETTLE_MS`, at the\n * shell's end and at the timeout alike. Then the sandbox lets go of the\n * output and answers with what was printed and with `outputHeld`. Letting go\n * is what the end of this process would do to whatever holds the output,\n * only sooner, and without it the open output keeps this process from ending\n * once its work is done.\n *\n * The timeout is the shell's: once the shell has ended it stops nothing, and\n * a command already judged by its exit code is not made a stopped one by it.\n *\n * Through the shell, on purpose: a probe's command is a line from the\n * repository's own brief - `npm test -- x` - which the person approved with\n * the brief, exactly as CI runs the repository's own scripts. Nothing from\n * outside the repository reaches it.\n *\n * The line is run as it is written. Its environment is the person's own as\n * `probeEnvironment` hands it on: `CI` set, and npm told to fetch nothing for\n * a command where neither that environment nor the line says what it may\n * fetch (ADR-0007).\n */\nexport function runCommand(line: string, cwd: string, timeoutSeconds: number): Promise<CommandRun> {\n install();\n return new Promise((resolve) => {\n // Elsewhere the command leads a process group of its own, so the timeout\n // can stop the group. Windows has none to signal, and taskkill follows\n // the tree instead; a command detached there loses its output, which the\n // tests catch on Windows. Everywhere else `detached` is true already, so\n // the mutants that make it true are equivalent there, as are\n // `windowsHide`'s.\n //\n // It is given no input: nobody is there to type any, and a pipe that is\n // never written to and never closed kept a command that reads its input\n // waiting until the timeout stopped it.\n const child = spawn(line, {\n cwd,\n shell: true,\n windowsHide: true,\n detached: process.platform !== 'win32',\n env: probeEnvironment(process.env),\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n running.add(child);\n let output = '';\n const keep = (chunk: Buffer): void => {\n // Enough to find a signature in; a runaway log is not kept whole.\n if (output.length < 4 * 1024 * 1024) output += chunk.toString('utf8');\n };\n // Both streams are piped, so both exist: `?.` only satisfies the type,\n // and its mutants are equivalent.\n child.stdout?.on('data', keep);\n child.stderr?.on('data', keep);\n const answer = (run: CommandRun): void => {\n if (!ending) resolve(run);\n };\n let stopped = false;\n let settling: NodeJS.Timeout | undefined;\n // Answers a command whose output is still open once the bound on the\n // wait for it has passed: `exitCode` is how its shell ended, or `null`\n // for one stopped at its timeout.\n const settle = (exitCode: number | null): void => {\n settling = setTimeout(() => {\n // With both let go, 'close' follows as soon as Node has seen the\n // shell end, and takes the command off the list of those running.\n // The streams exist, as above, so the mutants of `?.` are equivalent.\n child.stdout?.destroy();\n child.stderr?.destroy();\n answer({ exitCode, output, outputHeld: true });\n }, SETTLE_MS);\n };\n const timer = setTimeout(() => {\n stopped = true;\n stop(child);\n settle(null);\n }, timeoutSeconds * 1000);\n child.on('error', (error) => {\n // A spawn that failed starts no shell, whose end would clear the timer.\n clearTimeout(timer);\n resolve({ exitCode: 127, output: `${output}${error.message}\\n` });\n });\n child.on('exit', (code) => {\n // The shell its timeout stopped: the timeout has the answer already.\n if (stopped) return;\n // The shell ended by itself, so the timeout has nothing left to stop.\n clearTimeout(timer);\n // A group of the shell's id that still has a member is what the shell\n // left running in it, to be stopped when its job ends. The id is set:\n // a shell that was never started does not end. Windows has no group,\n // and answers that there is none.\n if (taken(-(child.pid as number))) left.set(child, cwd);\n // A shell that a signal ended has no code: a failure, as in 'close'.\n settle(code ?? 1);\n });\n child.on('close', (code) => {\n // The command's own timer is over by now: cleared as its shell ended\n // or as its spawn failed, or run. What is left is the bound.\n clearTimeout(settling);\n running.delete(child);\n // The second answer of a command already answered as held does nothing.\n answer({ exitCode: stopped ? null : (code ?? 1), output });\n });\n });\n}\n"]}
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Temporary worktrees: somewhere to run a command at a commit without\n * touching the person's own checkout.\n *\n * The family's tools read git and never write it (spec-core ADR-0005). The one\n * exception is this: a detached worktree under the system's temporary\n * directory, added for one job and removed after it, whether the job\n * succeeded, threw, or the process was interrupted (ADR-0003). The person's\n * branch, index, stash and working files are never touched; a failed round is\n * discarded by discarding its worktree, never by resetting theirs.\n *\n * Git forgets a worktree whatever becomes of its directory. A directory that\n * cannot be deleted, as on Windows while something a command started still\n * runs in it, costs the job nothing: its answer stands, the directory is\n * tried again as the process exits, and one still there then is named on the\n * standard error.\n */\n\nimport { execFileSync, spawn, type ChildProcess } from 'node:child_process';\nimport { mkdtempSync, rmSync } from 'node:fs';\nimport { constants, tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { addWorktree, ANSWER_MS, removeWorktree, WORK_MS } from './git.js';\nimport { probeEnvironment } from './probe.js';\n\nconst live = new Map<string, string>();\nconst running = new Set<ChildProcess>();\n/**\n * The commands whose shell has ended and left a process in its process\n * group, each with the directory it ran in: what `withWorktree` stops when\n * the job in that directory ends, and an interrupt or the exit of the process\n * whenever it comes. Linux and macOS alone have such a group; on Windows\n * nothing is kept, since nothing a command left can be reached once its\n * shell has ended (ADR-0003).\n */\nconst left = new Map<ChildProcess, string>();\nlet installed = false;\n/** Set once the process is interrupted: from then on a command's end is never answered. */\nlet ending = false;\n\n/**\n * How long the sandbox waits for the commands it stopped to let go of their\n * output and their directory. They were stopped forced, so this is only the\n * time the system takes to end them; whatever still holds either after it has\n * left the tree, and no wait would end it.\n *\n * It is also how long the output of a command whose shell ended by itself is\n * waited for: what still holds it then is something the command started and\n * did not wait for, which is no part of the command.\n */\nconst SETTLE_MS = 3_000;\n\n/**\n * Whether a process has this id now. Signal 0 asks and sends nothing, and any\n * answer but \"no such process\" says one has it: another user's process\n * answers that it may not be signalled.\n */\nfunction taken(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n}\n\n/**\n * Stops a command with what can be reached of what it started, forced:\n * SIGKILL to its process group on Linux and macOS, taskkill over its tree on\n * Windows. A process that left the group is not in it, and taskkill follows\n * a tree from parent to child while each parent runs: one whose parent has\n * ended is found under no root. Such a process runs on (ADR-0003).\n *\n * A command is stopped so at its timeout while its shell still runs, and at\n * an interrupt and at the exit of the process. One whose shell has ended is\n * answered and not stopped: what it left in its group runs on until the job\n * in its worktree ends, as what a step leaves runs on until its job ends in\n * CI, and is stopped then, by this.\n *\n * Both name the command by its id, and the id is the command's only while\n * something holds it (ADR-0003). Node holds the command's shell until it has\n * seen the shell end, and until then the system gives the id to nothing else.\n * After that the id is free on Windows, where a process started seconds later\n * can be given it: taskkill would stop that process with all it started, and\n * could not have found what the command left anyway, since it finds no tree\n * under a root that has ended. So a command whose shell has ended is not\n * stopped there. On Linux and macOS the id names the command's process group\n * as well, and stays out of use while the group has a member: what the shell\n * left in its group is still stopped, unless a process has the id now, which\n * says the group emptied and the id was given out again.\n *\n * `windowsHide` here and below only keeps a console window from opening on\n * Windows, which nothing reads, so its mutants are equivalent.\n */\nfunction stop(child: ChildProcess): void {\n // No pid means the spawn failed and nothing runs. Past the tick it failed\n // in, the kill below throws on the missing id and the fallback finds no\n // process, so the mutant that lets it through is equivalent; within that\n // tick nothing here stops a command.\n if (child.pid === undefined) return;\n // Node sets one of the two when it sees the shell end, and lets go of the\n // shell then. Windows reports no signal: there the second is set only once\n // the fallback below has stopped the shell, on the path no test takes.\n const held = child.exitCode === null && child.signalCode === null;\n // Windows is not asked whether a process has the id: one could be given it\n // between the answer and taskkill. Elsewhere `win32` is false already, so\n // the mutants that make it false are equivalent there.\n if (!held && (process.platform === 'win32' || taken(child.pid))) return;\n try {\n // False already on Linux and macOS, so the mutants that make it false\n // are equivalent there. On Windows the tests fail without taskkill:\n // stopping the shell alone leaves node holding the output. True already\n // on Windows, so the mutant that makes it true is equivalent there;\n // elsewhere there is no taskkill, and the shell alone is stopped.\n // taskkill is a question answered at once, and given the time one is (git.ts).\n if (process.platform === 'win32') execFileSync('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true, timeout: ANSWER_MS });\n else process.kill(-child.pid, 'SIGKILL');\n } catch {\n // Reached when the group is already gone, and the command's shell with\n // it, as when the command left something outside the group holding its\n // output; on Windows when the shell has only just ended, which taskkill\n // sees before Node does; and there when taskkill cannot be run, where\n // stopping the shell is what is left. No test takes that last path.\n // `kill` goes through Node's own hold on the shell, and does nothing\n // once that is gone.\n child.kill('SIGKILL');\n }\n}\n\n/**\n * Deletes a worktree's directory, trying again for up to `SETTLE_MS` while\n * something holds it, and answers `null` once it is gone, or else why it is\n * not. On Windows a command just stopped lets go of its directory a moment\n * after taskkill returns, and an exit handler, which runs synchronously, has\n * no other way to wait; elsewhere a directory in use is deleted all the same.\n */\nfunction discard(directory: string): Error | null {\n const deadline = Date.now() + SETTLE_MS;\n for (;;) {\n try {\n rmSync(directory, { recursive: true, force: true });\n return null;\n } catch (error) {\n // `>=` would differ only in the millisecond the deadline falls on, so\n // that mutant is equivalent.\n if (Date.now() > deadline) return error as Error;\n // The pause only spares the processor between attempts: without it\n // the directory is deleted, or given up on, at the same moment, so\n // that mutant is equivalent.\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);\n }\n }\n}\n\n/**\n * Has git remove the worktree at `directory` with its record of it, as\n * `removeWorktree` does and synchronously, and answers whether git did.\n */\nfunction forget(directory: string, repository: string): boolean {\n try {\n execFileSync('git', ['worktree', 'remove', '--force', directory], { cwd: repository, stdio: 'ignore', windowsHide: true, timeout: WORK_MS });\n // Asked again about a worktree it has forgotten, git changes nothing, so\n // the mutant that answers false here is equivalent.\n return true;\n } catch {\n // Git refused a worktree its job broke, could not delete all of the\n // directory, holds nothing of it any more, or cannot be run. The answer\n // is read with `!` and nowhere else, so the mutant that answers nothing\n // here is equivalent.\n return false;\n }\n}\n\n/**\n * Stops what the commands that ran in `directory` left in their process\n * groups, and forgets those commands: the end of a job, before its worktree\n * is removed. With no directory, what every command left: an interrupt, or\n * the exit of the process. One job's end leaves what another job's commands\n * left, which that job may still be using.\n */\nfunction clear(directory?: string): void {\n for (const [child, where] of left) {\n if (directory !== undefined && where !== directory) continue;\n stop(child);\n left.delete(child);\n }\n}\n\n/**\n * Stops every command still running, then removes every live worktree:\n * synchronously, the only kind of work an exit handler may do, so at exit\n * nothing waits for the commands to end but `discard`'s retries. A directory\n * that outlasts those is named on the standard error and left: nothing\n * thrown here could be caught, and the next worktree is still to remove.\n */\nfunction sweep(): void {\n for (const child of running) stop(child);\n clear();\n for (const [directory, repository] of live) {\n // In the order a job's end takes, for the reasons `withWorktree` gives.\n const forgotten = forget(directory, repository);\n const kept = discard(directory);\n if (kept !== null) process.stderr.write(`spec-harness: the temporary worktree at ${directory} could not be deleted and is left there: ${kept.message}\\n`);\n // The mutant that always asks again is equivalent, as in `forget`.\n else if (!forgotten) forget(directory, repository);\n }\n // A signal handler ends in an exit, which sweeps again: over worktrees\n // already gone and forgotten, where keeping them would change nothing, and\n // over one that could not be deleted, which would be named a second time.\n live.clear();\n}\n\n/**\n * Stops every running command with its tree, waits a bounded time for them to\n * let go of their output, removes the worktrees, and exits as a shell reports\n * a process the signal ended: 128 and the signal's number, the same on every\n * platform Node runs on. The commands lead process groups of their own on\n * Linux and macOS, so the terminal's signal never reached them.\n */\nasync function interrupted(signal: NodeJS.Signals): Promise<void> {\n ending = true;\n const stopping = [...running];\n for (const child of stopping) stop(child);\n // A command the stop ended is answered `SETTLE_MS` after its shell ended,\n // its output let go, so every one of them closes by then and the first of\n // the two below is over as soon as the second. The second is for a shell\n // the stop did not end, which no test can make: its mutant survives.\n await Promise.race([\n Promise.all(stopping.map((child) => new Promise((resolve) => child.once('close', resolve)))),\n new Promise((resolve) => setTimeout(resolve, SETTLE_MS)),\n ]);\n sweep();\n process.exit(128 + constants.signals[signal]);\n}\n\nfunction install(): void {\n if (installed) return;\n installed = true;\n process.once('exit', sweep);\n // `on`, not `once`: a second signal while the first waits would otherwise\n // meet Node's default, which ends the process before any 'exit' handler\n // runs, with the worktrees still in place. It runs the same steps again,\n // and the first to finish exits.\n //\n // SIGBREAK is Windows' own: Ctrl+Break, which GitHub's runner sends there,\n // after Ctrl+C, where it sends SIGTERM elsewhere. Unheard, it ends the\n // process before any 'exit' handler runs, and the commands run on.\n // Elsewhere there is no such signal and nothing calls its listener, so\n // its mutants are equivalent there.\n for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGBREAK'] satisfies NodeJS.Signals[]) process.on(signal, interrupted);\n}\n\n/**\n * Runs `work` in a detached worktree of `repository` at `revision`, and\n * removes the worktree after.\n *\n * Git removes it first, while it is as the job left it: git then forgets the\n * worktree whether or not all of its directory can be deleted. What git left\n * of the directory is deleted next, which is all of it when the job broke the\n * worktree, since git refuses one whose `.git` file is gone. Only then is\n * git asked again, once the directory is gone, when it forgets what it finds\n * missing (`removeWorktree`).\n *\n * A directory that cannot be deleted stays on the list for the exit to try\n * again, and does not take the job's answer with it.\n *\n * What the job's commands left running in their process groups is stopped\n * first, so that the worktree is removed with as little running in it as the\n * sandbox can reach.\n */\nexport async function withWorktree<T>(repository: string, revision: string, work: (directory: string) => Promise<T>): Promise<T> {\n install();\n const directory = mkdtempSync(join(tmpdir(), 'spec-harness-'));\n live.set(directory, repository);\n try {\n await addWorktree(directory, revision, repository);\n return await work(directory);\n } finally {\n clear(directory);\n const forgotten = await removeWorktree(directory, repository);\n if (discard(directory) === null) {\n // Asked again about a worktree it has forgotten, git changes nothing,\n // so the mutant that always asks again is equivalent.\n if (!forgotten) await removeWorktree(directory, repository);\n live.delete(directory);\n }\n }\n}\n\nexport interface CommandRun {\n /** How the command's shell ended; `null` when the command was stopped at its timeout. */\n readonly exitCode: number | null;\n /** What the command had printed by the time it was answered. */\n readonly output: string;\n /**\n * Set on a command answered with its output still open: something it\n * started holds the output, `SETTLE_MS` after its shell ended or after its\n * timeout stopped what it could reach, and runs on (ADR-0003).\n */\n readonly outputHeld?: true;\n}\n\n/**\n * Runs a command line in a directory, output and errors interleaved, until\n * its shell ends. A command is its shell: it is answered with the shell's\n * exit code and what was printed, once the shell has ended and its output\n * has closed. A command whose shell outlives `timeoutSeconds` is stopped\n * with what `stop` reaches of it, as is one still running when the process\n * is interrupted or exits. Once the process is interrupted it never answers:\n * the job waiting on it would otherwise carry on in a worktree being removed.\n *\n * The wait for the output is bounded, after the shell's own end as after the\n * timeout. A shell that ends leaves its output open only where something it\n * started still holds it, and that is no part of the command: the answer is\n * the shell's, as a step's is in CI, where GitHub's runner waits five seconds\n * for such an output and goes on. Here the bound is `SETTLE_MS`, at the\n * shell's end and at the timeout alike. Then the sandbox lets go of the\n * output and answers with what was printed and with `outputHeld`. Letting go\n * is what the end of this process would do to whatever holds the output,\n * only sooner, and without it the open output keeps this process from ending\n * once its work is done.\n *\n * The timeout is the shell's: once the shell has ended it stops nothing, and\n * a command already judged by its exit code is not made a stopped one by it.\n *\n * Through the shell, on purpose: a probe's command is a line from the\n * repository's own brief - `npm test -- x` - which the person approved with\n * the brief, exactly as CI runs the repository's own scripts. Nothing from\n * outside the repository reaches it.\n *\n * The line is run as it is written. Its environment is the person's own as\n * `probeEnvironment` hands it on: `CI` set, and npm told to fetch nothing for\n * a command where neither that environment nor the line says what it may\n * fetch (ADR-0007).\n */\nexport function runCommand(line: string, cwd: string, timeoutSeconds: number): Promise<CommandRun> {\n install();\n return new Promise((resolve) => {\n // Elsewhere the command leads a process group of its own, so the timeout\n // can stop the group. Windows has none to signal, and taskkill follows\n // the tree instead; a command detached there loses its output, which the\n // tests catch on Windows. Everywhere else `detached` is true already, so\n // the mutants that make it true are equivalent there, as are\n // `windowsHide`'s.\n //\n // It is given no input: nobody is there to type any, and a pipe that is\n // never written to and never closed kept a command that reads its input\n // waiting until the timeout stopped it.\n const child = spawn(line, {\n cwd,\n shell: true,\n windowsHide: true,\n detached: process.platform !== 'win32',\n env: probeEnvironment(process.env),\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n running.add(child);\n let output = '';\n const keep = (chunk: Buffer): void => {\n // Enough to find a signature in; a runaway log is not kept whole.\n if (output.length < 4 * 1024 * 1024) output += chunk.toString('utf8');\n };\n // Both streams are piped, so both exist: `?.` only satisfies the type,\n // and its mutants are equivalent.\n child.stdout?.on('data', keep);\n child.stderr?.on('data', keep);\n const answer = (run: CommandRun): void => {\n if (!ending) resolve(run);\n };\n let stopped = false;\n let settling: NodeJS.Timeout | undefined;\n // Answers a command whose output is still open once the bound on the\n // wait for it has passed: `exitCode` is how its shell ended, or `null`\n // for one stopped at its timeout.\n const settle = (exitCode: number | null): void => {\n settling = setTimeout(() => {\n // With both let go, 'close' follows as soon as Node has seen the\n // shell end, and takes the command off the list of those running.\n // The streams exist, as above, so the mutants of `?.` are equivalent.\n child.stdout?.destroy();\n child.stderr?.destroy();\n answer({ exitCode, output, outputHeld: true });\n }, SETTLE_MS);\n };\n const timer = setTimeout(() => {\n stopped = true;\n stop(child);\n settle(null);\n }, timeoutSeconds * 1000);\n child.on('error', (error) => {\n // A spawn that failed starts no shell, whose end would clear the timer.\n clearTimeout(timer);\n resolve({ exitCode: 127, output: `${output}${error.message}\\n` });\n });\n child.on('exit', (code) => {\n // The shell its timeout stopped: the timeout has the answer already.\n if (stopped) return;\n // The shell ended by itself, so the timeout has nothing left to stop.\n clearTimeout(timer);\n // A group of the shell's id that still has a member is what the shell\n // left running in it, to be stopped when its job ends. The id is set:\n // a shell that was never started does not end. Windows has no group,\n // and answers that there is none.\n if (taken(-(child.pid as number))) left.set(child, cwd);\n // A shell that a signal ended has no code: a failure, as in 'close'.\n settle(code ?? 1);\n });\n child.on('close', (code) => {\n // The command's own timer is over by now: cleared as its shell ended\n // or as its spawn failed, or run. What is left is the bound.\n clearTimeout(settling);\n running.delete(child);\n // The second answer of a command already answered as held does nothing.\n answer({ exitCode: stopped ? null : (code ?? 1), output });\n });\n });\n}\n"]}