@descent-vtt/spec-harness 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What `init` writes into each tool's configuration, and what `doctor` says\n * of the result.\n *\n * Pure: `setup.ts` and the command line read the files and ask git, and\n * write what these return, so the core sweep holds these to the unit suite.\n * Each merge keeps what a person wrote and returns `null` when there is\n * nothing to add.\n */\n\nimport { isAbsolute } from 'node:path';\nimport { runInNewContext } from 'node:vm';\n\nimport { WRITING_TOOLS } from './hooks.js';\nimport { literal } from './literal.js';\nimport type { AllowedSigner } from './signers.js';\nimport type { HookLine } from './usage.js';\nimport { parseGlobList } from './vendor/spec-core/pattern/index.js';\nimport { CLAUDE_CODE_MINIMUM, type ClaudeCodeCheck } from './versions.js';\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === 'object' && value !== null;\n}\n\nfunction sameStrings(value: unknown, expected: readonly string[]): boolean {\n return Array.isArray(value) && value.length === expected.length && value.every((item, index) => item === expected[index]);\n}\n\n/**\n * The command line as the project installed it. Claude Code starts a plugin's\n * server in the plugin's own directory and a hook wherever the session\n * stands, so neither can rely on `npx` finding the project's install; and on\n * Windows a server's command is started without a shell, where `npx` is a\n * shim that cannot start at all. `node` and the script's path work\n * everywhere. git's hook runs the same script, from the top of the work\n * tree, where git starts it.\n */\nconst BIN = 'node_modules/@descent-vtt/spec-harness/bin/spec-harness.js';\n\n/** The project root, as Claude Code substitutes it in a hook's arguments and in a plugin server's. */\nexport const PROJECT_DIR = '${CLAUDE_PROJECT_DIR}';\n\n/**\n * The project root in a project's own `.mcp.json`. Claude Code expands it\n * there from its own environment, which does not hold it, so it needs a\n * default; `.` is right, since a project's server starts in the project.\n */\nexport const PROJECT_DIR_OR_HERE = '${CLAUDE_PROJECT_DIR:-.}';\n\nconst HOOK_MATCHER = 'Edit|Write|MultiEdit|NotebookEdit';\n/** The event Claude Code runs before a tool call, the only one of the two where a hook can refuse the call. */\nconst BEFORE = 'PreToolUse';\n/** The event after a call that succeeded, where a hook can only tell the model what it wrote. */\nconst AFTER = 'PostToolUse';\nconst GUARDED_EVENTS = [BEFORE, AFTER];\nconst GUARD_ARGS: readonly string[] = Object.freeze([`${PROJECT_DIR}/${BIN}`, 'hook', 'claude']);\n\n/**\n * The guard as a Claude Code hook: exec form, `args` given, so the project's\n * path is one argument whatever it holds, and no shell is involved.\n */\nexport const GUARD_HOOK: Readonly<Json> = Object.freeze({ type: 'command', command: 'node', args: GUARD_ARGS, timeout: 60 });\n\n// bare-name: what 0.1 installed, an npx command found from wherever the\n// session stood. Read here so that init replaces it, and never run.\nconst LEGACY_HOOK = 'npx --no-install spec-harness hook claude';\nconst LEGACY_SERVER_ARGS = ['--no-install', 'spec-harness', 'mcp'];\n\nfunction isGuard(hook: unknown): boolean {\n return isObject(hook) && hook['command'] === 'node' && sameStrings(hook['args'], GUARD_ARGS);\n}\n\nfunction isLegacyGuard(hook: unknown): boolean {\n return isObject(hook) && hook['command'] === LEGACY_HOOK;\n}\n\nfunction hooksOf(group: unknown): unknown[] {\n return isObject(group) && Array.isArray(group['hooks']) ? group['hooks'] : [];\n}\n\n/** A group with 0.1's guard replaced where it stands, keeping its other fields; the group itself when it has none. */\nfunction upgraded(group: unknown): unknown {\n const hooks = hooksOf(group);\n if (!hooks.some(isLegacyGuard)) return group;\n return { ...(group as Json), hooks: hooks.map((hook) => (isLegacyGuard(hook) ? { ...(hook as Json), command: 'node', args: [...GUARD_ARGS] } : hook)) };\n}\n\n/**\n * The tools, of those that write a file, that a group's matcher has Claude\n * Code start the group's hooks for, by its hooks reference\n * (https://code.claude.com/docs/en/hooks, Matcher patterns, read\n * 2026-10-12): left out, empty or `*`, every tool; made of letters, digits,\n * `_`, `-`, spaces, `,` and `|` alone, the tools it names, one between each\n * `|` or `,`; with any other character in it, a JavaScript regular\n * expression that may match anywhere in a tool's name. `null` where the\n * reference does not say, or it cannot be told: a matcher that is not text,\n * is no pattern, or is a pattern whose reading runs out its budget.\n */\nfunction matchedTools(matcher: unknown): readonly string[] | null {\n if (matcher === undefined || matcher === '' || matcher === '*') return WRITING_TOOLS;\n if (typeof matcher !== 'string') return null;\n if (/^[A-Za-z0-9_\\- ,|]*$/.test(matcher)) {\n const names = matcher.split(/[|,]/).map((name) => name.trim());\n return WRITING_TOOLS.filter((tool) => names.includes(tool));\n }\n return patternTools(matcher);\n}\n\n/**\n * How long the reading of one pattern may take, in milliseconds of the\n * clock. A sane matcher is read in about half of one (ADR-0005), so only a\n * pattern that backtracks without end meets it; on a machine under load an\n * ordinary one may, and is then said as one that cannot be told, where an\n * idle machine reads it.\n */\nconst PATTERN_BUDGET = 100;\n\n/**\n * The writing tools a matcher that is a pattern matches, or `null` where it\n * is no pattern, or its reading runs out its budget.\n *\n * The pattern is a line of a settings file, which arrives with a clone, and\n * one can be written that a test of four short names never finishes:\n * `^((((([A-Za-z]*)*)*)*)*)*$X` ran for more than ten seconds. Tested as\n * written, one such entry and neither doctor nor init would come back, with\n * no word. So it is made and tested in a context of its own, whose run\n * takes a timeout where a test in this one takes none, and what throws\n * there, a pattern that is none or the stop itself, is a matcher that\n * cannot be told. The shape of a pattern does not say which will: groups in\n * a row backtrack as nested ones do.\n */\nfunction patternTools(source: string): readonly string[] | null {\n try {\n const matched: string[] = runInNewContext('tools.filter((tool) => new RegExp(source).test(tool))', { tools: WRITING_TOOLS, source }, { timeout: PATTERN_BUDGET });\n return matched;\n } catch {\n return null;\n }\n}\n\n/** Whether Claude Code runs a hook's entry in the background, where it waits on no answer of it. */\nfunction inBackground(hook: Json): boolean {\n return hook['async'] === true || hook['asyncRewake'] === true;\n}\n\n/**\n * The writing tools whose call Claude Code hands an entry under `event` and\n * waits for it on, or `null` where that cannot be told here. Before a write\n * an entry in the background answers too late to refuse it, so it is waited\n * on for none (the reference, Run hooks in the background). An `if` has the\n * entry started only for the calls its rule matches, in the syntax of a\n * permission rule, which is not read here.\n */\nfunction answered(event: string, matcher: unknown, hook: Json): readonly string[] | null {\n if (event === BEFORE && inBackground(hook)) return [];\n if (hook['if'] !== undefined) return null;\n return matchedTools(matcher);\n}\n\n/**\n * `.claude/settings.json`, or the plugin's hooks, with the guard hooks merged\n * in; `null` when they are already there.\n *\n * An event has the guard where Claude Code starts init's own line under it\n * for a write. Where the settings hold another line of the hook that it\n * starts for a write, one `isHook` knows as the hook's by the words after\n * the harness's command, nothing is merged in at all: the line is a\n * person's, a second one beside it would run for every write as well, and\n * init rewrites none but the one 0.1 wrote. Without `isHook`, only init's\n * own line is known: the default's `false` and an `undefined` read the same\n * in `some`, so that mutant is equivalent.\n */\nexport function mergeClaudeSettings(current: Json, isHook: (words: readonly string[]) => boolean = () => false): Json | null {\n const hooks = isObject(current['hooks']) ? current['hooks'] : {};\n const theirs = harnessEntries(current).some((entry) => !isGuard(entry.hook) && !isLegacyGuard(entry.hook) && isHook(entry.words) && isStarted(toolsOf(entry)));\n if (theirs) return null;\n let changed = false;\n const next: Json = { ...hooks };\n for (const event of GUARDED_EVENTS) {\n const listed = hooks[event];\n const before: unknown[] = Array.isArray(listed) ? listed : [];\n const groups = before.map(upgraded);\n const replaced = groups.some((group, index) => group !== before[index]);\n const present = harnessEntries({ hooks: { [event]: groups } }).some((entry) => isGuard(entry.hook) && isStarted(toolsOf(entry)));\n if (!present) groups.push({ matcher: HOOK_MATCHER, hooks: [{ ...GUARD_HOOK, args: [...GUARD_ARGS] }] });\n if (replaced || !present) {\n next[event] = groups;\n changed = true;\n }\n }\n return changed ? { ...current, hooks: next } : null;\n}\n\n/** The server's entry, reading the project at `projectDir`: {@link PROJECT_DIR} for the plugin, {@link PROJECT_DIR_OR_HERE} for a project. */\nexport function mcpServer(projectDir: string): Json {\n return { command: 'node', args: [`${projectDir}/${BIN}`, 'mcp', '--root', projectDir] };\n}\n\nfunction isLegacyServer(server: unknown): boolean {\n return isObject(server) && server['command'] === 'npx' && sameStrings(server['args'], LEGACY_SERVER_ARGS);\n}\n\n/**\n * A project's `.mcp.json` with the harness's server merged in, or `null` when\n * one is registered. A server registered under the name some other way is\n * the person's, and stays; 0.1's npx entry is replaced, keeping its other\n * fields.\n */\nexport function mergeMcp(current: Json): Json | null {\n const servers = isObject(current['mcpServers']) ? current['mcpServers'] : {};\n const existing = servers['spec-harness'];\n if ('spec-harness' in servers && !isLegacyServer(existing)) return null;\n return { ...current, mcpServers: { ...servers, 'spec-harness': { ...(existing as Json | undefined), ...mcpServer(PROJECT_DIR_OR_HERE) } } };\n}\n\n/** A key of a file read as JSON; a file that is missing, or is not a JSON object, holds nothing. */\nfunction field(file: unknown, key: string): unknown {\n return isObject(file) ? file[key] : undefined;\n}\n\n/** The harness's command on a line: its script, or its name, alone or at the end of a path. */\nfunction isLauncher(word: string): boolean {\n const name = word.split(/[\\\\/]/).at(-1);\n return name === 'spec-harness' || name === 'spec-harness.js';\n}\n\n/** Anything in a word that a shell reads before the program is handed it: a quote, a variable, an operator, a pattern. */\nconst SHELL_READS = /[^A-Za-z0-9_./:=@%+,-]/;\n\n/** A line of the harness's in Claude Code's settings: what follows its command there. */\nexport interface WrittenHook {\n /** The events whose hooks hold the line, of the two the guard answers. */\n readonly events: readonly string[];\n /** What follows the harness's command, word for word as written. */\n readonly words: readonly string[];\n /**\n * Whether a shell reads those words first, and can change them: a line\n * with no `args`, which Claude Code hands to a shell, holding a quote, a\n * variable or anything else a shell rewrites. What the hook is handed is\n * then the shell's to say. With `args`, Claude Code hands each word over\n * as it stands.\n */\n readonly shell: boolean;\n /** Whether the entry sets `onFailure` to `\"block\"`. */\n readonly blocks: boolean;\n}\n\nfunction writtenHook(hook: Json): Line | null {\n const { command, args } = hook;\n if (typeof command !== 'string') return null;\n let line: string[];\n // Without arguments the line is a shell's, which splits it at its spaces:\n // at each one here, and what stands between two of them is no word.\n if (args === undefined) line = command.split(/\\s/).filter((word) => word !== '');\n else if (Array.isArray(args) && args.every((arg): arg is string => typeof arg === 'string')) line = [command, ...args];\n // Arguments that are not all text are no line Claude Code can start.\n else return null;\n const shell = args === undefined;\n // A quote around the path of the command is the shell's, dropped to know the command by.\n const at = line.findIndex((word) => isLauncher(shell ? word.replace(/[\"']/g, '') : word));\n if (at === -1) return null;\n const words = line.slice(at + 1);\n return { words, shell: shell && words.some((word) => SHELL_READS.test(word)), blocks: hook['onFailure'] === 'block' };\n}\n\n/**\n * Every line in Claude Code's settings that runs the harness, under the two\n * events the guard answers: a line that stands under both, as init writes\n * it, is one line. Whose line each is, the guard's or another command's, is\n * the reader's to say (usage.ts): this knows the harness by its command\n * alone.\n */\nexport function writtenHooks(settings: unknown): WrittenHook[] {\n const found: { events: string[]; words: readonly string[]; shell: boolean; blocks: boolean }[] = [];\n for (const { event, words, shell, blocks } of harnessEntries(settings)) {\n const same = found.find((other) => sameLine(other, { words, shell, blocks }));\n if (same === undefined) found.push({ events: [event], words, shell, blocks });\n else if (!same.events.includes(event)) same.events.push(event);\n }\n return found;\n}\n\ntype Line = Omit<WrittenHook, 'events'>;\n\nfunction sameLine(one: Line, other: Line): boolean {\n return one.shell === other.shell && one.blocks === other.blocks && sameStrings(one.words, other.words);\n}\n\n/** An entry that runs the harness: its line, where it stands, and what decides whether Claude Code starts it there. */\ninterface HarnessEntry extends Line {\n readonly event: string;\n /** The matcher of the entry's group, as written; `undefined` where the group has none. */\n readonly matcher: unknown;\n readonly hook: Json;\n}\n\n/**\n * The writing tools whose call an entry is handed and waited on for, or\n * `null` where that cannot be told. Read where it is asked for and no\n * sooner: a matcher that is a pattern can cost its whole budget.\n */\nfunction toolsOf(entry: HarnessEntry): readonly string[] | null {\n return answered(entry.event, entry.matcher, entry.hook);\n}\n\n/** Every entry that runs the harness under the two events the guard answers, in the order the settings hold them. */\nfunction harnessEntries(settings: unknown): HarnessEntry[] {\n const hooks = field(settings, 'hooks');\n if (!isObject(hooks)) return [];\n return GUARDED_EVENTS.flatMap((event) => {\n const groups = hooks[event];\n if (!Array.isArray(groups)) return [];\n return groups.flatMap((group) =>\n hooksOf(group).flatMap((hook): HarnessEntry[] => {\n if (!isObject(hook)) return [];\n const written = writtenHook(hook);\n if (written === null) return [];\n return [{ ...written, event, matcher: field(group, 'matcher'), hook }];\n }),\n );\n });\n}\n\n/** Whether Claude Code starts a line for a write, by the tools it is waited on for: one whose tools cannot be told is taken as started. */\nexport function isStarted(tools: readonly string[] | null): boolean {\n return tools === null || tools.length > 0;\n}\n\n/** What doctor reports of one line of Claude Code's hook. */\nexport interface HookReport {\n /** The settings file that holds it, as a person finds it. */\n readonly file: string;\n readonly events: readonly string[];\n /** What follows the harness's command, as written. */\n readonly line: readonly string[];\n /**\n * `guards`: Claude Code waits on the hook before a write, and the hook\n * checks it. `off`: the hook checks no write, for a line it cannot read or\n * a root that is no directory. `held`: the hook holds every write, for a\n * brief the line names that is not one. `unstarted`: Claude Code waits on\n * the line before no write, so it is not the guard. `unknown`: what the\n * hook is handed, or which writes it is started for, cannot be told here.\n */\n readonly state: 'guards' | 'off' | 'held' | 'unstarted' | 'unknown';\n readonly onFailure: 'block' | null;\n /** What there is to say of what the hook does with the line, or `null`. */\n readonly detail: string | null;\n /** The writing tools Claude Code waits on the line before a write by, where the hook can refuse it; `null` where that cannot be told. */\n readonly before: readonly string[] | null;\n /** The writing tools Claude Code starts the line after a write by, where the hook can warn of it; `null` where that cannot be told. */\n readonly after: readonly string[] | null;\n /** What there is to say of the two, or `null` where they are every tool that writes, as init has it. */\n readonly cover: string | null;\n /** What `onFailure` changes, where the entry sets it to `\"block\"`. */\n readonly note: string | null;\n}\n\n/**\n * The release of Claude Code that reads `onFailure` on a hook's entry, by its\n * hooks reference (https://code.claude.com/docs/en/hooks, read 2026-10-12).\n */\nconst ON_FAILURE_SINCE = '2.1.295';\n\n/** What `onFailure: \"block\"` changes for a line, named by `where` it stands, or `null` where the entry does not set it. */\nfunction describeOnFailure(where: string, blocks: boolean, off: boolean): string | null {\n if (!blocks) return null;\n const holds = `${where} sets onFailure to \"block\", so Claude Code ${ON_FAILURE_SINCE} or later holds a write when the hook fails`;\n if (off) return `${holds}, which with this line is every write, the one that mends the line among them: mend it by hand`;\n return `${holds}, where it lets the write go ahead without it: by its exit 1 for a question it cannot read, by not starting, or by running past its timeout`;\n}\n\n/** Names as a sentence lists them: one, two with \"and\", more with commas before it. Never asked of none. */\nfunction named(names: readonly string[]): string {\n const last = names.at(-1)!;\n return names.length === 1 ? last : `${names.slice(0, -1).join(', ')} and ${last}`;\n}\n\n/** The writing tools a line's entries under `event` are waited on for between them, or `null` where an entry that cannot be told might add one. */\nfunction toolsUnder(event: string, entries: readonly HarnessEntry[]): readonly string[] | null {\n const read = entries.filter((entry) => entry.event === event).map(toolsOf);\n const sure = WRITING_TOOLS.filter((tool) => read.some((tools) => tools !== null && tools.includes(tool)));\n return sure.length < WRITING_TOOLS.length && read.some((tools) => tools === null) ? null : sure;\n}\n\n/** What a line's entries under `event` hold that decides when Claude Code starts them, as written. */\nfunction entriesUnder(event: string, entries: readonly HarnessEntry[]): string {\n const under = entries.filter((entry) => entry.event === event);\n if (under.length === 0) return `it stands under no ${event}`;\n const said = under.map(({ matcher, hook }) => {\n const pattern = matcher === undefined ? 'no matcher' : `the matcher ${JSON.stringify(matcher)}`;\n const background = inBackground(hook) ? ' in the background' : '';\n const rule = hook['if'] === undefined ? '' : ` with \"if\" ${JSON.stringify(hook['if'])}`;\n return `${pattern}${background}${rule}`;\n });\n return `under ${event} it has ${named([...new Set(said)])}`;\n}\n\n/**\n * What is said of the writes Claude Code starts a line for, by the event and\n * the matcher of each entry that holds it; `null` where it is waited on\n * before every tool that writes and started after each, as init writes it.\n */\nfunction describeCover(where: string, before: readonly string[] | null, after: readonly string[] | null, entries: readonly HarnessEntry[]): string | null {\n const parts: string[] = [];\n const left = (tools: readonly string[]): string[] => WRITING_TOOLS.filter((tool) => !tools.includes(tool));\n if (before === null) parts.push(`which writes Claude Code waits on it before cannot be told here (${entriesUnder(BEFORE, entries)})`);\n else if (before.length === 0) parts.push(`Claude Code waits on it before no write, so it is not the guard and refuses none (${entriesUnder(BEFORE, entries)})`);\n else if (left(before).length > 0) {\n parts.push(`Claude Code waits on it before a write by ${named(before)}, and before none by ${named(left(before))}, which goes unchecked (${entriesUnder(BEFORE, entries)})`);\n }\n if (after === null) parts.push(`which writes it is started after cannot be told here (${entriesUnder(AFTER, entries)})`);\n else if (after.length === 0) parts.push(`it is started after no write, so it warns of none (${entriesUnder(AFTER, entries)})`);\n else if (left(after).length > 0) parts.push(`it is started after a write by ${named(after)} alone (${entriesUnder(AFTER, entries)})`);\n return parts.length === 0 ? null : `${where}: ${parts.join('; ')}`;\n}\n\n/** The words Claude Code hands the hook for a line: what follows the harness's command, each `${CLAUDE_PROJECT_DIR}` filled with `project`. */\nfunction handedWords(words: readonly string[], project: string): string[] {\n return words.map((word) => word.split(PROJECT_DIR).join(project));\n}\n\n/** The words handed over for every line of the harness's in the settings files, for a caller that has to ask something of each before it reports them. */\nexport function handedLines(sources: readonly ClaudeSettings[], project: string): string[][] {\n return sources.flatMap(({ settings }) => writtenHooks(settings).map((hook) => handedWords(hook.words, project)));\n}\n\n/**\n * The lines of Claude Code's hook in the settings files, each with what the\n * hook does with it and which writes Claude Code starts it for. `read` is\n * the hook's own reading of the words it is handed (usage.ts), `null` for a\n * line that is not its; the words are handed to it as Claude Code hands them\n * to the hook, each `${CLAUDE_PROJECT_DIR}` filled with `project`.\n *\n * A line that guards and holds no more than a release wrote is reported\n * with nothing to say, as it always was. One with more on it is said as it\n * is, and fails nothing. One the hook cannot read, or whose root is no\n * directory, is a guard that is off, and one that names a brief which is not\n * one holds every write: each a problem, and doctor exits 1 for it. A line\n * Claude Code waits on before no write is not the guard, whatever the hook\n * would do with it.\n */\nexport function reportHooks(sources: readonly ClaudeSettings[], project: string, read: (words: readonly string[]) => HookLine | null): HookReport[] {\n return sources.flatMap(({ file, settings }) => {\n const entries = harnessEntries(settings);\n return writtenHooks(settings).flatMap((hook): HookReport[] => {\n const handed = read(handedWords(hook.words, project));\n if (handed === null) return [];\n const both = GUARDED_EVENTS.every((event) => hook.events.includes(event));\n // An empty word is shown as a shell spells one, where joined it would not show at all.\n // A line that is not under both events is under one.\n const where = `\"${hook.words.map((word) => (word === '' ? \"''\" : word)).join(' ')}\" in ${file}${both ? '' : ` (under ${hook.events[0]} alone)`}`;\n const mine = entries.filter((entry) => sameLine(entry, hook));\n const before = toolsUnder(BEFORE, mine);\n const after = toolsUnder(AFTER, mine);\n const written = { file, events: hook.events, line: hook.words, onFailure: hook.blocks ? 'block' : null, before, after, cover: describeCover(where, before, after, mine) } satisfies Partial<HookReport>;\n if (hook.shell) {\n const detail = `${where} is a shell's to read before the hook is handed it, so what the hook does with it cannot be told here: written with \"args\", each word reaches the hook as it stands`;\n return [{ ...written, state: 'unknown', detail, note: describeOnFailure(where, hook.blocks, false) }];\n }\n if (handed.state === 'off') {\n const detail = `${where}: ${handed.fault.wrong}, so the guard is off and no write is checked; ${handed.fault.mend}`;\n return [{ ...written, state: 'off', detail, note: describeOnFailure(where, hook.blocks, true) }];\n }\n const note = describeOnFailure(where, hook.blocks, false);\n // What the hook would do with a line it is never asked on before a write is not what guards.\n if (before !== null && before.length === 0) return [{ ...written, state: 'unstarted', detail: null, note }];\n if (handed.state === 'held') {\n const detail = `${where}: ${handed.wrong}, so the hook holds every write until the line is mended: name a brief spec-brief lists, or take --brief off the line`;\n return [{ ...written, state: 'held', detail, note }];\n }\n if (before === null) return [{ ...written, state: 'unknown', detail: null, note }];\n // What a release wrote: its hook, and nothing after it.\n if (sameStrings(hook.words, ['hook', 'claude'])) return [{ ...written, state: 'guards', detail: null, note }];\n const root = handed.root === undefined ? '' : `, and its root, ${handed.root}, is a directory`;\n return [{ ...written, state: 'guards', detail: `${where} is more than init writes, and guards: the hook reads the line${root}`, note }];\n });\n });\n}\n\n/** Whether a project's `.mcp.json` registers a server under the harness's name, however it runs it. */\nexport function registersServer(mcp: unknown): boolean {\n const servers = field(mcp, 'mcpServers');\n return isObject(servers) && 'spec-harness' in servers;\n}\n\n/** A Claude Code settings file, named as a person finds it, and what reading it gave: an object, or nothing usable. */\nexport interface ClaudeSettings {\n readonly file: string;\n readonly settings: unknown;\n}\n\n/** The plugin's id in `enabledPlugins`, and the settings file that turns it on. */\nexport interface EnabledPlugin {\n readonly id: string;\n readonly file: string;\n}\n\n/** `enabledPlugins` keys a plugin `<name>@<marketplace>`; this repository's marketplace lists the plugin as `spec-harness`. */\nconst PLUGIN_ID = /^spec-harness@[^@]+$/;\n\n/**\n * Whether Claude Code runs this package's plugin, from its settings files\n * given lowest precedence first: user, project, local. Claude Code merges\n * `enabledPlugins` key by key, so for each id the last file that sets it to\n * `true` or `false` decides. A plugin named `spec-harness` counts from any\n * marketplace, since another can list this repository. `null` when no file\n * turns it on.\n */\nexport function enabledPlugin(sources: readonly ClaudeSettings[]): EnabledPlugin | null {\n const decided = new Map<string, EnabledPlugin | null>();\n for (const { file, settings } of sources) {\n const plugins = field(settings, 'enabledPlugins');\n if (!isObject(plugins)) continue;\n for (const [id, on] of Object.entries(plugins)) {\n if (PLUGIN_ID.test(id) && typeof on === 'boolean') decided.set(id, on ? { id, file } : null);\n }\n }\n return [...decided.values()].find((entry) => entry !== null) ?? null;\n}\n\n/** Where the plugin is on, as a person would look it up. */\nfunction isOn(plugin: EnabledPlugin): string {\n return `the spec-harness plugin is on (${plugin.id} in ${plugin.file})`;\n}\n\n/** How to have init's entries in place of the plugin's, for this project alone. */\nfunction turnOff(plugin: EnabledPlugin): string {\n return `turn the plugin off for this project with claude plugin disable ${plugin.id} --scope local`;\n}\n\nconst PARTS = literal({\n hooks: { brings: 'the guard hooks', twice: 'every write is guarded twice', skipped: 'init writes none', entry: \"spec-harness's hooks\", them: 'them' },\n server: { brings: 'the server', twice: 'the server is registered twice', skipped: 'init registers none', entry: 'the spec-harness server', them: 'it' },\n});\n\n/**\n * What init says of a Claude Code file it leaves alone because the plugin is\n * on and brings the same `part`. A file that holds init's entry already is a\n * double install for the person to settle: init removes nothing, since the\n * file is the repository's and a clone without the plugin relies on it. So\n * is an entry `elsewhere`, in a settings file of the person's own, which\n * init does not write and doctor fails all the same.\n */\nexport function describeSkipped(plugin: EnabledPlugin, part: 'hooks' | 'server', present: boolean, elsewhere: readonly string[] = []): string {\n const words = PARTS[part];\n if (present) return `${isOn(plugin)} and brings ${words.brings} this file holds as well, so ${words.twice}: take ${words.entry} out of this file, or ${turnOff(plugin)}`;\n if (elsewhere.length > 0) {\n return `${isOn(plugin)} and brings ${words.brings} ${named(elsewhere)} ${elsewhere.length === 1 ? 'holds' : 'hold'} as well, so ${words.twice}: take ${words.entry} out there, or ${turnOff(plugin)}. init writes none here`;\n }\n return `${isOn(plugin)} and brings ${words.brings}, so ${words.skipped}: with both, ${words.twice}. To have ${words.them} here instead, for every clone of the repository, ${turnOff(plugin)} and run init again`;\n}\n\n/** How Claude Code is wired to the harness: the plugin, init's entries, both or neither. */\nexport interface ClaudeCodeWiring {\n readonly plugin: EnabledPlugin | null;\n /** The settings files that hold the guard hooks: a line of the hook that Claude Code starts for a write, before it or after. */\n readonly hooks: readonly string[];\n /** Each line of the hook in the settings files, with what the hook does with it and the writes it is started for. */\n readonly lines: readonly HookReport[];\n /** Whether `.mcp.json` registers the server. */\n readonly server: boolean;\n}\n\nexport type WiringState = 'plugin' | 'init' | 'both' | 'none';\n\n/** Which of the four the wiring is. `both` is a double install, and doctor fails it; either of init's entries counts. */\nexport function wiringState(wiring: Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'>): WiringState {\n const init = wiring.hooks.length > 0 || wiring.server;\n if (wiring.plugin === null) return init ? 'init' : 'none';\n return init ? 'both' : 'plugin';\n}\n\n/** What `doctor` says of the wiring, and what to do when it is doubled or missing. */\nexport function describeClaudeCode(wiring: Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'>): string {\n const { plugin } = wiring;\n const entries = [...wiring.hooks.map((file) => `the guard hooks in ${file}`), ...(wiring.server ? ['the server in .mcp.json'] : [])].join(', ');\n if (plugin === null) {\n if (entries === '') return 'neither the spec-harness plugin nor the hooks init writes, so Claude Code guards no write: run spec-harness init --write, or install the plugin';\n return `init's entries: ${entries}`;\n }\n if (entries === '') return `${isOn(plugin)} and brings the guard hooks and the server`;\n const twice = [...(wiring.hooks.length > 0 ? [PARTS.hooks.twice] : []), ...(wiring.server ? [PARTS.server.twice] : [])].join(' and ');\n return `${isOn(plugin)}, beside ${entries}: ${twice}. Keep one: take spec-harness's entries out of those files, or ${turnOff(plugin)}`;\n}\n\n/** The spec-brief plugin this package ships, as spec-brief's `plugins` names it. */\nexport const PLUGIN = '@descent-vtt/spec-harness/spec-brief-plugin';\n\n/** spec-brief's configuration files, in the order spec-brief looks for them in a directory. */\nexport const SPEC_BRIEF_CONFIGS: readonly string[] = ['.spec-brief.json', 'spec-brief.json'];\n\n/** The conditions an import meets in Node, its `defaultConditions`, and `default`, which every one meets. */\nconst IMPORT_CONDITIONS: readonly string[] = ['node', 'import', 'default'];\n\n/** A target Node refuses as invalid, which an array passes over and anything else stops at. */\nconst INVALID = Symbol('invalid target');\n\nfunction resolveTarget(target: unknown): string | null | undefined | typeof INVALID {\n if (typeof target === 'string') return target.startsWith('./') ? target : INVALID;\n if (Array.isArray(target)) {\n for (const item of target) {\n const resolved = resolveTarget(item);\n if (resolved !== undefined && resolved !== INVALID) return resolved;\n }\n return null;\n }\n if (typeof target !== 'object' || target === null) return target === null ? null : INVALID;\n for (const [condition, value] of Object.entries(target)) {\n if (!IMPORT_CONDITIONS.includes(condition)) continue;\n const resolved = resolveTarget(value);\n if (resolved !== undefined) return resolved;\n }\n return undefined;\n}\n\n/**\n * The file a package's `exports` target names for an import, as Node's\n * PACKAGE_TARGET_RESOLVE finds it, or `null` when it names none: a string\n * that starts with `./`; in an object, the target of the first key, in the\n * object's own order, that an import meets - `node`, `import` or\n * `default` - and that resolves to anything, a `null` included; in an\n * array, the first item that resolves, one Node refuses passed over. A\n * `null` target is not exported, and ends the search there, where a\n * condition an import does not meet lets it go on.\n */\nexport function exportedFile(target: unknown): string | null {\n const resolved = resolveTarget(target);\n return typeof resolved === 'string' ? resolved : null;\n}\n\n/**\n * Whether spec-brief's configuration loads the plugin, by name or as\n * `{ module, options }`. spec-brief also loads a plugin by a path, one that\n * starts with `.` or is absolute, read from the root; such a path is the\n * plugin when `isPluginFile` says it names the plugin's file, which only the\n * disk can tell. Without one, no path is: the default's `false` and an\n * `undefined` read the same in `some`, so that mutant is equivalent.\n */\nexport function loadsPlugin(config: Json, isPluginFile: (path: string) => boolean = () => false): boolean {\n const plugins = config['plugins'];\n const names = (specifier: unknown): boolean =>\n specifier === PLUGIN || (typeof specifier === 'string' && (specifier.startsWith('.') || isAbsolute(specifier)) && isPluginFile(specifier));\n return Array.isArray(plugins) && plugins.some((entry) => names(entry) || (isObject(entry) && names(entry['module'])));\n}\n\n/** Whether spec-brief's configuration names the base its archive measures a round from. */\nexport function measuresArchive(config: Json): boolean {\n const archiving = config['archiving'];\n return isObject(archiving) && typeof archiving['base'] === 'string';\n}\n\n/**\n * spec-brief's configuration with the plugin loaded and the archive measured\n * from `base`, or `null` when both already hold. spec-brief's archive\n * refuses a round that changed a protected file, and learns that a signed\n * ruling allows it only by asking the plugin (ADR-0006). It checks the file at\n * all only when it knows the base: without one it warns that the scope went\n * unmeasured and passes, so the gate is open until a base is named. A base a\n * person wrote is kept.\n */\nexport function mergeSpecBrief(current: Json, base: string | null = null, isPluginFile?: (path: string) => boolean): Json | null {\n const plugin = loadsPlugin(current, isPluginFile);\n const measure = base !== null && !measuresArchive(current);\n if (plugin && !measure) return null;\n const plugins: unknown[] = Array.isArray(current['plugins']) ? current['plugins'] : [];\n const archiving: Json = isObject(current['archiving']) ? current['archiving'] : {};\n return {\n ...current,\n ...(plugin ? {} : { plugins: [...plugins, PLUGIN] }),\n ...(measure ? { archiving: { ...archiving, base } } : {}),\n };\n}\n\n/** Whether spec-brief loads the plugin, as its configuration at the root says. */\nexport type PluginState =\n | { readonly kind: 'loaded' | 'not-loaded' | 'unreadable'; readonly file: string }\n | { readonly kind: 'unconfigured' };\n\n/** What a person reads about the plugin, and what to do when it is not loaded. */\nexport function describePlugin(state: PluginState): string {\n switch (state.kind) {\n case 'loaded':\n return `spec-brief loads spec-harness's plugin (${state.file}): its archive accepts a protected file a signed ruling allows`;\n case 'not-loaded':\n return `spec-brief does not load spec-harness's plugin, so its archive refuses a protected file whatever ruling is signed: add \"${PLUGIN}\" to \"plugins\" in ${state.file}, or run spec-harness init --write`;\n case 'unreadable':\n return `${state.file} cannot be read as JSON, so whether spec-brief loads spec-harness's plugin is unknown`;\n case 'unconfigured':\n return \"spec-brief has no configuration at the root, so it loads no plugin: spec-harness init --write writes one that loads spec-harness's\";\n }\n}\n\n/** What git says that tells a base apart. */\nexport interface BaseFacts {\n /** The remote's default branch as a local ref, such as `origin/main`, or `null`. */\n readonly remoteDefault: string | null;\n /** The branch checked out, or `null` on a detached head. */\n readonly branch: string | null;\n /** Every local branch. */\n readonly branches: readonly string[];\n}\n\n/** The base `init` names, and why; `base` is `null` when none can be told. */\nexport interface BaseChoice {\n readonly base: string | null;\n readonly detail: string;\n}\n\n/**\n * The base `init` writes into `.spec-harness.json`. Every ruling is verified\n * against the allowed signers on it, so it is named rather than left to be\n * found. The remote's default branch comes first, but git records it when\n * it clones, and before 2.48 not on a fetch: a repository made with `git\n * init` and pushed to a remote often has none. There the branch init runs on\n * is the base when it is `main` or `master`, or the only branch; otherwise\n * the person names it.\n */\nexport function chooseBase(facts: BaseFacts): BaseChoice {\n const { remoteDefault, branch } = facts;\n if (remoteDefault !== null) return { base: remoteDefault, detail: `rounds are measured from ${remoteDefault}, the remote's default branch` };\n const unrecorded = 'no remote records a default branch (refs/remotes/origin/HEAD)';\n if (branch !== null) {\n const conventional = branch === 'main' || branch === 'master';\n if (conventional || facts.branches.every((name) => name === branch)) {\n const which = conventional ? 'the branch init runs on' : 'the only branch';\n return { base: branch, detail: `rounds are measured from ${branch}, ${which}: ${unrecorded}; change \"base\" if rounds merge into another` };\n }\n }\n const where = branch === null ? 'HEAD is detached' : `${branch} is not main, master or the only branch`;\n return {\n base: null,\n detail: `no base can be told: ${unrecorded}, and ${where}; set \"base\" to the branch rounds merge into, or run git remote set-head origin --auto and init again`,\n };\n}\n\n/** Where a base came from: `--base`, the configuration, or the remote. */\nexport type BaseSource = 'flag' | 'config' | 'remote';\n\nconst SOURCES: Readonly<Record<BaseSource, string>> = { flag: '--base', config: '.spec-harness.json', remote: \"the remote's default branch\" };\n\n/** The base a command resolved, and how; or why there is none. */\nexport function describeBase(base: { readonly ref: string; readonly source: BaseSource; readonly mergeBase: string } | { readonly reason: string }): string {\n if ('reason' in base) return `none: ${base.reason}`;\n return `${base.ref} (${SOURCES[base.source]}), merge base ${base.mergeBase.slice(0, 12)}`;\n}\n\n/** Whether the allowed-signers file is on the base, where every ruling's signature is checked against it. */\nexport function describeSigners(file: string, base: string | null, onBase: boolean): string {\n if (base === null) return `${file}, read from the base, which could not be resolved: no ruling can count`;\n if (onBase) return `${file} is on ${base}`;\n return `${file} is not on ${base}, so no ruling can count: commit it there, one line per person: <email> namespaces=\"git\" <public key>`;\n}\n\n/**\n * The note doctor gives on the signers whose key is not FIDO2, or `null`\n * when every one's is. A note, never a failure: ADR-0006 accepts a key the\n * agent's account cannot read too, and a PIV or PKCS#11 hardware key is\n * written as a plain key.\n */\nexport function describeSignerKeys(signers: readonly Pick<AllowedSigner, 'line' | 'principals' | 'keyType'>[]): string | null {\n if (signers.length === 0) return null;\n const named = signers.map((signer) => `${signer.principals.join(',')} (${signer.keyType}, line ${signer.line})`).join(', ');\n return (\n `note: signers whose key is not a FIDO2 key: ${named}. ` +\n \"Where an agent runs as the person, ADR-0006 recommends a FIDO2 key, ssh-keygen -t ed25519-sk, whose signature needs a touch no process can supply, or a key the agent's account cannot read; \" +\n 'a PIV or PKCS#11 hardware key reads as a plain ssh-rsa or ecdsa line, so this is a note, not a failure'\n );\n}\n\n/** The note doctor gives on a line of the allowed-signers file that is not a signer. */\nexport function describeSignerProblem(problem: { readonly line: number; readonly message: string }): string {\n return `note: line ${problem.line} is not a signer: ${problem.message}`;\n}\n\n/** What doctor says of the Claude Code on `PATH`, which runs the guard's hooks only from the minimum on. */\nexport function describeClaudeRelease(check: ClaudeCodeCheck): string {\n // A version read from a package.json says so: nothing ran to tell it.\n const release = (found: { readonly version: string; readonly file?: string }): string =>\n `Claude Code ${found.version}${found.file === undefined ? '' : ` (as ${found.file} declares)`}`;\n switch (check.state) {\n case 'ok':\n return `${release(check)} runs the hooks, which need ${CLAUDE_CODE_MINIMUM} or later`;\n case 'outdated':\n return `${release(check)} is older than ${CLAUDE_CODE_MINIMUM}, which the hooks need: it ignores a hook's args and runs a bare node, which fails, and a PreToolUse hook that fails blocks nothing, so every write passes unguarded: update Claude Code, with claude update`;\n case 'unknown':\n return `whether Claude Code is ${CLAUDE_CODE_MINIMUM} or later, which the hooks need, cannot be told: ${check.reason}; an older release lets every write pass unguarded, so check claude --version where Claude Code runs`;\n }\n}\n\n/** Where git's pre-commit hook stands: git's path for it, shown from the root, and what is there. */\nexport type GitHookState =\n | { readonly state: 'runs' | 'absent' | 'other' | 'inert'; readonly file: string }\n | { readonly state: 'unknown'; readonly reason: string };\n\n/**\n * The advice for a missing hook, which init gives beside the file and doctor\n * with it. The hook is the guard for a write the agent's hooks never see,\n * one made through a shell (ADR-0005).\n */\nexport function missingGitHook(file: string | null): string {\n const where = file === null ? '' : ` (${file})`;\n return `no pre-commit hook runs spec-harness${where}: one refuses a commit that changes what the active brief protects, for any agent or none, a shell's writes included; run spec-harness init --git-hook --write to add it`;\n}\n\n/**\n * How to keep the files the rules live in from changing unread, on each\n * forge, as spec-core's ADR-0005 asks: the forge protects them, and CI checks\n * a change against the base branch's rules. GitLab Free has no Code Owners\n * approval, so there the person who merges is the reviewer.\n */\nexport const PROTECT_RULE_FILES =\n \"Have the forge protect this file, the ADRs, the tool configurations and the CI configuration, so no change to them reaches the base branch without a person, and check each change in CI against the base branch's rules: \" +\n 'on GitHub, CODEOWNERS and a protected branch; on GitLab Premium, Code Owners; on GitLab Free, a protected branch no one pushes to, merged by Maintainers, agents as Developers, and pipelines that must succeed. ' +\n \"spec-core's docs/adopting.md has the settings\";\n\n/**\n * The line to add to a hook the repository has of its own: node and the\n * script in the project's install, as Claude Code's hooks are run. git starts\n * a pre-commit hook at the top of the work tree it commits in, a linked\n * worktree's own, wherever the hook is kept, so the path is read from there.\n */\nexport const GIT_HOOK_LINE = `node ${BIN} hook git`;\n\n/**\n * The hook init writes. It is a POSIX sh script on every platform, since Git\n * for Windows runs a hook with the sh it ships. Where the project's install\n * is not in the work tree - a linked worktree nobody installed into, a\n * repository that shares its hooks with one that uses the harness - node\n * would end on a stack trace, so the hook says what is missing and where, and\n * the commit waits, as it did when npx found nothing to run.\n */\nexport const PRE_COMMIT = `#!/bin/sh\n# spec-harness: refuse a commit that changes what the active brief protects.\n# git runs this at the top of the work tree it commits in, a linked worktree's\n# own, wherever the hook is kept: the project's install is read from there.\nbin=${BIN}\nif [ ! -f \"$bin\" ]; then\n printf '%s\\\\n' \"spec-harness: $bin is not in $PWD, the work tree git commits in: install the project's dependencies there, as with npm ci, and commit again\" >&2\n exit 2\nfi\nexec node \"$bin\" hook git\n`;\n\n/**\n * What doctor and init add of a hook whose text runs the harness through\n * npx: the hook init wrote through 0.9.1, or the line it advised for a hook\n * of the repository's own. A note, never a failure: the hook guards as it\n * did. npx starts npm to start node, and npm 12 says on stderr what it runs,\n * twice a commit. A comment that names the command runs nothing, and neither\n * does another runner's line, which is the repository's to choose.\n */\nexport function gitHookNote(text: string): string | null {\n const npx = text.split('\\n').some((line) => /^[^#]*\\bnpx\\b.*\\bspec-harness\\s+hook\\s+git\\b/.test(line));\n if (!npx) return null;\n return `it runs spec-harness through npx, which starts npm to start node on every commit, and under npm 12 prints two \"npm notice run\" lines each time: to run it with node from the project's install, as Claude Code's hooks are, replace the npx command there with \"${GIT_HOOK_LINE}\"`;\n}\n\n/** What doctor says of git's pre-commit hook. */\nexport function describeGitHook(hook: GitHookState): string {\n switch (hook.state) {\n case 'runs':\n return `${hook.file} runs spec-harness`;\n case 'inert':\n return `${hook.file} runs spec-harness, but is not executable, so git skips it: chmod +x ${hook.file}`;\n case 'other':\n return `${hook.file} does not run spec-harness: add the line \"${GIT_HOOK_LINE}\" to it`;\n case 'absent':\n return missingGitHook(hook.file);\n case 'unknown':\n return `where git runs its hooks cannot be told: ${hook.reason}`;\n }\n}\n\n/** spec-graph's configuration files, in the order spec-graph reads them; then a \"spec-graph\" key in package.json. */\nexport const SPEC_GRAPH_CONFIGS: readonly string[] = ['.spec-graph.json', 'spec-graph.config.json'];\n\n/**\n * spec-graph's own patterns when its configuration names none, its\n * DEFAULT_PATTERNS as of 0.9.0. They decide only what init says, never what\n * it writes: `patterns` in the configuration replaces them, so writing the\n * briefs into it would freeze spec-graph's defaults into the file.\n */\nconst SPEC_GRAPH_DEFAULTS: readonly string[] = ['docs/**/*.md', 'doc/**/*.md', 'adr/**/*.md', 'rfcs/**/*.md', 'specs/**/*.md', '*.md'];\n\n/** Whether spec-graph, configured as `config` says, reads the briefs in the directory `briefs`. */\nexport function graphReadsBriefs(config: Json, briefs: string): boolean {\n const configured = Array.isArray(config['patterns']) ? config['patterns'].filter((pattern): pattern is string => typeof pattern === 'string') : [];\n const list = parseGlobList(configured.length > 0 ? configured : SPEC_GRAPH_DEFAULTS, { dialect: 'path', caseSensitive: true, backslash: 'separator' });\n return list.ok && list.list.match(`${briefs}/001_brief.md`);\n}\n\n/**\n * What the history entry does. spec-graph reads a brief whose status says\n * `archived` as a record already; the entry makes one a record whatever word\n * its status uses, or none - and it does anything only where spec-graph\n * reads the briefs, which its defaults do not in `briefs/`.\n */\nexport function describeGraph(archiveGlob: string, briefs: string, reads: boolean, added: boolean): string {\n const history = added ? `read ${archiveGlob} as history` : `${archiveGlob} is history`;\n if (reads) return `${history}: an archived brief is a record whatever its status says, so a live brief that depends on one is not a stale premise`;\n return `${history}, for when spec-graph reads the briefs; its patterns do not reach ${briefs}/, so it checks none of them now: add \"${briefs}/**/*.md\" to its \"patterns\" if it should`;\n}\n\n/** spec-graph's configuration with the archive read as history, or `null` when it already is. */\nexport function mergeSpecGraph(current: Json, archiveGlob: string): Json | null {\n const patterns = current['historyPatterns'];\n const history = Array.isArray(patterns) ? patterns.filter((p): p is string => typeof p === 'string') : [];\n if (history.includes(archiveGlob)) return null;\n return { ...current, historyPatterns: [...history, archiveGlob] };\n}\n"]}
1
+ {"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What `init` writes into each tool's configuration, and what `doctor` says\n * of the result.\n *\n * Pure: `setup.ts` and the command line read the files and ask git, and\n * write what these return, so the core sweep holds these to the unit suite.\n * Each merge keeps what a person wrote and returns `null` when there is\n * nothing to add.\n */\n\nimport { isAbsolute, join } from 'node:path';\nimport { runInNewContext } from 'node:vm';\n\nimport { CALLABLE_TOOLS } from './hooks.js';\nimport { literal } from './literal.js';\nimport type { AllowedSigner } from './signers.js';\nimport { namedTree, type HookLine } from './usage.js';\nimport { parseGlobList } from './vendor/spec-core/pattern/index.js';\nimport { CLAUDE_CODE_MINIMUM, meets, parseVersion, type ClaudeCodeCheck } from './versions.js';\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === 'object' && value !== null;\n}\n\nfunction sameStrings(value: unknown, expected: readonly string[]): boolean {\n return Array.isArray(value) && value.length === expected.length && value.every((item, index) => item === expected[index]);\n}\n\n/**\n * The command line as the project installed it. Claude Code starts a plugin's\n * server in the plugin's own directory and a hook wherever the session\n * stands, so neither can rely on `npx` finding the project's install; and on\n * Windows a server's command is started without a shell, where `npx` is a\n * shim that cannot start at all. `node` and the script's path work\n * everywhere. git's hook runs the same script, from the top of the work\n * tree, where git starts it.\n */\nconst BIN = 'node_modules/@descent-vtt/spec-harness/bin/spec-harness.js';\n\n/** The project root, as Claude Code substitutes it in a hook's arguments and in a plugin server's. */\nexport const PROJECT_DIR = '${CLAUDE_PROJECT_DIR}';\n\n/**\n * The project root in a project's own `.mcp.json`. Claude Code expands it\n * there from its own environment, which does not hold it, so it needs a\n * default; `.` is right, since a project's server starts in the project.\n */\nexport const PROJECT_DIR_OR_HERE = '${CLAUDE_PROJECT_DIR:-.}';\n\n/**\n * The matcher every release wrote: each name the hook reads a file from\n * (hooks.ts). `MultiEdit` is one no supported Claude Code has a tool for,\n * and Claude Code compares a listed name with a tool's exactly, so it starts\n * the hook for nothing there. It stays, since the hook is asked about a name\n * only under a matcher that lets the name through, and it reads this one for\n * whatever still sends it.\n */\nconst HOOK_MATCHER = 'Edit|Write|MultiEdit|NotebookEdit';\n/** The event Claude Code runs before a tool call, the only one of the two where a hook can refuse the call. */\nconst BEFORE = 'PreToolUse';\n/** The event after a call that succeeded, where a hook can only tell the model what it wrote. */\nconst AFTER = 'PostToolUse';\nconst GUARDED_EVENTS = [BEFORE, AFTER];\nconst GUARD_ARGS: readonly string[] = Object.freeze([`${PROJECT_DIR}/${BIN}`, 'hook', 'claude']);\n\n/**\n * The guard as a Claude Code hook: exec form, `args` given, so the project's\n * path is one argument whatever it holds, and no shell is involved.\n */\nexport const GUARD_HOOK: Readonly<Json> = Object.freeze({ type: 'command', command: 'node', args: GUARD_ARGS, timeout: 60 });\n\n// bare-name: what 0.1 installed, an npx command found from wherever the\n// session stood. Read here so that init replaces it, and never run.\nconst LEGACY_HOOK = 'npx --no-install spec-harness hook claude';\nconst LEGACY_SERVER_ARGS = ['--no-install', 'spec-harness', 'mcp'];\n\nfunction isGuard(hook: unknown): boolean {\n return isObject(hook) && hook['command'] === 'node' && sameStrings(hook['args'], GUARD_ARGS);\n}\n\nfunction isLegacyGuard(hook: unknown): boolean {\n return isObject(hook) && hook['command'] === LEGACY_HOOK;\n}\n\nfunction hooksOf(group: unknown): unknown[] {\n return isObject(group) && Array.isArray(group['hooks']) ? group['hooks'] : [];\n}\n\n/** A group with 0.1's guard replaced where it stands, keeping its other fields; the group itself when it has none. */\nfunction upgraded(group: unknown): unknown {\n const hooks = hooksOf(group);\n if (!hooks.some(isLegacyGuard)) return group;\n return { ...(group as Json), hooks: hooks.map((hook) => (isLegacyGuard(hook) ? { ...(hook as Json), command: 'node', args: [...GUARD_ARGS] } : hook)) };\n}\n\n/**\n * The tools, of those that write a file and a supported Claude Code can call\n * (hooks.ts), that a group's matcher has Claude Code start the group's hooks\n * for, by its hooks reference\n * (https://code.claude.com/docs/en/hooks, Matcher patterns, read\n * 2026-10-12): left out, empty or `*`, every tool; made of letters, digits,\n * `_`, `-`, spaces, `,` and `|` alone, the tools it names, one between each\n * `|` or `,`; with any other character in it, a JavaScript regular\n * expression that may match anywhere in a tool's name. `null` where the\n * reference does not say, or it cannot be told: a matcher that is neither\n * text nor an array, is no pattern, or is a pattern whose reading runs out\n * its budget.\n *\n * Two things its page on debugging a configuration adds\n * (https://code.claude.com/docs/en/debug-your-config, Check hooks and Check\n * common causes, read 2026-10-14). A matcher that is an array is an entry\n * Claude Code lists as an invalid setting, among the reasons a hook is not\n * loaded and never fires: no tool. And a comma separates names only from\n * {@link COMMA_SINCE} on, so a matcher that lists names with one is read as\n * `commas` has the Claude Code here read it.\n */\nfunction matchedTools(matcher: unknown, pattern: PatternReader, commas: Commas): readonly string[] | null {\n if (matcher === undefined || matcher === '' || matcher === '*') return CALLABLE_TOOLS;\n if (Array.isArray(matcher)) return [];\n if (typeof matcher !== 'string') return null;\n if (!NAMES.test(matcher)) return pattern(matcher);\n const comma = commas.as === 'separator' ? null : commaReading(matcher, pattern);\n if (comma === null) return listedTools(matcher);\n if (commas.as === 'pattern') return comma.earlier;\n // Which of the two readings holds cannot be told, and where both are no\n // tool that writes it need not be.\n return comma.earlier !== null && comma.listed.length === 0 ? comma.listed : null;\n}\n\n/** A matcher that is a name, or names between `|` and `,`: what the reference compares with a tool's name exactly. */\nconst NAMES = /^[A-Za-z0-9_\\- ,|]*$/;\n\n/** The writing tools a matcher of names lists, one between each `|` or `,`. */\nfunction listedTools(matcher: string): readonly string[] {\n const names = matcher.split(/[|,]/).map((name) => name.trim());\n return CALLABLE_TOOLS.filter((tool) => names.includes(tool));\n}\n\n/**\n * The release of Claude Code from which a comma in a matcher separates\n * names as a `|` does. Its page on debugging a configuration (Check hooks,\n * read 2026-10-14) has a comma before it fall through to the reading of a\n * pattern, under which the matcher never matched, and its changelog has the\n * fix under this release: hooks with comma-separated matchers no longer\n * silently never firing.\n */\nexport const COMMA_SINCE = '2.1.191';\n\n/**\n * How the Claude Code that runs the hooks reads a comma in a matcher of\n * names: as a separator, from {@link COMMA_SINCE} on; as part of a pattern,\n * in the release named, which is older; or it cannot be told, where the\n * release cannot.\n */\nexport type Commas = { readonly as: 'separator' } | { readonly as: 'pattern'; readonly release: string } | { readonly as: 'untold' };\n\n/** The reading every release from {@link COMMA_SINCE} on has, and what a caller that asks no release is given. */\nconst SEPARATOR: Commas = { as: 'separator' };\n\n/**\n * How the Claude Code doctor asked its release reads a comma. A release that\n * was not asked, or could not be told, leaves the reading untold: asked or\n * not, nothing says which it is.\n */\nexport function commasUnder(release: ClaudeCodeCheck | null): Commas {\n if (release === null || release.state === 'unknown') return { as: 'untold' };\n // A release that was told is one whose version was read as one, and the\n // constant is a version, so both parse.\n return meets(parseVersion(release.version)!, parseVersion(COMMA_SINCE)!) ? SEPARATOR : { as: 'pattern', release: release.version };\n}\n\n/** A matcher of names that holds a comma, by the two readings a release may have of it. */\ninterface CommaReading {\n /** From {@link COMMA_SINCE} on: the writing tools it lists. */\n readonly listed: readonly string[];\n /**\n * Before it: no tool, where the matcher read as a pattern matches none of\n * the writing tools, which is what the page has such a matcher do. `null`\n * where read as a pattern it matches one, as `Edit|Write,Bash` matches\n * `Edit`: the page says a comma is read as part of a pattern and says the\n * matcher never matched, and for such a matcher the two disagree.\n */\n readonly earlier: readonly string[] | null;\n}\n\n/** The two readings of a matcher of names that holds a comma, or `null` for any other matcher, which every release reads one way. */\nfunction commaReading(matcher: unknown, pattern: PatternReader): CommaReading | null {\n if (typeof matcher !== 'string' || !NAMES.test(matcher) || !matcher.includes(',')) return null;\n const read = pattern(matcher);\n return { listed: listedTools(matcher), earlier: read !== null && read.length === 0 ? read : null };\n}\n\n/**\n * How long the reading of one pattern may take, in milliseconds of the\n * clock. A sane matcher is read in about half of one (ADR-0005), so only a\n * pattern that backtracks without end meets it; on a machine under load an\n * ordinary one may, and is then said as one that cannot be told, where an\n * idle machine reads it.\n */\nconst PATTERN_BUDGET = 100;\n\n/**\n * The writing tools a matcher that is a pattern matches, or `null` where it\n * is no pattern, or its reading runs out its budget.\n *\n * The pattern is a line of a settings file, which arrives with a clone, and\n * one can be written that a test of a few short names never finishes:\n * `^((((([A-Za-z]*)*)*)*)*)*$X` ran for more than ten seconds. Tested as\n * written, one such entry and neither doctor nor init would come back, with\n * no word. So it is made and tested in a context of its own, whose run\n * takes a timeout where a test in this one takes none, and what throws\n * there, a pattern that is none or the stop itself, is a matcher that\n * cannot be told. The shape of a pattern does not say which will: groups in\n * a row backtrack as nested ones do.\n */\nfunction patternTools(source: string): readonly string[] | null {\n try {\n const matched: string[] = runInNewContext('tools.filter((tool) => new RegExp(source).test(tool))', { tools: CALLABLE_TOOLS, source }, { timeout: PATTERN_BUDGET });\n return matched;\n } catch {\n return null;\n }\n}\n\n/** What reads a matcher that is a pattern: the writing tools it matches, or `null` where that cannot be told. */\nexport type PatternReader = (source: string) => readonly string[] | null;\n\n/**\n * A reader for one run: a pattern is read the first time it is asked of,\n * and answered from that reading after.\n *\n * A reading that runs out its budget costs the whole of it, a settings file\n * can hold one matcher over any number of entries, and init asks of an\n * entry twice, for what doctor says of the file and for what to write into\n * it. Fifty entries under one such pattern were fifty readings, five and a\n * half seconds, and fifty-one for init; they are one. Nothing is spared a\n * file that holds a pattern of its own for each entry.\n *\n * Made where a run begins and handed down, never kept by this module: a\n * reading is of the clock, so one kept past its run would answer for a\n * machine that is busy no longer.\n */\nexport function patternReader(read: PatternReader = patternTools): PatternReader {\n const known = new Map<string, readonly string[] | null>();\n return (source) => {\n const before = known.get(source);\n if (before !== undefined) return before;\n const tools = read(source);\n known.set(source, tools);\n return tools;\n };\n}\n\n/** Whether Claude Code runs a hook's entry in the background, where it waits on no answer of it. */\nfunction inBackground(hook: Json): boolean {\n return hook['async'] === true || hook['asyncRewake'] === true;\n}\n\n/**\n * The writing tools whose call Claude Code hands an entry under `event` and\n * waits for it on, or `null` where that cannot be told here. Before a write\n * an entry in the background answers too late to refuse it, so it is waited\n * on for none (the reference, Run hooks in the background). An `if` has the\n * entry started only for the calls its rule matches, in the syntax of a\n * permission rule, which is not read here.\n */\nfunction answered(event: string, matcher: unknown, hook: Json, pattern: PatternReader, commas: Commas): readonly string[] | null {\n if (event === BEFORE && inBackground(hook)) return [];\n if (hook['if'] !== undefined) return null;\n return matchedTools(matcher, pattern, commas);\n}\n\n/**\n * `.claude/settings.json`, or the plugin's hooks, with the guard hooks merged\n * in; `null` when they are already there.\n *\n * An event has the guard where Claude Code starts init's own line under it\n * for a write. Where the settings hold another line of the hook that it\n * starts for a write, one `isHook` knows as the hook's by the words after\n * the harness's command, nothing is merged in at all: the line is a\n * person's, a second one beside it would run for every write as well, and\n * init rewrites none but the one 0.1 wrote. Without `isHook`, only init's\n * own line is known: the default's `false` and an `undefined` read the same\n * in `some`, so that mutant is equivalent.\n *\n * `pattern` reads a matcher that is a pattern: the run's own reader, where\n * the run has read the file's matchers already ({@link patternReader}).\n * `commas` is how the Claude Code here reads a comma in a matcher of names,\n * where the run asked its release ({@link commasUnder}): a line that\n * release starts for no write is no guard, and init's own is written beside\n * it.\n */\nexport function mergeClaudeSettings(\n current: Json,\n isHook: (words: readonly string[]) => boolean = () => false,\n pattern: PatternReader = patternReader(),\n commas: Commas = SEPARATOR,\n): Json | null {\n const hooks = isObject(current['hooks']) ? current['hooks'] : {};\n const theirs = harnessEntries(current).some((entry) => !isGuard(entry.hook) && !isLegacyGuard(entry.hook) && isHook(entry.words) && isStarted(toolsOf(entry, pattern, commas)));\n if (theirs) return null;\n let changed = false;\n const next: Json = { ...hooks };\n for (const event of GUARDED_EVENTS) {\n const listed = hooks[event];\n const before: unknown[] = Array.isArray(listed) ? listed : [];\n const groups = before.map(upgraded);\n const replaced = groups.some((group, index) => group !== before[index]);\n const present = harnessEntries({ hooks: { [event]: groups } }).some((entry) => isGuard(entry.hook) && isStarted(toolsOf(entry, pattern, commas)));\n if (!present) groups.push({ matcher: HOOK_MATCHER, hooks: [{ ...GUARD_HOOK, args: [...GUARD_ARGS] }] });\n if (replaced || !present) {\n next[event] = groups;\n changed = true;\n }\n }\n return changed ? { ...current, hooks: next } : null;\n}\n\n/** The server's entry, reading the project at `projectDir`: {@link PROJECT_DIR} for the plugin, {@link PROJECT_DIR_OR_HERE} for a project. */\nexport function mcpServer(projectDir: string): Json {\n return { command: 'node', args: [`${projectDir}/${BIN}`, 'mcp', '--root', projectDir] };\n}\n\nfunction isLegacyServer(server: unknown): boolean {\n return isObject(server) && server['command'] === 'npx' && sameStrings(server['args'], LEGACY_SERVER_ARGS);\n}\n\n/**\n * A project's `.mcp.json` with the harness's server merged in, or `null` when\n * one is registered. A server registered under the name some other way is\n * the person's, and stays; 0.1's npx entry is replaced, keeping its other\n * fields.\n */\nexport function mergeMcp(current: Json): Json | null {\n const servers = isObject(current['mcpServers']) ? current['mcpServers'] : {};\n const existing = servers['spec-harness'];\n if ('spec-harness' in servers && !isLegacyServer(existing)) return null;\n return { ...current, mcpServers: { ...servers, 'spec-harness': { ...(existing as Json | undefined), ...mcpServer(PROJECT_DIR_OR_HERE) } } };\n}\n\n/** A key of a file read as JSON; a file that is missing, or is not a JSON object, holds nothing. */\nfunction field(file: unknown, key: string): unknown {\n return isObject(file) ? file[key] : undefined;\n}\n\n/** The harness's command on a line: its script, or its name, alone or at the end of a path. */\nfunction isLauncher(word: string): boolean {\n const name = word.split(/[\\\\/]/).at(-1);\n return name === 'spec-harness' || name === 'spec-harness.js';\n}\n\n/** Anything in a word that a shell reads before the program is handed it: a quote, a variable, an operator, a pattern. */\nconst SHELL_READS = /[^A-Za-z0-9_./:=@%+,-]/;\n\n/** A line of the harness's in Claude Code's settings: what follows its command there. */\nexport interface WrittenHook {\n /** The events whose hooks hold the line, of the two the guard answers. */\n readonly events: readonly string[];\n /** What follows the harness's command, word for word as written. */\n readonly words: readonly string[];\n /**\n * Whether a shell reads those words first, and can change them: a line\n * with no `args`, which Claude Code hands to a shell, holding a quote, a\n * variable or anything else a shell rewrites. What the hook is handed is\n * then the shell's to say. With `args`, Claude Code hands each word over\n * as it stands.\n */\n readonly shell: boolean;\n /** Whether the entry sets `onFailure` to `\"block\"`. */\n readonly blocks: boolean;\n /**\n * What the entry has for `type` where that is not `\"command\"`, as it is\n * said of the line: none at all, or a word the reference does not list.\n * Whether Claude Code runs such an entry cannot be told. `null` for an\n * entry it runs as a command.\n */\n readonly untyped: string | null;\n}\n\n/**\n * The handler types that are no command, by Claude Code's hooks reference\n * (https://code.claude.com/docs/en/hooks, Hook handler fields, read\n * 2026-10-12): an entry of one sends a request, calls a tool of an MCP\n * server, or asks a model or an agent. It runs no command, the harness's or\n * any other, whatever else the entry holds.\n */\nconst OTHER_HANDLERS: readonly unknown[] = ['http', 'mcp_tool', 'prompt', 'agent'];\n\n/**\n * The line of an entry that runs the harness, or `null` for one that does\n * not. Only an entry Claude Code runs as a command is one: the reference\n * has `type` as a field every entry must have, with `\"command\"` for a\n * command and four other words, and says nothing of an entry with none or\n * with another word, which is kept, and said as one that cannot be told.\n */\nfunction writtenHook(hook: Json): Line | null {\n const { command, args, type } = hook;\n if (typeof command !== 'string' || OTHER_HANDLERS.includes(type)) return null;\n let line: string[];\n // Without arguments the line is a shell's, which splits it at its spaces:\n // at each one here, and what stands between two of them is no word.\n if (args === undefined) line = command.split(/\\s/).filter((word) => word !== '');\n else if (Array.isArray(args) && args.every((arg): arg is string => typeof arg === 'string')) line = [command, ...args];\n // Arguments that are not all text are no line Claude Code can start.\n else return null;\n const shell = args === undefined;\n // A quote around the path of the command is the shell's, dropped to know the command by.\n const at = line.findIndex((word) => isLauncher(shell ? word.replace(/[\"']/g, '') : word));\n if (at === -1) return null;\n const words = line.slice(at + 1);\n const untyped = type === 'command' ? null : type === undefined ? 'no \"type\"' : `the \"type\" ${JSON.stringify(type)}`;\n return { words, shell: shell && words.some((word) => SHELL_READS.test(word)), blocks: hook['onFailure'] === 'block', untyped };\n}\n\n/**\n * Every line in Claude Code's settings that runs the harness, under the two\n * events the guard answers: a line that stands under both, as init writes\n * it, is one line. Whose line each is, the guard's or another command's, is\n * the reader's to say (usage.ts): this knows the harness by its command\n * alone.\n */\nexport function writtenHooks(settings: unknown): WrittenHook[] {\n const found: { events: string[]; words: readonly string[]; shell: boolean; blocks: boolean; untyped: string | null }[] = [];\n for (const { event, words, shell, blocks, untyped } of harnessEntries(settings)) {\n const same = found.find((other) => sameLine(other, { words, shell, blocks, untyped }));\n if (same === undefined) found.push({ events: [event], words, shell, blocks, untyped });\n else if (!same.events.includes(event)) same.events.push(event);\n }\n return found;\n}\n\ntype Line = Omit<WrittenHook, 'events'>;\n\nfunction sameLine(one: Line, other: Line): boolean {\n return one.shell === other.shell && one.blocks === other.blocks && one.untyped === other.untyped && sameStrings(one.words, other.words);\n}\n\n/** An entry that runs the harness: its line, where it stands, and what decides whether Claude Code starts it there. */\ninterface HarnessEntry extends Line {\n readonly event: string;\n /** The matcher of the entry's group, as written; `undefined` where the group has none. */\n readonly matcher: unknown;\n readonly hook: Json;\n}\n\n/**\n * The writing tools whose call an entry is handed and waited on for, or\n * `null` where that cannot be told. Read where it is asked for and no\n * sooner: a matcher that is a pattern can cost its whole budget.\n */\nfunction toolsOf(entry: HarnessEntry, pattern: PatternReader, commas: Commas): readonly string[] | null {\n return answered(entry.event, entry.matcher, entry.hook, pattern, commas);\n}\n\n/** Every entry that runs the harness under the two events the guard answers, in the order the settings hold them. */\nfunction harnessEntries(settings: unknown): HarnessEntry[] {\n const hooks = field(settings, 'hooks');\n if (!isObject(hooks)) return [];\n return GUARDED_EVENTS.flatMap((event) => {\n const groups = hooks[event];\n if (!Array.isArray(groups)) return [];\n return groups.flatMap((group) =>\n hooksOf(group).flatMap((hook): HarnessEntry[] => {\n if (!isObject(hook)) return [];\n const written = writtenHook(hook);\n if (written === null) return [];\n return [{ ...written, event, matcher: field(group, 'matcher'), hook }];\n }),\n );\n });\n}\n\n/** Whether Claude Code starts a line for a write, by the tools it is waited on for: one whose tools cannot be told is taken as started. */\nexport function isStarted(tools: readonly string[] | null): boolean {\n return tools === null || tools.length > 0;\n}\n\n/** What doctor reports of one line of Claude Code's hook. */\nexport interface HookReport {\n /** The settings file that holds it, as a person finds it. */\n readonly file: string;\n readonly events: readonly string[];\n /** What follows the harness's command, as written. */\n readonly line: readonly string[];\n /**\n * `guards`: Claude Code waits on the hook before a write, and the hook\n * checks it. `off`: the hook checks no write, for a line it cannot read, a\n * root that is no directory, or a root that is a directory outside any\n * work tree; or it is never started, in a file an array for a matcher\n * keeps Claude Code from loading the hooks of. `held`: the hook holds every write, for a\n * brief the line names that is not one. `unstarted`: Claude Code waits on\n * the line before no write, so it is not the guard. `unknown`: what the\n * hook is handed, which writes it is started for, or whether Claude Code\n * runs the entry at all, cannot be told here.\n */\n readonly state: 'guards' | 'off' | 'held' | 'unstarted' | 'unknown';\n readonly onFailure: 'block' | null;\n /** What there is to say of what the hook does with the line, or `null`. */\n readonly detail: string | null;\n /** The writing tools Claude Code waits on the line before a write by, where the hook can refuse it, of those a supported Claude Code can call (hooks.ts); `null` where that cannot be told. */\n readonly before: readonly string[] | null;\n /** The writing tools Claude Code starts the line after a write by, where the hook can warn of it; `null` where that cannot be told. */\n readonly after: readonly string[] | null;\n /** What there is to say of the two, or `null` where they are every tool that writes, as init has it. */\n readonly cover: string | null;\n /** What `onFailure` changes, where the entry sets it to `\"block\"`. */\n readonly note: string | null;\n}\n\n/**\n * The release of Claude Code that reads `onFailure` on a hook's entry, by its\n * hooks reference (https://code.claude.com/docs/en/hooks, read 2026-10-12).\n */\nconst ON_FAILURE_SINCE = '2.1.295';\n\n/** What `onFailure: \"block\"` changes for a line, named by `where` it stands, or `null` where the entry does not set it. */\nfunction describeOnFailure(where: string, blocks: boolean, off: boolean): string | null {\n if (!blocks) return null;\n const holds = `${where} sets onFailure to \"block\", so Claude Code ${ON_FAILURE_SINCE} or later holds a write when the hook fails`;\n if (off) return `${holds}, which with this line is every write, the one that mends the line among them: mend it by hand`;\n return `${holds}, where it lets the write go ahead without it: by its exit 1 for a question it cannot read, by not starting, or by running past its timeout`;\n}\n\n/** Names as a sentence lists them: one, two with \"and\", more with commas before it. Never asked of none. */\nfunction named(names: readonly string[]): string {\n const last = names.at(-1)!;\n return names.length === 1 ? last : `${names.slice(0, -1).join(', ')} and ${last}`;\n}\n\n/** The writing tools a line's entries under `event` are waited on for between them, or `null` where an entry that cannot be told might add one. */\nfunction toolsUnder(event: string, entries: readonly HarnessEntry[], reading: Reading): readonly string[] | null {\n const read = entries.filter((entry) => entry.event === event).map((entry) => toolsOf(entry, reading.pattern, reading.commas));\n const sure = CALLABLE_TOOLS.filter((tool) => read.some((tools) => tools !== null && tools.includes(tool)));\n return sure.length < CALLABLE_TOOLS.length && read.some((tools) => tools === null) ? null : sure;\n}\n\n/** What a run reads every matcher with: its reader of patterns, and how the Claude Code here reads a comma. */\ninterface Reading {\n readonly pattern: PatternReader;\n readonly commas: Commas;\n}\n\n/**\n * What is said after a matcher that Claude Code does not read as its text\n * suggests: an array, which it loads no hook under, and names with a comma\n * where the release here reads the comma another way than the newest does,\n * or cannot be told. Nothing for any other matcher, and nothing for a comma\n * where both readings come to no tool that writes.\n */\nfunction saidOfMatcher(matcher: unknown, { pattern, commas }: Reading): string {\n if (Array.isArray(matcher)) return ', an array, which Claude Code lists as an invalid setting and loads no hook under';\n if (commas.as === 'separator') return '';\n const comma = commaReading(matcher, pattern);\n if (comma === null || (comma.earlier !== null && comma.listed.length === 0)) return '';\n const listed = comma.listed.length === 0 ? 'no tool that writes' : named(comma.listed);\n const earlier = comma.earlier === null ? 'a pattern whose matches its documentation does not give' : 'a pattern that matches no tool';\n if (commas.as === 'untold') return `, which is ${listed} from Claude Code ${COMMA_SINCE} on, where a comma separates names, and ${earlier} before it: the release here cannot be told`;\n return `, which Claude Code ${commas.release} reads as ${earlier}: a comma separates names from ${COMMA_SINCE} on, where the matcher is ${listed}`;\n}\n\n/** What a line's entries under `event` hold that decides when Claude Code starts them, as written. */\nfunction entriesUnder(event: string, entries: readonly HarnessEntry[], reading: Reading): string {\n const under = entries.filter((entry) => entry.event === event);\n if (under.length === 0) return `it stands under no ${event}`;\n const said = under.map(({ matcher, hook }) => {\n const pattern = matcher === undefined ? 'no matcher' : `the matcher ${JSON.stringify(matcher)}${saidOfMatcher(matcher, reading)}`;\n const background = inBackground(hook) ? ' in the background' : '';\n const rule = hook['if'] === undefined ? '' : ` with \"if\" ${JSON.stringify(hook['if'])}`;\n return `${pattern}${background}${rule}`;\n });\n return `under ${event} it has ${named([...new Set(said)])}`;\n}\n\n/**\n * What is said of the writes Claude Code starts a line for, by the event and\n * the matcher of each entry that holds it; `null` where it is waited on\n * before every tool that writes and started after each, as init writes it.\n * A tool is one a supported Claude Code can call: `MultiEdit`, which the\n * hook still reads a path from, is named as unchecked for no line, since no\n * such Claude Code has it to call (hooks.ts).\n */\nfunction describeCover(where: string, before: readonly string[] | null, after: readonly string[] | null, entries: readonly HarnessEntry[], reading: Reading): string | null {\n const parts: string[] = [];\n const left = (tools: readonly string[]): string[] => CALLABLE_TOOLS.filter((tool) => !tools.includes(tool));\n if (before === null) parts.push(`which writes Claude Code waits on it before cannot be told here (${entriesUnder(BEFORE, entries, reading)})`);\n else if (before.length === 0) parts.push(`Claude Code waits on it before no write, so it is not the guard and refuses none (${entriesUnder(BEFORE, entries, reading)})`);\n else if (left(before).length > 0) {\n parts.push(`Claude Code waits on it before a write by ${named(before)}, and before none by ${named(left(before))}, which goes unchecked (${entriesUnder(BEFORE, entries, reading)})`);\n }\n if (after === null) parts.push(`which writes it is started after cannot be told here (${entriesUnder(AFTER, entries, reading)})`);\n else if (after.length === 0) parts.push(`it is started after no write, so it warns of none (${entriesUnder(AFTER, entries, reading)})`);\n else if (left(after).length > 0) parts.push(`it is started after a write by ${named(after)} alone (${entriesUnder(AFTER, entries, reading)})`);\n return parts.length === 0 ? null : `${where}: ${parts.join('; ')}`;\n}\n\n/** The events under which an array for a matcher keeps Claude Code from loading the rest of a file's hooks. */\nconst UNLOADING: readonly string[] = [BEFORE, 'PermissionRequest'];\n\n/** An array that stands for a matcher where it unloads a settings file's hooks: the event it stands under, and the array as written. */\nexport interface ArrayMatcher {\n readonly event: string;\n readonly matcher: string;\n}\n\n/**\n * The first array that stands for a matcher under `PreToolUse` or\n * `PermissionRequest` in a settings file, or `null`.\n *\n * Claude Code's page on debugging a configuration\n * (https://code.claude.com/docs/en/debug-your-config, Check hooks, read\n * 2026-10-14) has a matcher that is an array, where it must be one string,\n * as an entry Claude Code lists as an invalid setting, at the start of an\n * interactive session and in `claude doctor`; and where the array is under\n * one of these two events, none of that file's other hooks load either. It\n * names no release. So a file that holds one runs no hook at all, whoever\n * wrote the entry and whatever it runs: the array's own is not loaded, and\n * neither is any other.\n */\nexport function arrayMatcher(settings: unknown): ArrayMatcher | null {\n const hooks = field(settings, 'hooks');\n for (const event of UNLOADING) {\n const groups = field(hooks, event);\n if (!Array.isArray(groups)) continue;\n const group = groups.find((candidate) => Array.isArray(field(candidate, 'matcher')));\n if (group !== undefined) return { event, matcher: JSON.stringify(field(group, 'matcher')) };\n }\n return null;\n}\n\n/** What is said of a settings file that an array for a matcher keeps Claude Code from loading the hooks of. */\nexport function describeArrayMatcher(file: string, { event, matcher }: ArrayMatcher): string {\n return `${file} has an array for a matcher under ${event}, ${matcher}, which Claude Code lists as an invalid setting, and beside one under PreToolUse or PermissionRequest it loads none of the file's other hooks`;\n}\n\n/** How a matcher that is an array is mended. */\nexport const ONE_STRING = 'write the matcher as one string, its names between \"|\"';\n\n/** The words Claude Code hands the hook for a line: what follows the harness's command, each `${CLAUDE_PROJECT_DIR}` filled with `project`. */\nfunction handedWords(words: readonly string[], project: string): string[] {\n return words.map((word) => word.split(PROJECT_DIR).join(project));\n}\n\n/** The words handed over for every line of the harness's in the settings files, for a caller that has to ask something of each before it reports them. */\nexport function handedLines(sources: readonly ClaudeSettings[], project: string): string[][] {\n return sources.flatMap(({ settings }) => writtenHooks(settings).map((hook) => handedWords(hook.words, project)));\n}\n\n/**\n * The lines of Claude Code's hook in the settings files, each with what the\n * hook does with it and which writes Claude Code starts it for. `read` is\n * the hook's own reading of the words it is handed (usage.ts), `null` for a\n * line that is not its; the words are handed to it as Claude Code hands them\n * to the hook, each `${CLAUDE_PROJECT_DIR}` filled with `project`.\n *\n * A line that guards and holds no more than a release wrote is reported\n * with nothing to say, as it always was. One with more on it is said as it\n * is, and fails nothing. One the hook cannot read, or whose root is no\n * directory, or is in no work tree that holds the project, is a guard that\n * is off, and one that names a brief which is not\n * one holds every write: each a problem, and doctor exits 1 for it. A line\n * Claude Code waits on before no write is not the guard, whatever the hook\n * would do with it.\n *\n * `pattern` reads a matcher that is a pattern, once for every entry under\n * it in every file: the run's own reader, where something else in the run\n * reads the same files ({@link patternReader}). `commas` is how the Claude\n * Code here reads a comma in a matcher of names, where its release was\n * asked ({@link commasUnder}); a caller that asks none reads a comma as\n * every release from {@link COMMA_SINCE} on does.\n *\n * A file that holds an array for a matcher under `PreToolUse` or\n * `PermissionRequest` has none of its hooks loaded ({@link arrayMatcher}):\n * each line of the hook there is started for no write, and one that stood\n * to be started for a write is a guard that is off.\n */\nexport function reportHooks(\n sources: readonly ClaudeSettings[],\n project: string,\n read: (words: readonly string[]) => HookLine | null,\n pattern: PatternReader = patternReader(),\n commas: Commas = SEPARATOR,\n): HookReport[] {\n const reading: Reading = { pattern, commas };\n return sources.flatMap(({ file, settings }) => {\n const entries = harnessEntries(settings);\n const array = arrayMatcher(settings);\n return writtenHooks(settings).flatMap((hook): HookReport[] => {\n const handed = read(handedWords(hook.words, project));\n if (handed === null) return [];\n const both = GUARDED_EVENTS.every((event) => hook.events.includes(event));\n // An empty word is shown as a shell spells one, where joined it would not show at all.\n // A line that is not under both events is under one.\n const where = `\"${hook.words.map((word) => (word === '' ? \"''\" : word)).join(' ')}\" in ${file}${both ? '' : ` (under ${hook.events[0]} alone)`}`;\n const mine = entries.filter((entry) => sameLine(entry, hook));\n const before = toolsUnder(BEFORE, mine, reading);\n const after = toolsUnder(AFTER, mine, reading);\n if (array !== null) {\n // Nothing of the file is loaded, whatever the line holds and\n // whatever the hook would do with it. A line that stood to be\n // started for a write, or stands under an array itself, where\n // someone meant a matcher, is a guard set up that checks nothing;\n // one that stood to be started for none leaves no write unchecked\n // that it was ever asked about.\n const unloaded = { file, events: hook.events, line: hook.words, onFailure: hook.blocks ? 'block' : null, before: [], after: [], cover: null, note: null } satisfies Partial<HookReport>;\n const said = `${where}: ${describeArrayMatcher(file, array)}`;\n if (isStarted(before) || isStarted(after) || mine.some((entry) => Array.isArray(entry.matcher))) {\n return [{ ...unloaded, state: 'off', detail: `${said}, so the guard is off and no write is checked; ${ONE_STRING}` }];\n }\n return [{ ...unloaded, state: 'unstarted', detail: `${said}: the line is not started, and stood to be started for no write as it is, so no guard is switched off` }];\n }\n const written = { file, events: hook.events, line: hook.words, onFailure: hook.blocks ? 'block' : null, before, after, cover: describeCover(where, before, after, mine, reading) } satisfies Partial<HookReport>;\n const note = describeOnFailure(where, hook.blocks, false);\n if (hook.untyped !== null) {\n const detail = `${where} stands on an entry with ${hook.untyped}, where Claude Code's hooks reference has \"type\": \"command\" on an entry it runs as a command, so whether Claude Code runs it cannot be told here: give the entry \"type\": \"command\"`;\n return [{ ...written, state: 'unknown', detail, note }];\n }\n if (hook.shell) {\n const detail = `${where} is a shell's to read before the hook is handed it, so what the hook does with it cannot be told here: written with \"args\", each word reaches the hook as it stands`;\n return [{ ...written, state: 'unknown', detail, note }];\n }\n // What the hook would do with a line it is never asked on before a write is not what guards.\n const unstarted: HookReport = { ...written, state: 'unstarted', detail: null, note };\n const waited = before === null || before.length > 0;\n if (handed.state === 'off') {\n const detail = `${where}: ${handed.fault.wrong}, so the guard is off and ${handed.unchecked ?? 'no write is checked'}; ${handed.fault.mend}`;\n // A fault the hook says, it says with exit 1 after every write it is\n // started for as well, so it is said wherever the line stands.\n if (handed.silent !== true) return [{ ...written, state: 'off', detail, note: describeOnFailure(where, hook.blocks, true) }];\n // A root outside any work tree, or in one that does not hold the\n // project, of which the hook says nothing: no run of it fails\n // there, so onFailure holds no write for it, and where the line is\n // waited on before no write there is none it leaves unchecked.\n return [waited ? { ...written, state: 'off', detail, note } : unstarted];\n }\n if (!waited) return [unstarted];\n if (handed.state === 'held') {\n const detail = `${where}: ${handed.wrong}, so the hook holds every write until the line is mended: name a brief spec-brief lists, or take --brief off the line`;\n return [{ ...written, state: 'held', detail, note }];\n }\n if (before === null) return [{ ...written, state: 'unknown', detail: null, note }];\n // What a release wrote: its hook, and nothing after it.\n if (sameStrings(hook.words, ['hook', 'claude'])) return [{ ...written, state: 'guards', detail: null, note }];\n const root = handed.root === undefined ? '' : `, and its root, ${handed.root}, is a directory`;\n // Whose briefs a write is checked by, where they are not the project's own.\n const holder = handed.holder === undefined ? '' : ` in ${namedTree(handed.holder)}, which holds this project: the hook checks a write here by that work tree's briefs and its branch, as a file under ${handed.holder.path}/ there`;\n return [{ ...written, state: 'guards', detail: `${where} is more than init writes, and guards: the hook reads the line${root}${holder}`, note }];\n });\n });\n}\n\n/** Whether a project's `.mcp.json` registers a server under the harness's name, however it runs it. */\nexport function registersServer(mcp: unknown): boolean {\n const servers = field(mcp, 'mcpServers');\n return isObject(servers) && 'spec-harness' in servers;\n}\n\n/** A Claude Code settings file, named as a person finds it, and what reading it gave: an object, or nothing usable. */\nexport interface ClaudeSettings {\n readonly file: string;\n readonly settings: unknown;\n}\n\n/** The plugin's id in `enabledPlugins`, and the settings file that turns it on. */\nexport interface EnabledPlugin {\n readonly id: string;\n readonly file: string;\n}\n\n/** `enabledPlugins` keys a plugin `<name>@<marketplace>`; this repository's marketplace lists the plugin as `spec-harness`. */\nconst PLUGIN_ID = /^spec-harness@[^@]+$/;\n\n/**\n * Whether Claude Code runs this package's plugin, from its settings files\n * given lowest precedence first: user, project, local. Claude Code merges\n * `enabledPlugins` key by key, so for each id the last file that sets it to\n * `true` or `false` decides. A plugin named `spec-harness` counts from any\n * marketplace, since another can list this repository. `null` when no file\n * turns it on.\n */\nexport function enabledPlugin(sources: readonly ClaudeSettings[]): EnabledPlugin | null {\n const decided = new Map<string, EnabledPlugin | null>();\n for (const { file, settings } of sources) {\n const plugins = field(settings, 'enabledPlugins');\n if (!isObject(plugins)) continue;\n for (const [id, on] of Object.entries(plugins)) {\n if (PLUGIN_ID.test(id) && typeof on === 'boolean') decided.set(id, on ? { id, file } : null);\n }\n }\n return [...decided.values()].find((entry) => entry !== null) ?? null;\n}\n\n/**\n * The settings file whose `disableAllHooks` turns Claude Code's hooks off,\n * or `null` where none does.\n *\n * By its settings reference\n * (https://code.claude.com/docs/en/settings-reference, disableAllHooks, read\n * 2026-10-12) the key is a Boolean any settings file may hold, and `true`\n * turns hooks off. Set outside managed settings, it turns off the hooks of\n * the user's, the project's and the local settings and of plugins, and the\n * hooks of managed settings, of the Agent SDK and of a plugin that managed\n * settings force on keep running. By its hooks reference (Disable or remove\n * hooks) the value that counts is the one left after settings precedence:\n * of the files given, lowest precedence first, the last that sets a Boolean\n * decides. A value that is no Boolean is passed over, as the key left out.\n */\nexport function hooksDisabled(sources: readonly ClaudeSettings[]): string | null {\n let file: string | null = null;\n for (const source of sources) {\n const value = field(source.settings, 'disableAllHooks');\n if (typeof value === 'boolean') file = value ? source.file : null;\n }\n return file;\n}\n\n/** The project's settings file for Claude Code, as it is named among the sources. */\nexport const PROJECT_SETTINGS = '.claude/settings.json';\n\n/** Where Claude Code records the marketplaces it has fetched, in a directory it keeps plugins in. */\nexport const MARKETPLACE_REGISTRY = 'known_marketplaces.json';\n\n/** Where it records the marketplaces hosted on claude.ai, in a shape its reference does not give. */\nexport const HOSTED_REGISTRY = 'known_marketplaces_claudeai.json';\n\n/**\n * The origins in a plugin's id that are no marketplace, by Claude Code's\n * plugin loading reference (https://code.claude.com/docs/en/plugins/loading,\n * Find where a plugin came from, read 2026-10-12): a plugin started from a\n * directory or an archive, one saved under a skills directory, and one\n * synced from a claude.ai account. None has a marketplace, and the first\n * and the last no record on disk that the reference describes.\n */\nconst OTHER_ORIGINS: readonly string[] = ['inline', 'skills-dir', 'synced'];\n\n/** A name a directory can be looked up by: no separator, and no way out of the directory it is looked up in. */\nconst DIRECTORY_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\n/**\n * The marketplace a plugin's id names, where it names one whose directory\n * can be looked up: `null` for an origin that is no marketplace, and for\n * text that names no directory.\n */\nexport function pluginMarketplace(id: string): string | null {\n const origin = id.slice(id.indexOf('@') + 1);\n return OTHER_ORIGINS.includes(origin) || !DIRECTORY_NAME.test(origin) ? null : origin;\n}\n\n/** What one of the directories Claude Code keeps plugins in holds of a plugin and its marketplace. */\nexport interface PluginsRoot {\n readonly directory: string;\n /** Whether its cache holds a version of the plugin that no `.orphaned_at` marks as left behind. */\n readonly cached: boolean;\n /** Its `known_marketplaces.json` as read: `null` where there is none. */\n readonly registry: Json | null | 'unreadable';\n /** Whether a record of marketplaces hosted on claude.ai stands beside it. */\n readonly hosted: boolean;\n}\n\n/**\n * Whether this machine has what Claude Code loads a plugin from. `detail`\n * is why, where the plugin is not simply there.\n */\nexport type PluginPresence = { readonly state: 'present'; readonly detail: null } | { readonly state: 'absent' | 'unknown'; readonly detail: string };\n\nfunction turnsOn(settings: unknown, id: string): boolean {\n const plugins = field(settings, 'enabledPlugins');\n return isObject(plugins) && plugins[id] === true;\n}\n\nfunction holds(record: unknown, name: string): boolean {\n return isObject(record) && Object.hasOwn(record, name);\n}\n\n/**\n * Whether the plugin that settings turn on is on this machine, by Claude\n * Code's plugin loading reference\n * (https://code.claude.com/docs/en/plugins/loading, read 2026-10-12), from\n * the settings files and from what the directories it keeps plugins in\n * hold: its plugins root, and each seed directory.\n *\n * `present`: a version of it is in a cache, where the reference has one\n * directory for each installed version of a marketplace plugin (Find\n * plugins on disk).\n *\n * `absent` is said only where the reference leaves the plugin no way to\n * load (Enabled in project settings but not installed): its only `true` is\n * in the project's `.claude/settings.json`, for which Claude Code fetches\n * no plugin a machine lacks, and neither of the page's two exceptions is\n * met, a marketplace that lists it by a relative path, since no marketplace\n * of that name is recorded as fetched or declared in settings, and a seed\n * directory that holds it.\n *\n * Everything else is `unknown`: an origin that is no marketplace, a record\n * that is not there or cannot be read, a marketplace that is there or is\n * declared, whose own list is not read here, and a `true` in a settings\n * file of the person's own, for which Claude Code fetches.\n */\nexport function pluginPresence(plugin: EnabledPlugin, sources: readonly ClaudeSettings[], roots: readonly PluginsRoot[]): PluginPresence {\n const untold = (detail: string): PluginPresence => ({ state: 'unknown', detail });\n const marketplace = pluginMarketplace(plugin.id);\n if (marketplace === null) return untold(`${plugin.id} names no marketplace whose plugins are kept in a cache: a plugin from --plugin-dir, a skills directory or a claude.ai account comes another way`);\n if (roots.length === 0) return untold('where Claude Code keeps its plugins is not known here: none of CLAUDE_CODE_PLUGIN_CACHE_DIR, CLAUDE_CONFIG_DIR and a home directory is set');\n if (roots.some((root) => root.cached)) return { state: 'present', detail: null };\n const unread = roots.find((root) => !isObject(root.registry));\n if (unread !== undefined) {\n const wrong = unread.registry === null ? 'is not there' : 'cannot be read as JSON';\n return untold(`${join(unread.directory, MARKETPLACE_REGISTRY)}, where Claude Code records the marketplaces it has fetched, ${wrong}`);\n }\n const fetched = roots.find((root) => holds(root.registry, marketplace));\n if (fetched !== undefined) {\n return untold(\n `its marketplace, ${marketplace}, is on this machine (${join(fetched.directory, MARKETPLACE_REGISTRY)}) and no version of the plugin is in the cache: Claude Code loads a plugin that its marketplace lists by a relative path from the marketplace itself, and the marketplace's list is not read here`,\n );\n }\n const declaring = sources.find(({ settings }) => holds(field(settings, 'extraKnownMarketplaces'), marketplace));\n if (declaring !== undefined) return untold(`${declaring.file} declares its marketplace, ${marketplace}, under extraKnownMarketplaces, which Claude Code fetches after a session has started: nothing of it is on this machine now`);\n const hosted = roots.find((root) => root.hosted);\n if (hosted !== undefined) return untold(`${join(hosted.directory, HOSTED_REGISTRY)} records the marketplaces hosted on claude.ai, in a shape Claude Code's reference does not give, so whether ${marketplace} is one cannot be read`);\n const own = sources.filter(({ file, settings }) => file !== PROJECT_SETTINGS && turnsOn(settings, plugin.id)).map(({ file }) => file);\n if (own.length > 0) return untold(`${named(own)} ${own.length === 1 ? 'turns' : 'turn'} it on, and Claude Code fetches a plugin that settings of the person's own turn on: neither a version of it nor its marketplace, ${marketplace}, is on this machine now`);\n return {\n state: 'absent',\n detail: `${PROJECT_SETTINGS} alone turns it on, and Claude Code fetches no plugin that a project's settings alone turn on, unless its marketplace lists it by a relative path or a seed directory holds it: no marketplace ${marketplace} is recorded as fetched or declared in settings, and no version of the plugin is in a cache (${roots.map((root) => join(root.directory, 'cache')).join(', ')})`,\n };\n}\n\n/** Where the plugin is on, as a person would look it up. */\nfunction isOn(plugin: EnabledPlugin): string {\n return `the spec-harness plugin is on (${plugin.id} in ${plugin.file})`;\n}\n\n/** How to have init's entries in place of the plugin's, for this project alone. */\nfunction turnOff(plugin: EnabledPlugin): string {\n return `turn the plugin off for this project with claude plugin disable ${plugin.id} --scope local`;\n}\n\nconst PARTS = literal({\n hooks: { brings: 'the guard hooks', twice: 'every write is guarded twice', skipped: 'init writes none', entry: \"spec-harness's hooks\", them: 'them', none: 'no hook' },\n server: { brings: 'the server', twice: 'the server is registered twice', skipped: 'init registers none', entry: 'the spec-harness server', them: 'it', none: 'no server' },\n});\n\n/** How to have a plugin that is not on this machine brought to it, in the commands Claude Code's plugin pages give. */\nfunction bring(plugin: EnabledPlugin): string {\n return `install it here, with claude plugin install ${plugin.id} once its marketplace is added`;\n}\n\n/** That the plugin settings turn on is not on this machine, and why. */\nfunction isAbsent(plugin: EnabledPlugin, detail: string, brought: string): string {\n return `${isOn(plugin)} and is not on this machine, so it brings ${brought} here: ${detail}`;\n}\n\n/**\n * What init says of a Claude Code file where the plugin that settings turn\n * on is not on this machine. It writes nothing on that reading alone: a\n * plugin that is there after all would bring the same `part` a second time.\n * A file that holds init's entry already is `present`.\n */\nexport function describeAbsent(plugin: EnabledPlugin, detail: string, part: 'hooks' | 'server', present: boolean): string {\n const words = PARTS[part];\n const absent = isAbsent(plugin, detail, words.none);\n if (present) return `${absent}. This file holds ${words.entry}; with the plugin installed as well, ${words.twice}: ${turnOff(plugin)}`;\n return `${absent}. On that reading alone ${words.skipped}, since with a plugin that is there after all ${words.twice}: ${bring(plugin)}, or to have ${words.them} here instead, ${turnOff(plugin)} and run init again`;\n}\n\n/**\n * What init says of a Claude Code file it leaves alone because the plugin is\n * on and brings the same `part`. A file that holds init's entry already is a\n * double install for the person to settle: init removes nothing, since the\n * file is the repository's and a clone without the plugin relies on it. So\n * is an entry `elsewhere`, in a settings file of the person's own, which\n * init does not write and doctor fails all the same.\n */\nexport function describeSkipped(plugin: EnabledPlugin, part: 'hooks' | 'server', present: boolean, elsewhere: readonly string[] = []): string {\n const words = PARTS[part];\n if (present) return `${isOn(plugin)} and brings ${words.brings} this file holds as well, so ${words.twice}: take ${words.entry} out of this file, or ${turnOff(plugin)}`;\n if (elsewhere.length > 0) {\n return `${isOn(plugin)} and brings ${words.brings} ${named(elsewhere)} ${elsewhere.length === 1 ? 'holds' : 'hold'} as well, so ${words.twice}: take ${words.entry} out there, or ${turnOff(plugin)}. init writes none here`;\n }\n return `${isOn(plugin)} and brings ${words.brings}, so ${words.skipped}: with both, ${words.twice}. To have ${words.them} here instead, for every clone of the repository, ${turnOff(plugin)} and run init again`;\n}\n\n/** How Claude Code is wired to the harness: the plugin, init's entries, both or neither. */\nexport interface ClaudeCodeWiring {\n readonly plugin: EnabledPlugin | null;\n /** Whether this machine has what Claude Code loads that plugin from; `null` where no settings file turns one on. */\n readonly presence: PluginPresence | null;\n /** The settings file whose `disableAllHooks` turns the hooks off, or `null`. */\n readonly hooksOff: string | null;\n /** The settings files that hold the guard hooks: a line of the hook that Claude Code starts for a write, before it or after. */\n readonly hooks: readonly string[];\n /** Each line of the hook in the settings files, with what the hook does with it and the writes it is started for. */\n readonly lines: readonly HookReport[];\n /** Whether `.mcp.json` registers the server. */\n readonly server: boolean;\n /**\n * The release of the Claude Code on `PATH`, where it was asked: a matcher\n * that lists names with a comma is read as that release reads it\n * ({@link commasUnder}). `null` where it was not asked.\n */\n readonly release: ClaudeCodeCheck | null;\n}\n\nexport type WiringState = 'plugin' | 'init' | 'both' | 'none';\n\n/** The wiring as its descriptions read it: what a caller knows of the plugin's presence, which one that does not ask leaves out. */\ntype Wired = Pick<ClaudeCodeWiring, 'plugin' | 'hooks' | 'server'> & { readonly presence?: PluginPresence | null };\n\n/** Why the plugin settings turn on is not on this machine, or `null` where it is, may be, or none is on. */\nfunction absence(wiring: Wired): string | null {\n return wiring.presence?.state === 'absent' ? wiring.presence.detail : null;\n}\n\n/**\n * Which of the four the wiring is. `both` is a double install, and doctor\n * fails it; either of init's entries counts. A plugin that is not on this\n * machine brings nothing to it, and is not counted.\n */\nexport function wiringState(wiring: Wired): WiringState {\n const init = wiring.hooks.length > 0 || wiring.server;\n if (wiring.plugin === null || absence(wiring) !== null) return init ? 'init' : 'none';\n return init ? 'both' : 'plugin';\n}\n\n/**\n * Whether hooks that would guard are switched off: `disableAllHooks` in a\n * settings file, where a settings file holds the guard hooks or a plugin\n * that may be on this machine brings them. A guard someone set up, which\n * checks no write.\n */\nexport function guardSwitchedOff(wiring: Wired & Pick<ClaudeCodeWiring, 'hooksOff'>): boolean {\n return wiring.hooksOff !== null && (wiring.hooks.length > 0 || (wiring.plugin !== null && absence(wiring) === null));\n}\n\n/**\n * What doctor and init say of `disableAllHooks` in `file`. `guarded` is\n * whether there are guard hooks for it to switch off; without any it is a\n * note on what the key would do to them.\n */\nexport function describeHooksOff(file: string, guarded: boolean): string {\n const off = `\"disableAllHooks\" is true in ${file}, so Claude Code runs no hook of the user's, the project's or the local settings, and none of a plugin`;\n if (!guarded) return `note: ${off}: the hooks init writes, and those the plugin brings, would not run while it stands`;\n return `${off}: no write is guarded. Take the key out of ${file}, or set it to false, to have the guard back. Hooks of managed settings, and of a plugin managed settings force on, keep running, and no managed settings are read here`;\n}\n\n/**\n * What doctor adds of the plugin settings turn on, where it is not simply on\n * this machine: that it cannot be told, which is never fine, or that it is\n * not, beside entries of init's. `null` where there is no more to say: no\n * plugin, one that is there, and one that is not where nothing else is\n * wired, which the wiring's own sentence says.\n */\nexport function describePresence(wiring: Wired): string | null {\n const { plugin, presence } = wiring;\n if (plugin === null || presence === undefined || presence === null || presence.state === 'present') return null;\n if (presence.state === 'unknown') return `whether ${plugin.id} is on this machine cannot be told: ${presence.detail}. A plugin that is not there brings no hook: Claude Code's /plugin lists it, and its errors`;\n if (wiring.hooks.length > 0) return `${isAbsent(plugin, presence.detail, 'no hook')}. With the plugin installed as well, ${PARTS.hooks.twice}: ${turnOff(plugin)}`;\n return wiring.server ? unguarded(plugin, presence.detail) : null;\n}\n\n/** That the plugin settings turn on is not on this machine and no hook of init's stands in for it, with the two ways to a guard. */\nfunction unguarded(plugin: EnabledPlugin, detail: string): string {\n return `${isAbsent(plugin, detail, 'no hook')}, and Claude Code guards no write. To have the guard, ${bring(plugin)}, or ${turnOff(plugin)} and run spec-harness init --write`;\n}\n\n/** What `doctor` says of the wiring, and what to do when it is doubled or missing. */\nexport function describeClaudeCode(wiring: Wired): string {\n const { plugin } = wiring;\n const entries = [...wiring.hooks.map((file) => `the guard hooks in ${file}`), ...(wiring.server ? ['the server in .mcp.json'] : [])].join(', ');\n const own = `init's entries: ${entries}`;\n if (plugin === null) {\n if (entries === '') return 'neither the spec-harness plugin nor the hooks init writes, so Claude Code guards no write: run spec-harness init --write, or install the plugin';\n return own;\n }\n const absent = absence(wiring);\n if (absent !== null) return entries === '' ? unguarded(plugin, absent) : own;\n if (entries === '') return `${isOn(plugin)} and brings the guard hooks and the server`;\n const twice = [...(wiring.hooks.length > 0 ? [PARTS.hooks.twice] : []), ...(wiring.server ? [PARTS.server.twice] : [])].join(' and ');\n return `${isOn(plugin)}, beside ${entries}: ${twice}. Keep one: take spec-harness's entries out of those files, or ${turnOff(plugin)}`;\n}\n\n/** The spec-brief plugin this package ships, as spec-brief's `plugins` names it. */\nexport const PLUGIN = '@descent-vtt/spec-harness/spec-brief-plugin';\n\n/** spec-brief's configuration files, in the order spec-brief looks for them in a directory. */\nexport const SPEC_BRIEF_CONFIGS: readonly string[] = ['.spec-brief.json', 'spec-brief.json'];\n\n/** The conditions an import meets in Node, its `defaultConditions`, and `default`, which every one meets. */\nconst IMPORT_CONDITIONS: readonly string[] = ['node', 'import', 'default'];\n\n/** A target Node refuses as invalid, which an array passes over and anything else stops at. */\nconst INVALID = Symbol('invalid target');\n\nfunction resolveTarget(target: unknown): string | null | undefined | typeof INVALID {\n if (typeof target === 'string') return target.startsWith('./') ? target : INVALID;\n if (Array.isArray(target)) {\n for (const item of target) {\n const resolved = resolveTarget(item);\n if (resolved !== undefined && resolved !== INVALID) return resolved;\n }\n return null;\n }\n if (typeof target !== 'object' || target === null) return target === null ? null : INVALID;\n for (const [condition, value] of Object.entries(target)) {\n if (!IMPORT_CONDITIONS.includes(condition)) continue;\n const resolved = resolveTarget(value);\n if (resolved !== undefined) return resolved;\n }\n return undefined;\n}\n\n/**\n * The file a package's `exports` target names for an import, as Node's\n * PACKAGE_TARGET_RESOLVE finds it, or `null` when it names none: a string\n * that starts with `./`; in an object, the target of the first key, in the\n * object's own order, that an import meets - `node`, `import` or\n * `default` - and that resolves to anything, a `null` included; in an\n * array, the first item that resolves, one Node refuses passed over. A\n * `null` target is not exported, and ends the search there, where a\n * condition an import does not meet lets it go on.\n */\nexport function exportedFile(target: unknown): string | null {\n const resolved = resolveTarget(target);\n return typeof resolved === 'string' ? resolved : null;\n}\n\n/**\n * Whether spec-brief's configuration loads the plugin, by name or as\n * `{ module, options }`. spec-brief also loads a plugin by a path, one that\n * starts with `.` or is absolute, read from the root; such a path is the\n * plugin when `isPluginFile` says it names the plugin's file, which only the\n * disk can tell. Without one, no path is: the default's `false` and an\n * `undefined` read the same in `some`, so that mutant is equivalent.\n */\nexport function loadsPlugin(config: Json, isPluginFile: (path: string) => boolean = () => false): boolean {\n const plugins = config['plugins'];\n const names = (specifier: unknown): boolean =>\n specifier === PLUGIN || (typeof specifier === 'string' && (specifier.startsWith('.') || isAbsolute(specifier)) && isPluginFile(specifier));\n return Array.isArray(plugins) && plugins.some((entry) => names(entry) || (isObject(entry) && names(entry['module'])));\n}\n\n/** Whether spec-brief's configuration names the base its archive measures a round from. */\nexport function measuresArchive(config: Json): boolean {\n const archiving = config['archiving'];\n return isObject(archiving) && typeof archiving['base'] === 'string';\n}\n\n/**\n * spec-brief's configuration with the plugin loaded and the archive measured\n * from `base`, or `null` when both already hold. spec-brief's archive\n * refuses a round that changed a protected file, and learns that a signed\n * ruling allows it only by asking the plugin (ADR-0006). It checks the file at\n * all only when it knows the base: without one it warns that the scope went\n * unmeasured and passes, so the gate is open until a base is named. A base a\n * person wrote is kept.\n */\nexport function mergeSpecBrief(current: Json, base: string | null = null, isPluginFile?: (path: string) => boolean): Json | null {\n const plugin = loadsPlugin(current, isPluginFile);\n const measure = base !== null && !measuresArchive(current);\n if (plugin && !measure) return null;\n const plugins: unknown[] = Array.isArray(current['plugins']) ? current['plugins'] : [];\n const archiving: Json = isObject(current['archiving']) ? current['archiving'] : {};\n return {\n ...current,\n ...(plugin ? {} : { plugins: [...plugins, PLUGIN] }),\n ...(measure ? { archiving: { ...archiving, base } } : {}),\n };\n}\n\n/** Whether spec-brief loads the plugin, as its configuration at the root says. */\nexport type PluginState =\n | { readonly kind: 'loaded' | 'not-loaded' | 'unreadable'; readonly file: string }\n | { readonly kind: 'unconfigured' };\n\n/** What a person reads about the plugin, and what to do when it is not loaded. */\nexport function describePlugin(state: PluginState): string {\n switch (state.kind) {\n case 'loaded':\n return `spec-brief loads spec-harness's plugin (${state.file}): its archive accepts a protected file a signed ruling allows`;\n case 'not-loaded':\n return `spec-brief does not load spec-harness's plugin, so its archive refuses a protected file whatever ruling is signed: add \"${PLUGIN}\" to \"plugins\" in ${state.file}, or run spec-harness init --write`;\n case 'unreadable':\n return `${state.file} cannot be read as JSON, so whether spec-brief loads spec-harness's plugin is unknown`;\n case 'unconfigured':\n return \"spec-brief has no configuration at the root, so it loads no plugin: spec-harness init --write writes one that loads spec-harness's\";\n }\n}\n\n/** What git says that tells a base apart. */\nexport interface BaseFacts {\n /** The remote's default branch as a local ref, such as `origin/main`, or `null`. */\n readonly remoteDefault: string | null;\n /** The branch checked out, or `null` on a detached head. */\n readonly branch: string | null;\n /** Every local branch. */\n readonly branches: readonly string[];\n}\n\n/** The base `init` names, and why; `base` is `null` when none can be told. */\nexport interface BaseChoice {\n readonly base: string | null;\n readonly detail: string;\n}\n\n/**\n * The base `init` writes into `.spec-harness.json`. Every ruling is verified\n * against the allowed signers on it, so it is named rather than left to be\n * found. The remote's default branch comes first, but git records it when\n * it clones, and before 2.48 not on a fetch: a repository made with `git\n * init` and pushed to a remote often has none. There the branch init runs on\n * is the base when it is `main` or `master`, or the only branch; otherwise\n * the person names it.\n */\nexport function chooseBase(facts: BaseFacts): BaseChoice {\n const { remoteDefault, branch } = facts;\n if (remoteDefault !== null) return { base: remoteDefault, detail: `rounds are measured from ${remoteDefault}, the remote's default branch` };\n const unrecorded = 'no remote records a default branch (refs/remotes/origin/HEAD)';\n if (branch !== null) {\n const conventional = branch === 'main' || branch === 'master';\n if (conventional || facts.branches.every((name) => name === branch)) {\n const which = conventional ? 'the branch init runs on' : 'the only branch';\n return { base: branch, detail: `rounds are measured from ${branch}, ${which}: ${unrecorded}; change \"base\" if rounds merge into another` };\n }\n }\n const where = branch === null ? 'HEAD is detached' : `${branch} is not main, master or the only branch`;\n return {\n base: null,\n detail: `no base can be told: ${unrecorded}, and ${where}; set \"base\" to the branch rounds merge into, or run git remote set-head origin --auto and init again`,\n };\n}\n\n/** Where a base came from: `--base`, the configuration, or the remote. */\nexport type BaseSource = 'flag' | 'config' | 'remote';\n\nconst SOURCES: Readonly<Record<BaseSource, string>> = { flag: '--base', config: '.spec-harness.json', remote: \"the remote's default branch\" };\n\n/** The base a command resolved, and how; or why there is none. */\nexport function describeBase(base: { readonly ref: string; readonly source: BaseSource; readonly mergeBase: string } | { readonly reason: string }): string {\n if ('reason' in base) return `none: ${base.reason}`;\n return `${base.ref} (${SOURCES[base.source]}), merge base ${base.mergeBase.slice(0, 12)}`;\n}\n\n/** Whether the allowed-signers file is on the base, where every ruling's signature is checked against it. */\nexport function describeSigners(file: string, base: string | null, onBase: boolean): string {\n if (base === null) return `${file}, read from the base, which could not be resolved: no ruling can count`;\n if (onBase) return `${file} is on ${base}`;\n return `${file} is not on ${base}, so no ruling can count: commit it there, one line per person: <email> namespaces=\"git\" <public key>`;\n}\n\n/**\n * The note doctor gives on the signers whose key is not FIDO2, or `null`\n * when every one's is. A note, never a failure: ADR-0006 accepts a key the\n * agent's account cannot read too, and a PIV or PKCS#11 hardware key is\n * written as a plain key.\n */\nexport function describeSignerKeys(signers: readonly Pick<AllowedSigner, 'line' | 'principals' | 'keyType'>[]): string | null {\n if (signers.length === 0) return null;\n const named = signers.map((signer) => `${signer.principals.join(',')} (${signer.keyType}, line ${signer.line})`).join(', ');\n return (\n `note: signers whose key is not a FIDO2 key: ${named}. ` +\n \"Where an agent runs as the person, ADR-0006 recommends a FIDO2 key, ssh-keygen -t ed25519-sk, whose signature needs a touch no process can supply, or a key the agent's account cannot read; \" +\n 'a PIV or PKCS#11 hardware key reads as a plain ssh-rsa or ecdsa line, so this is a note, not a failure'\n );\n}\n\n/** The note doctor gives on a line of the allowed-signers file that is not a signer. */\nexport function describeSignerProblem(problem: { readonly line: number; readonly message: string }): string {\n return `note: line ${problem.line} is not a signer: ${problem.message}`;\n}\n\n/** What doctor says of the Claude Code on `PATH`, which runs the guard's hooks only from the minimum on. */\nexport function describeClaudeRelease(check: ClaudeCodeCheck): string {\n // A version read from a package.json says so: nothing ran to tell it.\n const release = (found: { readonly version: string; readonly file?: string }): string =>\n `Claude Code ${found.version}${found.file === undefined ? '' : ` (as ${found.file} declares)`}`;\n switch (check.state) {\n case 'ok':\n return `${release(check)} runs the hooks, which need ${CLAUDE_CODE_MINIMUM} or later`;\n case 'outdated':\n return `${release(check)} is older than ${CLAUDE_CODE_MINIMUM}, which the hooks need: it ignores a hook's args and runs a bare node, which fails, and a PreToolUse hook that fails blocks nothing, so every write passes unguarded: update Claude Code, with claude update`;\n case 'unknown':\n return `whether Claude Code is ${CLAUDE_CODE_MINIMUM} or later, which the hooks need, cannot be told: ${check.reason}; an older release lets every write pass unguarded, so check claude --version where Claude Code runs`;\n }\n}\n\n/** Where git's pre-commit hook stands: git's path for it, shown from the root, and what is there. */\nexport type GitHookState =\n | { readonly state: 'runs' | 'absent' | 'other' | 'inert'; readonly file: string }\n /**\n * What stands at the path is no file, `what` it is instead. `stops`: git\n * can execute it, tries to run it as the hook, fails, and stops every\n * commit. `ignored`: git cannot execute it, and skips it as it skips a\n * hook that is not executable.\n */\n | { readonly state: 'stops' | 'ignored'; readonly file: string; readonly what: string }\n | { readonly state: 'unknown'; readonly reason: string };\n\n/**\n * The advice for a missing hook, which init gives beside the file and doctor\n * with it. The hook is the guard for a write the agent's hooks never see,\n * one made through a shell (ADR-0005).\n */\nexport function missingGitHook(file: string | null): string {\n const where = file === null ? '' : ` (${file})`;\n return `no pre-commit hook runs spec-harness${where}: one refuses a commit that changes what the active brief protects, for any agent or none, a shell's writes included; run spec-harness init --git-hook --write to add it`;\n}\n\n/**\n * How to keep the files the rules live in from changing unread, on each\n * forge, as spec-core's ADR-0005 asks: the forge protects them, and CI checks\n * a change against the base branch's rules. GitLab Free has no Code Owners\n * approval, so there the person who merges is the reviewer.\n */\nexport const PROTECT_RULE_FILES =\n \"Have the forge protect this file, the ADRs, the tool configurations and the CI configuration, so no change to them reaches the base branch without a person, and check each change in CI against the base branch's rules: \" +\n 'on GitHub, CODEOWNERS and a protected branch; on GitLab Premium, Code Owners; on GitLab Free, a protected branch no one pushes to, merged by Maintainers, agents as Developers, and pipelines that must succeed. ' +\n \"spec-core's docs/adopting.md has the settings\";\n\n/**\n * The line to add to a hook the repository has of its own: node and the\n * script in the project's install, as Claude Code's hooks are run. git starts\n * a pre-commit hook at the top of the work tree it commits in, a linked\n * worktree's own, wherever the hook is kept, so the path is read from there.\n */\nexport const GIT_HOOK_LINE = `node ${BIN} hook git`;\n\n/**\n * The hook init writes. It is a POSIX sh script on every platform, since Git\n * for Windows runs a hook with the sh it ships. Where the project's install\n * is not in the work tree - a linked worktree nobody installed into, a\n * repository that shares its hooks with one that uses the harness - node\n * would end on a stack trace, so the hook says what is missing and where, and\n * the commit waits, as it did when npx found nothing to run.\n */\nexport const PRE_COMMIT = `#!/bin/sh\n# spec-harness: refuse a commit that changes what the active brief protects.\n# git runs this at the top of the work tree it commits in, a linked worktree's\n# own, wherever the hook is kept: the project's install is read from there.\nbin=${BIN}\nif [ ! -f \"$bin\" ]; then\n printf '%s\\\\n' \"spec-harness: $bin is not in $PWD, the work tree git commits in: install the project's dependencies there, as with npm ci, and commit again\" >&2\n exit 2\nfi\nexec node \"$bin\" hook git\n`;\n\n/**\n * What doctor and init add of a hook whose text runs the harness through\n * npx: the hook init wrote through 0.9.1, or the line it advised for a hook\n * of the repository's own. A note, never a failure: the hook guards as it\n * did. npx starts npm to start node, and npm 12 says on stderr what it runs,\n * twice a commit. A comment that names the command runs nothing, and neither\n * does another runner's line, which is the repository's to choose.\n */\nexport function gitHookNote(text: string): string | null {\n const npx = text.split('\\n').some((line) => /^[^#]*\\bnpx\\b.*\\bspec-harness\\s+hook\\s+git\\b/.test(line));\n if (!npx) return null;\n return `it runs spec-harness through npx, which starts npm to start node on every commit, and under npm 12 prints two \"npm notice run\" lines each time: to run it with node from the project's install, as Claude Code's hooks are, replace the npx command there with \"${GIT_HOOK_LINE}\"`;\n}\n\n/** What doctor says of git's pre-commit hook. */\nexport function describeGitHook(hook: GitHookState): string {\n switch (hook.state) {\n case 'runs':\n return `${hook.file} runs spec-harness`;\n case 'inert':\n return `${hook.file} runs spec-harness, but is not executable, so git skips it: chmod +x ${hook.file}`;\n case 'other':\n return `${hook.file} does not run spec-harness: add the line \"${GIT_HOOK_LINE}\" to it`;\n case 'stops':\n return `${hook.file} is ${hook.what}, not a hook, and git stops every commit at it, since it cannot run it (\"cannot spawn\" on Windows, \"cannot exec\" elsewhere): nothing is checked there, and nothing is committed. Take it away, then run spec-harness init --git-hook --write`;\n case 'ignored':\n return `${hook.file} is ${hook.what}, not a hook, and is not executable, so git skips it and runs no hook: take it away, then run spec-harness init --git-hook --write`;\n case 'absent':\n return missingGitHook(hook.file);\n case 'unknown':\n return `where git runs its hooks cannot be told: ${hook.reason}`;\n }\n}\n\n/** spec-graph's configuration files, in the order spec-graph reads them; then a \"spec-graph\" key in package.json. */\nexport const SPEC_GRAPH_CONFIGS: readonly string[] = ['.spec-graph.json', 'spec-graph.config.json'];\n\n/**\n * spec-graph's own patterns when its configuration names none, its\n * DEFAULT_PATTERNS as of 0.9.0. They decide only what init says, never what\n * it writes: `patterns` in the configuration replaces them, so writing the\n * briefs into it would freeze spec-graph's defaults into the file.\n */\nconst SPEC_GRAPH_DEFAULTS: readonly string[] = ['docs/**/*.md', 'doc/**/*.md', 'adr/**/*.md', 'rfcs/**/*.md', 'specs/**/*.md', '*.md'];\n\n/** Whether spec-graph, configured as `config` says, reads the briefs in the directory `briefs`. */\nexport function graphReadsBriefs(config: Json, briefs: string): boolean {\n const configured = Array.isArray(config['patterns']) ? config['patterns'].filter((pattern): pattern is string => typeof pattern === 'string') : [];\n const list = parseGlobList(configured.length > 0 ? configured : SPEC_GRAPH_DEFAULTS, { dialect: 'path', caseSensitive: true, backslash: 'separator' });\n return list.ok && list.list.match(`${briefs}/001_brief.md`);\n}\n\n/**\n * What the history entry does. spec-graph reads a brief whose status says\n * `archived` as a record already; the entry makes one a record whatever word\n * its status uses, or none - and it does anything only where spec-graph\n * reads the briefs, which its defaults do not in `briefs/`.\n */\nexport function describeGraph(archiveGlob: string, briefs: string, reads: boolean, added: boolean): string {\n const history = added ? `read ${archiveGlob} as history` : `${archiveGlob} is history`;\n if (reads) return `${history}: an archived brief is a record whatever its status says, so a live brief that depends on one is not a stale premise`;\n return `${history}, for when spec-graph reads the briefs; its patterns do not reach ${briefs}/, so it checks none of them now: add \"${briefs}/**/*.md\" to its \"patterns\" if it should`;\n}\n\n/** spec-graph's configuration with the archive read as history, or `null` when it already is. */\nexport function mergeSpecGraph(current: Json, archiveGlob: string): Json | null {\n const patterns = current['historyPatterns'];\n const history = Array.isArray(patterns) ? patterns.filter((p): p is string => typeof p === 'string') : [];\n if (history.includes(archiveGlob)) return null;\n return { ...current, historyPatterns: [...history, archiveGlob] };\n}\n"]}
package/dist/fs.d.ts CHANGED
@@ -17,6 +17,16 @@ export declare function loadConfig(root: string): Promise<{
17
17
  * `src/db/schema.ts` on Windows or macOS, where both name one file.
18
18
  */
19
19
  export declare function realSpelling(path: string): string;
20
+ /**
21
+ * Whether `directory` is the one git names as the top of a work tree: the
22
+ * two spelled alike once the filesystem has spelled the directory, links
23
+ * and short names resolved, as git spells a top. A spelling that differs is
24
+ * read as another directory: what git said from the one is then not taken
25
+ * for what it would say from the other.
26
+ */
27
+ export declare function isTop(directory: string, top: string): boolean;
28
+ /** Whether a `.git` stands in `directory`, a repository's or the file that names one, as at the top of a work tree. */
29
+ export declare function holdsGit(directory: string): boolean;
20
30
  /**
21
31
  * A path as the repository names it - relative to the root, POSIX-separated,
22
32
  * real spelling - or `null` when it lies outside the root.
package/dist/fs.js CHANGED
@@ -53,6 +53,20 @@ export function realSpelling(path) {
53
53
  }
54
54
  }
55
55
  }
56
+ /**
57
+ * Whether `directory` is the one git names as the top of a work tree: the
58
+ * two spelled alike once the filesystem has spelled the directory, links
59
+ * and short names resolved, as git spells a top. A spelling that differs is
60
+ * read as another directory: what git said from the one is then not taken
61
+ * for what it would say from the other.
62
+ */
63
+ export function isTop(directory, top) {
64
+ return realSpelling(directory).split(sep).join('/') === top;
65
+ }
66
+ /** Whether a `.git` stands in `directory`, a repository's or the file that names one, as at the top of a work tree. */
67
+ export function holdsGit(directory) {
68
+ return existsSync(join(directory, '.git'));
69
+ }
56
70
  /**
57
71
  * A path as the repository names it - relative to the root, POSIX-separated,
58
72
  * real spelling - or `null` when it lies outside the root.
package/dist/fs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The edge where the harness meets the disk: the configuration, the state\n * directory outside the work tree, and paths as the filesystem spells them.\n */\n\nimport { existsSync, realpathSync, statSync } from 'node:fs';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\n\nimport { ConfigError, CONFIG_FILE, DEFAULT_CONFIG, parseConfig, type HarnessConfig } from './config.js';\n\n/** Reads `.spec-harness.json` at the root, or the defaults when there is none. */\nexport async function loadConfig(root: string): Promise<{ config: HarnessConfig; file: string | null }> {\n const file = join(root, CONFIG_FILE);\n if (!existsSync(file)) return { config: DEFAULT_CONFIG, file: null };\n let raw: unknown;\n try {\n // A Buffer parses as its text, so the encoding is equivalent to its mutant.\n raw = JSON.parse(await readFile(file, 'utf8'));\n } catch (error) {\n // A directory under the file's name is not JSON that went wrong, and\n // Node's words for it, EISDIR, are not the harness's.\n if ((error as NodeJS.ErrnoException).code === 'EISDIR') throw new ConfigError(`${CONFIG_FILE} is a directory, not a configuration file`);\n throw new ConfigError(`${CONFIG_FILE} is not valid JSON: ${(error as Error).message}`);\n }\n return { config: parseConfig(raw), file };\n}\n\n/**\n * The real spelling of a path: links resolved and, on a filesystem that\n * ignores case, the case the directory entries have. A path that does not\n * exist yet is resolved through its nearest existing ancestor.\n *\n * This is what stops `SRC/db/schema.ts` from walking past a protection on\n * `src/db/schema.ts` on Windows or macOS, where both name one file.\n */\nexport function realSpelling(path: string): string {\n const missing: string[] = [];\n let current = resolve(path);\n for (;;) {\n try {\n // join leaves a real path as it is, and reads a segment's leading\n // separator as the one between it and the last.\n return join(realpathSync.native(current), ...missing.reverse());\n } catch {\n const parent = dirname(current);\n // Only a root that does not exist fails at the top, a drive Windows\n // does not have; everywhere else the loop ends in the try.\n if (parent === current) return resolve(path);\n missing.push(current.slice(parent.length));\n current = parent;\n }\n }\n}\n\n/**\n * A path as the repository names it - relative to the root, POSIX-separated,\n * real spelling - or `null` when it lies outside the root.\n */\nexport function repositoryPath(given: string, root: string, cwd: string): string | null {\n const absolute = isAbsolute(given) ? given : resolve(cwd, given);\n const real = realSpelling(absolute);\n const realRoot = realSpelling(root);\n const rel = relative(realRoot, real);\n // `..env` at the root is inside it; only a `..` segment climbs out.\n if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) return null;\n return rel.split(sep).join('/');\n}\n\n/** The harness's own directory under the git common directory, created on demand (ADR-0003). */\nexport async function stateDirectory(commonDir: string, ...parts: string[]): Promise<string> {\n const directory = join(commonDir, 'spec-harness', ...parts);\n await mkdir(directory, { recursive: true });\n return directory;\n}\n\n/** Writes a file whole or not at all: a temporary file renamed over the target. */\nexport async function writeAtomic(file: string, content: string): Promise<void> {\n await mkdir(dirname(file), { recursive: true });\n const temporary = `${file}.${process.pid}.tmp`;\n // utf8 is writeFile's own default, so naming it is equivalent to its mutant.\n await writeFile(temporary, content, 'utf8');\n await rename(temporary, file);\n}\n\n/** A JSON object from a file: `null` when there is no file, `'unreadable'` when it holds anything else. */\nexport async function readJsonObject(file: string): Promise<Record<string, unknown> | null | 'unreadable'> {\n if (!existsSync(file)) return null;\n try {\n // A Buffer parses as its text, so the encoding is equivalent to its mutant.\n const value: unknown = JSON.parse(await readFile(file, 'utf8'));\n return typeof value === 'object' && value !== null && !Array.isArray(value) ? (value as Record<string, unknown>) : 'unreadable';\n } catch {\n return 'unreadable';\n }\n}\n\n/** Whether a path names a directory that is there; one that cannot be read names none. */\nexport function isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n // Each caller reads the answer with `!`, so the mutant that answers\n // nothing here is equivalent.\n return false;\n }\n}\n\nexport async function readText(file: string): Promise<string | null> {\n try {\n return await readFile(file, 'utf8');\n } catch {\n return null;\n }\n}\n"]}
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAE9E,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAC;AAExG,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACrE,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,4EAA4E;QAC5E,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qEAAqE;QACrE,sDAAsD;QACtD,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,WAAW,CAAC,GAAG,WAAW,2CAA2C,CAAC,CAAC;QACzI,MAAM,IAAI,WAAW,CAAC,GAAG,WAAW,uBAAwB,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,SAAS,CAAC;QACR,IAAI,CAAC;YACH,kEAAkE;YAClE,gDAAgD;YAChD,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YAChC,oEAAoE;YACpE,2DAA2D;YAC3D,IAAI,MAAM,KAAK,OAAO;gBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC3C,OAAO,GAAG,MAAM,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,SAAiB,EAAE,GAAW;IAClD,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;AAC9D,CAAC;AAED,uHAAuH;AACvH,MAAM,UAAU,QAAQ,CAAC,SAAiB;IACxC,OAAO,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY,EAAE,GAAW;IACrE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrC,oEAAoE;IACpE,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/E,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,SAAiB,EAAE,GAAG,KAAe;IACxE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC,CAAC;IAC5D,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAe;IAC7D,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IAC/C,6EAA6E;IAC7E,MAAM,SAAS,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,4EAA4E;QAC5E,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAChE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAiC,CAAC,CAAC,CAAC,YAAY,CAAC;IAClI,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,YAAY,CAAC;IACtB,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,8BAA8B;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY;IACzC,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["/**\n * The edge where the harness meets the disk: the configuration, the state\n * directory outside the work tree, and paths as the filesystem spells them.\n */\n\nimport { existsSync, realpathSync, statSync } from 'node:fs';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\n\nimport { ConfigError, CONFIG_FILE, DEFAULT_CONFIG, parseConfig, type HarnessConfig } from './config.js';\n\n/** Reads `.spec-harness.json` at the root, or the defaults when there is none. */\nexport async function loadConfig(root: string): Promise<{ config: HarnessConfig; file: string | null }> {\n const file = join(root, CONFIG_FILE);\n if (!existsSync(file)) return { config: DEFAULT_CONFIG, file: null };\n let raw: unknown;\n try {\n // A Buffer parses as its text, so the encoding is equivalent to its mutant.\n raw = JSON.parse(await readFile(file, 'utf8'));\n } catch (error) {\n // A directory under the file's name is not JSON that went wrong, and\n // Node's words for it, EISDIR, are not the harness's.\n if ((error as NodeJS.ErrnoException).code === 'EISDIR') throw new ConfigError(`${CONFIG_FILE} is a directory, not a configuration file`);\n throw new ConfigError(`${CONFIG_FILE} is not valid JSON: ${(error as Error).message}`);\n }\n return { config: parseConfig(raw), file };\n}\n\n/**\n * The real spelling of a path: links resolved and, on a filesystem that\n * ignores case, the case the directory entries have. A path that does not\n * exist yet is resolved through its nearest existing ancestor.\n *\n * This is what stops `SRC/db/schema.ts` from walking past a protection on\n * `src/db/schema.ts` on Windows or macOS, where both name one file.\n */\nexport function realSpelling(path: string): string {\n const missing: string[] = [];\n let current = resolve(path);\n for (;;) {\n try {\n // join leaves a real path as it is, and reads a segment's leading\n // separator as the one between it and the last.\n return join(realpathSync.native(current), ...missing.reverse());\n } catch {\n const parent = dirname(current);\n // Only a root that does not exist fails at the top, a drive Windows\n // does not have; everywhere else the loop ends in the try.\n if (parent === current) return resolve(path);\n missing.push(current.slice(parent.length));\n current = parent;\n }\n }\n}\n\n/**\n * Whether `directory` is the one git names as the top of a work tree: the\n * two spelled alike once the filesystem has spelled the directory, links\n * and short names resolved, as git spells a top. A spelling that differs is\n * read as another directory: what git said from the one is then not taken\n * for what it would say from the other.\n */\nexport function isTop(directory: string, top: string): boolean {\n return realSpelling(directory).split(sep).join('/') === top;\n}\n\n/** Whether a `.git` stands in `directory`, a repository's or the file that names one, as at the top of a work tree. */\nexport function holdsGit(directory: string): boolean {\n return existsSync(join(directory, '.git'));\n}\n\n/**\n * A path as the repository names it - relative to the root, POSIX-separated,\n * real spelling - or `null` when it lies outside the root.\n */\nexport function repositoryPath(given: string, root: string, cwd: string): string | null {\n const absolute = isAbsolute(given) ? given : resolve(cwd, given);\n const real = realSpelling(absolute);\n const realRoot = realSpelling(root);\n const rel = relative(realRoot, real);\n // `..env` at the root is inside it; only a `..` segment climbs out.\n if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) return null;\n return rel.split(sep).join('/');\n}\n\n/** The harness's own directory under the git common directory, created on demand (ADR-0003). */\nexport async function stateDirectory(commonDir: string, ...parts: string[]): Promise<string> {\n const directory = join(commonDir, 'spec-harness', ...parts);\n await mkdir(directory, { recursive: true });\n return directory;\n}\n\n/** Writes a file whole or not at all: a temporary file renamed over the target. */\nexport async function writeAtomic(file: string, content: string): Promise<void> {\n await mkdir(dirname(file), { recursive: true });\n const temporary = `${file}.${process.pid}.tmp`;\n // utf8 is writeFile's own default, so naming it is equivalent to its mutant.\n await writeFile(temporary, content, 'utf8');\n await rename(temporary, file);\n}\n\n/** A JSON object from a file: `null` when there is no file, `'unreadable'` when it holds anything else. */\nexport async function readJsonObject(file: string): Promise<Record<string, unknown> | null | 'unreadable'> {\n if (!existsSync(file)) return null;\n try {\n // A Buffer parses as its text, so the encoding is equivalent to its mutant.\n const value: unknown = JSON.parse(await readFile(file, 'utf8'));\n return typeof value === 'object' && value !== null && !Array.isArray(value) ? (value as Record<string, unknown>) : 'unreadable';\n } catch {\n return 'unreadable';\n }\n}\n\n/** Whether a path names a directory that is there; one that cannot be read names none. */\nexport function isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n // Each caller reads the answer with `!`, so the mutant that answers\n // nothing here is equivalent.\n return false;\n }\n}\n\nexport async function readText(file: string): Promise<string | null> {\n try {\n return await readFile(file, 'utf8');\n } catch {\n return null;\n }\n}\n"]}