@descent-vtt/spec-harness 0.20.0 → 0.21.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":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `spec-harness mcp`: the round's questions, served over the Model Context\n * Protocol on stdio (ADR-0008). The protocol is spec-core's `jsonrpc` module;\n * this file is the five tools, the four prompts, and nothing else. Every\n * request reads the repository afresh: a brief edited a minute ago is the\n * brief the next answer uses.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Readable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\n\nimport { describeMeasured } from './audit.js';\nimport { findActive } from './briefs.js';\nimport { briefIdFromBranch } from './branch.js';\nimport { titleOf } from './context.js';\nimport { createReader } from './reader.js';\nimport { realSpelling } from './fs.js';\nimport { buildContext, checkPaths, raiseEscalation, runAudit } from './round.js';\nimport type { EscalationOption } from './rulings.js';\nimport type { BriefRow } from './types.js';\nimport { emptyValue, isBlank, type ValuedOption } from './usage.js';\nimport {\n CLIENT_CAPABILITIES_KEY,\n createMcpServer,\n isObject,\n serveLines,\n toolError,\n unknownArguments,\n type JsonObject,\n type PromptDefinition,\n type ToolDefinition,\n type ToolOutcome,\n} from './vendor/spec-core/jsonrpc/index.js';\nimport { describeActive, findTree, foundCommonDir, mayBeElsewhere, openFound, openWorkspace, version, writesBy, type CliIO, type Options, type Workspace } from './workspace.js';\n\nconst reader = createReader();\n\nexport const INSTRUCTIONS =\n 'spec-harness keeps a round of work inside the brief a person approved. ' +\n 'Call start_round before working: it returns the brief, the scope you may write, what you must not touch, the rules in force and the documents the brief cites. ' +\n 'Call check_path before writing a file you are unsure of. A protected file needs a ruling: call request_escalation and stop until a person rules. ' +\n 'Call audit_round when the work is done, and fix what it reports; archiving is a person\\'s decision. ' +\n 'For the architecture rules themselves, spec-guard\\'s own server answers get_architectural_rules.';\n\nconst briefProperty = { type: 'string', description: 'The brief id. Omit to use the brief the branch or SPEC_BRIEF names; an empty id is refused.' };\nconst baseProperty = {\n type: 'string',\n description:\n 'The branch the round is measured from, whose allowed signers a ruling is verified against. Omit to use the configured base; an empty one is refused.',\n};\n\n/**\n * The tool error for an argument that is given and names nothing, in the\n * words the command line has for its option. Read as left out, an empty\n * `brief` was answered for the branch's brief and an empty `base` with no\n * ruling verified, and nothing told the agent that neither was the answer to\n * what it had asked.\n */\nfunction namesNothing(argument: string, option: ValuedOption, value: string): ToolOutcome {\n return toolError(`${emptyValue(`\"${argument}\"`, option, value)}.`);\n}\n\nconst directoryProperty = {\n type: 'string',\n description:\n \"A directory in the work tree the round is in, such as the worktree you work in. Omit to use the work tree the client's roots name, where they name one of this repository, or else the project's.\",\n};\n\n/**\n * The directories a client's roots name, or `null` where it declared no\n * roots, answered with an error, or did not answer in time.\n */\nexport type Roots = () => Promise<readonly string[] | null>;\n\n/** No client to ask: the tools as a caller of the package builds them, with no server around them. */\nconst NO_ROOTS: Roots = async () => null;\n\n/** How long a client is given to answer `roots/list`: Claude Code answers from what it holds (its MCP page, below). */\nexport const ROOTS_MS = 5_000;\n\n/**\n * The client's roots, asked as MCP has a server ask them, with a request of\n * the server's own, `roots/list`, where the client declared the capability\n * as it started: in its `initialize`, or a later request's `_meta`. Claude\n * Code's MCP page (https://code.claude.com/docs/en/mcp, Option 3: Add a local\n * stdio server, read 2026-10-19) has it answer with the session's launch\n * directory and every working directory added to it, and\n * `CLAUDE_PROJECT_DIR` the stable project root, which does not move with\n * them. The answer arrives on the input as a response, which the protocol's\n * module passes over: it is read here first, by the id it was asked under.\n */\nexport interface RootsClient {\n /** Reads a message before the protocol's handler does: `true` where it was the answer to a request of this one's, which is then no one else's. */\n observe(message: unknown): boolean;\n readonly ask: Roots;\n}\n\nexport function rootsClient(write: (line: string) => void, limit = ROOTS_MS): RootsClient {\n let declared = false;\n let asked = 0;\n const waiting = new Map<string, (answer: unknown) => void>();\n const declares = (capabilities: unknown): boolean => isObject(capabilities) && isObject(capabilities['roots']);\n return {\n observe(message) {\n if (!isObject(message)) return false;\n const params = isObject(message['params']) ? message['params'] : {};\n const meta = isObject(params['_meta']) ? params['_meta'] : {};\n if ((message['method'] === 'initialize' && declares(params['capabilities'])) || declares(meta[CLIENT_CAPABILITIES_KEY])) declared = true;\n const id = message['id'];\n // The server's requests have strings for ids, so one that is no string\n // finds nothing waiting either way: the mutant that drops the test is\n // equivalent.\n const settle = typeof id === 'string' && message['method'] === undefined ? waiting.get(id) : undefined;\n if (settle === undefined) return false;\n settle(message);\n return true;\n },\n async ask() {\n if (!declared) return null;\n asked += 1;\n const id = `spec-harness-roots-${asked}`;\n const answer = await new Promise<unknown>((settled) => {\n const timer = setTimeout(() => settled(null), limit);\n waiting.set(id, (message) => {\n clearTimeout(timer);\n settled(message);\n });\n write(JSON.stringify({ jsonrpc: '2.0', id, method: 'roots/list' }));\n });\n waiting.delete(id);\n const result = isObject(answer) ? answer['result'] : undefined;\n const roots = isObject(result) ? result['roots'] : undefined;\n if (!Array.isArray(roots)) return null;\n // A root is a `file:` URI, by the protocol; Node refuses one of any other scheme, which names no directory here.\n return roots.flatMap((root: unknown) => {\n const uri = isObject(root) ? root['uri'] : undefined;\n if (typeof uri !== 'string') return [];\n try {\n return [fileURLToPath(uri)];\n } catch {\n return [];\n }\n });\n },\n };\n}\n\n/** Where a tool reads the round: the work tree, and what named it. */\ninterface Chosen {\n readonly workspace: Workspace;\n readonly from: 'argument' | 'roots' | 'server';\n}\n\n/**\n * The work tree of the server's repository that holds a directory: the\n * server's own where it is in that, with no `.git` between, and otherwise the\n * one git names, where it shares the git directory the server's repository\n * keeps; `null` where the directory is in another repository, or in none.\n */\nasync function treeOf(server: Workspace, io: CliIO, directory: string): Promise<Workspace | null> {\n // Asked anyway, git names the server's own top for a directory in it,\n // which answers the server's own below: the mutant that always asks is\n // equivalent, at a process's cost.\n if (!mayBeElsewhere(directory, server.root)) return server;\n const found = await findTree(directory);\n if (found === null) return null;\n // Its own work tree, opened again, reads every answer the same way: the\n // check saves a start of git, and its mutant is equivalent.\n if (realSpelling(found.root) === realSpelling(server.root)) return server;\n const common = await foundCommonDir(found);\n // git names a common directory wherever it names a top, so `null` is there for the type.\n if (common === null || realSpelling(common) !== realSpelling(server.commonDir)) return null;\n return openFound(found, io, () => [server.root]);\n}\n\n/**\n * The work tree a tool that reads a branch reads the round in (ADR-0008):\n * the one a `directory` given names; where none is given, the one the\n * client's roots name, where they name one work tree of this repository and\n * no other; and the server's own otherwise, as before. The server is started\n * once, for the project Claude Code names, and a session in a worktree\n * names that worktree to it in neither the project nor the server's root.\n */\nasync function chosen(server: Workspace, io: CliIO, roots: Roots, given: unknown): Promise<Chosen | ToolOutcome> {\n if (given !== undefined) {\n if (typeof given !== 'string') return toolError('\"directory\" must be a string.');\n if (isBlank(given)) return toolError(`\"directory\" is ${JSON.stringify(given)}, which names no directory; give it the directory the round is in, or leave it out.`);\n const workspace = await treeOf(server, io, resolve(server.root, given));\n if (workspace === null) return toolError(`\"directory\" is ${JSON.stringify(given)}, which is in no work tree of this repository; give a directory in the project or in one of its worktrees, or leave it out.`);\n return { workspace, from: 'argument' };\n }\n const named = await roots();\n if (named !== null) {\n const trees = new Map<string, Workspace>();\n for (const directory of named) {\n const workspace = await treeOf(server, io, directory);\n if (workspace !== null) trees.set(realSpelling(workspace.root), workspace);\n }\n const [only, ...more] = [...trees.values()];\n if (only !== undefined && more.length === 0) return { workspace: only, from: 'roots' };\n }\n return { workspace: server, from: 'server' };\n}\n\n/** What a tool's answer says of the work tree it read: always in its structured part, and in its text where it is not the server's own. */\nfunction readIn(where: Chosen): { readonly said: string; readonly workTree: JsonObject } {\n const how = where.from === 'argument' ? 'the \"directory\" given' : \"the client's roots\";\n return { said: where.from === 'server' ? '' : `\\n\\nRead in the work tree at ${where.workspace.root}, which ${how} name.`, workTree: { root: where.workspace.root, from: where.from } };\n}\n\n/** The `base` argument, or the tool error for one that is not a string, or names no commit. */\nfunction baseOf(args: JsonObject): { base: string | undefined } | ToolOutcome {\n const base = args['base'];\n if (base !== undefined && typeof base !== 'string') return toolError('\"base\" must be a string.');\n if (base !== undefined && isBlank(base)) return namesNothing('base', 'base', base);\n return { base };\n}\n\n/** The `paths` argument, or the tool error for one that is no list of files, or has a place that names none. */\nfunction pathsOf(args: JsonObject): { paths: string[] } | ToolOutcome {\n const paths = args['paths'];\n if (!Array.isArray(paths) || !paths.every((p) => typeof p === 'string') || paths.length === 0) {\n return toolError('\"paths\" must be a non-empty array of strings.');\n }\n const empty = paths.findIndex(isBlank);\n if (empty !== -1) return namesNothing(`paths[${empty}]`, 'path', paths[empty] as string);\n return { paths };\n}\n\n/**\n * The `options` argument as the memo's choices, or the tool error for one\n * the memo cannot be written with: a choice is its label, and one without\n * was written as a number and two empty stars. What a choice costs may be\n * left out, and the memo then gives the choice alone.\n */\nfunction optionsOf(args: JsonObject): { options: EscalationOption[] } | ToolOutcome {\n const raw = args['options'] ?? [];\n if (!Array.isArray(raw)) return toolError('\"options\" must be an array.');\n const options: EscalationOption[] = [];\n for (const [index, item] of raw.entries()) {\n // An item that is no object has no label, and is refused for that.\n const entry: JsonObject = item ?? {};\n const label = entry['label'];\n const consequence = entry['consequence'] ?? '';\n if (typeof label !== 'string') return toolError(`\"options[${index}].label\" must be a string.`);\n if (isBlank(label)) return toolError(`\"options[${index}].label\" is ${JSON.stringify(label)}, which names no choice; give the option a label, or leave the option out.`);\n if (typeof consequence !== 'string') return toolError(`\"options[${index}].consequence\" must be a string.`);\n options.push({ label: label.trim(), consequence: consequence.trim() });\n }\n return { options };\n}\n\nasync function round(workspace: Workspace, env: CliIO['env'], id: unknown): Promise<{ brief: BriefRow; briefs: BriefRow[] } | ToolOutcome> {\n if (id !== undefined && typeof id !== 'string') return toolError('\"brief\" must be a string.');\n if (id !== undefined && isBlank(id)) return namesNothing('brief', 'brief', id);\n const briefs = await workspace.siblings.briefs();\n const fromBranch = briefIdFromBranch(workspace.config.branches, workspace.branch);\n const active = findActive(briefs, { argument: id, environment: env['SPEC_BRIEF'], branch: fromBranch });\n // Named as every argument of a tool is, where it was called the flag, and\n // a tool call has none.\n const { brief, note, problem } = describeActive(active, '\"brief\"');\n if (problem !== null) return toolError(problem);\n if (brief === null) return toolError(note);\n return { brief, briefs };\n}\n\nexport function tools(workspace: Workspace, env: CliIO['env'], roots: Roots = NO_ROOTS): ToolDefinition[] {\n const readOnly = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };\n // A tool writes nothing to the server's streams, so these are never\n // written to, and their mutants are equivalent: what a tool says is its\n // answer.\n const quiet = { write: (): boolean => true };\n const io: CliIO = { stdout: quiet, stderr: quiet, cwd: workspace.cwd, env };\n return [\n {\n descriptor: {\n name: 'start_round',\n title: 'Start a round',\n description:\n 'Everything needed to start the round: the brief in full, the files it may write and must not change, signed rulings, the briefs it depends on, the architecture rules in force for its scope, and the documents it cites.',\n inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty, directory: directoryProperty }, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['brief', 'base', 'directory']);\n if (unknown) return unknown;\n const base = baseOf(args);\n if ('text' in base) return base;\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const found = await round(where.workspace, env, args['brief']);\n if ('text' in found) return found;\n const packet = await buildContext(where.workspace, found.brief, found.briefs, reader, base.base);\n const { said, workTree } = readIn(where);\n return {\n text: `${packet.markdown}${said}`,\n structured: {\n workTree,\n brief: found.brief.id,\n included: [...packet.included],\n omitted: [...packet.omitted],\n unresolved: [...packet.unresolved],\n unclosedFrontMatter: [...packet.unclosedFrontMatter],\n unreadableFrontMatter: [...packet.unreadableFrontMatter],\n unreadableScope: [...packet.unreadableScope],\n unreadableProtections: [...packet.unreadableProtections],\n unreadableRulingPaths: [...packet.unreadableRulingPaths],\n unmatchedSpecs: [...packet.unmatchedSpecs],\n },\n };\n },\n },\n {\n descriptor: {\n name: 'check_path',\n title: 'May the round write these files',\n description:\n 'For each path: allowed (in scope, or covered by a signed ruling), outside the scope, or refused (protected by the brief). Works for files that do not exist yet.',\n inputSchema: {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: 'Paths relative to the top of the work tree the round is in, or absolute; an absolute one in another work tree of this repository is decided by that one. An empty one is refused.',\n },\n brief: briefProperty,\n base: baseProperty,\n directory: directoryProperty,\n },\n required: ['paths'],\n additionalProperties: false,\n },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['paths', 'brief', 'base', 'directory']);\n if (unknown) return unknown;\n const given = pathsOf(args);\n if ('text' in given) return given;\n const base = baseOf(args);\n if ('text' in base) return base;\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n // Each path by the work tree of this repository that holds it, as the\n // hook decides a write: the one read, another, or the server's own.\n const decisions = [];\n for (const part of await writesBy(workspace, where.workspace.root, given.paths, io)) {\n const found = await round(part.workspace, env, args['brief']);\n if ('text' in found) return found;\n decisions.push(...(await checkPaths(part.workspace, found.brief, undefined, part.paths, where.workspace.root, reader, base.base)));\n }\n const text = decisions.map((d) => `${d.verdict}: ${d.message}${d.verdict === 'allow' ? '' : `. Next: ${d.hint}`}`).join('\\n');\n const { said, workTree } = readIn(where);\n return { text: `${text}${said}`, structured: { workTree, decisions: decisions.map((d) => ({ ...d })) } };\n },\n },\n {\n descriptor: {\n name: 'request_escalation',\n title: 'Ask a person to rule',\n description:\n 'When the round cannot be finished without changing something the brief protects, record the request and stop. A person reads the memo and rules; only a ruling they sign lets the change through.',\n inputSchema: {\n type: 'object',\n properties: {\n paths: { type: 'array', items: { type: 'string' }, description: 'The protected files the round needs to change. An empty one is refused.' },\n reason: { type: 'string', description: 'Why the round cannot be done without them. It is required, and may not be empty.' },\n options: {\n type: 'array',\n items: { type: 'object', properties: { label: { type: 'string' }, consequence: { type: 'string' } }, required: ['label', 'consequence'] },\n description: 'The choices the person has, each with what it costs. A choice whose label is empty is refused.',\n },\n recommendation: { type: 'string', description: 'Which option you recommend, and why. Omit it when there is none: an empty one is refused.' },\n brief: briefProperty,\n directory: directoryProperty,\n },\n required: ['paths', 'reason'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['paths', 'reason', 'options', 'recommendation', 'brief', 'directory']);\n if (unknown) return unknown;\n // Every part of the memo before anything is written: a person rules\n // on what it says, and cannot rule on a part that says nothing.\n const given = pathsOf(args);\n if ('text' in given) return given;\n const reason = args['reason'];\n if (typeof reason !== 'string' || isBlank(reason)) return toolError('\"reason\" is required.');\n const choices = optionsOf(args);\n if ('text' in choices) return choices;\n const recommendation = args['recommendation'];\n if (recommendation !== undefined && typeof recommendation !== 'string') return toolError('\"recommendation\" must be a string.');\n if (recommendation !== undefined && isBlank(recommendation)) return namesNothing('recommendation', 'recommend', recommendation);\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const found = await round(where.workspace, env, args['brief']);\n if ('text' in found) return found;\n const { request, memo } = await raiseEscalation(where.workspace, found.brief, {\n paths: given.paths,\n reason,\n options: choices.options,\n recommendation: recommendation ?? null,\n });\n const { said, workTree } = readIn(where);\n return { text: `${memo}\\nStop here until a person rules on ${request.id}.${said}`, structured: { id: request.id, workTree } };\n },\n },\n {\n descriptor: {\n name: 'audit_round',\n title: 'Audit the round',\n description:\n 'Did the round stay inside the lines: what the archive would refuse (open boxes, protected files, files outside the scope), the brief\\'s own assertions, unverified rulings, every dependency added and every package allowed to run install scripts.',\n inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty, directory: directoryProperty }, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['brief', 'base', 'directory']);\n if (unknown) return unknown;\n const base = baseOf(args);\n if ('text' in base) return base;\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const found = await round(where.workspace, env, args['brief']);\n if ('text' in found) return found;\n const result = await runAudit(where.workspace, found.brief, reader, base.base);\n const { counts, findings, measured } = result.report;\n // What was measured beside what was found: \"nothing found\" from an\n // audit that ran no goal is not a round that is done.\n const text =\n findings.length === 0\n ? 'The audit found nothing in what it measured.'\n : findings.map((f) => `${f.severity} ${f.rule}: ${f.message}. Next: ${f.hint}`).join('\\n');\n const { said, workTree } = readIn(where);\n return {\n text: `${text}\\n\\n${describeMeasured(measured)}\\n\\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)${said}`,\n structured: { workTree, counts, measured: { ...measured }, findings: findings.map((f) => ({ ...f })) },\n };\n },\n },\n {\n descriptor: {\n name: 'list_rounds',\n title: 'List the rounds',\n description: 'The live briefs: status, wave, what each waits on, and which are ready to start.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, []);\n if (unknown) return unknown;\n const live = (await workspace.siblings.briefs()).filter((brief) => brief.phase === 'live');\n const text = live\n .map((b) => `${[b.id, titleOf(b)].filter((part) => part !== null).join(' ')} - ${b.status ?? 'unknown'}, wave ${b.wave ?? '-'}, ${b.ready ? 'ready' : `waits on ${b.waitingOn.join(', ')}`}`)\n .join('\\n');\n return { text: text === '' ? 'No live brief.' : text, structured: { briefs: live.map((b) => ({ ...b, title: titleOf(b) })) } };\n },\n },\n ];\n}\n\nconst SKILLS: readonly { name: string; title: string; argument: string; description: string }[] = [\n { name: 'draft-brief', title: 'Draft a brief', argument: 'request', description: 'What the round should achieve, in the person\\'s words.' },\n { name: 'split-goal', title: 'Split a goal into rounds', argument: 'goal', description: 'The goal to split.' },\n { name: 'run-round', title: 'Run a round', argument: 'brief', description: 'The brief id.' },\n { name: 'close-round', title: 'Close a round', argument: 'brief', description: 'The brief id.' },\n];\n\nfunction skillText(name: string): string {\n // The package ships the skills beside dist/ (package.json's files), so one\n // that cannot be read is a broken install, and the request fails saying so\n // rather than serving an empty prompt.\n const text = readFileSync(fileURLToPath(new URL(`../skills/${name}/SKILL.md`, import.meta.url)), 'utf8');\n // Every skill opens with its front matter (tests/source.test.ts), so the\n // anchor is equivalent to its mutant here.\n return text.replace(/^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n/, '').trim();\n}\n\nexport function prompts(): PromptDefinition[] {\n return SKILLS.map((skill) => ({\n descriptor: {\n name: skill.name,\n title: skill.title,\n arguments: [{ name: skill.argument, description: skill.description, required: false }],\n },\n async get(args: Readonly<Record<string, string>>): Promise<JsonObject> {\n const given = args[skill.argument];\n const text = `${skillText(skill.name)}${given === undefined || given === '' ? '' : `\\n\\n${skill.argument}: ${given}`}`;\n return { description: skill.title, messages: [{ role: 'user', content: { type: 'text', text } }] };\n },\n }));\n}\n\nexport async function mcpCommand(options: Options, io: CliIO): Promise<number> {\n // Claude Code starts a plugin's server in the plugin's directory, and names\n // the project in CLAUDE_PROJECT_DIR; the server answers for the project.\n const workspace = await openWorkspace({ ...options, root: options.root ?? (io.env['CLAUDE_PROJECT_DIR'] || undefined) }, io);\n const write = (line: string): void => {\n io.stdout.write(`${line}\\n`);\n };\n // The work tree a session is in, where its client names it (ADR-0008).\n const roots = rootsClient(write);\n const handle = createMcpServer({ name: 'spec-harness', version: version(), instructions: INSTRUCTIONS, tools: tools(workspace, io.env, roots.ask), prompts: prompts() });\n // A session handed over whole, as a test hands it, is served as a client\n // would stream it on stdin. Only the built command line serves\n // process.stdin, and the suite spawns it from dist/, outside the sweep\n // (tests/integration/mcp.test.ts), so a mutant that ignores it survives.\n const input = io.stdin === undefined ? process.stdin : Readable.from([Buffer.from(await io.stdin())]);\n await serveLines(input, write, async (message) => (roots.observe(message) ? null : handle(message)));\n return 0;\n}\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `spec-harness mcp`: the round's questions, served over the Model Context\n * Protocol on stdio (ADR-0008). The protocol is spec-core's `jsonrpc` module;\n * this file is the five tools, the four prompts, and nothing else. Every\n * request reads the repository afresh: a brief edited a minute ago is the\n * brief the next answer uses.\n */\n\nimport { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { Readable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\n\nimport { describeMeasured } from './audit.js';\nimport { findActive, type ActiveBrief } from './briefs.js';\nimport { briefIdFromBranch } from './branch.js';\nimport { titleOf } from './context.js';\nimport { createReader } from './reader.js';\nimport { outsideEvery, realSpelling } from './fs.js';\nimport { heldBy, type Decision } from './guard.js';\nimport { buildContext, checkPaths, raiseEscalation, runAudit } from './round.js';\nimport type { EscalationOption } from './rulings.js';\nimport type { BriefRow } from './types.js';\nimport { emptyValue, isBlank, type ValuedOption } from './usage.js';\nimport {\n CLIENT_CAPABILITIES_KEY,\n createMcpServer,\n isObject,\n serveLines,\n toolError,\n unknownArguments,\n type JsonObject,\n type PromptDefinition,\n type ToolDefinition,\n type ToolOutcome,\n} from './vendor/spec-core/jsonrpc/index.js';\nimport { describeActive, findTree, foundCommonDir, mayBeElsewhere, namedId, openFound, openWorkspace, version, writesBy, type CliIO, type Options, type Workspace } from './workspace.js';\n\nconst reader = createReader();\n\nexport const INSTRUCTIONS =\n 'spec-harness keeps a round of work inside the brief a person approved. ' +\n 'Call start_round before working: it returns the brief, the scope you may write, what you must not touch, the rules in force and the documents the brief cites. ' +\n 'Call check_path before writing a file you are unsure of. A protected file needs a ruling: call request_escalation and stop until a person rules. ' +\n 'Call audit_round when the work is done, and fix what it reports; archiving is a person\\'s decision. ' +\n 'For the architecture rules themselves, spec-guard\\'s own server answers get_architectural_rules.';\n\nconst briefProperty = { type: 'string', description: 'The brief id. Omit to use the brief the branch or SPEC_BRIEF names; an empty id is refused.' };\nconst baseProperty = {\n type: 'string',\n description:\n 'The branch the round is measured from, whose allowed signers a ruling is verified against. Omit to use the configured base; an empty one is refused.',\n};\n\n/**\n * The tool error for an argument that is given and names nothing, in the\n * words the command line has for its option. Read as left out, an empty\n * `brief` was answered for the branch's brief and an empty `base` with no\n * ruling verified, and nothing told the agent that neither was the answer to\n * what it had asked.\n */\nfunction namesNothing(argument: string, option: ValuedOption, value: string): ToolOutcome {\n return toolError(`${emptyValue(`\"${argument}\"`, option, value)}.`);\n}\n\nconst directoryProperty = {\n type: 'string',\n description:\n \"A directory in the work tree the round is in, such as the worktree you work in. Omit to use the work tree the client's roots name, where they name one of this repository, or else the project's.\",\n};\n\n/**\n * The directories a client's roots name, or `null` where it declared no\n * roots, answered with an error, or did not answer in time.\n */\nexport type Roots = () => Promise<readonly string[] | null>;\n\n/** No client to ask: the tools as a caller of the package builds them, with no server around them. */\nconst NO_ROOTS: Roots = async () => null;\n\n/** How long a client is given to answer `roots/list`: Claude Code answers from what it holds (its MCP page, below). */\nexport const ROOTS_MS = 5_000;\n\n/**\n * The client's roots, asked as MCP has a server ask them, with a request of\n * the server's own, `roots/list`, where the client declared the capability\n * as it started: in its `initialize`, or a later request's `_meta`. Claude\n * Code's MCP page (https://code.claude.com/docs/en/mcp, Option 3: Add a local\n * stdio server, read 2026-10-19) has it answer with the session's launch\n * directory and every working directory added to it, and\n * `CLAUDE_PROJECT_DIR` the stable project root, which does not move with\n * them. The answer arrives on the input as a response, which the protocol's\n * module passes over: it is read here first, by the id it was asked under.\n */\nexport interface RootsClient {\n /** Reads a message before the protocol's handler does: `true` where it was the answer to a request of this one's, which is then no one else's. */\n observe(message: unknown): boolean;\n readonly ask: Roots;\n}\n\nexport function rootsClient(write: (line: string) => void, limit = ROOTS_MS): RootsClient {\n let declared = false;\n let asked = 0;\n const waiting = new Map<string, (answer: unknown) => void>();\n const declares = (capabilities: unknown): boolean => isObject(capabilities) && isObject(capabilities['roots']);\n return {\n observe(message) {\n if (!isObject(message)) return false;\n const params = isObject(message['params']) ? message['params'] : {};\n const meta = isObject(params['_meta']) ? params['_meta'] : {};\n if ((message['method'] === 'initialize' && declares(params['capabilities'])) || declares(meta[CLIENT_CAPABILITIES_KEY])) declared = true;\n const id = message['id'];\n // The server's requests have strings for ids, so one that is no string\n // finds nothing waiting either way: the mutant that drops the test is\n // equivalent.\n const settle = typeof id === 'string' && message['method'] === undefined ? waiting.get(id) : undefined;\n if (settle === undefined) return false;\n settle(message);\n return true;\n },\n async ask() {\n if (!declared) return null;\n asked += 1;\n const id = `spec-harness-roots-${asked}`;\n const answer = await new Promise<unknown>((settled) => {\n const timer = setTimeout(() => settled(null), limit);\n waiting.set(id, (message) => {\n clearTimeout(timer);\n settled(message);\n });\n write(JSON.stringify({ jsonrpc: '2.0', id, method: 'roots/list' }));\n });\n waiting.delete(id);\n const result = isObject(answer) ? answer['result'] : undefined;\n const roots = isObject(result) ? result['roots'] : undefined;\n if (!Array.isArray(roots)) return null;\n // A root is a `file:` URI, by the protocol; Node refuses one of any other scheme, which names no directory here.\n return roots.flatMap((root: unknown) => {\n const uri = isObject(root) ? root['uri'] : undefined;\n if (typeof uri !== 'string') return [];\n try {\n return [fileURLToPath(uri)];\n } catch {\n return [];\n }\n });\n },\n };\n}\n\n/** Where a tool reads the round: the work tree, and what named it. */\ninterface Chosen {\n readonly workspace: Workspace;\n readonly from: 'argument' | 'roots' | 'server';\n}\n\n/**\n * The work tree of the server's repository that holds a directory: the\n * server's own where it is in that, with no `.git` between, and otherwise the\n * one git names, where it shares the git directory the server's repository\n * keeps; `null` where the directory is in another repository, or in none.\n */\nasync function treeOf(server: Workspace, io: CliIO, directory: string): Promise<Workspace | null> {\n // Asked anyway, git names the server's own top for a directory in it,\n // which answers the server's own below: the mutant that always asks is\n // equivalent, at a process's cost.\n if (!mayBeElsewhere(directory, server.root)) return server;\n const found = await findTree(directory);\n if (found === null) return null;\n // Its own work tree, opened again, reads every answer the same way: the\n // check saves a start of git, and its mutant is equivalent.\n if (realSpelling(found.root) === realSpelling(server.root)) return server;\n const common = await foundCommonDir(found);\n // git names a common directory wherever it names a top, so `null` is there for the type.\n if (common === null || realSpelling(common) !== realSpelling(server.commonDir)) return null;\n return openFound(found, io, () => [server.root]);\n}\n\n/**\n * The work tree a tool that reads a branch reads the round in (ADR-0008):\n * the one a `directory` given names; where none is given, the one the\n * client's roots name, where they name one work tree of this repository and\n * no other; and the server's own otherwise, as before. The server is started\n * once, for the project Claude Code names, and a session in a worktree\n * names that worktree to it in neither the project nor the server's root.\n */\nasync function chosen(server: Workspace, io: CliIO, roots: Roots, given: unknown): Promise<Chosen | ToolOutcome> {\n if (given !== undefined) {\n if (typeof given !== 'string') return toolError('\"directory\" must be a string.');\n if (isBlank(given)) return toolError(`\"directory\" is ${JSON.stringify(given)}, which names no directory; give it the directory the round is in, or leave it out.`);\n const workspace = await treeOf(server, io, resolve(server.root, given));\n if (workspace === null) return toolError(`\"directory\" is ${JSON.stringify(given)}, which is in no work tree of this repository; give a directory in the project or in one of its worktrees, or leave it out.`);\n return { workspace, from: 'argument' };\n }\n const named = await roots();\n if (named !== null) {\n const trees = new Map<string, Workspace>();\n for (const directory of named) {\n const workspace = await treeOf(server, io, directory);\n if (workspace !== null) trees.set(realSpelling(workspace.root), workspace);\n }\n const [only, ...more] = [...trees.values()];\n if (only !== undefined && more.length === 0) return { workspace: only, from: 'roots' };\n }\n return { workspace: server, from: 'server' };\n}\n\n/** What a tool's answer says of the work tree it read: always in its structured part, and in its text where it is not the server's own. */\nfunction readIn(where: Chosen): { readonly said: string; readonly workTree: JsonObject } {\n const how = where.from === 'argument' ? 'the \"directory\" given' : \"the client's roots\";\n return { said: where.from === 'server' ? '' : `\\n\\nRead in the work tree at ${where.workspace.root}, which ${how} name.`, workTree: { root: where.workspace.root, from: where.from } };\n}\n\n/** The `base` argument, or the tool error for one that is not a string, or names no commit. */\nfunction baseOf(args: JsonObject): { base: string | undefined } | ToolOutcome {\n const base = args['base'];\n if (base !== undefined && typeof base !== 'string') return toolError('\"base\" must be a string.');\n if (base !== undefined && isBlank(base)) return namesNothing('base', 'base', base);\n return { base };\n}\n\n/** The `paths` argument, or the tool error for one that is no list of files, or has a place that names none. */\nfunction pathsOf(args: JsonObject): { paths: string[] } | ToolOutcome {\n const paths = args['paths'];\n if (!Array.isArray(paths) || !paths.every((p) => typeof p === 'string') || paths.length === 0) {\n return toolError('\"paths\" must be a non-empty array of strings.');\n }\n const empty = paths.findIndex(isBlank);\n if (empty !== -1) return namesNothing(`paths[${empty}]`, 'path', paths[empty] as string);\n return { paths };\n}\n\n/**\n * The `options` argument as the memo's choices, or the tool error for one\n * the memo cannot be written with: a choice is its label, and one without\n * was written as a number and two empty stars. What a choice costs may be\n * left out, and the memo then gives the choice alone.\n */\nfunction optionsOf(args: JsonObject): { options: EscalationOption[] } | ToolOutcome {\n const raw = args['options'] ?? [];\n if (!Array.isArray(raw)) return toolError('\"options\" must be an array.');\n const options: EscalationOption[] = [];\n for (const [index, item] of raw.entries()) {\n // An item that is no object has no label, and is refused for that.\n const entry: JsonObject = item ?? {};\n const label = entry['label'];\n const consequence = entry['consequence'] ?? '';\n if (typeof label !== 'string') return toolError(`\"options[${index}].label\" must be a string.`);\n if (isBlank(label)) return toolError(`\"options[${index}].label\" is ${JSON.stringify(label)}, which names no choice; give the option a label, or leave the option out.`);\n if (typeof consequence !== 'string') return toolError(`\"options[${index}].consequence\" must be a string.`);\n options.push({ label: label.trim(), consequence: consequence.trim() });\n }\n return { options };\n}\n\nasync function round(workspace: Workspace, env: CliIO['env'], id: unknown): Promise<{ brief: BriefRow; briefs: BriefRow[] } | ToolOutcome> {\n if (id !== undefined && typeof id !== 'string') return toolError('\"brief\" must be a string.');\n if (id !== undefined && isBlank(id)) return namesNothing('brief', 'brief', id);\n const briefs = await workspace.siblings.briefs();\n const fromBranch = briefIdFromBranch(workspace.config.branches, workspace.branch);\n const active = findActive(briefs, { argument: id, environment: env['SPEC_BRIEF'], branch: fromBranch });\n // Named as every argument of a tool is, where it was called the flag, and\n // a tool call has none.\n const { brief, note, problem } = describeActive(active, '\"brief\"');\n if (problem !== null) return toolError(problem);\n if (brief === null) return toolError(note);\n return { brief, briefs };\n}\n\n/**\n * The brief the argument, `SPEC_BRIEF` or the branch names, as the hook\n * finds it: where nothing names one, spec-brief is not asked, and the answer\n * is no brief whatever spec-brief would say (ADR-0004), so the empty list is\n * equivalent to its mutant.\n */\nasync function namedBrief(workspace: Workspace, env: CliIO['env'], id: string | undefined): Promise<ActiveBrief> {\n if (namedId(workspace, { brief: id }, env) === null) return findActive([], {});\n const briefs = await workspace.siblings.briefs();\n return findActive(briefs, { argument: id, environment: env['SPEC_BRIEF'], branch: briefIdFromBranch(workspace.config.branches, workspace.branch) });\n}\n\n/**\n * Each path as the hook decides a write of it alone (ADR-0005, ADR-0008): one\n * outside every work tree of the repository as a file outside it, with no\n * brief asked about, whatever names one; the rest by the brief named, with\n * no brief where nothing names one, and held, in the hook's words, where\n * what names it names none a round can work under. spec-brief is asked only\n * where a path is inside, as the hook asks it.\n */\nasync function asTheHook(workspace: Workspace, env: CliIO['env'], id: string | undefined, paths: readonly string[], cwd: string, base: string | undefined): Promise<Decision[]> {\n const outside = paths.map((path) => outsideEvery([path], workspace.root, workspace.commonDir, cwd));\n // Paths all outside ask about no brief, and are answered as with none\n // named: the empty list is equivalent to its mutant, as in namedBrief.\n const { brief, note, problem } = describeActive(outside.every((each) => each) ? findActive([], {}) : await namedBrief(workspace, env, id), '\"brief\"');\n if (problem === null) return checkPaths(workspace, brief, note, paths, cwd, reader, base);\n // Decided by no brief, a path outside is decided as outside the\n // repository, and one inside is held, named as the repository names it.\n const decided = await checkPaths(workspace, null, undefined, paths, cwd, reader, base);\n return decided.map((decision, at) => (outside[at] ? decision : heldBy(decision.path, problem)));\n}\n\nexport function tools(workspace: Workspace, env: CliIO['env'], roots: Roots = NO_ROOTS): ToolDefinition[] {\n const readOnly = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };\n // A tool writes nothing to the server's streams, so these are never\n // written to, and their mutants are equivalent: what a tool says is its\n // answer.\n const quiet = { write: (): boolean => true };\n const io: CliIO = { stdout: quiet, stderr: quiet, cwd: workspace.cwd, env };\n return [\n {\n descriptor: {\n name: 'start_round',\n title: 'Start a round',\n description:\n 'Everything needed to start the round: the brief in full, the files it may write and must not change, signed rulings, the briefs it depends on, the architecture rules in force for its scope, and the documents it cites.',\n inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty, directory: directoryProperty }, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['brief', 'base', 'directory']);\n if (unknown) return unknown;\n const base = baseOf(args);\n if ('text' in base) return base;\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const found = await round(where.workspace, env, args['brief']);\n if ('text' in found) return found;\n const packet = await buildContext(where.workspace, found.brief, found.briefs, reader, base.base);\n const { said, workTree } = readIn(where);\n return {\n text: `${packet.markdown}${said}`,\n structured: {\n workTree,\n brief: found.brief.id,\n included: [...packet.included],\n omitted: [...packet.omitted],\n unresolved: [...packet.unresolved],\n unclosedFrontMatter: [...packet.unclosedFrontMatter],\n unreadableFrontMatter: [...packet.unreadableFrontMatter],\n unreadableScope: [...packet.unreadableScope],\n unreadableProtections: [...packet.unreadableProtections],\n unreadableRulingPaths: [...packet.unreadableRulingPaths],\n unmatchedSpecs: [...packet.unmatchedSpecs],\n },\n };\n },\n },\n {\n descriptor: {\n name: 'check_path',\n title: 'May the round write these files',\n description:\n 'For each path, as the guard hook decides a write of it: allowed (in scope, covered by a signed ruling, outside every work tree of the repository, or with no brief named), outside the scope, or refused (protected by the brief, or held where what names the brief names none a round can work under). Works for files that do not exist yet.',\n inputSchema: {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: 'Paths relative to the top of the work tree the round is in, or absolute; an absolute one in another work tree of this repository is decided by that one. An empty one is refused.',\n },\n brief: briefProperty,\n base: baseProperty,\n directory: directoryProperty,\n },\n required: ['paths'],\n additionalProperties: false,\n },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['paths', 'brief', 'base', 'directory']);\n if (unknown) return unknown;\n const given = pathsOf(args);\n if ('text' in given) return given;\n const base = baseOf(args);\n if ('text' in base) return base;\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const id = args['brief'];\n if (id !== undefined && typeof id !== 'string') return toolError('\"brief\" must be a string.');\n if (id !== undefined && isBlank(id)) return namesNothing('brief', 'brief', id);\n // Each path by the work tree of this repository that holds it, as the\n // hook decides a write: the one read, another, or the server's own.\n const decisions: Decision[] = [];\n for (const part of await writesBy(workspace, where.workspace.root, given.paths, io)) {\n decisions.push(...(await asTheHook(part.workspace, env, id, part.paths, where.workspace.root, base.base)));\n }\n const text = decisions.map((d) => `${d.verdict}: ${d.message}${d.verdict === 'allow' ? '' : `. Next: ${d.hint}`}`).join('\\n');\n const { said, workTree } = readIn(where);\n return { text: `${text}${said}`, structured: { workTree, decisions: decisions.map((d) => ({ ...d })) } };\n },\n },\n {\n descriptor: {\n name: 'request_escalation',\n title: 'Ask a person to rule',\n description:\n 'When the round cannot be finished without changing something the brief protects, record the request and stop. A person reads the memo and rules; only a ruling they sign lets the change through.',\n inputSchema: {\n type: 'object',\n properties: {\n paths: { type: 'array', items: { type: 'string' }, description: 'The protected files the round needs to change. An empty one is refused.' },\n reason: { type: 'string', description: 'Why the round cannot be done without them. It is required, and may not be empty.' },\n options: {\n type: 'array',\n items: { type: 'object', properties: { label: { type: 'string' }, consequence: { type: 'string' } }, required: ['label', 'consequence'] },\n description: 'The choices the person has, each with what it costs. A choice whose label is empty is refused.',\n },\n recommendation: { type: 'string', description: 'Which option you recommend, and why. Omit it when there is none: an empty one is refused.' },\n brief: briefProperty,\n directory: directoryProperty,\n },\n required: ['paths', 'reason'],\n additionalProperties: false,\n },\n annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['paths', 'reason', 'options', 'recommendation', 'brief', 'directory']);\n if (unknown) return unknown;\n // Every part of the memo before anything is written: a person rules\n // on what it says, and cannot rule on a part that says nothing.\n const given = pathsOf(args);\n if ('text' in given) return given;\n const reason = args['reason'];\n if (typeof reason !== 'string' || isBlank(reason)) return toolError('\"reason\" is required.');\n const choices = optionsOf(args);\n if ('text' in choices) return choices;\n const recommendation = args['recommendation'];\n if (recommendation !== undefined && typeof recommendation !== 'string') return toolError('\"recommendation\" must be a string.');\n if (recommendation !== undefined && isBlank(recommendation)) return namesNothing('recommendation', 'recommend', recommendation);\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const found = await round(where.workspace, env, args['brief']);\n if ('text' in found) return found;\n const { request, memo } = await raiseEscalation(where.workspace, found.brief, {\n paths: given.paths,\n reason,\n options: choices.options,\n recommendation: recommendation ?? null,\n });\n const { said, workTree } = readIn(where);\n return { text: `${memo}\\nStop here until a person rules on ${request.id}.${said}`, structured: { id: request.id, workTree } };\n },\n },\n {\n descriptor: {\n name: 'audit_round',\n title: 'Audit the round',\n description:\n 'Did the round stay inside the lines: what the archive would refuse (open boxes, protected files, files outside the scope), the brief\\'s own assertions, unverified rulings, every dependency added and every package allowed to run install scripts.',\n inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty, directory: directoryProperty }, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['brief', 'base', 'directory']);\n if (unknown) return unknown;\n const base = baseOf(args);\n if ('text' in base) return base;\n const where = await chosen(workspace, io, roots, args['directory']);\n if ('text' in where) return where;\n const found = await round(where.workspace, env, args['brief']);\n if ('text' in found) return found;\n const result = await runAudit(where.workspace, found.brief, reader, base.base);\n const { counts, findings, measured } = result.report;\n // What was measured beside what was found: \"nothing found\" from an\n // audit that ran no goal is not a round that is done.\n const text =\n findings.length === 0\n ? 'The audit found nothing in what it measured.'\n : findings.map((f) => `${f.severity} ${f.rule}: ${f.message}. Next: ${f.hint}`).join('\\n');\n const { said, workTree } = readIn(where);\n return {\n text: `${text}\\n\\n${describeMeasured(measured)}\\n\\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)${said}`,\n structured: { workTree, counts, measured: { ...measured }, findings: findings.map((f) => ({ ...f })) },\n };\n },\n },\n {\n descriptor: {\n name: 'list_rounds',\n title: 'List the rounds',\n description: 'The live briefs: status, wave, what each waits on, and which are ready to start.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, []);\n if (unknown) return unknown;\n const live = (await workspace.siblings.briefs()).filter((brief) => brief.phase === 'live');\n const text = live\n .map((b) => `${[b.id, titleOf(b)].filter((part) => part !== null).join(' ')} - ${b.status ?? 'unknown'}, wave ${b.wave ?? '-'}, ${b.ready ? 'ready' : `waits on ${b.waitingOn.join(', ')}`}`)\n .join('\\n');\n return { text: text === '' ? 'No live brief.' : text, structured: { briefs: live.map((b) => ({ ...b, title: titleOf(b) })) } };\n },\n },\n ];\n}\n\nconst SKILLS: readonly { name: string; title: string; argument: string; description: string }[] = [\n { name: 'draft-brief', title: 'Draft a brief', argument: 'request', description: 'What the round should achieve, in the person\\'s words.' },\n { name: 'split-goal', title: 'Split a goal into rounds', argument: 'goal', description: 'The goal to split.' },\n { name: 'run-round', title: 'Run a round', argument: 'brief', description: 'The brief id.' },\n { name: 'close-round', title: 'Close a round', argument: 'brief', description: 'The brief id.' },\n];\n\nfunction skillText(name: string): string {\n // The package ships the skills beside dist/ (package.json's files), so one\n // that cannot be read is a broken install, and the request fails saying so\n // rather than serving an empty prompt.\n const text = readFileSync(fileURLToPath(new URL(`../skills/${name}/SKILL.md`, import.meta.url)), 'utf8');\n // Every skill opens with its front matter (tests/source.test.ts), so the\n // anchor is equivalent to its mutant here.\n return text.replace(/^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n/, '').trim();\n}\n\nexport function prompts(): PromptDefinition[] {\n return SKILLS.map((skill) => ({\n descriptor: {\n name: skill.name,\n title: skill.title,\n arguments: [{ name: skill.argument, description: skill.description, required: false }],\n },\n async get(args: Readonly<Record<string, string>>): Promise<JsonObject> {\n const given = args[skill.argument];\n const text = `${skillText(skill.name)}${given === undefined || given === '' ? '' : `\\n\\n${skill.argument}: ${given}`}`;\n return { description: skill.title, messages: [{ role: 'user', content: { type: 'text', text } }] };\n },\n }));\n}\n\nexport async function mcpCommand(options: Options, io: CliIO): Promise<number> {\n // Claude Code starts a plugin's server in the plugin's directory, and names\n // the project in CLAUDE_PROJECT_DIR; the server answers for the project.\n const workspace = await openWorkspace({ ...options, root: options.root ?? (io.env['CLAUDE_PROJECT_DIR'] || undefined) }, io);\n const write = (line: string): void => {\n io.stdout.write(`${line}\\n`);\n };\n // The work tree a session is in, where its client names it (ADR-0008).\n const roots = rootsClient(write);\n const handle = createMcpServer({ name: 'spec-harness', version: version(), instructions: INSTRUCTIONS, tools: tools(workspace, io.env, roots.ask), prompts: prompts() });\n // A session handed over whole, as a test hands it, is served as a client\n // would stream it on stdin. Only the built command line serves\n // process.stdin, and the suite spawns it from dist/, outside the sweep\n // (tests/integration/mcp.test.ts), so a mutant that ignores it survives.\n const input = io.stdin === undefined ? process.stdin : Readable.from([Buffer.from(await io.stdin())]);\n await serveLines(input, write, async (message) => (roots.observe(message) ? null : handle(message)));\n return 0;\n}\n"]}
@@ -57,9 +57,11 @@ export declare function declaredVersion(file: string): unknown;
57
57
  *
58
58
  * Never through a shell: an argument is a path or a brief id, and a shell
59
59
  * would read it as syntax. `node` as a command's first word is this Node, so
60
- * `["node", "path/to/bin.js"]` works on every host; a Windows `.cmd` shim such
61
- * as `npx` cannot be started without a shell, and the error says to name the
62
- * script instead.
60
+ * `["node", "path/to/bin.js"]` works on every host. A program that cannot be
61
+ * started is answered on every host in one way, code -1 and a line that says
62
+ * to name the tool's script: one not found, a script named without `node`,
63
+ * a Windows `.cmd` shim such as `npx`, which cannot be started without a
64
+ * shell, a directory or a file the account may not run.
63
65
  *
64
66
  * A sibling that does not answer within `limit` is stopped, and rejected as
65
67
  * a `SiblingError` that names it: what it was asked waits on it, the hook
package/dist/siblings.js CHANGED
@@ -17,7 +17,7 @@ import { existsSync, readFileSync } from 'node:fs';
17
17
  import { join } from 'node:path';
18
18
  import { inputsOf, parseBriefList, SiblingOutputError } from './briefs.js';
19
19
  import { hasher, isFile, keepAnswer, keptAnswer, readsAsListed } from './fs.js';
20
- import { ANSWER_MS, stoppedAtLimit, WORK_MS } from './git.js';
20
+ import { ANSWER_MS, stoppedAtLimit, timeFor, WORK_MS } from './git.js';
21
21
  import { checkVersion } from './versions.js';
22
22
  /**
23
23
  * Where a sibling is, or why it cannot be run. It is looked for in `root`'s
@@ -74,9 +74,11 @@ export function declaredVersion(file) {
74
74
  *
75
75
  * Never through a shell: an argument is a path or a brief id, and a shell
76
76
  * would read it as syntax. `node` as a command's first word is this Node, so
77
- * `["node", "path/to/bin.js"]` works on every host; a Windows `.cmd` shim such
78
- * as `npx` cannot be started without a shell, and the error says to name the
79
- * script instead.
77
+ * `["node", "path/to/bin.js"]` works on every host. A program that cannot be
78
+ * started is answered on every host in one way, code -1 and a line that says
79
+ * to name the tool's script: one not found, a script named without `node`,
80
+ * a Windows `.cmd` shim such as `npx`, which cannot be started without a
81
+ * shell, a directory or a file the account may not run.
80
82
  *
81
83
  * A sibling that does not answer within `limit` is stopped, and rejected as
82
84
  * a `SiblingError` that names it: what it was asked waits on it, the hook
@@ -85,34 +87,53 @@ export function declaredVersion(file) {
85
87
  export function runSibling(name, command, args, root, limit = WORK_MS) {
86
88
  const [first, ...rest] = command;
87
89
  const program = first === 'node' ? process.execPath : first;
90
+ const { ms, said } = timeFor(limit);
91
+ if (ms === 0)
92
+ return Promise.reject(new SiblingError(`${name} was not started: ${said} had passed`));
93
+ const unstarted = {
94
+ code: -1,
95
+ stdout: '',
96
+ stderr: `cannot start "${first}": name the tool's script, such as ["node", "node_modules/@descent-vtt/<tool>/bin/<tool>.js"]`,
97
+ };
88
98
  return new Promise((resolve, reject) => {
89
- execFile(program, [...rest, ...args], {
90
- cwd: root,
91
- maxBuffer: 256 * 1024 * 1024,
92
- encoding: 'utf8',
93
- // Keeps a console window from opening on Windows; the sweep runs on
94
- // Linux, where the mutant is equivalent.
95
- windowsHide: true,
96
- timeout: limit,
97
- shell: false,
98
- env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },
99
- }, (error, stdout, stderr) => {
100
- if (stoppedAtLimit(error)) {
101
- reject(new SiblingError(`${name} did not answer within ${limit / 1000} seconds, and was stopped`));
102
- return;
103
- }
104
- const failure = error;
105
- if (failure !== null && failure.code === 'ENOENT') {
106
- resolve({
107
- code: -1,
108
- stdout: '',
109
- stderr: `cannot start "${first}": name the tool's script, such as ["node", "node_modules/@descent-vtt/<tool>/bin/<tool>.js"]`,
110
- });
111
- return;
112
- }
113
- const code = failure === null ? 0 : typeof failure.code === 'number' ? failure.code : -1;
114
- resolve({ code, stdout, stderr });
115
- });
99
+ try {
100
+ execFile(program, [...rest, ...args], {
101
+ cwd: root,
102
+ maxBuffer: 256 * 1024 * 1024,
103
+ encoding: 'utf8',
104
+ // Keeps a console window from opening on Windows; the sweep runs on
105
+ // Linux, where the mutant is equivalent.
106
+ windowsHide: true,
107
+ timeout: ms,
108
+ shell: false,
109
+ env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },
110
+ }, (error, stdout, stderr) => {
111
+ if (stoppedAtLimit(error)) {
112
+ reject(new SiblingError(`${name} did not answer within ${said}, and was stopped`));
113
+ return;
114
+ }
115
+ const failure = error;
116
+ // Of what reaches here, only the error of a process that was never
117
+ // made names the system call that failed, `spawn` and the program:
118
+ // ENOENT, and on Linux and macOS EACCES for a directory or a file
119
+ // that may not be run. One that ran has its exit code, and one
120
+ // stopped at its limit was answered above.
121
+ if (failure !== null && typeof failure.syscall === 'string') {
122
+ resolve(unstarted);
123
+ return;
124
+ }
125
+ const code = failure === null ? 0 : typeof failure.code === 'number' ? failure.code : -1;
126
+ resolve({ code, stdout, stderr });
127
+ });
128
+ }
129
+ catch {
130
+ // Some programs are refused before a process is made, and Node throws
131
+ // that rather than pass it to the callback: on Windows a script, as
132
+ // EFTYPE, and a `.cmd` or `.bat`, as EINVAL; on every host a NUL in a
133
+ // word of the command. The options are this function's own, so what
134
+ // execFile throws is a command it could not start.
135
+ resolve(unstarted);
136
+ }
116
137
  });
117
138
  }
118
139
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"siblings.js","sourceRoot":"","sources":["../src/siblings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The edge where the harness meets spec-brief, spec-graph and spec-guard.\n *\n * Through their command lines and their versioned JSON, never by importing\n * their packages: each is released, pinned and dropped on its own, and none\n * becomes a dependency of this one (spec-core ADR-0005, ADR-0002 here).\n *\n * A sibling is found as the repository installed it -\n * `node_modules/@descent-vtt/<name>/bin/<name>.js`, run with this Node - or\n * as `.spec-harness.json` names it. One that is not there is `absent`, and\n * what needed it says so; nothing it would have checked is reported clean.\n * One installed below this release's minimum is `outdated`, and is reported\n * the same way rather than run (versions.ts).\n */\n\nimport { execFile } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { inputsOf, parseBriefList, SiblingOutputError } from './briefs.js';\nimport type { HarnessConfig, SiblingName } from './config.js';\nimport { hasher, isFile, keepAnswer, keptAnswer, readsAsListed, type Hash } from './fs.js';\nimport { ANSWER_MS, stoppedAtLimit, WORK_MS } from './git.js';\nimport type { BriefRow } from './types.js';\nimport { checkVersion } from './versions.js';\n\nexport interface SiblingRun {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nexport type Sibling =\n /**\n * `version` is `null` for a command `.spec-harness.json` names, whose\n * version is not checked. `elsewhere` is the directory whose install it\n * is, where that is not the work tree's own.\n */\n | { readonly kind: 'found'; readonly command: readonly string[]; readonly version: string | null; readonly elsewhere?: string }\n | { readonly kind: 'absent'; readonly reason: string }\n /** Installed, at a version below the minimum or one that cannot be read, which is `null`. */\n | { readonly kind: 'outdated'; readonly reason: string; readonly version: string | null; readonly elsewhere?: string };\n\n/**\n * Where a sibling is, or why it cannot be run. It is looked for in `root`'s\n * install, then in each of `installs` in turn, and the first that has it\n * decides, at this release's floor: a work tree with an install of its own\n * runs it, outdated or not, and one with none is checked with the\n * project's, as git's hook and Claude Code's are where a linked worktree has\n * none (ADR-0005).\n */\n// A name a mutant puts on the default list is a directory relative to where\n// the run is, which holds no install: equivalent, here and below.\nexport function locate(name: SiblingName, root: string, config: HarnessConfig, installs: readonly string[] = []): Sibling {\n // A command the configuration names is run as named: which package it runs,\n // and so which version, is the configuration's to say.\n const configured = config.tools[name];\n if (configured !== null) return { kind: 'found', command: configured, version: null };\n for (const place of [root, ...installs]) {\n const directory = join(place, 'node_modules', '@descent-vtt', name);\n const bin = join(directory, 'bin', `${name}.js`);\n if (!existsSync(bin)) continue;\n const check = checkVersion(name, declaredVersion(join(directory, 'package.json')));\n const where = place === root ? {} : { elsewhere: place };\n if (!check.ok) return { kind: 'outdated', reason: check.reason, version: check.version, ...where };\n return { kind: 'found', command: [process.execPath, bin], version: check.version, ...where };\n }\n return {\n kind: 'absent',\n reason: `${name} is not installed here: npm install --save-dev @descent-vtt/${name}, or name its command under \"tools\" in .spec-harness.json`,\n };\n}\n\n/** The `version` a package.json declares, or `undefined` when there is no such file or it is not JSON. */\nexport function declaredVersion(file: string): unknown {\n // Only a file is read: a named pipe under the name was read without end,\n // and before any sibling ran (ADR-0002).\n if (!isFile(file)) return undefined;\n // A manifest that holds null throws on the read, and any other value that\n // is not an object has no version, so the catch answers for both. Falling\n // out of it answers undefined as well, and a Buffer parses as its text:\n // the empty catch and the encoding are equivalent to their mutants.\n try {\n const manifest: { version?: unknown } = JSON.parse(readFileSync(file, 'utf8'));\n return manifest.version;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Runs a sibling with arguments, in the repository root.\n *\n * Never through a shell: an argument is a path or a brief id, and a shell\n * would read it as syntax. `node` as a command's first word is this Node, so\n * `[\"node\", \"path/to/bin.js\"]` works on every host; a Windows `.cmd` shim such\n * as `npx` cannot be started without a shell, and the error says to name the\n * script instead.\n *\n * A sibling that does not answer within `limit` is stopped, and rejected as\n * a `SiblingError` that names it: what it was asked waits on it, the hook\n * before a write among them, which then holds the write (ADR-0002).\n */\nexport function runSibling(name: string, command: readonly string[], args: readonly string[], root: string, limit = WORK_MS): Promise<SiblingRun> {\n const [first, ...rest] = command;\n const program = first === 'node' ? process.execPath : (first as string);\n return new Promise((resolve, reject) => {\n execFile(\n program,\n [...rest, ...args],\n {\n cwd: root,\n maxBuffer: 256 * 1024 * 1024,\n encoding: 'utf8',\n // Keeps a console window from opening on Windows; the sweep runs on\n // Linux, where the mutant is equivalent.\n windowsHide: true,\n timeout: limit,\n shell: false,\n env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },\n },\n (error, stdout, stderr) => {\n if (stoppedAtLimit(error)) {\n reject(new SiblingError(`${name} did not answer within ${limit / 1000} seconds, and was stopped`));\n return;\n }\n const failure = error as (Error & { code?: unknown }) | null;\n if (failure !== null && failure.code === 'ENOENT') {\n resolve({\n code: -1,\n stdout: '',\n stderr: `cannot start \"${first}\": name the tool's script, such as [\"node\", \"node_modules/@descent-vtt/<tool>/bin/<tool>.js\"]`,\n });\n return;\n }\n const code = failure === null ? 0 : typeof failure.code === 'number' ? failure.code : -1;\n resolve({ code, stdout, stderr });\n },\n );\n });\n}\n\n/**\n * Where and under what a session's answer of spec-brief's is kept, or\n * `null` where none is. A command `tools` names is started every time:\n * which version it runs cannot be told without starting it.\n */\nasync function keeperOf(kept: Kept, root: string, sibling: Extract<Sibling, { kind: 'found' }>): Promise<{ readonly commonDir: string; readonly key: string; readonly name: string; readonly version: string; readonly hash: Hash } | null> {\n // A command with no version is kept nothing by the test of the version an\n // answer names, too: the mutant without this one reads, for every write, a\n // kept answer there is none of, and is equivalent.\n if (sibling.version === null) return null;\n const hash = await hasher();\n const key = answerKey(root, kept.session, sibling.command, sibling.version);\n return { commonDir: kept.commonDir, key, name: `${hash(key)}.json`, version: sibling.version, hash };\n}\n\n/**\n * The briefs a kept answer gives, or `null` where it is not to be given:\n * nothing kept, or what was kept is not a list document that names what it\n * was read from in the version installed, or anything it names reads\n * otherwise.\n */\nasync function givenAgain(stdout: string | null, version: string, root: string, hash: Hash): Promise<BriefRow[] | null> {\n // JSON.parse reads null as null, which names no inputs, and a null read\n // past the test of none below throws, which answers null: the two tests\n // are the compiler's, and their mutants equivalent.\n if (stdout === null) return null;\n try {\n const document: unknown = JSON.parse(stdout);\n const inputs = inputsOf(document);\n if (inputs === null || inputs.tool !== version || !(await readsAsListed(root, inputs, hash))) return null;\n return parseBriefList(document);\n } catch {\n // What another program wrote there is no answer of spec-brief's.\n return null;\n }\n}\n\nexport class SiblingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SiblingError';\n }\n}\n\nfunction parseJson(name: string, run: SiblingRun): unknown {\n try {\n return JSON.parse(run.stdout);\n } catch {\n const said = (run.stderr.trim() || run.stdout.trim()).split('\\n').slice(0, 3).join(' ');\n throw new SiblingError(`${name} exited ${run.code} without JSON${said ? `: ${said}` : ''}`);\n }\n}\n\nexport interface Siblings {\n readonly root: string;\n locate(name: SiblingName): Sibling;\n /**\n * Every brief, live and archived. Exit 2 from spec-brief is an error here\n * too, and so is a spec-brief that does not answer within `limit`, the\n * time a question is given unless a caller gives another.\n */\n briefs(limit?: number): Promise<BriefRow[]>;\n /**\n * The same siblings, with spec-brief's list of the briefs kept for a\n * session under the common directory and given again to that session's\n * runs where every input it lists reads as listed (ADR-0002).\n */\n keeping(commonDir: string, session: string): Siblings;\n /** A sibling's JSON output for a command line, with its exit code and what it said on stderr; `absent` says why it cannot be run, missing or outdated. */\n json(name: SiblingName, args: readonly string[]): Promise<{ readonly code: number; readonly document: unknown; readonly stderr: string } | { readonly absent: string }>;\n}\n\n/** The command line spec-brief is asked for the briefs with. */\nconst LIST: readonly string[] = ['list', '--archived', '--format', 'json', '--no-color'];\n\n/**\n * The variables beyond git's own that an answer of spec-brief's can turn on\n * and its list does not name: which git and which Node run, where git finds\n * the person's configuration and ignore files, and how Node runs a script.\n * Every variable whose name begins `GIT_` is read with them.\n */\nconst ANSWER_VARIABLES: readonly string[] = ['PATH', 'HOME', 'USERPROFILE', 'HOMEDRIVE', 'HOMEPATH', 'XDG_CONFIG_HOME', 'NODE_OPTIONS', 'NODE_PATH'];\n\n/**\n * What a kept answer is the answer to: the work tree, the session, the\n * spec-brief that answered, by its command, its version and the Node it ran\n * on, the command line, and the variables above, as spec-brief is started\n * with them (runSibling). An answer is given again only for the same.\n */\nexport function answerKey(root: string, session: string, command: readonly string[], version: string, env: Readonly<Record<string, string | undefined>> = process.env): string {\n const variables = Object.keys(env)\n .filter((name) => /^GIT_/i.test(name) || ANSWER_VARIABLES.includes(name.toUpperCase()))\n // One case for each name, whichever: the mutant that folds to the other is equivalent.\n .map((name) => [name.toUpperCase(), env[name]])\n .sort();\n return JSON.stringify({ root, session, command, version, node: process.version, args: LIST, variables });\n}\n\n/** The siblings of the work tree at `root`, looked for in its install and then in each of `installs` (locate). */\nexport function createSiblings(root: string, config: HarnessConfig, installs: readonly string[] = []): Siblings {\n return siblingsOf(root, config, installs, null);\n}\n\n/** Where a session's answers are kept, and which session's they are. */\ninterface Kept {\n readonly commonDir: string;\n readonly session: string;\n}\n\nfunction siblingsOf(root: string, config: HarnessConfig, installs: readonly string[], kept: Kept | null): Siblings {\n return {\n root,\n locate: (name) => locate(name, root, config, installs),\n async briefs(limit = ANSWER_MS) {\n const sibling = locate('spec-brief', root, config, installs);\n if (sibling.kind !== 'found') throw new SiblingError(sibling.reason);\n const keeper = kept === null ? null : await keeperOf(kept, root, sibling);\n if (keeper !== null) {\n const again = await givenAgain(await keptAnswer(keeper.commonDir, keeper.name, keeper.key), keeper.version, root, keeper.hash);\n if (again !== null) return again;\n }\n const run = await runSibling('spec-brief', sibling.command, LIST, root, limit);\n if (run.code === 2) {\n throw new SiblingError(`spec-brief could not list the briefs: ${run.stderr.trim().split('\\n')[0] || 'exit 2'}`);\n }\n let document: unknown;\n let rows: BriefRow[];\n try {\n document = parseJson('spec-brief', run);\n rows = parseBriefList(document);\n } catch (error) {\n // parseJson throws a SiblingError, which this would copy, and\n // parseBriefList nothing but its own: the check is equivalent to its\n // mutant, and keeps any other error the stack trace it needs.\n if (error instanceof SiblingOutputError) throw new SiblingError(error.message);\n throw error;\n }\n // Kept only where spec-brief said all was well and named what it read,\n // in the version that answered: any other answer is read once.\n if (keeper !== null && run.code === 0 && inputsOf(document)?.tool === keeper.version) {\n await keepAnswer(keeper.commonDir, keeper.name, keeper.key, run.stdout);\n }\n return rows;\n },\n keeping: (commonDir, session) => siblingsOf(root, config, installs, { commonDir, session }),\n async json(name, args) {\n const sibling = locate(name, root, config, installs);\n if (sibling.kind !== 'found') return { absent: sibling.reason };\n const run = await runSibling(name, sibling.command, args, root);\n return { code: run.code, document: parseJson(name, run), stderr: run.stderr };\n },\n };\n}\n"]}
1
+ {"version":3,"file":"siblings.js","sourceRoot":"","sources":["../src/siblings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The edge where the harness meets spec-brief, spec-graph and spec-guard.\n *\n * Through their command lines and their versioned JSON, never by importing\n * their packages: each is released, pinned and dropped on its own, and none\n * becomes a dependency of this one (spec-core ADR-0005, ADR-0002 here).\n *\n * A sibling is found as the repository installed it -\n * `node_modules/@descent-vtt/<name>/bin/<name>.js`, run with this Node - or\n * as `.spec-harness.json` names it. One that is not there is `absent`, and\n * what needed it says so; nothing it would have checked is reported clean.\n * One installed below this release's minimum is `outdated`, and is reported\n * the same way rather than run (versions.ts).\n */\n\nimport { execFile } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { inputsOf, parseBriefList, SiblingOutputError } from './briefs.js';\nimport type { HarnessConfig, SiblingName } from './config.js';\nimport { hasher, isFile, keepAnswer, keptAnswer, readsAsListed, type Hash } from './fs.js';\nimport { ANSWER_MS, stoppedAtLimit, timeFor, WORK_MS } from './git.js';\nimport type { BriefRow } from './types.js';\nimport { checkVersion } from './versions.js';\n\nexport interface SiblingRun {\n readonly code: number;\n readonly stdout: string;\n readonly stderr: string;\n}\n\nexport type Sibling =\n /**\n * `version` is `null` for a command `.spec-harness.json` names, whose\n * version is not checked. `elsewhere` is the directory whose install it\n * is, where that is not the work tree's own.\n */\n | { readonly kind: 'found'; readonly command: readonly string[]; readonly version: string | null; readonly elsewhere?: string }\n | { readonly kind: 'absent'; readonly reason: string }\n /** Installed, at a version below the minimum or one that cannot be read, which is `null`. */\n | { readonly kind: 'outdated'; readonly reason: string; readonly version: string | null; readonly elsewhere?: string };\n\n/**\n * Where a sibling is, or why it cannot be run. It is looked for in `root`'s\n * install, then in each of `installs` in turn, and the first that has it\n * decides, at this release's floor: a work tree with an install of its own\n * runs it, outdated or not, and one with none is checked with the\n * project's, as git's hook and Claude Code's are where a linked worktree has\n * none (ADR-0005).\n */\n// A name a mutant puts on the default list is a directory relative to where\n// the run is, which holds no install: equivalent, here and below.\nexport function locate(name: SiblingName, root: string, config: HarnessConfig, installs: readonly string[] = []): Sibling {\n // A command the configuration names is run as named: which package it runs,\n // and so which version, is the configuration's to say.\n const configured = config.tools[name];\n if (configured !== null) return { kind: 'found', command: configured, version: null };\n for (const place of [root, ...installs]) {\n const directory = join(place, 'node_modules', '@descent-vtt', name);\n const bin = join(directory, 'bin', `${name}.js`);\n if (!existsSync(bin)) continue;\n const check = checkVersion(name, declaredVersion(join(directory, 'package.json')));\n const where = place === root ? {} : { elsewhere: place };\n if (!check.ok) return { kind: 'outdated', reason: check.reason, version: check.version, ...where };\n return { kind: 'found', command: [process.execPath, bin], version: check.version, ...where };\n }\n return {\n kind: 'absent',\n reason: `${name} is not installed here: npm install --save-dev @descent-vtt/${name}, or name its command under \"tools\" in .spec-harness.json`,\n };\n}\n\n/** The `version` a package.json declares, or `undefined` when there is no such file or it is not JSON. */\nexport function declaredVersion(file: string): unknown {\n // Only a file is read: a named pipe under the name was read without end,\n // and before any sibling ran (ADR-0002).\n if (!isFile(file)) return undefined;\n // A manifest that holds null throws on the read, and any other value that\n // is not an object has no version, so the catch answers for both. Falling\n // out of it answers undefined as well, and a Buffer parses as its text:\n // the empty catch and the encoding are equivalent to their mutants.\n try {\n const manifest: { version?: unknown } = JSON.parse(readFileSync(file, 'utf8'));\n return manifest.version;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Runs a sibling with arguments, in the repository root.\n *\n * Never through a shell: an argument is a path or a brief id, and a shell\n * would read it as syntax. `node` as a command's first word is this Node, so\n * `[\"node\", \"path/to/bin.js\"]` works on every host. A program that cannot be\n * started is answered on every host in one way, code -1 and a line that says\n * to name the tool's script: one not found, a script named without `node`,\n * a Windows `.cmd` shim such as `npx`, which cannot be started without a\n * shell, a directory or a file the account may not run.\n *\n * A sibling that does not answer within `limit` is stopped, and rejected as\n * a `SiblingError` that names it: what it was asked waits on it, the hook\n * before a write among them, which then holds the write (ADR-0002).\n */\nexport function runSibling(name: string, command: readonly string[], args: readonly string[], root: string, limit = WORK_MS): Promise<SiblingRun> {\n const [first, ...rest] = command;\n const program = first === 'node' ? process.execPath : (first as string);\n const { ms, said } = timeFor(limit);\n if (ms === 0) return Promise.reject(new SiblingError(`${name} was not started: ${said} had passed`));\n const unstarted: SiblingRun = {\n code: -1,\n stdout: '',\n stderr: `cannot start \"${first}\": name the tool's script, such as [\"node\", \"node_modules/@descent-vtt/<tool>/bin/<tool>.js\"]`,\n };\n return new Promise((resolve, reject) => {\n try {\n execFile(\n program,\n [...rest, ...args],\n {\n cwd: root,\n maxBuffer: 256 * 1024 * 1024,\n encoding: 'utf8',\n // Keeps a console window from opening on Windows; the sweep runs on\n // Linux, where the mutant is equivalent.\n windowsHide: true,\n timeout: ms,\n shell: false,\n env: { ...process.env, NO_COLOR: '1', FORCE_COLOR: '0' },\n },\n (error, stdout, stderr) => {\n if (stoppedAtLimit(error)) {\n reject(new SiblingError(`${name} did not answer within ${said}, and was stopped`));\n return;\n }\n const failure = error as (Error & { code?: unknown; syscall?: unknown }) | null;\n // Of what reaches here, only the error of a process that was never\n // made names the system call that failed, `spawn` and the program:\n // ENOENT, and on Linux and macOS EACCES for a directory or a file\n // that may not be run. One that ran has its exit code, and one\n // stopped at its limit was answered above.\n if (failure !== null && typeof failure.syscall === 'string') {\n resolve(unstarted);\n return;\n }\n const code = failure === null ? 0 : typeof failure.code === 'number' ? failure.code : -1;\n resolve({ code, stdout, stderr });\n },\n );\n } catch {\n // Some programs are refused before a process is made, and Node throws\n // that rather than pass it to the callback: on Windows a script, as\n // EFTYPE, and a `.cmd` or `.bat`, as EINVAL; on every host a NUL in a\n // word of the command. The options are this function's own, so what\n // execFile throws is a command it could not start.\n resolve(unstarted);\n }\n });\n}\n\n/**\n * Where and under what a session's answer of spec-brief's is kept, or\n * `null` where none is. A command `tools` names is started every time:\n * which version it runs cannot be told without starting it.\n */\nasync function keeperOf(kept: Kept, root: string, sibling: Extract<Sibling, { kind: 'found' }>): Promise<{ readonly commonDir: string; readonly key: string; readonly name: string; readonly version: string; readonly hash: Hash } | null> {\n // A command with no version is kept nothing by the test of the version an\n // answer names, too: the mutant without this one reads, for every write, a\n // kept answer there is none of, and is equivalent.\n if (sibling.version === null) return null;\n const hash = await hasher();\n const key = answerKey(root, kept.session, sibling.command, sibling.version);\n return { commonDir: kept.commonDir, key, name: `${hash(key)}.json`, version: sibling.version, hash };\n}\n\n/**\n * The briefs a kept answer gives, or `null` where it is not to be given:\n * nothing kept, or what was kept is not a list document that names what it\n * was read from in the version installed, or anything it names reads\n * otherwise.\n */\nasync function givenAgain(stdout: string | null, version: string, root: string, hash: Hash): Promise<BriefRow[] | null> {\n // JSON.parse reads null as null, which names no inputs, and a null read\n // past the test of none below throws, which answers null: the two tests\n // are the compiler's, and their mutants equivalent.\n if (stdout === null) return null;\n try {\n const document: unknown = JSON.parse(stdout);\n const inputs = inputsOf(document);\n if (inputs === null || inputs.tool !== version || !(await readsAsListed(root, inputs, hash))) return null;\n return parseBriefList(document);\n } catch {\n // What another program wrote there is no answer of spec-brief's.\n return null;\n }\n}\n\nexport class SiblingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SiblingError';\n }\n}\n\nfunction parseJson(name: string, run: SiblingRun): unknown {\n try {\n return JSON.parse(run.stdout);\n } catch {\n const said = (run.stderr.trim() || run.stdout.trim()).split('\\n').slice(0, 3).join(' ');\n throw new SiblingError(`${name} exited ${run.code} without JSON${said ? `: ${said}` : ''}`);\n }\n}\n\nexport interface Siblings {\n readonly root: string;\n locate(name: SiblingName): Sibling;\n /**\n * Every brief, live and archived. Exit 2 from spec-brief is an error here\n * too, and so is a spec-brief that does not answer within `limit`, the\n * time a question is given unless a caller gives another.\n */\n briefs(limit?: number): Promise<BriefRow[]>;\n /**\n * The same siblings, with spec-brief's list of the briefs kept for a\n * session under the common directory and given again to that session's\n * runs where every input it lists reads as listed (ADR-0002).\n */\n keeping(commonDir: string, session: string): Siblings;\n /** A sibling's JSON output for a command line, with its exit code and what it said on stderr; `absent` says why it cannot be run, missing or outdated. */\n json(name: SiblingName, args: readonly string[]): Promise<{ readonly code: number; readonly document: unknown; readonly stderr: string } | { readonly absent: string }>;\n}\n\n/** The command line spec-brief is asked for the briefs with. */\nconst LIST: readonly string[] = ['list', '--archived', '--format', 'json', '--no-color'];\n\n/**\n * The variables beyond git's own that an answer of spec-brief's can turn on\n * and its list does not name: which git and which Node run, where git finds\n * the person's configuration and ignore files, and how Node runs a script.\n * Every variable whose name begins `GIT_` is read with them.\n */\nconst ANSWER_VARIABLES: readonly string[] = ['PATH', 'HOME', 'USERPROFILE', 'HOMEDRIVE', 'HOMEPATH', 'XDG_CONFIG_HOME', 'NODE_OPTIONS', 'NODE_PATH'];\n\n/**\n * What a kept answer is the answer to: the work tree, the session, the\n * spec-brief that answered, by its command, its version and the Node it ran\n * on, the command line, and the variables above, as spec-brief is started\n * with them (runSibling). An answer is given again only for the same.\n */\nexport function answerKey(root: string, session: string, command: readonly string[], version: string, env: Readonly<Record<string, string | undefined>> = process.env): string {\n const variables = Object.keys(env)\n .filter((name) => /^GIT_/i.test(name) || ANSWER_VARIABLES.includes(name.toUpperCase()))\n // One case for each name, whichever: the mutant that folds to the other is equivalent.\n .map((name) => [name.toUpperCase(), env[name]])\n .sort();\n return JSON.stringify({ root, session, command, version, node: process.version, args: LIST, variables });\n}\n\n/** The siblings of the work tree at `root`, looked for in its install and then in each of `installs` (locate). */\nexport function createSiblings(root: string, config: HarnessConfig, installs: readonly string[] = []): Siblings {\n return siblingsOf(root, config, installs, null);\n}\n\n/** Where a session's answers are kept, and which session's they are. */\ninterface Kept {\n readonly commonDir: string;\n readonly session: string;\n}\n\nfunction siblingsOf(root: string, config: HarnessConfig, installs: readonly string[], kept: Kept | null): Siblings {\n return {\n root,\n locate: (name) => locate(name, root, config, installs),\n async briefs(limit = ANSWER_MS) {\n const sibling = locate('spec-brief', root, config, installs);\n if (sibling.kind !== 'found') throw new SiblingError(sibling.reason);\n const keeper = kept === null ? null : await keeperOf(kept, root, sibling);\n if (keeper !== null) {\n const again = await givenAgain(await keptAnswer(keeper.commonDir, keeper.name, keeper.key), keeper.version, root, keeper.hash);\n if (again !== null) return again;\n }\n const run = await runSibling('spec-brief', sibling.command, LIST, root, limit);\n if (run.code === 2) {\n throw new SiblingError(`spec-brief could not list the briefs: ${run.stderr.trim().split('\\n')[0] || 'exit 2'}`);\n }\n let document: unknown;\n let rows: BriefRow[];\n try {\n document = parseJson('spec-brief', run);\n rows = parseBriefList(document);\n } catch (error) {\n // parseJson throws a SiblingError, which this would copy, and\n // parseBriefList nothing but its own: the check is equivalent to its\n // mutant, and keeps any other error the stack trace it needs.\n if (error instanceof SiblingOutputError) throw new SiblingError(error.message);\n throw error;\n }\n // Kept only where spec-brief said all was well and named what it read,\n // in the version that answered: any other answer is read once.\n if (keeper !== null && run.code === 0 && inputsOf(document)?.tool === keeper.version) {\n await keepAnswer(keeper.commonDir, keeper.name, keeper.key, run.stdout);\n }\n return rows;\n },\n keeping: (commonDir, session) => siblingsOf(root, config, installs, { commonDir, session }),\n async json(name, args) {\n const sibling = locate(name, root, config, installs);\n if (sibling.kind !== 'found') return { absent: sibling.reason };\n const run = await runSibling(name, sibling.command, args, root);\n return { code: run.code, document: parseJson(name, run), stderr: run.stderr };\n },\n };\n}\n"]}
package/dist/workspace.js CHANGED
@@ -3,11 +3,11 @@
3
3
  * runs in, and which brief the round is working on.
4
4
  */
5
5
  import { readFileSync } from 'node:fs';
6
- import { dirname, join, resolve } from 'node:path';
6
+ import { dirname, join } from 'node:path';
7
7
  import { parseArgs } from 'node:util';
8
8
  import { findActive } from './briefs.js';
9
9
  import { briefIdFromBranch, ciBranch } from './branch.js';
10
- import { holdsGit, isTop, loadConfig, mainWorkTree, realSpelling, repositoryPath } from './fs.js';
10
+ import { holdsGit, isTop, loadConfig, mainWorkTree, reachedBy, realSpelling, repositoryPath } from './fs.js';
11
11
  import { commonDirectory, currentBranch, workTree, workTreeRoot } from './git.js';
12
12
  import { createSiblings } from './siblings.js';
13
13
  export const EXIT_OK = 0;
@@ -337,8 +337,9 @@ function topAbove(path) {
337
337
  }
338
338
  /**
339
339
  * The innermost work tree of the repository the work tree `named` is one of
340
- * that holds a path, where it is not `named` itself: a linked worktree or the
341
- * main one, inside the project, beside it, or around it (ADR-0005). The
340
+ * that holds a file, given by its real spelling, where it is not `named`
341
+ * itself: a linked worktree or the main one, inside the project, beside it,
342
+ * or around it (ADR-0005). The
342
343
  * directories above the path are looked through, with no process, for each
343
344
  * that holds a `.git`; git is asked of each that is not `named`'s top, and
344
345
  * one that git names as no work tree of this repository's, a submodule's, a
@@ -347,10 +348,9 @@ function topAbove(path) {
347
348
  * met is `named`, or none is: the path is decided by `named`, as before, a
348
349
  * path in no work tree of the repository among them.
349
350
  */
350
- async function treeHolding(named, path, from) {
351
+ async function treeHolding(named, spelled) {
351
352
  const own = realSpelling(named.root);
352
- // An absolute path, as Claude Code sends one, is what resolve leaves it.
353
- for (let top = topAbove(realSpelling(resolve(from, path))); top !== null; top = topAbove(top)) {
353
+ for (let top = topAbove(spelled); top !== null; top = topAbove(top)) {
354
354
  if (top === own)
355
355
  return null;
356
356
  const tree = await otherTree(named, top);
@@ -387,12 +387,22 @@ export async function writesBy(named, cwd, paths, io) {
387
387
  // The parts in the order their work trees are first met, each with its
388
388
  // paths in the order they were named.
389
389
  for (const path of paths) {
390
- const tree = await treeHolding(named, path, from);
391
- const part = trees.find((other) => other.tree?.root === tree?.root);
392
- if (part === undefined)
393
- trees.push({ tree, paths: [path] });
394
- else
395
- part.paths.push(path);
390
+ // Each file the path reaches, as it reads and as the system writes it,
391
+ // by the work tree that holds that file: a link can lead from one work
392
+ // tree into another, and each decides the file it holds.
393
+ const held = [];
394
+ for (const spelled of reachedBy(path, from)) {
395
+ const tree = await treeHolding(named, spelled);
396
+ if (!held.some((other) => other?.root === tree?.root))
397
+ held.push(tree);
398
+ }
399
+ for (const tree of held) {
400
+ const part = trees.find((other) => other.tree?.root === tree?.root);
401
+ if (part === undefined)
402
+ trees.push({ tree, paths: [path] });
403
+ else
404
+ part.paths.push(path);
405
+ }
396
406
  }
397
407
  // The root's own last, as it was decided after the work tree Claude works in.
398
408
  const ordered = [...trees.filter((part) => part.tree !== null), ...trees.filter((part) => part.tree === null)];