@descent-vtt/spec-harness 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +72 -0
- package/README.md +9 -3
- package/dist/branch.js +12 -0
- package/dist/branch.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +19 -40
- package/dist/cli.js.map +1 -1
- package/dist/configure.d.ts +48 -16
- package/dist/configure.js +242 -59
- package/dist/configure.js.map +1 -1
- package/dist/reader.js +5 -1
- package/dist/reader.js.map +1 -1
- package/dist/round.d.ts +19 -5
- package/dist/round.js +75 -10
- package/dist/round.js.map +1 -1
- package/dist/rulings.js +6 -0
- package/dist/rulings.js.map +1 -1
- package/dist/setup.d.ts +1 -1
- package/dist/setup.js +34 -13
- package/dist/setup.js.map +1 -1
- package/dist/signers.js +5 -1
- package/dist/signers.js.map +1 -1
- package/dist/usage.d.ts +33 -8
- package/dist/usage.js +17 -1
- package/dist/usage.js.map +1 -1
- package/dist/vendor/spec-core/jsonrpc/mcp.js.map +1 -1
- package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -1
- package/dist/vendor/spec-core/markdown/headings.js.map +1 -1
- package/dist/vendor/spec-core/markdown/links.js.map +1 -1
- package/dist/vendor/spec-core/markdown/scan.js.map +1 -1
- package/dist/vendor/spec-core/pattern/automaton.js.map +1 -1
- package/dist/vendor/spec-core/pattern/charset.js.map +1 -1
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -1
- package/dist/vendor/spec-core/text/lines.js.map +1 -1
- package/dist/vendor/spec-core/text/width.js.map +1 -1
- package/dist/workspace.d.ts +3 -3
- package/dist/workspace.js.map +1 -1
- package/package.json +1 -1
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\nimport { createHash } from 'node:crypto';\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 { audit, tally, type ArchiveReason, type AssertionOutcome, type AuditInput, type AuditReport, type UnreadableAssertion } from './audit.js';\nimport { SiblingOutputError } from './briefs.js';\nimport { sameId } from './branch.js';\nimport {\n enabledPlugin,\n exportedFile,\n loadsPlugin,\n registersServer,\n reportHooks,\n SPEC_BRIEF_CONFIGS,\n type BaseSource,\n type ClaudeCodeWiring,\n type ClaudeSettings,\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, isUncommitted, mergeBase, remoteDefault, revision, show, verifyCommit } 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 } from './usage.js';\nimport { parseOptions, UsageError, type CliIO, 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 const sha = await revision(ref, workspace.root);\n if (sha === null) return { kind: 'unresolved', reason: `\"${ref}\" names no commit` };\n const head = await revision('HEAD', workspace.root);\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 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/** Decides paths against the brief, with the rulings verified against the base `baseFlag` names, or the configured one. */\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,\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 a blame and a signature check each, so they are read only\n // when a write reaches a protected file. Read anyway, they decide the same,\n // since a ruling allows only a protected path, so mutants that always read\n // them are equivalent; and with no brief nothing is protected, so the null\n // check is there for the type.\n if (brief === null || !first.some((decision) => decision.reason === 'protected')) return first;\n const base = await resolveBase(workspace, baseFlag);\n return decideAll((await checkRulings(workspace, brief, await briefText(workspace, brief), reader, 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/**\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 home = (platform === 'win32' ? env['USERPROFILE'] : env['HOME']) || undefined;\n const configDir = env['CLAUDE_CONFIG_DIR'] || (home === undefined ? undefined : join(home, '.claude'));\n const user = configDir === undefined ? null : join(configDir, 'settings.json');\n return [\n ...(user === null ? [] : [{ file: user, path: user }]),\n { file: '.claude/settings.json', 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. The plugin's own hooks are not read:\n * they are files of a release, in a directory Claude Code keeps, and no\n * release wrote more than the hook on their line (ADR-0012).\n */\nexport async function claudeCodeWiring(root: string, env: CliIO['env']): Promise<ClaudeCodeWiring> {\n const sources = await claudeSettings(root, env);\n const lines = reportHooks(sources, root, (words) => claudeHookLine(words, parseOptions, root, (path) => isDirectory(resolve(root, path))));\n return {\n plugin: enabledPlugin(sources),\n hooks: sources.map(({ file }) => file).filter((file) => lines.some((line) => line.file === file)),\n lines,\n server: registersServer(await readJsonObject(join(root, '.mcp.json'))),\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 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\nimport { createHash } from 'node:crypto';\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 { audit, tally, type ArchiveReason, type AssertionOutcome, type AuditInput, type AuditReport, type UnreadableAssertion } from './audit.js';\nimport { SiblingOutputError } from './briefs.js';\nimport { sameId } from './branch.js';\nimport {\n enabledPlugin,\n exportedFile,\n handedLines,\n isStarted,\n loadsPlugin,\n registersServer,\n reportHooks,\n SPEC_BRIEF_CONFIGS,\n type BaseSource,\n type ClaudeCodeWiring,\n type ClaudeSettings,\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, isUncommitted, mergeBase, remoteDefault, revision, show, verifyCommit } 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, emptyValue, heldHookLine, isBlank, type HookLine } from './usage.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 const sha = await revision(ref, workspace.root);\n if (sha === null) return { kind: 'unresolved', reason: `\"${ref}\" names no commit` };\n const head = await revision('HEAD', workspace.root);\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 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/** Decides paths against the brief, with the rulings verified against the base `baseFlag` names, or the configured one. */\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,\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 a blame and a signature check each, so they are read only\n // when a write reaches a protected file. Read anyway, they decide the same,\n // since a ruling allows only a protected path, so mutants that always read\n // them are equivalent; and with no brief nothing is protected, so the null\n // check is there for the type.\n if (brief === null || !first.some((decision) => decision.reason === 'protected')) return first;\n const base = await resolveBase(workspace, baseFlag);\n return decideAll((await checkRulings(workspace, brief, await briefText(workspace, brief), reader, 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/**\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 home = (platform === 'win32' ? env['USERPROFILE'] : env['HOME']) || undefined;\n const configDir = env['CLAUDE_CONFIG_DIR'] || (home === undefined ? undefined : join(home, '.claude'));\n const user = configDir === undefined ? null : join(configDir, 'settings.json');\n return [\n ...(user === null ? [] : [{ file: user, path: user }]),\n { file: '.claude/settings.json', 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).\n *\n * `init` reads the wiring through this too, so that it and `doctor` say\n * the same of every tree.\n */\nexport async function claudeCodeWiring(root: string, io: CliIO): 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 lines = reportHooks(sources, root, (words) => read.get(JSON.stringify(words))!);\n return {\n plugin: enabledPlugin(sources),\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 hooks: sources.map(({ file }) => file).filter((file) => lines.some((line) => line.file === file && (isStarted(line.before) || isStarted(line.after)))),\n lines,\n server: registersServer(await readJsonObject(join(root, '.mcp.json'))),\n };\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 one step past it, where the\n * line guards and names a brief. The hook opens the work tree its root is\n * in, asks spec-brief there which brief the name is, and holds every write\n * under a name that is none (ADR-0004). So this asks the same, of the same\n * work tree.\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 names a brief, so the check of its state is the\n // compiler's, and its mutant is equivalent.\n if (line === null || line.state !== 'guards' || line.brief === undefined) return line;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ root: line.root === undefined ? root : resolve(root, line.root) }, io);\n } catch (error) {\n // A root outside a work tree, where the hook reads no brief and checks\n // no write: said of the line as it was, by its root (ADR-0005).\n if (!(error instanceof UsageError)) throw error;\n return line;\n }\n const { problem } = await diagnoseBrief(workspace, { brief: line.brief }, io.env);\n return problem === null ? line : 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 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"]}
|
package/dist/rulings.js
CHANGED
|
@@ -91,6 +91,8 @@ export function nextId(prefix, brief, taken) {
|
|
|
91
91
|
if (!id.toUpperCase().startsWith(stem.toUpperCase()))
|
|
92
92
|
continue;
|
|
93
93
|
const n = Number(id.slice(stem.length));
|
|
94
|
+
// A number equal to the highest is the highest already, so `>=` for `>`
|
|
95
|
+
// is equivalent.
|
|
94
96
|
if (Number.isInteger(n) && n > highest)
|
|
95
97
|
highest = n;
|
|
96
98
|
}
|
|
@@ -139,6 +141,8 @@ export function renderRow(id, paths, decision, note) {
|
|
|
139
141
|
export function addRulingRow(text, section, row, where) {
|
|
140
142
|
const eol = text.includes('\r\n') ? '\r\n' : '\n';
|
|
141
143
|
const lines = text.split(/\r?\n/);
|
|
144
|
+
// A text splits into one line at least, so the first check here is the
|
|
145
|
+
// compiler's, and its mutants are equivalent.
|
|
142
146
|
const trailing = lines.length > 0 && lines[lines.length - 1] === '' ? lines.pop() : undefined;
|
|
143
147
|
const header = ['| Ruling | Paths | Decision | Note |', '| --- | --- | --- | --- |'];
|
|
144
148
|
if (where.tableEndLine !== null) {
|
|
@@ -151,6 +155,8 @@ export function addRulingRow(text, section, row, where) {
|
|
|
151
155
|
lines.splice(where.headingLine, 0, '', ...header, row, ...gap);
|
|
152
156
|
}
|
|
153
157
|
else {
|
|
158
|
+
// The last line is read only where there is one, so the `?.` is the
|
|
159
|
+
// compiler's, and the mutant without it is equivalent.
|
|
154
160
|
if (lines.length > 0 && lines[lines.length - 1]?.trim() !== '')
|
|
155
161
|
lines.push('');
|
|
156
162
|
lines.push(`## ${section}`, '', ...header, row);
|
package/dist/rulings.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rulings.js","sourceRoot":"","sources":["../src/rulings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Escalations an agent raises and the rulings a person signs.\n *\n * A brief says what a round may not touch. When the round cannot be done\n * without touching it, the agent stops and asks; a person decides; and the\n * decision becomes a row in the brief's rulings table:\n *\n * ```markdown\n * ## Rulings\n *\n * | Ruling | Paths | Decision | Note |\n * | --- | --- | --- | --- |\n * | R-012-1 | `src/db/schema.ts` | allow | Add rotated_at; no other schema change. |\n * ```\n *\n * A row is text, and an agent can write text. What makes a row a ruling is\n * the commit that last changed it: signed, with a key listed in the allowed\n * signers file as the base branch has it (ADR-0006). The row states the\n * decision; the signature says a person made it; the base branch says whose\n * signatures count. A hash of the row, which the agent could compute as well\n * as anyone, would say none of that.\n *\n * The request itself lives outside the work tree while it waits\n * (`<git-common-dir>/spec-harness/escalations/`): it is in-flight state, and\n * only its outcome belongs in the record (spec-core ADR-0005).\n */\n\nexport interface EscalationOption {\n readonly label: string;\n readonly consequence: string;\n}\n\nexport interface EscalationRequest {\n readonly id: string;\n readonly brief: string;\n readonly briefFile: string;\n readonly paths: readonly string[];\n readonly reason: string;\n readonly options: readonly EscalationOption[];\n readonly recommendation: string | null;\n readonly created: string;\n readonly branch: string | null;\n readonly head: string | null;\n}\n\nexport interface RulingRow {\n readonly id: string;\n readonly paths: readonly string[];\n readonly decision: 'allow' | 'deny';\n readonly note: string;\n /** 1-based line of the row in the brief. */\n readonly line: number;\n}\n\n/** A table as the Markdown scanner reads it: header cells, and rows with their lines. */\nexport interface TableView {\n readonly headers: readonly string[];\n readonly rows: readonly { readonly cells: readonly string[]; readonly line: number }[];\n}\n\nexport type RulingProblem = { readonly line: number; readonly message: string };\n\nfunction normal(text: string): string {\n return text.replace(/[*_`]/g, '').trim().toLowerCase();\n}\n\n/** The globs a paths cell names: backtick-quoted, or comma-separated. */\nexport function pathsOf(cell: string): string[] {\n const quoted = [...cell.matchAll(/`([^`]+)`/g)].map((match) => (match[1] as string).trim());\n if (quoted.length > 0) return quoted.filter((path) => path !== '');\n return cell\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part !== '');\n}\n\n/**\n * The rulings in a brief's rulings section, from its tables. A table whose\n * header does not name the columns is not a rulings table; a row that cannot\n * be read is a problem to report, never a ruling.\n */\nexport function readRulings(tables: readonly TableView[]): { rulings: RulingRow[]; problems: RulingProblem[] } {\n const rulings: RulingRow[] = [];\n const problems: RulingProblem[] = [];\n for (const table of tables) {\n const headers = table.headers.map(normal);\n const at = (...names: string[]): number => headers.findIndex((header) => names.includes(header));\n const idColumn = at('ruling', 'id');\n const pathsColumn = at('paths', 'path', 'files');\n const decisionColumn = at('decision');\n const noteColumn = at('note', 'notes', 'reason');\n if (idColumn < 0 || pathsColumn < 0 || decisionColumn < 0) continue;\n for (const row of table.rows) {\n const id = normal(row.cells[idColumn] ?? '').toUpperCase();\n const paths = pathsOf(row.cells[pathsColumn] ?? '');\n const decision = normal(row.cells[decisionColumn] ?? '');\n if (id === '') {\n problems.push({ line: row.line, message: 'a ruling row has no id' });\n continue;\n }\n if (paths.length === 0) {\n problems.push({ line: row.line, message: `ruling ${id} names no path` });\n continue;\n }\n if (decision !== 'allow' && decision !== 'deny') {\n problems.push({ line: row.line, message: `ruling ${id} decides \"${decision}\"; a decision is allow or deny` });\n continue;\n }\n if (rulings.some((ruling) => ruling.id === id)) {\n problems.push({ line: row.line, message: `ruling ${id} appears twice` });\n continue;\n }\n rulings.push({ id, paths, decision, note: (row.cells[noteColumn] ?? '').trim(), line: row.line });\n }\n }\n return { rulings, problems };\n}\n\n/**\n * The next free escalation id for a brief, given the ids already taken. The\n * stem compares without case: `readRulings` reads ids in capitals, so a brief\n * named `auth` has `R-AUTH-1` taken when this writes `R-auth-2`.\n */\nexport function nextId(prefix: 'E' | 'R', brief: string, taken: readonly string[]): string {\n let highest = 0;\n const stem = `${prefix}-${brief}-`;\n for (const id of taken) {\n if (!id.toUpperCase().startsWith(stem.toUpperCase())) continue;\n const n = Number(id.slice(stem.length));\n if (Number.isInteger(n) && n > highest) highest = n;\n }\n return `${stem}${highest + 1}`;\n}\n\n/** The memo a person reads to rule: what, why, the choices, and what each costs. */\nexport function renderMemo(request: EscalationRequest): string {\n const lines = [\n `# Escalation ${request.id}`,\n '',\n `Brief ${request.brief} (\\`${request.briefFile}\\`)${request.branch === null ? '' : ` on \\`${request.branch}\\``}${request.head === null ? '' : ` at \\`${request.head.slice(0, 12)}\\``}, raised ${request.created}.`,\n '',\n '## What the round needs to change',\n '',\n ...request.paths.map((path) => `- \\`${path}\\``),\n '',\n '## Why',\n '',\n request.reason.trim(),\n '',\n ];\n if (request.options.length > 0) {\n lines.push('## Options', '');\n // A choice whose cost was not given is written as the choice alone,\n // with no dash that leads nowhere.\n request.options.forEach((option, index) => lines.push(`${index + 1}. **${option.label}**${option.consequence === '' ? '' : ` - ${option.consequence}`}`));\n lines.push('');\n }\n if (request.recommendation !== null) lines.push('## The agent recommends', '', request.recommendation.trim(), '');\n lines.push(\n '## To rule',\n '',\n `Allow: \\`spec-harness rule ${request.id} --allow --note \"<what exactly is allowed>\"\\``,\n `Refuse: \\`spec-harness rule ${request.id} --deny --note \"<why>\"\\``,\n '',\n 'Either writes a row into the brief\\'s rulings table. Commit it signed (`git commit -S`) with a key the base branch lists in its allowed signers; an unsigned row allows nothing.',\n '',\n );\n return lines.join('\\n');\n}\n\nfunction cell(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\r?\\n/g, ' ').trim();\n}\n\n/** The table row a ruling writes. */\nexport function renderRow(id: string, paths: readonly string[], decision: 'allow' | 'deny', note: string): string {\n return `| ${id} | ${paths.map((path) => `\\`${cell(path)}\\``).join(', ')} | ${decision} | ${cell(note)} |`;\n}\n\n/**\n * The brief with a ruling row added: under the rulings section's table when\n * there is one, or in a new section at the end. Every other line is left as\n * it was; line endings are the brief's own.\n */\nexport function addRulingRow(\n text: string,\n section: string,\n row: string,\n where: { readonly headingLine: number | null; readonly tableEndLine: number | null },\n): string {\n const eol = text.includes('\\r\\n') ? '\\r\\n' : '\\n';\n const lines = text.split(/\\r?\\n/);\n const trailing = lines.length > 0 && lines[lines.length - 1] === '' ? lines.pop() : undefined;\n const header = ['| Ruling | Paths | Decision | Note |', '| --- | --- | --- | --- |'];\n if (where.tableEndLine !== null) {\n lines.splice(where.tableEndLine, 0, row);\n } else if (where.headingLine !== null) {\n // A line of prose right under the table would read as one more row.\n const next = lines[where.headingLine];\n const gap = next !== undefined && next.trim() !== '' ? [''] : [];\n lines.splice(where.headingLine, 0, '', ...header, row, ...gap);\n } else {\n if (lines.length > 0 && lines[lines.length - 1]?.trim() !== '') lines.push('');\n lines.push(`## ${section}`, '', ...header, row);\n }\n if (trailing !== undefined) lines.push(trailing);\n return lines.join(eol);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rulings.js","sourceRoot":"","sources":["../src/rulings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Escalations an agent raises and the rulings a person signs.\n *\n * A brief says what a round may not touch. When the round cannot be done\n * without touching it, the agent stops and asks; a person decides; and the\n * decision becomes a row in the brief's rulings table:\n *\n * ```markdown\n * ## Rulings\n *\n * | Ruling | Paths | Decision | Note |\n * | --- | --- | --- | --- |\n * | R-012-1 | `src/db/schema.ts` | allow | Add rotated_at; no other schema change. |\n * ```\n *\n * A row is text, and an agent can write text. What makes a row a ruling is\n * the commit that last changed it: signed, with a key listed in the allowed\n * signers file as the base branch has it (ADR-0006). The row states the\n * decision; the signature says a person made it; the base branch says whose\n * signatures count. A hash of the row, which the agent could compute as well\n * as anyone, would say none of that.\n *\n * The request itself lives outside the work tree while it waits\n * (`<git-common-dir>/spec-harness/escalations/`): it is in-flight state, and\n * only its outcome belongs in the record (spec-core ADR-0005).\n */\n\nexport interface EscalationOption {\n readonly label: string;\n readonly consequence: string;\n}\n\nexport interface EscalationRequest {\n readonly id: string;\n readonly brief: string;\n readonly briefFile: string;\n readonly paths: readonly string[];\n readonly reason: string;\n readonly options: readonly EscalationOption[];\n readonly recommendation: string | null;\n readonly created: string;\n readonly branch: string | null;\n readonly head: string | null;\n}\n\nexport interface RulingRow {\n readonly id: string;\n readonly paths: readonly string[];\n readonly decision: 'allow' | 'deny';\n readonly note: string;\n /** 1-based line of the row in the brief. */\n readonly line: number;\n}\n\n/** A table as the Markdown scanner reads it: header cells, and rows with their lines. */\nexport interface TableView {\n readonly headers: readonly string[];\n readonly rows: readonly { readonly cells: readonly string[]; readonly line: number }[];\n}\n\nexport type RulingProblem = { readonly line: number; readonly message: string };\n\nfunction normal(text: string): string {\n return text.replace(/[*_`]/g, '').trim().toLowerCase();\n}\n\n/** The globs a paths cell names: backtick-quoted, or comma-separated. */\nexport function pathsOf(cell: string): string[] {\n const quoted = [...cell.matchAll(/`([^`]+)`/g)].map((match) => (match[1] as string).trim());\n if (quoted.length > 0) return quoted.filter((path) => path !== '');\n return cell\n .split(',')\n .map((part) => part.trim())\n .filter((part) => part !== '');\n}\n\n/**\n * The rulings in a brief's rulings section, from its tables. A table whose\n * header does not name the columns is not a rulings table; a row that cannot\n * be read is a problem to report, never a ruling.\n */\nexport function readRulings(tables: readonly TableView[]): { rulings: RulingRow[]; problems: RulingProblem[] } {\n const rulings: RulingRow[] = [];\n const problems: RulingProblem[] = [];\n for (const table of tables) {\n const headers = table.headers.map(normal);\n const at = (...names: string[]): number => headers.findIndex((header) => names.includes(header));\n const idColumn = at('ruling', 'id');\n const pathsColumn = at('paths', 'path', 'files');\n const decisionColumn = at('decision');\n const noteColumn = at('note', 'notes', 'reason');\n if (idColumn < 0 || pathsColumn < 0 || decisionColumn < 0) continue;\n for (const row of table.rows) {\n const id = normal(row.cells[idColumn] ?? '').toUpperCase();\n const paths = pathsOf(row.cells[pathsColumn] ?? '');\n const decision = normal(row.cells[decisionColumn] ?? '');\n if (id === '') {\n problems.push({ line: row.line, message: 'a ruling row has no id' });\n continue;\n }\n if (paths.length === 0) {\n problems.push({ line: row.line, message: `ruling ${id} names no path` });\n continue;\n }\n if (decision !== 'allow' && decision !== 'deny') {\n problems.push({ line: row.line, message: `ruling ${id} decides \"${decision}\"; a decision is allow or deny` });\n continue;\n }\n if (rulings.some((ruling) => ruling.id === id)) {\n problems.push({ line: row.line, message: `ruling ${id} appears twice` });\n continue;\n }\n rulings.push({ id, paths, decision, note: (row.cells[noteColumn] ?? '').trim(), line: row.line });\n }\n }\n return { rulings, problems };\n}\n\n/**\n * The next free escalation id for a brief, given the ids already taken. The\n * stem compares without case: `readRulings` reads ids in capitals, so a brief\n * named `auth` has `R-AUTH-1` taken when this writes `R-auth-2`.\n */\nexport function nextId(prefix: 'E' | 'R', brief: string, taken: readonly string[]): string {\n let highest = 0;\n const stem = `${prefix}-${brief}-`;\n for (const id of taken) {\n if (!id.toUpperCase().startsWith(stem.toUpperCase())) continue;\n const n = Number(id.slice(stem.length));\n // A number equal to the highest is the highest already, so `>=` for `>`\n // is equivalent.\n if (Number.isInteger(n) && n > highest) highest = n;\n }\n return `${stem}${highest + 1}`;\n}\n\n/** The memo a person reads to rule: what, why, the choices, and what each costs. */\nexport function renderMemo(request: EscalationRequest): string {\n const lines = [\n `# Escalation ${request.id}`,\n '',\n `Brief ${request.brief} (\\`${request.briefFile}\\`)${request.branch === null ? '' : ` on \\`${request.branch}\\``}${request.head === null ? '' : ` at \\`${request.head.slice(0, 12)}\\``}, raised ${request.created}.`,\n '',\n '## What the round needs to change',\n '',\n ...request.paths.map((path) => `- \\`${path}\\``),\n '',\n '## Why',\n '',\n request.reason.trim(),\n '',\n ];\n if (request.options.length > 0) {\n lines.push('## Options', '');\n // A choice whose cost was not given is written as the choice alone,\n // with no dash that leads nowhere.\n request.options.forEach((option, index) => lines.push(`${index + 1}. **${option.label}**${option.consequence === '' ? '' : ` - ${option.consequence}`}`));\n lines.push('');\n }\n if (request.recommendation !== null) lines.push('## The agent recommends', '', request.recommendation.trim(), '');\n lines.push(\n '## To rule',\n '',\n `Allow: \\`spec-harness rule ${request.id} --allow --note \"<what exactly is allowed>\"\\``,\n `Refuse: \\`spec-harness rule ${request.id} --deny --note \"<why>\"\\``,\n '',\n 'Either writes a row into the brief\\'s rulings table. Commit it signed (`git commit -S`) with a key the base branch lists in its allowed signers; an unsigned row allows nothing.',\n '',\n );\n return lines.join('\\n');\n}\n\nfunction cell(text: string): string {\n return text.replace(/\\|/g, '\\\\|').replace(/\\r?\\n/g, ' ').trim();\n}\n\n/** The table row a ruling writes. */\nexport function renderRow(id: string, paths: readonly string[], decision: 'allow' | 'deny', note: string): string {\n return `| ${id} | ${paths.map((path) => `\\`${cell(path)}\\``).join(', ')} | ${decision} | ${cell(note)} |`;\n}\n\n/**\n * The brief with a ruling row added: under the rulings section's table when\n * there is one, or in a new section at the end. Every other line is left as\n * it was; line endings are the brief's own.\n */\nexport function addRulingRow(\n text: string,\n section: string,\n row: string,\n where: { readonly headingLine: number | null; readonly tableEndLine: number | null },\n): string {\n const eol = text.includes('\\r\\n') ? '\\r\\n' : '\\n';\n const lines = text.split(/\\r?\\n/);\n // A text splits into one line at least, so the first check here is the\n // compiler's, and its mutants are equivalent.\n const trailing = lines.length > 0 && lines[lines.length - 1] === '' ? lines.pop() : undefined;\n const header = ['| Ruling | Paths | Decision | Note |', '| --- | --- | --- | --- |'];\n if (where.tableEndLine !== null) {\n lines.splice(where.tableEndLine, 0, row);\n } else if (where.headingLine !== null) {\n // A line of prose right under the table would read as one more row.\n const next = lines[where.headingLine];\n const gap = next !== undefined && next.trim() !== '' ? [''] : [];\n lines.splice(where.headingLine, 0, '', ...header, row, ...gap);\n } else {\n // The last line is read only where there is one, so the `?.` is the\n // compiler's, and the mutant without it is equivalent.\n if (lines.length > 0 && lines[lines.length - 1]?.trim() !== '') lines.push('');\n lines.push(`## ${section}`, '', ...header, row);\n }\n if (trailing !== undefined) lines.push(trailing);\n return lines.join(eol);\n}\n"]}
|
package/dist/setup.d.ts
CHANGED
|
@@ -32,5 +32,5 @@ export declare function gitHook(root: string): Promise<{
|
|
|
32
32
|
readonly path: string | null;
|
|
33
33
|
readonly note: string | null;
|
|
34
34
|
}>;
|
|
35
|
-
export declare function plan(workspace: Workspace, options: Options,
|
|
35
|
+
export declare function plan(workspace: Workspace, options: Options, io: CliIO): Promise<Step[]>;
|
|
36
36
|
export declare function initCommand(options: Options, io: CliIO): Promise<number>;
|
package/dist/setup.js
CHANGED
|
@@ -15,12 +15,14 @@ import { existsSync, statSync } from 'node:fs';
|
|
|
15
15
|
import { chmod, mkdir, readFile } from 'node:fs/promises';
|
|
16
16
|
import { dirname, isAbsolute, join, relative, sep } from 'node:path';
|
|
17
17
|
import { CONFIG_FILE } from './config.js';
|
|
18
|
-
import { chooseBase, describeGitHook, describeGraph, describeSkipped,
|
|
18
|
+
import { chooseBase, describeGitHook, describeGraph, describeSkipped, GIT_HOOK_LINE, gitHookNote, graphReadsBriefs, GUARD_HOOK, isStarted, loadsPlugin, measuresArchive, mergeClaudeSettings, mergeMcp, mergeSpecBrief, mergeSpecGraph, missingGitHook, PLUGIN, PRE_COMMIT, PROTECT_RULE_FILES, registersServer, SPEC_BRIEF_CONFIGS, SPEC_GRAPH_CONFIGS, } from './configure.js';
|
|
19
19
|
import { readJsonObject as readJson, writeAtomic } from './fs.js';
|
|
20
20
|
import { hookPath, localBranches, remoteDefault } from './git.js';
|
|
21
|
-
import {
|
|
21
|
+
import { claudeCodeWiring, pluginFile } from './round.js';
|
|
22
22
|
import { runSibling } from './siblings.js';
|
|
23
23
|
import { EXIT_ERROR, EXIT_OK, json, openWorkspace } from './workspace.js';
|
|
24
|
+
/** The project's settings file for Claude Code, as a person finds it and as doctor names it. */
|
|
25
|
+
const SETTINGS = '.claude/settings.json';
|
|
24
26
|
function stringify(value) {
|
|
25
27
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
26
28
|
}
|
|
@@ -59,7 +61,7 @@ export async function gitHook(root) {
|
|
|
59
61
|
const inert = process.platform !== 'win32' && (statSync(path).mode & 0o111) === 0;
|
|
60
62
|
return { hook: { state: inert ? 'inert' : 'runs', file }, path, note: gitHookNote(text) };
|
|
61
63
|
}
|
|
62
|
-
export async function plan(workspace, options,
|
|
64
|
+
export async function plan(workspace, options, io) {
|
|
63
65
|
const { root } = workspace;
|
|
64
66
|
const steps = [];
|
|
65
67
|
// The base rounds merge into, decided once: spec-harness verifies rulings
|
|
@@ -185,26 +187,45 @@ export async function plan(workspace, options, env) {
|
|
|
185
187
|
}
|
|
186
188
|
// The agent's hooks and server, unless the plugin brings them: Claude Code
|
|
187
189
|
// runs a plugin's hook beside the same hook in settings, so both would
|
|
188
|
-
// guard every write twice (ADR-0012).
|
|
189
|
-
|
|
190
|
+
// guard every write twice (ADR-0012). The hook's lines are known as doctor
|
|
191
|
+
// knows them, by the hook's own reading and by the writes Claude Code
|
|
192
|
+
// starts each for, so that the two say the same of every file (ADR-0005).
|
|
193
|
+
const wiring = await claudeCodeWiring(root, io);
|
|
194
|
+
const { plugin } = wiring;
|
|
190
195
|
const settingsFile = join(root, '.claude', 'settings.json');
|
|
191
196
|
const settings = await readJson(settingsFile);
|
|
197
|
+
const lines = wiring.lines.filter((line) => line.file === SETTINGS);
|
|
198
|
+
// What doctor says of a line this file holds is said here too, with why
|
|
199
|
+
// init leaves the line: one a person changed is theirs, and a second line
|
|
200
|
+
// beside one that is started would run for every write as well.
|
|
201
|
+
const said = lines.flatMap((line) => [line.detail, line.cover]).filter((note) => note !== null);
|
|
202
|
+
const left = said.length === 0 ? '' : `${said.join('; ')}; init rewrites no line of the hook it did not write, and writes none beside one Claude Code starts for a write`;
|
|
192
203
|
if (plugin !== null) {
|
|
193
|
-
|
|
194
|
-
|
|
204
|
+
// Doubled in this file or in one of the person's own, it is the double
|
|
205
|
+
// install doctor fails: said here too, though init writes neither file.
|
|
206
|
+
// This file's own entry is said first, so the others are named only
|
|
207
|
+
// where it holds none.
|
|
208
|
+
const present = wiring.hooks.includes(SETTINGS);
|
|
209
|
+
steps.push({ file: SETTINGS, action: wiring.hooks.length > 0 ? 'advise' : 'skip', detail: describeSkipped(plugin, 'hooks', present, wiring.hooks) });
|
|
195
210
|
}
|
|
196
211
|
else if (settings === 'unreadable') {
|
|
197
|
-
steps.push({ file:
|
|
212
|
+
steps.push({ file: SETTINGS, action: 'advise', detail: `cannot be read as JSON; add the guard as a PreToolUse and a PostToolUse hook by hand: ${JSON.stringify(GUARD_HOOK)}` });
|
|
198
213
|
}
|
|
199
214
|
else {
|
|
200
|
-
|
|
215
|
+
// An entry is a line of the hook where doctor reports its words as one in this file.
|
|
216
|
+
const reported = new Set(lines.map((line) => JSON.stringify(line.line)));
|
|
217
|
+
const merged = mergeClaudeSettings(settings ?? {}, (words) => reported.has(JSON.stringify(words)));
|
|
218
|
+
// A line that turns the guard off or holds every write is one doctor
|
|
219
|
+
// fails, and lines of which none is waited on before a write are no
|
|
220
|
+
// guard between them: left as they are, they are for the person to mend.
|
|
221
|
+
const broken = lines.some((line) => line.state === 'off' || line.state === 'held') || !lines.some((line) => isStarted(line.before));
|
|
201
222
|
if (merged === null)
|
|
202
|
-
steps.push({ file:
|
|
223
|
+
steps.push({ file: SETTINGS, action: broken ? 'advise' : 'keep', detail: left === '' ? 'the guard hooks are installed' : left });
|
|
203
224
|
else
|
|
204
225
|
steps.push({
|
|
205
|
-
file:
|
|
226
|
+
file: SETTINGS,
|
|
206
227
|
action: settings === null ? 'create' : 'update',
|
|
207
|
-
detail:
|
|
228
|
+
detail: `the guard hooks, run with node from the project's install: a PreToolUse hook refuses writes to protected files; a PostToolUse hook warns about writes outside the scope${left === '' ? '' : `; ${left}`}`,
|
|
208
229
|
apply: () => writeAtomic(settingsFile, stringify(merged)),
|
|
209
230
|
});
|
|
210
231
|
}
|
|
@@ -277,7 +298,7 @@ export async function plan(workspace, options, env) {
|
|
|
277
298
|
}
|
|
278
299
|
export async function initCommand(options, io) {
|
|
279
300
|
const workspace = await openWorkspace(options, io);
|
|
280
|
-
const steps = await plan(workspace, options, io
|
|
301
|
+
const steps = await plan(workspace, options, io);
|
|
281
302
|
if (options.write) {
|
|
282
303
|
for (const step of steps) {
|
|
283
304
|
if (step.apply !== undefined) {
|