@descent-vtt/spec-harness 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +212 -0
  4. package/README.md +30 -15
  5. package/dist/briefs.d.ts +45 -0
  6. package/dist/briefs.js +73 -0
  7. package/dist/briefs.js.map +1 -1
  8. package/dist/cli.d.ts +1 -1
  9. package/dist/cli.js +211 -134
  10. package/dist/cli.js.map +1 -1
  11. package/dist/commands.js +7 -2
  12. package/dist/commands.js.map +1 -1
  13. package/dist/config.d.ts +13 -1
  14. package/dist/config.js +14 -3
  15. package/dist/config.js.map +1 -1
  16. package/dist/configure.d.ts +55 -1
  17. package/dist/configure.js +130 -22
  18. package/dist/configure.js.map +1 -1
  19. package/dist/fs.d.ts +78 -1
  20. package/dist/fs.js +289 -10
  21. package/dist/fs.js.map +1 -1
  22. package/dist/git.d.ts +50 -2
  23. package/dist/git.js +98 -8
  24. package/dist/git.js.map +1 -1
  25. package/dist/hooks.d.ts +45 -0
  26. package/dist/hooks.js +62 -3
  27. package/dist/hooks.js.map +1 -1
  28. package/dist/round.d.ts +8 -0
  29. package/dist/round.js +23 -8
  30. package/dist/round.js.map +1 -1
  31. package/dist/sandbox.js +4 -3
  32. package/dist/sandbox.js.map +1 -1
  33. package/dist/server.d.ts +25 -1
  34. package/dist/server.js +194 -27
  35. package/dist/server.js.map +1 -1
  36. package/dist/setup.js +40 -10
  37. package/dist/setup.js.map +1 -1
  38. package/dist/siblings.d.ts +24 -3
  39. package/dist/siblings.js +106 -14
  40. package/dist/siblings.js.map +1 -1
  41. package/dist/usage.d.ts +42 -7
  42. package/dist/usage.js +65 -6
  43. package/dist/usage.js.map +1 -1
  44. package/dist/workspace.d.ts +45 -3
  45. package/dist/workspace.js +133 -13
  46. package/dist/workspace.js.map +1 -1
  47. package/package.json +1 -1
package/dist/server.d.ts CHANGED
@@ -8,6 +8,30 @@
8
8
  import { type PromptDefinition, type ToolDefinition } from './vendor/spec-core/jsonrpc/index.js';
9
9
  import { type CliIO, type Options, type Workspace } from './workspace.js';
10
10
  export declare const INSTRUCTIONS: string;
11
- export declare function tools(workspace: Workspace, env: CliIO['env']): ToolDefinition[];
11
+ /**
12
+ * The directories a client's roots name, or `null` where it declared no
13
+ * roots, answered with an error, or did not answer in time.
14
+ */
15
+ export type Roots = () => Promise<readonly string[] | null>;
16
+ /** How long a client is given to answer `roots/list`: Claude Code answers from what it holds (its MCP page, below). */
17
+ export declare const ROOTS_MS = 5000;
18
+ /**
19
+ * The client's roots, asked as MCP has a server ask them, with a request of
20
+ * the server's own, `roots/list`, where the client declared the capability
21
+ * as it started: in its `initialize`, or a later request's `_meta`. Claude
22
+ * Code's MCP page (https://code.claude.com/docs/en/mcp, Option 3: Add a local
23
+ * stdio server, read 2026-10-19) has it answer with the session's launch
24
+ * directory and every working directory added to it, and
25
+ * `CLAUDE_PROJECT_DIR` the stable project root, which does not move with
26
+ * them. The answer arrives on the input as a response, which the protocol's
27
+ * module passes over: it is read here first, by the id it was asked under.
28
+ */
29
+ export interface RootsClient {
30
+ /** 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. */
31
+ observe(message: unknown): boolean;
32
+ readonly ask: Roots;
33
+ }
34
+ export declare function rootsClient(write: (line: string) => void, limit?: number): RootsClient;
35
+ export declare function tools(workspace: Workspace, env: CliIO['env'], roots?: Roots): ToolDefinition[];
12
36
  export declare function prompts(): PromptDefinition[];
13
37
  export declare function mcpCommand(options: Options, io: CliIO): Promise<number>;
package/dist/server.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * brief the next answer uses.
7
7
  */
8
8
  import { readFileSync } from 'node:fs';
9
+ import { resolve } from 'node:path';
9
10
  import { Readable } from 'node:stream';
10
11
  import { fileURLToPath } from 'node:url';
11
12
  import { describeMeasured } from './audit.js';
@@ -13,10 +14,11 @@ import { findActive } from './briefs.js';
13
14
  import { briefIdFromBranch } from './branch.js';
14
15
  import { titleOf } from './context.js';
15
16
  import { createReader } from './reader.js';
17
+ import { realSpelling } from './fs.js';
16
18
  import { buildContext, checkPaths, raiseEscalation, runAudit } from './round.js';
17
19
  import { emptyValue, isBlank } from './usage.js';
18
- import { createMcpServer, serveLines, toolError, unknownArguments, } from './vendor/spec-core/jsonrpc/index.js';
19
- import { describeActive, openWorkspace, version } from './workspace.js';
20
+ import { CLIENT_CAPABILITIES_KEY, createMcpServer, isObject, serveLines, toolError, unknownArguments, } from './vendor/spec-core/jsonrpc/index.js';
21
+ import { describeActive, findTree, foundCommonDir, mayBeElsewhere, openFound, openWorkspace, version, writesBy } from './workspace.js';
20
22
  const reader = createReader();
21
23
  export const INSTRUCTIONS = 'spec-harness keeps a round of work inside the brief a person approved. ' +
22
24
  '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. ' +
@@ -38,6 +40,133 @@ const baseProperty = {
38
40
  function namesNothing(argument, option, value) {
39
41
  return toolError(`${emptyValue(`"${argument}"`, option, value)}.`);
40
42
  }
43
+ const directoryProperty = {
44
+ type: 'string',
45
+ description: "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.",
46
+ };
47
+ /** No client to ask: the tools as a caller of the package builds them, with no server around them. */
48
+ const NO_ROOTS = async () => null;
49
+ /** How long a client is given to answer `roots/list`: Claude Code answers from what it holds (its MCP page, below). */
50
+ export const ROOTS_MS = 5_000;
51
+ export function rootsClient(write, limit = ROOTS_MS) {
52
+ let declared = false;
53
+ let asked = 0;
54
+ const waiting = new Map();
55
+ const declares = (capabilities) => isObject(capabilities) && isObject(capabilities['roots']);
56
+ return {
57
+ observe(message) {
58
+ if (!isObject(message))
59
+ return false;
60
+ const params = isObject(message['params']) ? message['params'] : {};
61
+ const meta = isObject(params['_meta']) ? params['_meta'] : {};
62
+ if ((message['method'] === 'initialize' && declares(params['capabilities'])) || declares(meta[CLIENT_CAPABILITIES_KEY]))
63
+ declared = true;
64
+ const id = message['id'];
65
+ // The server's requests have strings for ids, so one that is no string
66
+ // finds nothing waiting either way: the mutant that drops the test is
67
+ // equivalent.
68
+ const settle = typeof id === 'string' && message['method'] === undefined ? waiting.get(id) : undefined;
69
+ if (settle === undefined)
70
+ return false;
71
+ settle(message);
72
+ return true;
73
+ },
74
+ async ask() {
75
+ if (!declared)
76
+ return null;
77
+ asked += 1;
78
+ const id = `spec-harness-roots-${asked}`;
79
+ const answer = await new Promise((settled) => {
80
+ const timer = setTimeout(() => settled(null), limit);
81
+ waiting.set(id, (message) => {
82
+ clearTimeout(timer);
83
+ settled(message);
84
+ });
85
+ write(JSON.stringify({ jsonrpc: '2.0', id, method: 'roots/list' }));
86
+ });
87
+ waiting.delete(id);
88
+ const result = isObject(answer) ? answer['result'] : undefined;
89
+ const roots = isObject(result) ? result['roots'] : undefined;
90
+ if (!Array.isArray(roots))
91
+ return null;
92
+ // A root is a `file:` URI, by the protocol; Node refuses one of any other scheme, which names no directory here.
93
+ return roots.flatMap((root) => {
94
+ const uri = isObject(root) ? root['uri'] : undefined;
95
+ if (typeof uri !== 'string')
96
+ return [];
97
+ try {
98
+ return [fileURLToPath(uri)];
99
+ }
100
+ catch {
101
+ return [];
102
+ }
103
+ });
104
+ },
105
+ };
106
+ }
107
+ /**
108
+ * The work tree of the server's repository that holds a directory: the
109
+ * server's own where it is in that, with no `.git` between, and otherwise the
110
+ * one git names, where it shares the git directory the server's repository
111
+ * keeps; `null` where the directory is in another repository, or in none.
112
+ */
113
+ async function treeOf(server, io, directory) {
114
+ // Asked anyway, git names the server's own top for a directory in it,
115
+ // which answers the server's own below: the mutant that always asks is
116
+ // equivalent, at a process's cost.
117
+ if (!mayBeElsewhere(directory, server.root))
118
+ return server;
119
+ const found = await findTree(directory);
120
+ if (found === null)
121
+ return null;
122
+ // Its own work tree, opened again, reads every answer the same way: the
123
+ // check saves a start of git, and its mutant is equivalent.
124
+ if (realSpelling(found.root) === realSpelling(server.root))
125
+ return server;
126
+ const common = await foundCommonDir(found);
127
+ // git names a common directory wherever it names a top, so `null` is there for the type.
128
+ if (common === null || realSpelling(common) !== realSpelling(server.commonDir))
129
+ return null;
130
+ return openFound(found, io, () => [server.root]);
131
+ }
132
+ /**
133
+ * The work tree a tool that reads a branch reads the round in (ADR-0008):
134
+ * the one a `directory` given names; where none is given, the one the
135
+ * client's roots name, where they name one work tree of this repository and
136
+ * no other; and the server's own otherwise, as before. The server is started
137
+ * once, for the project Claude Code names, and a session in a worktree
138
+ * names that worktree to it in neither the project nor the server's root.
139
+ */
140
+ async function chosen(server, io, roots, given) {
141
+ if (given !== undefined) {
142
+ if (typeof given !== 'string')
143
+ return toolError('"directory" must be a string.');
144
+ if (isBlank(given))
145
+ return toolError(`"directory" is ${JSON.stringify(given)}, which names no directory; give it the directory the round is in, or leave it out.`);
146
+ const workspace = await treeOf(server, io, resolve(server.root, given));
147
+ if (workspace === null)
148
+ 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.`);
149
+ return { workspace, from: 'argument' };
150
+ }
151
+ const named = await roots();
152
+ if (named !== null) {
153
+ const trees = new Map();
154
+ for (const directory of named) {
155
+ const workspace = await treeOf(server, io, directory);
156
+ if (workspace !== null)
157
+ trees.set(realSpelling(workspace.root), workspace);
158
+ }
159
+ const [only, ...more] = [...trees.values()];
160
+ if (only !== undefined && more.length === 0)
161
+ return { workspace: only, from: 'roots' };
162
+ }
163
+ return { workspace: server, from: 'server' };
164
+ }
165
+ /** 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. */
166
+ function readIn(where) {
167
+ const how = where.from === 'argument' ? 'the "directory" given' : "the client's roots";
168
+ 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 } };
169
+ }
41
170
  /** The `base` argument, or the tool error for one that is not a string, or names no commit. */
42
171
  function baseOf(args) {
43
172
  const base = args['base'];
@@ -101,31 +230,41 @@ async function round(workspace, env, id) {
101
230
  return toolError(note);
102
231
  return { brief, briefs };
103
232
  }
104
- export function tools(workspace, env) {
233
+ export function tools(workspace, env, roots = NO_ROOTS) {
105
234
  const readOnly = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };
235
+ // A tool writes nothing to the server's streams, so these are never
236
+ // written to, and their mutants are equivalent: what a tool says is its
237
+ // answer.
238
+ const quiet = { write: () => true };
239
+ const io = { stdout: quiet, stderr: quiet, cwd: workspace.cwd, env };
106
240
  return [
107
241
  {
108
242
  descriptor: {
109
243
  name: 'start_round',
110
244
  title: 'Start a round',
111
245
  description: '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.',
112
- inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty }, additionalProperties: false },
246
+ inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty, directory: directoryProperty }, additionalProperties: false },
113
247
  annotations: readOnly,
114
248
  },
115
249
  async call(args) {
116
- const unknown = unknownArguments(args, ['brief', 'base']);
250
+ const unknown = unknownArguments(args, ['brief', 'base', 'directory']);
117
251
  if (unknown)
118
252
  return unknown;
119
253
  const base = baseOf(args);
120
254
  if ('text' in base)
121
255
  return base;
122
- const found = await round(workspace, env, args['brief']);
256
+ const where = await chosen(workspace, io, roots, args['directory']);
257
+ if ('text' in where)
258
+ return where;
259
+ const found = await round(where.workspace, env, args['brief']);
123
260
  if ('text' in found)
124
261
  return found;
125
- const packet = await buildContext(workspace, found.brief, found.briefs, reader, base.base);
262
+ const packet = await buildContext(where.workspace, found.brief, found.briefs, reader, base.base);
263
+ const { said, workTree } = readIn(where);
126
264
  return {
127
- text: packet.markdown,
265
+ text: `${packet.markdown}${said}`,
128
266
  structured: {
267
+ workTree,
129
268
  brief: found.brief.id,
130
269
  included: [...packet.included],
131
270
  omitted: [...packet.omitted],
@@ -148,9 +287,14 @@ export function tools(workspace, env) {
148
287
  inputSchema: {
149
288
  type: 'object',
150
289
  properties: {
151
- paths: { type: 'array', items: { type: 'string' }, description: 'Paths relative to the project root, or absolute inside it. An empty one is refused.' },
290
+ paths: {
291
+ type: 'array',
292
+ items: { type: 'string' },
293
+ 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.',
294
+ },
152
295
  brief: briefProperty,
153
296
  base: baseProperty,
297
+ directory: directoryProperty,
154
298
  },
155
299
  required: ['paths'],
156
300
  additionalProperties: false,
@@ -158,7 +302,7 @@ export function tools(workspace, env) {
158
302
  annotations: readOnly,
159
303
  },
160
304
  async call(args) {
161
- const unknown = unknownArguments(args, ['paths', 'brief', 'base']);
305
+ const unknown = unknownArguments(args, ['paths', 'brief', 'base', 'directory']);
162
306
  if (unknown)
163
307
  return unknown;
164
308
  const given = pathsOf(args);
@@ -167,12 +311,21 @@ export function tools(workspace, env) {
167
311
  const base = baseOf(args);
168
312
  if ('text' in base)
169
313
  return base;
170
- const found = await round(workspace, env, args['brief']);
171
- if ('text' in found)
172
- return found;
173
- const decisions = await checkPaths(workspace, found.brief, undefined, given.paths, workspace.root, reader, base.base);
314
+ const where = await chosen(workspace, io, roots, args['directory']);
315
+ if ('text' in where)
316
+ return where;
317
+ // Each path by the work tree of this repository that holds it, as the
318
+ // hook decides a write: the one read, another, or the server's own.
319
+ const decisions = [];
320
+ for (const part of await writesBy(workspace, where.workspace.root, given.paths, io)) {
321
+ const found = await round(part.workspace, env, args['brief']);
322
+ if ('text' in found)
323
+ return found;
324
+ decisions.push(...(await checkPaths(part.workspace, found.brief, undefined, part.paths, where.workspace.root, reader, base.base)));
325
+ }
174
326
  const text = decisions.map((d) => `${d.verdict}: ${d.message}${d.verdict === 'allow' ? '' : `. Next: ${d.hint}`}`).join('\n');
175
- return { text, structured: { decisions: decisions.map((d) => ({ ...d })) } };
327
+ const { said, workTree } = readIn(where);
328
+ return { text: `${text}${said}`, structured: { workTree, decisions: decisions.map((d) => ({ ...d })) } };
176
329
  },
177
330
  },
178
331
  {
@@ -192,6 +345,7 @@ export function tools(workspace, env) {
192
345
  },
193
346
  recommendation: { type: 'string', description: 'Which option you recommend, and why. Omit it when there is none: an empty one is refused.' },
194
347
  brief: briefProperty,
348
+ directory: directoryProperty,
195
349
  },
196
350
  required: ['paths', 'reason'],
197
351
  additionalProperties: false,
@@ -199,7 +353,7 @@ export function tools(workspace, env) {
199
353
  annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },
200
354
  },
201
355
  async call(args) {
202
- const unknown = unknownArguments(args, ['paths', 'reason', 'options', 'recommendation', 'brief']);
356
+ const unknown = unknownArguments(args, ['paths', 'reason', 'options', 'recommendation', 'brief', 'directory']);
203
357
  if (unknown)
204
358
  return unknown;
205
359
  // Every part of the memo before anything is written: a person rules
@@ -218,16 +372,20 @@ export function tools(workspace, env) {
218
372
  return toolError('"recommendation" must be a string.');
219
373
  if (recommendation !== undefined && isBlank(recommendation))
220
374
  return namesNothing('recommendation', 'recommend', recommendation);
221
- const found = await round(workspace, env, args['brief']);
375
+ const where = await chosen(workspace, io, roots, args['directory']);
376
+ if ('text' in where)
377
+ return where;
378
+ const found = await round(where.workspace, env, args['brief']);
222
379
  if ('text' in found)
223
380
  return found;
224
- const { request, memo } = await raiseEscalation(workspace, found.brief, {
381
+ const { request, memo } = await raiseEscalation(where.workspace, found.brief, {
225
382
  paths: given.paths,
226
383
  reason,
227
384
  options: choices.options,
228
385
  recommendation: recommendation ?? null,
229
386
  });
230
- return { text: `${memo}\nStop here until a person rules on ${request.id}.`, structured: { id: request.id } };
387
+ const { said, workTree } = readIn(where);
388
+ return { text: `${memo}\nStop here until a person rules on ${request.id}.${said}`, structured: { id: request.id, workTree } };
231
389
  },
232
390
  },
233
391
  {
@@ -235,29 +393,33 @@ export function tools(workspace, env) {
235
393
  name: 'audit_round',
236
394
  title: 'Audit the round',
237
395
  description: '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.',
238
- inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty }, additionalProperties: false },
396
+ inputSchema: { type: 'object', properties: { brief: briefProperty, base: baseProperty, directory: directoryProperty }, additionalProperties: false },
239
397
  annotations: readOnly,
240
398
  },
241
399
  async call(args) {
242
- const unknown = unknownArguments(args, ['brief', 'base']);
400
+ const unknown = unknownArguments(args, ['brief', 'base', 'directory']);
243
401
  if (unknown)
244
402
  return unknown;
245
403
  const base = baseOf(args);
246
404
  if ('text' in base)
247
405
  return base;
248
- const found = await round(workspace, env, args['brief']);
406
+ const where = await chosen(workspace, io, roots, args['directory']);
407
+ if ('text' in where)
408
+ return where;
409
+ const found = await round(where.workspace, env, args['brief']);
249
410
  if ('text' in found)
250
411
  return found;
251
- const result = await runAudit(workspace, found.brief, reader, base.base);
412
+ const result = await runAudit(where.workspace, found.brief, reader, base.base);
252
413
  const { counts, findings, measured } = result.report;
253
414
  // What was measured beside what was found: "nothing found" from an
254
415
  // audit that ran no goal is not a round that is done.
255
416
  const text = findings.length === 0
256
417
  ? 'The audit found nothing in what it measured.'
257
418
  : findings.map((f) => `${f.severity} ${f.rule}: ${f.message}. Next: ${f.hint}`).join('\n');
419
+ const { said, workTree } = readIn(where);
258
420
  return {
259
- text: `${text}\n\n${describeMeasured(measured)}\n\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)`,
260
- structured: { counts, measured: { ...measured }, findings: findings.map((f) => ({ ...f })) },
421
+ text: `${text}\n\n${describeMeasured(measured)}\n\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)${said}`,
422
+ structured: { workTree, counts, measured: { ...measured }, findings: findings.map((f) => ({ ...f })) },
261
423
  };
262
424
  },
263
425
  },
@@ -315,13 +477,18 @@ export async function mcpCommand(options, io) {
315
477
  // Claude Code starts a plugin's server in the plugin's directory, and names
316
478
  // the project in CLAUDE_PROJECT_DIR; the server answers for the project.
317
479
  const workspace = await openWorkspace({ ...options, root: options.root ?? (io.env['CLAUDE_PROJECT_DIR'] || undefined) }, io);
318
- const handle = createMcpServer({ name: 'spec-harness', version: version(), instructions: INSTRUCTIONS, tools: tools(workspace, io.env), prompts: prompts() });
480
+ const write = (line) => {
481
+ io.stdout.write(`${line}\n`);
482
+ };
483
+ // The work tree a session is in, where its client names it (ADR-0008).
484
+ const roots = rootsClient(write);
485
+ const handle = createMcpServer({ name: 'spec-harness', version: version(), instructions: INSTRUCTIONS, tools: tools(workspace, io.env, roots.ask), prompts: prompts() });
319
486
  // A session handed over whole, as a test hands it, is served as a client
320
487
  // would stream it on stdin. Only the built command line serves
321
488
  // process.stdin, and the suite spawns it from dist/, outside the sweep
322
489
  // (tests/integration/mcp.test.ts), so a mutant that ignores it survives.
323
490
  const input = io.stdin === undefined ? process.stdin : Readable.from([Buffer.from(await io.stdin())]);
324
- await serveLines(input, (line) => io.stdout.write(`${line}\n`), handle);
491
+ await serveLines(input, write, async (message) => (roots.observe(message) ? null : handle(message)));
325
492
  return 0;
326
493
  }
327
494
  //# sourceMappingURL=server.js.map
@@ -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 { 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 { 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 createMcpServer,\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, openWorkspace, version, 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\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']): ToolDefinition[] {\n const readOnly = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };\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 }, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['brief', 'base']);\n if (unknown) return unknown;\n const base = baseOf(args);\n if ('text' in base) return base;\n const found = await round(workspace, env, args['brief']);\n if ('text' in found) return found;\n const packet = await buildContext(workspace, found.brief, found.briefs, reader, base.base);\n return {\n text: packet.markdown,\n structured: {\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: { type: 'array', items: { type: 'string' }, description: 'Paths relative to the project root, or absolute inside it. An empty one is refused.' },\n brief: briefProperty,\n base: baseProperty,\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']);\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 found = await round(workspace, env, args['brief']);\n if ('text' in found) return found;\n const decisions = await checkPaths(workspace, found.brief, undefined, given.paths, workspace.root, reader, base.base);\n const text = decisions.map((d) => `${d.verdict}: ${d.message}${d.verdict === 'allow' ? '' : `. Next: ${d.hint}`}`).join('\\n');\n return { text, structured: { 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 },\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']);\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 found = await round(workspace, env, args['brief']);\n if ('text' in found) return found;\n const { request, memo } = await raiseEscalation(workspace, found.brief, {\n paths: given.paths,\n reason,\n options: choices.options,\n recommendation: recommendation ?? null,\n });\n return { text: `${memo}\\nStop here until a person rules on ${request.id}.`, structured: { id: request.id } };\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 }, additionalProperties: false },\n annotations: readOnly,\n },\n async call(args: JsonObject): Promise<ToolOutcome> {\n const unknown = unknownArguments(args, ['brief', 'base']);\n if (unknown) return unknown;\n const base = baseOf(args);\n if ('text' in base) return base;\n const found = await round(workspace, env, args['brief']);\n if ('text' in found) return found;\n const result = await runAudit(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 return {\n text: `${text}\\n\\n${describeMeasured(measured)}\\n\\n${counts.error} error(s), ${counts.warning} warning(s), ${counts.note} note(s)`,\n structured: { 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 handle = createMcpServer({ name: 'spec-harness', version: version(), instructions: INSTRUCTIONS, tools: tools(workspace, io.env), 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, (line) => io.stdout.write(`${line}\\n`), handle);\n return 0;\n}\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGjF,OAAO,EAAE,UAAU,EAAE,OAAO,EAAqB,MAAM,YAAY,CAAC;AACpE,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,QAAQ,EACR,UAAU,EACV,SAAS,EACT,gBAAgB,GAKjB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAA4C,MAAM,gBAAgB,CAAC;AAEjL,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,YAAY,GACvB,yEAAyE;IACzE,iKAAiK;IACjK,mJAAmJ;IACnJ,sGAAsG;IACtG,kGAAkG,CAAC;AAErG,MAAM,aAAa,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6FAA6F,EAAE,CAAC;AACrJ,MAAM,YAAY,GAAG;IACnB,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,sJAAsJ;CACzJ,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,QAAgB,EAAE,MAAoB,EAAE,KAAa;IACzE,OAAO,SAAS,CAAC,GAAG,UAAU,CAAC,IAAI,QAAQ,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,iBAAiB,GAAG;IACxB,IAAI,EAAE,QAAQ;IACd,WAAW,EACT,mMAAmM;CACtM,CAAC;AAQF,sGAAsG;AACtG,MAAM,QAAQ,GAAU,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC;AAEzC,uHAAuH;AACvH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAmB9B,MAAM,UAAU,WAAW,CAAC,KAA6B,EAAE,KAAK,GAAG,QAAQ;IACzE,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqC,CAAC;IAC7D,MAAM,QAAQ,GAAG,CAAC,YAAqB,EAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/G,OAAO;QACL,OAAO,CAAC,OAAO;YACb,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,OAAO,KAAK,CAAC;YACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,YAAY,IAAI,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;gBAAE,QAAQ,GAAG,IAAI,CAAC;YACzI,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YACzB,uEAAuE;YACvE,sEAAsE;YACtE,cAAc;YACd,MAAM,MAAM,GAAG,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvG,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YACvC,MAAM,CAAC,OAAO,CAAC,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,CAAC,GAAG;YACP,IAAI,CAAC,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC3B,KAAK,IAAI,CAAC,CAAC;YACX,MAAM,EAAE,GAAG,sBAAsB,KAAK,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;gBACpD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBACrD,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE;oBAC1B,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnB,CAAC,CAAC,CAAC;gBACH,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnB,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACvC,iHAAiH;YACjH,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAa,EAAE,EAAE;gBACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrD,IAAI,OAAO,GAAG,KAAK,QAAQ;oBAAE,OAAO,EAAE,CAAC;gBACvC,IAAI,CAAC;oBACH,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9B,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AAQD;;;;;GAKG;AACH,KAAK,UAAU,MAAM,CAAC,MAAiB,EAAE,EAAS,EAAE,SAAiB;IACnE,sEAAsE;IACtE,uEAAuE;IACvE,mCAAmC;IACnC,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,wEAAwE;IACxE,4DAA4D;IAC5D,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1E,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;IAC3C,yFAAyF;IACzF,IAAI,MAAM,KAAK,IAAI,IAAI,YAAY,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5F,OAAO,SAAS,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,MAAM,CAAC,MAAiB,EAAE,EAAS,EAAE,KAAY,EAAE,KAAc;IAC9E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC,+BAA+B,CAAC,CAAC;QACjF,IAAI,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,qFAAqF,CAAC,CAAC;QACnK,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QACxE,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,6HAA6H,CAAC,CAAC;QAC/M,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IACzC,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,CAAC;IAC5B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;QAC3C,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC;YACtD,IAAI,SAAS,KAAK,IAAI;gBAAE,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACzF,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC/C,CAAC;AAED,2IAA2I;AAC3I,SAAS,MAAM,CAAC,KAAa;IAC3B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACvF,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gCAAgC,KAAK,CAAC,SAAS,CAAC,IAAI,WAAW,GAAG,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;AACzL,CAAC;AAED,+FAA+F;AAC/F,SAAS,MAAM,CAAC,IAAgB;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC,0BAA0B,CAAC,CAAC;IACjG,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACnF,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC;AAED,gHAAgH;AAChH,SAAS,OAAO,CAAC,IAAgB;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9F,OAAO,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,YAAY,CAAC,SAAS,KAAK,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAW,CAAC,CAAC;IACzF,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,SAAS,SAAS,CAAC,IAAgB;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC,6BAA6B,CAAC,CAAC;IACzE,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;QAC1C,mEAAmE;QACnE,MAAM,KAAK,GAAe,IAAI,IAAI,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC,YAAY,KAAK,4BAA4B,CAAC,CAAC;QAC/F,IAAI,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC,YAAY,KAAK,eAAe,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;QACxK,IAAI,OAAO,WAAW,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC,YAAY,KAAK,kCAAkC,CAAC,CAAC;QAC3G,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,SAAoB,EAAE,GAAiB,EAAE,EAAW;IACvE,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAC9F,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACxG,0EAA0E;IAC1E,wBAAwB;IACxB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnE,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,SAAoB,EAAE,GAAiB,EAAE,KAAK,GAAU,QAAQ;IACpF,MAAM,QAAQ,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IACpF,oEAAoE;IACpE,wEAAwE;IACxE,UAAU;IACV,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,GAAY,EAAE,CAAC,IAAI,EAAE,CAAC;IAC7C,MAAM,EAAE,GAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAC5E,OAAO;QACL;YACE,UAAU,EAAE;gBACV,IAAI,EAAE,aAAa;gBACnB,KAAK,EAAE,eAAe;gBACtB,WAAW,EACT,2NAA2N;gBAC7N,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;gBACpJ,WAAW,EAAE,QAAQ;aACtB;YACD,KAAK,CAAC,IAAI,CAAC,IAAgB;gBACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;gBACvE,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC1B,IAAI,MAAM,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAC;gBAChC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;gBACpE,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC/D,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBACjG,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACzC,OAAO;oBACL,IAAI,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,IAAI,EAAE;oBACjC,UAAU,EAAE;wBACV,QAAQ;wBACR,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE;wBACrB,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC;wBAC9B,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;wBAC5B,UAAU,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC;wBAClC,mBAAmB,EAAE,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC;wBACpD,qBAAqB,EAAE,CAAC,GAAG,MAAM,CAAC,qBAAqB,CAAC;wBACxD,eAAe,EAAE,CAAC,GAAG,MAAM,CAAC,eAAe,CAAC;wBAC5C,qBAAqB,EAAE,CAAC,GAAG,MAAM,CAAC,qBAAqB,CAAC;wBACxD,qBAAqB,EAAE,CAAC,GAAG,MAAM,CAAC,qBAAqB,CAAC;wBACxD,cAAc,EAAE,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC;qBAC3C;iBACF,CAAC;YACJ,CAAC;SACF;QACD;YACE,UAAU,EAAE;gBACV,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,iCAAiC;gBACxC,WAAW,EACT,kKAAkK;gBACpK,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,KAAK,EAAE;4BACL,IAAI,EAAE,OAAO;4BACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;4BACzB,WAAW,EAAE,mLAAmL;yBACjM;wBACD,KAAK,EAAE,aAAa;wBACpB,IAAI,EAAE,YAAY;wBAClB,SAAS,EAAE,iBAAiB;qBAC7B;oBACD,QAAQ,EAAE,CAAC,OAAO,CAAC;oBACnB,oBAAoB,EAAE,KAAK;iBAC5B;gBACD,WAAW,EAAE,QAAQ;aACtB;YACD,KAAK,CAAC,IAAI,CAAC,IAAgB;gBACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;gBAChF,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC1B,IAAI,MAAM,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAC;gBAChC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;gBACpE,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,sEAAsE;gBACtE,oEAAoE;gBACpE,MAAM,SAAS,GAAG,EAAE,CAAC;gBACrB,KAAK,MAAM,IAAI,IAAI,MAAM,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;oBACpF,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;oBAC9D,IAAI,MAAM,IAAI,KAAK;wBAAE,OAAO,KAAK,CAAC;oBAClC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACrI,CAAC;gBACD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9H,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACzC,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YAC3G,CAAC;SACF;QACD;YACE,UAAU,EAAE;gBACV,IAAI,EAAE,oBAAoB;gBAC1B,KAAK,EAAE,sBAAsB;gBAC7B,WAAW,EACT,mMAAmM;gBACrM,WAAW,EAAE;oBACX,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,yEAAyE,EAAE;wBAC3I,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kFAAkF,EAAE;wBAC3H,OAAO,EAAE;4BACP,IAAI,EAAE,OAAO;4BACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE;4BACzI,WAAW,EAAE,gGAAgG;yBAC9G;wBACD,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2FAA2F,EAAE;wBAC5I,KAAK,EAAE,aAAa;wBACpB,SAAS,EAAE,iBAAiB;qBAC7B;oBACD,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;oBAC7B,oBAAoB,EAAE,KAAK;iBAC5B;gBACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE;aAClF;YACD,KAAK,CAAC,IAAI,CAAC,IAAgB;gBACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;gBAC/G,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBAC5B,oEAAoE;gBACpE,gEAAgE;gBAChE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC9B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;oBAAE,OAAO,SAAS,CAAC,uBAAuB,CAAC,CAAC;gBAC7F,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,MAAM,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBACtC,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBAC9C,IAAI,cAAc,KAAK,SAAS,IAAI,OAAO,cAAc,KAAK,QAAQ;oBAAE,OAAO,SAAS,CAAC,oCAAoC,CAAC,CAAC;gBAC/H,IAAI,cAAc,KAAK,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;oBAAE,OAAO,YAAY,CAAC,gBAAgB,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;gBAChI,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;gBACpE,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC/D,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE;oBAC5E,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,MAAM;oBACN,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,cAAc,EAAE,cAAc,IAAI,IAAI;iBACvC,CAAC,CAAC;gBACH,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACzC,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,uCAAuC,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC;YAChI,CAAC;SACF;QACD;YACE,UAAU,EAAE;gBACV,IAAI,EAAE,aAAa;gBACnB,KAAK,EAAE,iBAAiB;gBACxB,WAAW,EACT,sPAAsP;gBACxP,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;gBACpJ,WAAW,EAAE,QAAQ;aACtB;YACD,KAAK,CAAC,IAAI,CAAC,IAAgB;gBACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;gBACvE,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC1B,IAAI,MAAM,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAC;gBAChC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;gBACpE,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC/D,IAAI,MAAM,IAAI,KAAK;oBAAE,OAAO,KAAK,CAAC;gBAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/E,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;gBACrD,mEAAmE;gBACnE,sDAAsD;gBACtD,MAAM,IAAI,GACR,QAAQ,CAAC,MAAM,KAAK,CAAC;oBACnB,CAAC,CAAC,8CAA8C;oBAChD,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/F,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACzC,OAAO;oBACL,IAAI,EAAE,GAAG,IAAI,OAAO,gBAAgB,CAAC,QAAQ,CAAC,OAAO,MAAM,CAAC,KAAK,cAAc,MAAM,CAAC,OAAO,gBAAgB,MAAM,CAAC,IAAI,WAAW,IAAI,EAAE;oBACzI,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,GAAG,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE;iBACvG,CAAC;YACJ,CAAC;SACF;QACD;YACE,UAAU,EAAE;gBACV,IAAI,EAAE,aAAa;gBACnB,KAAK,EAAE,iBAAiB;gBACxB,WAAW,EAAE,kFAAkF;gBAC/F,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE;gBAC5E,WAAW,EAAE,QAAQ;aACtB;YACD,KAAK,CAAC,IAAI,CAAC,IAAgB;gBACzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC3C,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBAC5B,MAAM,IAAI,GAAG,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;gBAC3F,MAAM,IAAI,GAAG,IAAI;qBACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,SAAS,UAAU,CAAC,CAAC,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;qBAC5L,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YACjI,CAAC;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAsF;IAChG,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,wDAAwD,EAAE;IAC3I,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,0BAA0B,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,oBAAoB,EAAE;IAC9G,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE;IAC5F,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE;CACjG,CAAC;AAEF,SAAS,SAAS,CAAC,IAAY;IAC7B,2EAA2E;IAC3E,2EAA2E;IAC3E,uCAAuC;IACvC,MAAM,IAAI,GAAG,YAAY,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,aAAa,IAAI,WAAW,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACzG,yEAAyE;IACzE,2CAA2C;IAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,UAAU,EAAE;YACV,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;SACvF;QACD,KAAK,CAAC,GAAG,CAAC,IAAsC;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,QAAQ,KAAK,KAAK,EAAE,EAAE,CAAC;YACvH,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACrG,CAAC;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB,EAAE,EAAS;IAC1D,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7H,MAAM,KAAK,GAAG,CAAC,IAAY,EAAQ,EAAE;QACnC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC;IACF,uEAAuE;IACvE,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACzK,yEAAyE;IACzE,+DAA+D;IAC/D,uEAAuE;IACvE,yEAAyE;IACzE,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACtG,MAAM,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACrG,OAAO,CAAC,CAAC;AACX,CAAC","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"]}