@descent-vtt/spec-harness 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8,25 +8,24 @@
8
8
  * failed, an output its reader closed, an error nothing here expected. A run
9
9
  * that could not look must never exit as though it looked and found nothing
10
10
  * (spec-core ADR-0005).
11
+ *
12
+ * A command loads what it runs. This module imports what every run needs,
13
+ * the hook's before a write among them, and a module that only some
14
+ * commands run is imported where one of them is the command: the hook
15
+ * runs before and after every write an agent makes, and what it loaded of
16
+ * the other commands was a wait before each (ADR-0002). A module that
17
+ * cannot be loaded is thrown where it was asked for, and ends the run in a
18
+ * line and exit 2, as every error does.
11
19
  */
12
20
  import { SiblingOutputError } from './briefs.js';
13
- import { auditCommand, contextCommand, escalateCommand, probeCommand, ruleCommand, rulingsCommand } from './commands.js';
14
21
  import { ConfigError, SIBLINGS } from './config.js';
15
- import { describeBase, describeClaudeCode, describeClaudeRelease, describeGitHook, describePlugin, describeSignerKeys, describeSignerProblem, describeSigners, wiringState, } from './configure.js';
16
22
  import { isDirectory } from './fs.js';
17
23
  import { GitError, show, stagedChanges } from './git.js';
18
24
  import { claudeResponse, gitResponse, parseClaudeHook } from './hooks.js';
19
- import { claudeVersion } from './host.js';
20
- import { premisesCommand } from './premises.js';
21
- import { createReader } from './reader.js';
22
- import { checkPaths, claudeCodeWiring, diagnoseBrief, resolveBase, specBriefPlugin } from './round.js';
23
- import { mcpCommand } from './server.js';
24
- import { gitHook, initCommand } from './setup.js';
25
- import { notFido2, readAllowedSigners } from './signers.js';
26
25
  import { SiblingError } from './siblings.js';
27
26
  import { emptyValue, heldHookLine, isBlank, isClaudeHook, readHookLine, refusal, unreadHookLine } from './usage.js';
28
- import { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';
29
- import { activeBrief, describeActive, EXIT_ERROR, EXIT_FAILED, EXIT_OK, json, openWorkspace, parseOptions, UsageError, version, } from './workspace.js';
27
+ import { CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';
28
+ import { activeBrief, answerOf, describeActive, EXIT_ERROR, EXIT_FAILED, EXIT_OK, json, openWorkspace, parseOptions, UsageError, version, } from './workspace.js';
30
29
  export { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version } from './workspace.js';
31
30
  export const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work
32
31
 
@@ -61,7 +60,10 @@ Commands:
61
60
  named, how Claude Code runs the guard, and git's hook. Exit 1
62
61
  when a sibling is older than this release needs, the guard is
63
62
  installed twice, its hook's line turns it off or holds every
64
- write, or Claude Code is too old to run its hooks.
63
+ write, disableAllHooks or an array for a matcher switches it
64
+ off, the plugin that is turned on is not on this machine and
65
+ nothing else guards, Claude Code is too old to run its hooks,
66
+ or git stops every commit at what stands for its hook.
65
67
 
66
68
  Options:
67
69
  --brief <id> The brief the round works on. Otherwise SPEC_BRIEF, then the branch.
@@ -86,12 +88,17 @@ nothing for either.
86
88
  Exit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.
87
89
  `;
88
90
  /* ------------------------------------------------------------------- guard */
89
- const reader = createReader();
91
+ /**
92
+ * The reader of a brief's rulings, loaded where a ruling is read: a write
93
+ * to a file no brief protects reads none.
94
+ */
95
+ const reader = async () => (await import('./reader.js')).createReader();
90
96
  async function decisionsFor(workspace, options, io, given, cwd) {
91
97
  const active = await activeBrief(workspace, options, io.env);
92
98
  const { brief, note, problem } = describeActive(active);
93
99
  if (problem !== null)
94
100
  return { problem };
101
+ const { checkPaths } = await import('./round.js');
95
102
  return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };
96
103
  }
97
104
  const SYMBOL = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };
@@ -241,7 +248,41 @@ async function hookCommand(options, io) {
241
248
  throw new UsageError('hook takes "claude" or "git"');
242
249
  }
243
250
  /* ------------------------------------------------------------------ doctor */
251
+ /**
252
+ * The base, and the allowed-signers file as it is on it: the file waits on
253
+ * the base, and the two on nothing else doctor asks. A --base given nothing
254
+ * is no base, said as the brief's is, in the report.
255
+ */
256
+ async function baseAndSigners({ resolveBase }, workspace, flag, signersFile) {
257
+ // Nothing in doctor asks what kind a base is but whether it is resolved, so
258
+ // the mutant that names this one otherwise is equivalent.
259
+ const base = flag !== undefined && isBlank(flag) ? { kind: 'unresolved', reason: emptyValue('--base', 'base', flag) } : await resolveBase(workspace, flag);
260
+ // An unresolved base has no commit: git shows nothing for one, so asking
261
+ // anyway reads as no file, and that mutant is equivalent.
262
+ const signersText = base.kind === 'resolved' ? await show(base.sha, signersFile, workspace.root) : null;
263
+ return { base, signersText };
264
+ }
265
+ /**
266
+ * How Claude Code is wired to the guard, and the release of the one on
267
+ * `PATH`, which waits on the wiring: only a Claude Code that runs the guard
268
+ * is asked its release, since one older than the hooks need lets every
269
+ * write through unguarded. `null` where it was not asked. The wiring asks
270
+ * it itself, since which writes a line is started for can turn on the
271
+ * release as well (round.ts); the two are told apart here for the report,
272
+ * which has a place of its own for the release.
273
+ */
274
+ async function wiringAndRelease({ claudeCodeWiring }, root, io) {
275
+ const { release, ...wiring } = await claudeCodeWiring(root, io);
276
+ return { wiring, release };
277
+ }
244
278
  async function doctorCommand(options, io) {
279
+ // What doctor alone runs of them, loaded before anything is asked: the
280
+ // five things below are asked at once, and none waits on a module.
281
+ const [configure, round, setup, signing] = await Promise.all([import('./configure.js'), import('./round.js'), import('./setup.js'), import('./signers.js')]);
282
+ const { describeBase, describeClaudeCode, describeClaudeRelease, describeGitHook, describeHooksOff, describePlugin, describePresence, describeSignerKeys, describeSignerProblem, describeSigners, guardSwitchedOff, wiringState } = configure;
283
+ const { diagnoseBrief, specBriefPlugin } = round;
284
+ const { gitHook } = setup;
285
+ const { notFido2, readAllowedSigners } = signing;
245
286
  const workspace = await openWorkspace(options, io);
246
287
  const rows = SIBLINGS.map((name) => {
247
288
  const sibling = workspace.siblings.locate(name);
@@ -254,19 +295,25 @@ async function doctorCommand(options, io) {
254
295
  const detail = sibling.version === null ? `${command} (named in .spec-harness.json; its version is not checked)` : `${command} (${sibling.version})`;
255
296
  return { ...row, version: sibling.version, detail };
256
297
  });
257
- const named = await diagnoseBrief(workspace, options, io.env);
298
+ const signersFile = workspace.config.rulings.allowedSigners;
299
+ // Five things that wait on the work tree and on nothing of one another,
300
+ // each a process or a chain of them. Asked one after another, Claude
301
+ // Code's release, the longest wait of a doctor on Windows, was asked for
302
+ // only when every answer of git's before it was in. So they are asked at
303
+ // once, and read below in the order they were asked in before: where more
304
+ // than one fails, the first of that order is the one thrown, whichever
305
+ // failed first by the clock (ADR-0002).
306
+ const [briefAsked, baseAsked, pluginAsked, claudeAsked, hookAsked] = await Promise.allSettled([
307
+ diagnoseBrief(workspace, options, io.env),
308
+ baseAndSigners(round, workspace, options.base, signersFile),
309
+ specBriefPlugin(workspace.root),
310
+ wiringAndRelease(round, workspace.root, io),
311
+ gitHook(workspace.root),
312
+ ]);
313
+ const named = answerOf(briefAsked);
258
314
  // A ruling counts only by a signature checked against the allowed signers
259
315
  // on the base, and only once spec-brief's archive asks the plugin about it.
260
- // A --base given nothing is no base, said as the brief's is, in the report.
261
- // Nothing below asks what kind a base is but whether it is resolved, so the
262
- // mutant that names this one otherwise is equivalent.
263
- const base = options.base !== undefined && isBlank(options.base)
264
- ? { kind: 'unresolved', reason: emptyValue('--base', 'base', options.base) }
265
- : await resolveBase(workspace, options.base);
266
- const signersFile = workspace.config.rulings.allowedSigners;
267
- // An unresolved base has no commit: git shows nothing for one, so asking
268
- // anyway reads as no file, and that mutant is equivalent.
269
- const signersText = base.kind === 'resolved' ? await show(base.sha, signersFile, workspace.root) : null;
316
+ const { base, signersText } = answerOf(baseAsked);
270
317
  const onBase = base.kind === 'resolved' ? signersText !== null : null;
271
318
  const signers = describeSigners(signersFile, base.kind === 'resolved' ? base.ref : null, onBase === true);
272
319
  // Which keys sign, as notes: a key that is not FIDO2 can still be one the
@@ -274,10 +321,10 @@ async function doctorCommand(options, io) {
274
321
  const read = readAllowedSigners(signersText ?? '');
275
322
  const plain = notFido2(read.signers);
276
323
  const signerNotes = [describeSignerKeys(plain), ...read.problems.map(describeSignerProblem)].filter((note) => note !== null);
277
- const plugin = await specBriefPlugin(workspace.root);
324
+ const plugin = answerOf(pluginAsked);
278
325
  // The plugin and init's entries both on: Claude Code runs every guard twice
279
326
  // and registers the server twice (ADR-0012).
280
- const wiring = await claudeCodeWiring(workspace.root, io);
327
+ const { wiring, release } = answerOf(claudeAsked);
281
328
  const claude = wiringState(wiring);
282
329
  // What the hook does with each line the settings hold for it, where there
283
330
  // is something to say: more on it than init writes, a line that turns the
@@ -285,12 +332,14 @@ async function doctorCommand(options, io) {
285
332
  // Claude Code starts it for where they are not all of them, and what
286
333
  // onFailure changes.
287
334
  const lineNotes = wiring.lines.flatMap((line) => [line.detail, line.cover, line.note]).filter((note) => note !== null);
288
- // Only a Claude Code that runs the guard is asked its release: one older
289
- // than the hooks need lets every write through unguarded.
290
- const release = claude === 'none' ? null : checkClaudeCode(await claudeVersion(io.env));
335
+ // What stands over every line: a plugin that is turned on and is not on
336
+ // this machine, or cannot be told to be, and disableAllHooks, which
337
+ // switches off whatever hooks there are.
338
+ const switchedOff = guardSwitchedOff(wiring);
339
+ const wiringNotes = [describePresence(wiring), wiring.hooksOff === null ? null : describeHooksOff(wiring.hooksOff, switchedOff)].filter((note) => note !== null);
291
340
  // How the hook runs the harness is a note: one that goes through npx guards
292
341
  // as well as one that does not, and fails nothing, --strict or not.
293
- const { hook, note: hookNote } = await gitHook(workspace.root);
342
+ const { hook, note: hookNote } = answerOf(hookAsked);
294
343
  const branch = workspace.branch === null ? '(detached)' : `${workspace.branch}${workspace.branchSource === undefined ? '' : ` (detached; ${workspace.branchSource} names it)`}`;
295
344
  if (options.format === 'json') {
296
345
  io.stdout.write(json('doctor', {
@@ -312,6 +361,7 @@ async function doctorCommand(options, io) {
312
361
  state: claude,
313
362
  ...wiring,
314
363
  detail: describeClaudeCode(wiring),
364
+ notes: wiringNotes,
315
365
  release: release === null
316
366
  ? { state: 'unchecked', version: null, minimum: CLAUDE_CODE_MINIMUM, detail: 'not asked: nothing wires Claude Code to the guard here' }
317
367
  : { state: release.state, version: 'version' in release ? release.version : null, minimum: CLAUDE_CODE_MINIMUM, detail: describeClaudeRelease(release) },
@@ -331,6 +381,7 @@ async function doctorCommand(options, io) {
331
381
  ...more(signerNotes),
332
382
  `plugin ${describePlugin(plugin)}`,
333
383
  `claude ${describeClaudeCode(wiring)}`,
384
+ ...more(wiringNotes),
334
385
  ...more(lineNotes),
335
386
  ...more(release === null ? [] : [describeClaudeRelease(release)]),
336
387
  `git ${describeGitHook(hook)}`,
@@ -345,15 +396,21 @@ async function doctorCommand(options, io) {
345
396
  // a choice; with none installed, the harness can check nothing. A double
346
397
  // install is a problem too, where no Claude Code wiring at all is a choice,
347
398
  // and so are a hook whose own line turns the guard off or holds every
348
- // write, and a Claude Code too old to run the hooks. A release that cannot
349
- // be told is not fine either, nor a line whose reading cannot be: --strict
350
- // fails both.
399
+ // write, guard hooks that disableAllHooks switches off, a plugin that is
400
+ // turned on and is not on this machine where no hook of init's stands in
401
+ // for it, a Claude Code too old to run the hooks, and something at the
402
+ // path of git's pre-commit hook that git cannot run and stops every
403
+ // commit at. A release that cannot be told is not fine either, nor a
404
+ // line whose reading cannot be, nor a plugin that cannot be told to be on
405
+ // this machine: --strict fails the three.
351
406
  const outdated = rows.some((row) => row.state === 'outdated');
352
407
  const usable = rows.some((row) => row.state === 'found');
353
408
  const off = wiring.lines.some((line) => line.state === 'off' || line.state === 'held');
409
+ const missing = wiring.presence?.state === 'absent' && wiring.hooks.length === 0;
354
410
  const tooOld = release?.state === 'outdated';
355
- const untold = options.strict && (release?.state === 'unknown' || wiring.lines.some((line) => line.state === 'unknown'));
356
- return outdated || !usable || claude === 'both' || off || tooOld || untold ? EXIT_FAILED : EXIT_OK;
411
+ const stopped = hook.state === 'stops';
412
+ const untold = options.strict && (release?.state === 'unknown' || wiring.lines.some((line) => line.state === 'unknown') || wiring.presence?.state === 'unknown');
413
+ return outdated || !usable || claude === 'both' || off || switchedOff || missing || tooOld || stopped || untold ? EXIT_FAILED : EXIT_OK;
357
414
  }
358
415
  /* ---------------------------------------------------------------- dispatch */
359
416
  /**
@@ -363,19 +420,21 @@ async function doctorCommand(options, io) {
363
420
  * construct` is an unknown command with exit 2.
364
421
  */
365
422
  const COMMANDS = new Map(
366
- // One for every command that has a shape (usage.ts), which the compiler holds.
423
+ // One for every command that has a shape (usage.ts), which the compiler
424
+ // holds. A command of another module loads its module when it is the one
425
+ // typed, and no other command's.
367
426
  Object.entries({
368
427
  guard: guardCommand,
369
428
  hook: hookCommand,
370
- context: contextCommand,
371
- audit: auditCommand,
372
- escalate: escalateCommand,
373
- rule: ruleCommand,
374
- rulings: rulingsCommand,
375
- probe: probeCommand,
376
- premises: premisesCommand,
377
- init: initCommand,
378
- mcp: mcpCommand,
429
+ context: async (options, io) => (await import('./commands.js')).contextCommand(options, io),
430
+ audit: async (options, io) => (await import('./commands.js')).auditCommand(options, io),
431
+ escalate: async (options, io) => (await import('./commands.js')).escalateCommand(options, io),
432
+ rule: async (options, io) => (await import('./commands.js')).ruleCommand(options, io),
433
+ rulings: async (options, io) => (await import('./commands.js')).rulingsCommand(options, io),
434
+ probe: async (options, io) => (await import('./commands.js')).probeCommand(options, io),
435
+ premises: async (options, io) => (await import('./premises.js')).premisesCommand(options, io),
436
+ init: async (options, io) => (await import('./setup.js')).initCommand(options, io),
437
+ mcp: async (options, io) => (await import('./server.js')).mcpCommand(options, io),
379
438
  doctor: doctorCommand,
380
439
  }));
381
440
  async function dispatch(argv, io) {
@@ -433,6 +492,12 @@ async function dispatch(argv, io) {
433
492
  * launcher answers in the same words; here it is a caller's stream that
434
493
  * throws it. It is read by its code: stdout and stderr are the only pipes
435
494
  * the harness writes to.
495
+ *
496
+ * Nor is a module of the build that is not there. The launcher says a build
497
+ * without its command line in a line, and a module a command asks for where
498
+ * it runs is said in the same line: a build with a file missing is not a
499
+ * defect a stack leads to. It is read by its code too: the harness imports
500
+ * nothing but its own modules and Node's.
436
501
  */
437
502
  export async function run(argv, io) {
438
503
  try {
@@ -454,6 +519,8 @@ export async function run(argv, io) {
454
519
  io.stderr.write(`spec-harness: unexpected error: ${String(error)}\n`);
455
520
  else if (error.code === 'EPIPE')
456
521
  io.stderr.write('spec-harness: stdout was closed before all of the output was written\n');
522
+ else if (error.code === 'ERR_MODULE_NOT_FOUND')
523
+ io.stderr.write('spec-harness: build output is missing; run "npm run build" first, or install the published package.\n');
457
524
  else
458
525
  io.stderr.write(`spec-harness: unexpected error: ${error.stack ?? error.message}\n`);
459
526
  return EXIT_ERROR;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACzH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAoB,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAa,MAAM,YAAY,CAAC;AAClH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAgC,MAAM,YAAY,CAAC;AAClJ,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EACL,WAAW,EACX,cAAc,EACd,UAAU,EACV,WAAW,EACX,OAAO,EACP,IAAI,EACJ,aAAa,EACb,YAAY,EACZ,UAAU,EACV,OAAO,GAKR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAc,MAAM,gBAAgB,CAAC;AAEnG,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDnB,CAAC;AAGF,+EAA+E;AAE/E,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAE9B,KAAK,UAAU,YAAY,CACzB,SAAoB,EACpB,OAAgB,EAChB,EAAS,EACT,KAAwB,EACxB,GAAW;IAEX,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IACzC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;AACnG,CAAC;AAED,MAAM,MAAM,GAAwC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAE3H,KAAK,UAAU,YAAY,CAAC,OAAgB,EAAE,EAAS;IACrD,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;IAC5F,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IACxF,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QACtD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;YACtE,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO;gBAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;IAC3D,OAAO,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;AACvE,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,SAAS,CAAC,EAAS;IAChC,2EAA2E;IAC3E,6EAA6E;IAC7E,8CAA8C;IAC9C,IAAI,EAAE,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IACtE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,UAAU,CAAC,EAAS;IACjC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uEAAuE;QACvE,iEAAiE;QACjE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,mDAAoD,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QACjG,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACvB,sEAAsE;QACtE,+DAA+D;QAC/D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QACpD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,EAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAa;IACrD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,wDAAwD,IAAI,IAAI,CAAC,CAAC;IACxG,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,EAAS;IAC/C,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,OAAO,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,OAAgB,EAAE,EAAS;IACpD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC;QAChD,sEAAsE;QACtE,kEAAkE;QAClE,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC7D,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC;QAClC,IAAI,SAAoB,CAAC;QACzB,IAAI,CAAC;YACH,SAAS,GAAG,MAAM,aAAa,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9G,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,UAAU;gBAAE,OAAO,OAAO,CAAC;YAChD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC/E,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;gBACzB,uEAAuE;gBACvE,mEAAmE;gBACnE,2DAA2D;gBAC3D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,iDAAiD,CAAC,CAAC;gBACvH,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YAClE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjC,OAAO,QAAQ,CAAC,QAAQ,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,KAAK,KAAK,YAAY;gBAAE,MAAM,KAAK,CAAC;YAChD,mEAAmE;YACnE,4DAA4D;YAC5D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA2C,KAAe,CAAC,OAAO,IAAI,CAAC,CAAC;YACxF,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAClF,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;YACtD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC3B,CAAC;IACD,MAAM,IAAI,UAAU,CAAC,8BAA8B,CAAC,CAAC;AACvD,CAAC;AAED,+EAA+E;AAE/E,KAAK,UAAU,aAAa,CAAC,OAAgB,EAAE,EAAS;IACtD,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QACjF,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACxF,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACrG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,4DAA4D,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,CAAC;QACrJ,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC9D,0EAA0E;IAC1E,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,sDAAsD;IACtD,MAAM,IAAI,GACR,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;QACjD,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;QAC5E,CAAC,CAAC,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;IAC5D,yEAAyE;IACzE,0DAA0D;IAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxG,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC;IAC1G,0EAA0E;IAC1E,mEAAmE;IACnE,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC7I,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrD,4EAA4E;IAC5E,6CAA6C;IAC7C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,qEAAqE;IACrE,qBAAqB;IACrB,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvI,yEAAyE;IACzE,0DAA0D;IAC1D,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxF,4EAA4E;IAC5E,oEAAoE;IACpE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,SAAS,CAAC,YAAY,YAAY,EAAE,CAAC;IAChL,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,EAAE,CAAC,MAAM,CAAC,KAAK,CACb,IAAI,CAAC,QAAQ,EAAE;YACb,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,IAAI;YAC5C,KAAK,EAAE,KAAK,CAAC,EAAE;YACf,YAAY,EAAE,KAAK,CAAC,OAAO;YAC3B,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE;YAChI,cAAc,EAAE;gBACd,IAAI,EAAE,WAAW;gBACjB,MAAM;gBACN,MAAM,EAAE,OAAO;gBACf,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;gBACvF,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB;YACD,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE;YAC3G,UAAU,EAAE;gBACV,KAAK,EAAE,MAAM;gBACb,GAAG,MAAM;gBACT,MAAM,EAAE,kBAAkB,CAAC,MAAM,CAAC;gBAClC,OAAO,EACL,OAAO,KAAK,IAAI;oBACd,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,wDAAwD,EAAE;oBACvI,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE;aAC7J;YACD,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE;YACtH,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,CAAC,KAAwB,EAAY,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QAC5F,EAAE,CAAC,MAAM,CAAC,KAAK,CACb;YACE,WAAW,SAAS,CAAC,IAAI,EAAE;YAC3B,WAAW,MAAM,EAAE;YACnB,WAAW,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,OAAO,EAAE,EAAE;YAC7F,WAAW,YAAY,CAAC,IAAI,CAAC,EAAE;YAC/B,WAAW,OAAO,EAAE;YACpB,GAAG,IAAI,CAAC,WAAW,CAAC;YACpB,WAAW,cAAc,CAAC,MAAM,CAAC,EAAE;YACnC,WAAW,kBAAkB,CAAC,MAAM,CAAC,EAAE;YACvC,GAAG,IAAI,CAAC,SAAS,CAAC;YAClB,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;YACjE,WAAW,eAAe,CAAC,IAAI,CAAC,EAAE;YAClC,GAAG,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC5C,EAAE;YACF,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7G,CAAC;IACD,2EAA2E;IAC3E,yEAAyE;IACzE,4EAA4E;IAC5E,sEAAsE;IACtE,2EAA2E;IAC3E,2EAA2E;IAC3E,cAAc;IACd,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,OAAO,EAAE,KAAK,KAAK,UAAU,CAAC;IAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC;IACzH,OAAO,QAAQ,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;AACrG,CAAC;AAED,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,QAAQ,GAA0E,IAAI,GAAG;AAC7F,+EAA+E;AAC/E,MAAM,CAAC,OAAO,CAAC;IACb,KAAK,EAAE,YAAY;IACnB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,YAAY;IACnB,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,aAAa;CACsD,CAAC,CAC/E,CAAC;AAEF,KAAK,UAAU,QAAQ,CAAC,IAAuB,EAAE,EAAS;IACxD,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qEAAqE;QACrE,mEAAmE;QACnE,gBAAgB;QAChB,MAAM,OAAO,GAAG,KAAuB,CAAC;QACxC,IAAI,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7F,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;QACtD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7C,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,OAAO,CAAC,OAAO,8BAA8B,CAAC,CAAC;QACjG,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,4EAA4E;IAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAuB,EAAE,EAAS;IAC1D,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,oEAAoE;QACpE,sEAAsE;QACtE,IACE,KAAK,YAAY,UAAU;YAC3B,KAAK,YAAY,WAAW;YAC5B,KAAK,YAAY,YAAY;YAC7B,KAAK,YAAY,kBAAkB;YACnC,KAAK,YAAY,QAAQ,EACzB,CAAC;YACD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;YACpD,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAChG,IAAK,KAA+B,CAAC,IAAI,KAAK,OAAO;YAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;;YACjJ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;QAC1F,OAAO,UAAU,CAAC;IACpB,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,6EAA6E;AAC7E,cAAc;AACd,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAI,GAAsB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,OAAO,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAC7G,CAAC","sourcesContent":["/**\n * The command line: arguments, dispatch, output and exit codes.\n *\n * Exit 0: done, nothing refused. Exit 1: something refused or found. Exit 2:\n * the answer cannot be trusted - a bad flag, an option, an argument or a\n * value that names nothing, a configuration that does not load, a sibling\n * that is missing or printed something unreadable, a git command that\n * failed, an output its reader closed, an error nothing here expected. A run\n * that could not look must never exit as though it looked and found nothing\n * (spec-core ADR-0005).\n */\n\nimport { SiblingOutputError } from './briefs.js';\nimport { auditCommand, contextCommand, escalateCommand, probeCommand, ruleCommand, rulingsCommand } from './commands.js';\nimport { ConfigError, SIBLINGS } from './config.js';\nimport {\n describeBase,\n describeClaudeCode,\n describeClaudeRelease,\n describeGitHook,\n describePlugin,\n describeSignerKeys,\n describeSignerProblem,\n describeSigners,\n wiringState,\n} from './configure.js';\nimport { isDirectory } from './fs.js';\nimport { GitError, show, stagedChanges } from './git.js';\nimport type { Decision } from './guard.js';\nimport { claudeResponse, gitResponse, parseClaudeHook, type HookRequest } from './hooks.js';\nimport { claudeVersion } from './host.js';\nimport { premisesCommand } from './premises.js';\nimport { createReader } from './reader.js';\nimport { checkPaths, claudeCodeWiring, diagnoseBrief, resolveBase, specBriefPlugin, type Base } from './round.js';\nimport { mcpCommand } from './server.js';\nimport { gitHook, initCommand } from './setup.js';\nimport { notFido2, readAllowedSigners } from './signers.js';\nimport { SiblingError } from './siblings.js';\nimport { emptyValue, heldHookLine, isBlank, isClaudeHook, readHookLine, refusal, unreadHookLine, type Command, type LineFault } from './usage.js';\nimport { checkClaudeCode, CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS } from './versions.js';\nimport {\n activeBrief,\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n openWorkspace,\n parseOptions,\n UsageError,\n version,\n type CliIO,\n type Options,\n type UnreadableLine,\n type Workspace,\n} from './workspace.js';\n\nexport { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';\n\nexport const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work\n\nUsage:\n spec-harness <command> [options]\n\nCommands:\n context [brief] What an agent needs to start a round: the brief, its scope,\n rulings, dependencies, the rules in force, the cited documents.\n guard <path...> May the round write these paths? Exit 1 if one is refused.\n hook claude Answer a Claude Code PreToolUse or PostToolUse hook (stdin).\n hook git Answer git's pre-commit hook for the staged files.\n escalate Ask a person to rule: --path <file> (repeatable) --reason <why>\n [--option \"<label>: <cost>\"]... [--recommend <text>].\n --list shows what waits; --show <id> prints one memo. Neither\n raises a request: beside one, only --root and --format are read.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note <text>. It counts once committed signed.\n rulings [brief] The brief's rulings, and whether each one's signature verifies.\n audit [brief] Did the round stay inside the lines: what the archive would say,\n the brief's assertions, unverified rulings, new dependencies\n and the install scripts it allowed.\n probe [brief] Run the brief's probes: red at the base, green at the head.\n --at <base|head|both>, --id <probe>.\n premises Do the live briefs' premises still hold? For CI: exit 1 when one\n is stale, or, with --strict, when spec-guard cannot read one.\n init Configure the spec-* tools to agree. Prints the plan; --write\n applies it; --git-hook adds a pre-commit hook.\n mcp Serve start_round, check_path, request_escalation, audit_round,\n list_rounds and the workflow prompts over MCP on stdio.\n doctor Which siblings are installed, at which versions, which brief is\n named, how Claude Code runs the guard, and git's hook. Exit 1\n when a sibling is older than this release needs, the guard is\n installed twice, its hook's line turns it off or holds every\n write, or Claude Code is too old to run its hooks.\n\nOptions:\n --brief <id> The brief the round works on. Otherwise SPEC_BRIEF, then the branch.\n For context, guard, hook, escalate, rulings, audit, probe, premises\n and doctor.\n --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch. For context,\n guard, hook, rulings, audit, probe and doctor.\n --root <dir> Run from another directory, which must exist. For every command.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n For every command but hook and mcp.\n --strict Warnings fail the run. For guard, audit, premises and doctor.\n --help, --version\n\nAn option a command does not read, an argument it does not take, an option or an\nargument given an empty value, and a brief given both as the argument and as --brief\nare refused, exit 2, not read as if they were not there. doctor says an empty --brief\nor --base in its report. hook claude reads its line as every release has, and says a\nline it cannot read, and a --root that is not a directory, with exit 1: it refuses\nnothing for either.\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n`;\n\n\n/* ------------------------------------------------------------------- guard */\n\nconst reader = createReader();\n\nasync function decisionsFor(\n workspace: Workspace,\n options: Options,\n io: CliIO,\n given: readonly string[],\n cwd: string,\n): Promise<{ readonly decisions: Decision[] } | { readonly problem: string }> {\n const active = await activeBrief(workspace, options, io.env);\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) return { problem };\n return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };\n}\n\nconst SYMBOL: Record<Decision['verdict'], string> = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };\n\nasync function guardCommand(options: Options, io: CliIO): Promise<number> {\n if (options.positionals.length === 0) throw new UsageError('guard needs at least one path');\n const workspace = await openWorkspace(options, io);\n const decided = await decisionsFor(workspace, options, io, options.positionals, io.cwd);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const { decisions } = decided;\n if (options.format === 'json') {\n io.stdout.write(json('guard', { decisions }));\n } else {\n for (const decision of decisions) {\n io.stdout.write(`${SYMBOL[decision.verdict]} ${decision.message}\\n`);\n if (decision.verdict !== 'allow') io.stdout.write(` ${decision.hint}\\n`);\n }\n }\n const refused = decisions.some((d) => d.verdict === 'deny' || d.verdict === 'ask');\n const warned = decisions.some((d) => d.verdict === 'warn');\n return refused || (options.strict && warned) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------------- hook */\n\nasync function readStdin(io: CliIO): Promise<string> {\n // Only the built command line reads process.stdin, and the suite spawns it\n // from dist/, outside the sweep (tests/integration/claude-code.test.ts): the\n // lines below survive it untested in-process.\n if (io.stdin !== undefined) return io.stdin();\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n}\n\n/**\n * The write Claude Code asks the hook about, or the exit code that answers\n * already: 1 for a question that cannot be read, 0 for a tool that writes\n * no file. Asked before anything on the hook's own line is, so that a line\n * that is wrong is said where there is a write it leaves unchecked.\n */\nasync function writeAsked(io: CliIO): Promise<HookRequest | number> {\n let question: string;\n try {\n question = await readStdin(io);\n } catch (error) {\n // A question that could not be read is one the hook cannot see, as one\n // it cannot parse is, below: it has no event to hold a write by.\n io.stderr.write(`spec-harness: the hook input could not be read: ${(error as Error).message}\\n`);\n return EXIT_FAILED;\n }\n const request = parseClaudeHook(question);\n if ('error' in request) {\n // A hook that cannot read its question refuses nothing it cannot see,\n // but says so where the person reads it: a non-blocking error.\n io.stderr.write(`spec-harness: ${request.error}\\n`);\n return EXIT_FAILED;\n }\n return request.paths.length === 0 ? EXIT_OK : request;\n}\n\n/**\n * What is wrong with the hook's own line, said and nothing refused for it:\n * one line, since Claude Code shows the first line of the stderr of a hook\n * that exits 1 and goes on with the write, where exit 2 would hold every\n * write of the session, the one that mends the line among them (ADR-0005).\n */\nfunction guardOff(io: CliIO, { wrong, mend }: LineFault): number {\n io.stderr.write(`spec-harness: ${wrong}, so the guard is off and this write is not checked; ${mend}\\n`);\n return EXIT_FAILED;\n}\n\n/**\n * Claude Code's hook on a line the parser refused: an option no command has,\n * an option left without its value, a --format or an --at that is none. It\n * was exit 2 before the question was read, for the line a settings file\n * holds as for one typed at a terminal. What is said of it is `doctor`'s\n * to say as well, of a line it finds in a settings file (usage.ts).\n */\nasync function unreadLine(said: string, io: CliIO): Promise<number> {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n return guardOff(io, unreadHookLine(said).fault);\n}\n\nasync function hookCommand(options: Options, io: CliIO): Promise<number> {\n const kind = options.positionals[0];\n if (kind === 'claude') {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n // The root the line gives, or what is wrong with it: read as `doctor`\n // reads the line where it finds it in a settings file (usage.ts).\n const line = readHookLine(options.root, io.cwd, isDirectory);\n if (line.state === 'off') return guardOff(io, line.fault);\n const cwd = request.cwd ?? io.cwd;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ ...options, root: line.root ?? io.env['CLAUDE_PROJECT_DIR'] ?? cwd }, io);\n } catch (error) {\n if (error instanceof UsageError) return EXIT_OK;\n throw error;\n }\n try {\n const decided = await decisionsFor(workspace, options, io, request.paths, cwd);\n if ('problem' in decided) {\n // Exit 2 blocks the tool call, and its stderr reaches the model. Where\n // the name stands on the hook's own line, what is wrong with it is\n // `doctor`'s to say as well, in the same words (usage.ts).\n io.stderr.write(`spec-harness: ${heldHookLine(decided.problem).wrong}. Fix the brief or the branch before writing.\\n`);\n return EXIT_ERROR;\n }\n const response = claudeResponse(request.event, decided.decisions);\n io.stdout.write(response.stdout);\n return response.exitCode;\n } catch (error) {\n if (request.event !== 'PreToolUse') throw error;\n // A round is named and its briefs cannot be read: the guard cannot\n // tell a protected file from any other, so the write waits.\n io.stderr.write(`spec-harness: cannot check this write: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n }\n if (kind === 'git') {\n const workspace = await openWorkspace(options, io);\n const staged = await stagedChanges(workspace.root);\n const paths = staged.flatMap((change) => (change.from === undefined ? [change.path] : [change.from, change.path]));\n if (paths.length === 0) return EXIT_OK;\n const decided = await decisionsFor(workspace, options, io, paths, workspace.root);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const response = gitResponse(decided.decisions);\n io.stderr.write(response.text);\n return response.exitCode;\n }\n throw new UsageError('hook takes \"claude\" or \"git\"');\n}\n\n/* ------------------------------------------------------------------ doctor */\n\nasync function doctorCommand(options: Options, io: CliIO): Promise<number> {\n const workspace = await openWorkspace(options, io);\n const rows = SIBLINGS.map((name) => {\n const sibling = workspace.siblings.locate(name);\n const row = { tool: name, state: sibling.kind, minimum: MINIMUM_VERSIONS[name] };\n if (sibling.kind === 'absent') return { ...row, version: null, detail: sibling.reason };\n if (sibling.kind === 'outdated') return { ...row, version: sibling.version, detail: sibling.reason };\n const command = sibling.command.join(' ');\n const detail = sibling.version === null ? `${command} (named in .spec-harness.json; its version is not checked)` : `${command} (${sibling.version})`;\n return { ...row, version: sibling.version, detail };\n });\n const named = await diagnoseBrief(workspace, options, io.env);\n // A ruling counts only by a signature checked against the allowed signers\n // on the base, and only once spec-brief's archive asks the plugin about it.\n // A --base given nothing is no base, said as the brief's is, in the report.\n // Nothing below asks what kind a base is but whether it is resolved, so the\n // mutant that names this one otherwise is equivalent.\n const base: Base =\n options.base !== undefined && isBlank(options.base)\n ? { kind: 'unresolved', reason: emptyValue('--base', 'base', options.base) }\n : await resolveBase(workspace, options.base);\n const signersFile = workspace.config.rulings.allowedSigners;\n // An unresolved base has no commit: git shows nothing for one, so asking\n // anyway reads as no file, and that mutant is equivalent.\n const signersText = base.kind === 'resolved' ? await show(base.sha, signersFile, workspace.root) : null;\n const onBase = base.kind === 'resolved' ? signersText !== null : null;\n const signers = describeSigners(signersFile, base.kind === 'resolved' ? base.ref : null, onBase === true);\n // Which keys sign, as notes: a key that is not FIDO2 can still be one the\n // agent cannot use, and a PIV key reads as a plain one (ADR-0006).\n const read = readAllowedSigners(signersText ?? '');\n const plain = notFido2(read.signers);\n const signerNotes = [describeSignerKeys(plain), ...read.problems.map(describeSignerProblem)].filter((note): note is string => note !== null);\n const plugin = await specBriefPlugin(workspace.root);\n // The plugin and init's entries both on: Claude Code runs every guard twice\n // and registers the server twice (ADR-0012).\n const wiring = await claudeCodeWiring(workspace.root, io);\n const claude = wiringState(wiring);\n // What the hook does with each line the settings hold for it, where there\n // is something to say: more on it than init writes, a line that turns the\n // guard off or holds every write, one only a shell can read, the writes\n // Claude Code starts it for where they are not all of them, and what\n // onFailure changes.\n const lineNotes = wiring.lines.flatMap((line) => [line.detail, line.cover, line.note]).filter((note): note is string => note !== null);\n // Only a Claude Code that runs the guard is asked its release: one older\n // than the hooks need lets every write through unguarded.\n const release = claude === 'none' ? null : checkClaudeCode(await claudeVersion(io.env));\n // How the hook runs the harness is a note: one that goes through npx guards\n // as well as one that does not, and fails nothing, --strict or not.\n const { hook, note: hookNote } = await gitHook(workspace.root);\n const branch = workspace.branch === null ? '(detached)' : `${workspace.branch}${workspace.branchSource === undefined ? '' : ` (detached; ${workspace.branchSource} names it)`}`;\n if (options.format === 'json') {\n io.stdout.write(\n json('doctor', {\n root: workspace.root,\n branch: workspace.branch,\n branchSource: workspace.branchSource ?? null,\n brief: named.id,\n briefProblem: named.problem,\n base: base.kind === 'resolved' ? { ref: base.ref, source: base.source, mergeBase: base.mergeBase } : { unresolved: base.reason },\n allowedSigners: {\n file: signersFile,\n onBase,\n detail: signers,\n notFido2: plain.map(({ line, principals, keyType }) => ({ line, principals, keyType })),\n problems: read.problems,\n },\n plugin: { state: plugin.kind, file: 'file' in plugin ? plugin.file : null, detail: describePlugin(plugin) },\n claudeCode: {\n state: claude,\n ...wiring,\n detail: describeClaudeCode(wiring),\n release:\n release === null\n ? { state: 'unchecked', version: null, minimum: CLAUDE_CODE_MINIMUM, detail: 'not asked: nothing wires Claude Code to the guard here' }\n : { state: release.state, version: 'version' in release ? release.version : null, minimum: CLAUDE_CODE_MINIMUM, detail: describeClaudeRelease(release) },\n },\n gitHook: { state: hook.state, file: 'file' in hook ? hook.file : null, detail: describeGitHook(hook), note: hookNote },\n siblings: rows,\n }),\n );\n } else {\n const more = (notes: readonly string[]): string[] => notes.map((note) => ` ${note}`);\n io.stdout.write(\n [\n `root ${workspace.root}`,\n `branch ${branch}`,\n `brief ${named.problem === null ? (named.id ?? '(none named)') : `none: ${named.problem}`}`,\n `base ${describeBase(base)}`,\n `signers ${signers}`,\n ...more(signerNotes),\n `plugin ${describePlugin(plugin)}`,\n `claude ${describeClaudeCode(wiring)}`,\n ...more(lineNotes),\n ...more(release === null ? [] : [describeClaudeRelease(release)]),\n `git ${describeGitHook(hook)}`,\n ...more(hookNote === null ? [] : [hookNote]),\n '',\n '',\n ].join('\\n'),\n );\n for (const row of rows) io.stdout.write(`${row.state.padEnd(8)} ${row.tool.padEnd(10)} ${row.detail}\\n`);\n }\n // An outdated sibling is a problem to fix, where a missing optional one is\n // a choice; with none installed, the harness can check nothing. A double\n // install is a problem too, where no Claude Code wiring at all is a choice,\n // and so are a hook whose own line turns the guard off or holds every\n // write, and a Claude Code too old to run the hooks. A release that cannot\n // be told is not fine either, nor a line whose reading cannot be: --strict\n // fails both.\n const outdated = rows.some((row) => row.state === 'outdated');\n const usable = rows.some((row) => row.state === 'found');\n const off = wiring.lines.some((line) => line.state === 'off' || line.state === 'held');\n const tooOld = release?.state === 'outdated';\n const untold = options.strict && (release?.state === 'unknown' || wiring.lines.some((line) => line.state === 'unknown'));\n return outdated || !usable || claude === 'both' || off || tooOld || untold ? EXIT_FAILED : EXIT_OK;\n}\n\n/* ---------------------------------------------------------------- dispatch */\n\n/**\n * A map, because the command is the first word a person types and an object\n * answers to more names than it was given: `spec-harness constructor` ran\n * `Object` as a command and ended on a stack trace, where `spec-harness\n * construct` is an unknown command with exit 2.\n */\nconst COMMANDS: ReadonlyMap<string, (options: Options, io: CliIO) => Promise<number>> = new Map(\n // One for every command that has a shape (usage.ts), which the compiler holds.\n Object.entries({\n guard: guardCommand,\n hook: hookCommand,\n context: contextCommand,\n audit: auditCommand,\n escalate: escalateCommand,\n rule: ruleCommand,\n rulings: rulingsCommand,\n probe: probeCommand,\n premises: premisesCommand,\n init: initCommand,\n mcp: mcpCommand,\n doctor: doctorCommand,\n } satisfies Record<Command, (options: Options, io: CliIO) => Promise<number>>),\n);\n\nasync function dispatch(argv: readonly string[], io: CliIO): Promise<number> {\n let options: Options;\n try {\n options = parseOptions(argv);\n } catch (error) {\n // The parser throws nothing but its refusal of the line, which holds\n // whose line it was. Claude Code's hook says its own, and holds no\n // write for it.\n const refused = error as UnreadableLine;\n if (isClaudeHook(refused.words[0], refused.words[1])) return unreadLine(refused.message, io);\n io.stderr.write(`spec-harness: ${refused.message}\\n`);\n return EXIT_ERROR;\n }\n if (options.version) {\n io.stdout.write(`${version()}\\n`);\n return EXIT_OK;\n }\n if (options.help || options.command === undefined) {\n io.stdout.write(HELP);\n return options.help ? EXIT_OK : EXIT_ERROR;\n }\n const command = COMMANDS.get(options.command);\n if (command === undefined) {\n io.stderr.write(`spec-harness: unknown command \"${options.command}\"; see spec-harness --help\\n`);\n return EXIT_ERROR;\n }\n // What parsed and names nothing, before anything is read or written for it.\n const refused = refusal(options, isDirectory);\n if (refused !== null) {\n io.stderr.write(`spec-harness: ${refused}\\n`);\n return EXIT_ERROR;\n }\n return command(options, io);\n}\n\n/**\n * Runs the command line and resolves to the exit code, for an error nothing\n * below expected too.\n *\n * Such an error is neither a refusal nor a finding: the answer cannot be\n * trusted, which is exit 2 (spec-core ADR-0005). Rejected instead, it reached\n * the launcher as Node's uncaught error, exit 1, \"refused or found something\"\n * to a script, and to Claude Code a hook that failed without blocking: the\n * write the guard could not check went ahead. The stack is what makes a\n * report of it something to act on, and it goes to stderr alone: a script\n * that reads a document from stdout is handed no part of one.\n *\n * A write its reader had closed the pipe for is not such an error: the answer\n * was not delivered, which is still 2, and nothing in the harness is at\n * fault, so it is said in a line and no stack sends a person looking for a\n * defect. The process's own streams report it as an event, which the\n * launcher answers in the same words; here it is a caller's stream that\n * throws it. It is read by its code: stdout and stderr are the only pipes\n * the harness writes to.\n */\nexport async function run(argv: readonly string[], io: CliIO): Promise<number> {\n try {\n return await dispatch(argv, io);\n } catch (error) {\n // A sibling's document of a shape the harness does not read is a sibling\n // that printed something it cannot read (answers.ts): exit 2. A git\n // command that failed is what git said, and no line of the harness's.\n if (\n error instanceof UsageError ||\n error instanceof ConfigError ||\n error instanceof SiblingError ||\n error instanceof SiblingOutputError ||\n error instanceof GitError\n ) {\n io.stderr.write(`spec-harness: ${error.message}\\n`);\n return EXIT_ERROR;\n }\n if (!(error instanceof Error)) io.stderr.write(`spec-harness: unexpected error: ${String(error)}\\n`);\n else if ((error as NodeJS.ErrnoException).code === 'EPIPE') io.stderr.write('spec-harness: stdout was closed before all of the output was written\\n');\n else io.stderr.write(`spec-harness: unexpected error: ${error.stack ?? error.message}\\n`);\n return EXIT_ERROR;\n }\n}\n\n// What bin/spec-harness.js runs; the suite spawns the built one, from dist/,\n// outside the sweep (tests/integration/cli.test.ts), so it survives untested\n// in-process.\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n return run(argv, { stdout: process.stdout, stderr: process.stderr, cwd: process.cwd(), env: process.env });\n}\n\n"]}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The command line: arguments, dispatch, output and exit codes.\n *\n * Exit 0: done, nothing refused. Exit 1: something refused or found. Exit 2:\n * the answer cannot be trusted - a bad flag, an option, an argument or a\n * value that names nothing, a configuration that does not load, a sibling\n * that is missing or printed something unreadable, a git command that\n * failed, an output its reader closed, an error nothing here expected. A run\n * that could not look must never exit as though it looked and found nothing\n * (spec-core ADR-0005).\n *\n * A command loads what it runs. This module imports what every run needs,\n * the hook's before a write among them, and a module that only some\n * commands run is imported where one of them is the command: the hook\n * runs before and after every write an agent makes, and what it loaded of\n * the other commands was a wait before each (ADR-0002). A module that\n * cannot be loaded is thrown where it was asked for, and ends the run in a\n * line and exit 2, as every error does.\n */\n\nimport { SiblingOutputError } from './briefs.js';\nimport { ConfigError, SIBLINGS } from './config.js';\nimport type { ClaudeCodeWiring } from './configure.js';\nimport { isDirectory } from './fs.js';\nimport { GitError, show, stagedChanges } from './git.js';\nimport type { DocumentReader } from './document.js';\nimport type { Decision } from './guard.js';\nimport { claudeResponse, gitResponse, parseClaudeHook, type HookRequest } from './hooks.js';\nimport type { Base } from './round.js';\nimport { SiblingError } from './siblings.js';\nimport { emptyValue, heldHookLine, isBlank, isClaudeHook, readHookLine, refusal, unreadHookLine, type Command, type LineFault } from './usage.js';\nimport { CLAUDE_CODE_MINIMUM, MINIMUM_VERSIONS, type ClaudeCodeCheck } from './versions.js';\nimport {\n activeBrief,\n answerOf,\n describeActive,\n EXIT_ERROR,\n EXIT_FAILED,\n EXIT_OK,\n json,\n openWorkspace,\n parseOptions,\n UsageError,\n version,\n type CliIO,\n type Options,\n type UnreadableLine,\n type Workspace,\n} from './workspace.js';\n\nexport { EXIT_ERROR, EXIT_FAILED, EXIT_OK, UsageError, version, type CliIO } from './workspace.js';\n\nexport const HELP = `spec-harness - context, guards, audits and rulings for rounds of agent work\n\nUsage:\n spec-harness <command> [options]\n\nCommands:\n context [brief] What an agent needs to start a round: the brief, its scope,\n rulings, dependencies, the rules in force, the cited documents.\n guard <path...> May the round write these paths? Exit 1 if one is refused.\n hook claude Answer a Claude Code PreToolUse or PostToolUse hook (stdin).\n hook git Answer git's pre-commit hook for the staged files.\n escalate Ask a person to rule: --path <file> (repeatable) --reason <why>\n [--option \"<label>: <cost>\"]... [--recommend <text>].\n --list shows what waits; --show <id> prints one memo. Neither\n raises a request: beside one, only --root and --format are read.\n rule <id> Record a person's ruling in the brief: --allow or --deny, with\n --note <text>. It counts once committed signed.\n rulings [brief] The brief's rulings, and whether each one's signature verifies.\n audit [brief] Did the round stay inside the lines: what the archive would say,\n the brief's assertions, unverified rulings, new dependencies\n and the install scripts it allowed.\n probe [brief] Run the brief's probes: red at the base, green at the head.\n --at <base|head|both>, --id <probe>.\n premises Do the live briefs' premises still hold? For CI: exit 1 when one\n is stale, or, with --strict, when spec-guard cannot read one.\n init Configure the spec-* tools to agree. Prints the plan; --write\n applies it; --git-hook adds a pre-commit hook.\n mcp Serve start_round, check_path, request_escalation, audit_round,\n list_rounds and the workflow prompts over MCP on stdio.\n doctor Which siblings are installed, at which versions, which brief is\n named, how Claude Code runs the guard, and git's hook. Exit 1\n when a sibling is older than this release needs, the guard is\n installed twice, its hook's line turns it off or holds every\n write, disableAllHooks or an array for a matcher switches it\n off, the plugin that is turned on is not on this machine and\n nothing else guards, Claude Code is too old to run its hooks,\n or git stops every commit at what stands for its hook.\n\nOptions:\n --brief <id> The brief the round works on. Otherwise SPEC_BRIEF, then the branch.\n For context, guard, hook, escalate, rulings, audit, probe, premises\n and doctor.\n --base <ref> What the round is measured from. Otherwise \"base\" in\n .spec-harness.json, then the remote's default branch. For context,\n guard, hook, rulings, audit, probe and doctor.\n --root <dir> Run from another directory, which must exist. For every command.\n --format <fmt> pretty or json; audit and premises also gitlab, sarif or github.\n For every command but hook and mcp.\n --strict Warnings fail the run. For guard, audit, premises and doctor.\n --help, --version\n\nAn option a command does not read, an argument it does not take, an option or an\nargument given an empty value, and a brief given both as the argument and as --brief\nare refused, exit 2, not read as if they were not there. doctor says an empty --brief\nor --base in its report. hook claude reads its line as every release has, and says a\nline it cannot read, and a --root that is not a directory, with exit 1: it refuses\nnothing for either.\n\nExit codes: 0 clean, 1 refused or found something, 2 the answer cannot be trusted.\n`;\n\n\n/* ------------------------------------------------------------------- guard */\n\n/**\n * The reader of a brief's rulings, loaded where a ruling is read: a write\n * to a file no brief protects reads none.\n */\nconst reader = async (): Promise<DocumentReader> => (await import('./reader.js')).createReader();\n\nasync function decisionsFor(\n workspace: Workspace,\n options: Options,\n io: CliIO,\n given: readonly string[],\n cwd: string,\n): Promise<{ readonly decisions: Decision[] } | { readonly problem: string }> {\n const active = await activeBrief(workspace, options, io.env);\n const { brief, note, problem } = describeActive(active);\n if (problem !== null) return { problem };\n const { checkPaths } = await import('./round.js');\n return { decisions: await checkPaths(workspace, brief, note, given, cwd, reader, options.base) };\n}\n\nconst SYMBOL: Record<Decision['verdict'], string> = { allow: 'ok ', warn: 'warning', ask: 'ask ', deny: 'refused' };\n\nasync function guardCommand(options: Options, io: CliIO): Promise<number> {\n if (options.positionals.length === 0) throw new UsageError('guard needs at least one path');\n const workspace = await openWorkspace(options, io);\n const decided = await decisionsFor(workspace, options, io, options.positionals, io.cwd);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const { decisions } = decided;\n if (options.format === 'json') {\n io.stdout.write(json('guard', { decisions }));\n } else {\n for (const decision of decisions) {\n io.stdout.write(`${SYMBOL[decision.verdict]} ${decision.message}\\n`);\n if (decision.verdict !== 'allow') io.stdout.write(` ${decision.hint}\\n`);\n }\n }\n const refused = decisions.some((d) => d.verdict === 'deny' || d.verdict === 'ask');\n const warned = decisions.some((d) => d.verdict === 'warn');\n return refused || (options.strict && warned) ? EXIT_FAILED : EXIT_OK;\n}\n\n/* -------------------------------------------------------------------- hook */\n\nasync function readStdin(io: CliIO): Promise<string> {\n // Only the built command line reads process.stdin, and the suite spawns it\n // from dist/, outside the sweep (tests/integration/claude-code.test.ts): the\n // lines below survive it untested in-process.\n if (io.stdin !== undefined) return io.stdin();\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer);\n return Buffer.concat(chunks).toString('utf8');\n}\n\n/**\n * The write Claude Code asks the hook about, or the exit code that answers\n * already: 1 for a question that cannot be read, 0 for a tool that writes\n * no file. Asked before anything on the hook's own line is, so that a line\n * that is wrong is said where there is a write it leaves unchecked.\n */\nasync function writeAsked(io: CliIO): Promise<HookRequest | number> {\n let question: string;\n try {\n question = await readStdin(io);\n } catch (error) {\n // A question that could not be read is one the hook cannot see, as one\n // it cannot parse is, below: it has no event to hold a write by.\n io.stderr.write(`spec-harness: the hook input could not be read: ${(error as Error).message}\\n`);\n return EXIT_FAILED;\n }\n const request = parseClaudeHook(question);\n if ('error' in request) {\n // A hook that cannot read its question refuses nothing it cannot see,\n // but says so where the person reads it: a non-blocking error.\n io.stderr.write(`spec-harness: ${request.error}\\n`);\n return EXIT_FAILED;\n }\n return request.paths.length === 0 ? EXIT_OK : request;\n}\n\n/**\n * What is wrong with the hook's own line, said and nothing refused for it:\n * one line, since Claude Code shows the first line of the stderr of a hook\n * that exits 1 and goes on with the write, where exit 2 would hold every\n * write of the session, the one that mends the line among them (ADR-0005).\n */\nfunction guardOff(io: CliIO, { wrong, mend }: LineFault): number {\n io.stderr.write(`spec-harness: ${wrong}, so the guard is off and this write is not checked; ${mend}\\n`);\n return EXIT_FAILED;\n}\n\n/**\n * Claude Code's hook on a line the parser refused: an option no command has,\n * an option left without its value, a --format or an --at that is none. It\n * was exit 2 before the question was read, for the line a settings file\n * holds as for one typed at a terminal. What is said of it is `doctor`'s\n * to say as well, of a line it finds in a settings file (usage.ts).\n */\nasync function unreadLine(said: string, io: CliIO): Promise<number> {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n return guardOff(io, unreadHookLine(said).fault);\n}\n\nasync function hookCommand(options: Options, io: CliIO): Promise<number> {\n const kind = options.positionals[0];\n if (kind === 'claude') {\n const request = await writeAsked(io);\n if (typeof request === 'number') return request;\n // The root the line gives, or what is wrong with it: read as `doctor`\n // reads the line where it finds it in a settings file (usage.ts).\n const line = readHookLine(options.root, io.cwd, isDirectory);\n if (line.state === 'off') return guardOff(io, line.fault);\n const cwd = request.cwd ?? io.cwd;\n let workspace: Workspace;\n try {\n workspace = await openWorkspace({ ...options, root: line.root ?? io.env['CLAUDE_PROJECT_DIR'] ?? cwd }, io);\n } catch (error) {\n if (error instanceof UsageError) return EXIT_OK;\n throw error;\n }\n try {\n const decided = await decisionsFor(workspace, options, io, request.paths, cwd);\n if ('problem' in decided) {\n // Exit 2 blocks the tool call, and its stderr reaches the model. Where\n // the name stands on the hook's own line, what is wrong with it is\n // `doctor`'s to say as well, in the same words (usage.ts).\n io.stderr.write(`spec-harness: ${heldHookLine(decided.problem).wrong}. Fix the brief or the branch before writing.\\n`);\n return EXIT_ERROR;\n }\n const response = claudeResponse(request.event, decided.decisions);\n io.stdout.write(response.stdout);\n return response.exitCode;\n } catch (error) {\n if (request.event !== 'PreToolUse') throw error;\n // A round is named and its briefs cannot be read: the guard cannot\n // tell a protected file from any other, so the write waits.\n io.stderr.write(`spec-harness: cannot check this write: ${(error as Error).message}\\n`);\n return EXIT_ERROR;\n }\n }\n if (kind === 'git') {\n const workspace = await openWorkspace(options, io);\n const staged = await stagedChanges(workspace.root);\n const paths = staged.flatMap((change) => (change.from === undefined ? [change.path] : [change.from, change.path]));\n if (paths.length === 0) return EXIT_OK;\n const decided = await decisionsFor(workspace, options, io, paths, workspace.root);\n if ('problem' in decided) {\n io.stderr.write(`spec-harness: ${decided.problem}\\n`);\n return EXIT_ERROR;\n }\n const response = gitResponse(decided.decisions);\n io.stderr.write(response.text);\n return response.exitCode;\n }\n throw new UsageError('hook takes \"claude\" or \"git\"');\n}\n\n/* ------------------------------------------------------------------ doctor */\n\n/**\n * The base, and the allowed-signers file as it is on it: the file waits on\n * the base, and the two on nothing else doctor asks. A --base given nothing\n * is no base, said as the brief's is, in the report.\n */\nasync function baseAndSigners(\n { resolveBase }: Pick<typeof import('./round.js'), 'resolveBase'>,\n workspace: Workspace,\n flag: string | undefined,\n signersFile: string,\n): Promise<{ readonly base: Base; readonly signersText: string | null }> {\n // Nothing in doctor asks what kind a base is but whether it is resolved, so\n // the mutant that names this one otherwise is equivalent.\n const base: Base = flag !== undefined && isBlank(flag) ? { kind: 'unresolved', reason: emptyValue('--base', 'base', flag) } : await resolveBase(workspace, flag);\n // An unresolved base has no commit: git shows nothing for one, so asking\n // anyway reads as no file, and that mutant is equivalent.\n const signersText = base.kind === 'resolved' ? await show(base.sha, signersFile, workspace.root) : null;\n return { base, signersText };\n}\n\n/**\n * How Claude Code is wired to the guard, and the release of the one on\n * `PATH`, which waits on the wiring: only a Claude Code that runs the guard\n * is asked its release, since one older than the hooks need lets every\n * write through unguarded. `null` where it was not asked. The wiring asks\n * it itself, since which writes a line is started for can turn on the\n * release as well (round.ts); the two are told apart here for the report,\n * which has a place of its own for the release.\n */\nasync function wiringAndRelease(\n { claudeCodeWiring }: Pick<typeof import('./round.js'), 'claudeCodeWiring'>,\n root: string,\n io: CliIO,\n): Promise<{ readonly wiring: Omit<ClaudeCodeWiring, 'release'>; readonly release: ClaudeCodeCheck | null }> {\n const { release, ...wiring } = await claudeCodeWiring(root, io);\n return { wiring, release };\n}\n\nasync function doctorCommand(options: Options, io: CliIO): Promise<number> {\n // What doctor alone runs of them, loaded before anything is asked: the\n // five things below are asked at once, and none waits on a module.\n const [configure, round, setup, signing] = await Promise.all([import('./configure.js'), import('./round.js'), import('./setup.js'), import('./signers.js')]);\n const { describeBase, describeClaudeCode, describeClaudeRelease, describeGitHook, describeHooksOff, describePlugin, describePresence, describeSignerKeys, describeSignerProblem, describeSigners, guardSwitchedOff, wiringState } = configure;\n const { diagnoseBrief, specBriefPlugin } = round;\n const { gitHook } = setup;\n const { notFido2, readAllowedSigners } = signing;\n const workspace = await openWorkspace(options, io);\n const rows = SIBLINGS.map((name) => {\n const sibling = workspace.siblings.locate(name);\n const row = { tool: name, state: sibling.kind, minimum: MINIMUM_VERSIONS[name] };\n if (sibling.kind === 'absent') return { ...row, version: null, detail: sibling.reason };\n if (sibling.kind === 'outdated') return { ...row, version: sibling.version, detail: sibling.reason };\n const command = sibling.command.join(' ');\n const detail = sibling.version === null ? `${command} (named in .spec-harness.json; its version is not checked)` : `${command} (${sibling.version})`;\n return { ...row, version: sibling.version, detail };\n });\n const signersFile = workspace.config.rulings.allowedSigners;\n // Five things that wait on the work tree and on nothing of one another,\n // each a process or a chain of them. Asked one after another, Claude\n // Code's release, the longest wait of a doctor on Windows, was asked for\n // only when every answer of git's before it was in. So they are asked at\n // once, and read below in the order they were asked in before: where more\n // than one fails, the first of that order is the one thrown, whichever\n // failed first by the clock (ADR-0002).\n const [briefAsked, baseAsked, pluginAsked, claudeAsked, hookAsked] = await Promise.allSettled([\n diagnoseBrief(workspace, options, io.env),\n baseAndSigners(round, workspace, options.base, signersFile),\n specBriefPlugin(workspace.root),\n wiringAndRelease(round, workspace.root, io),\n gitHook(workspace.root),\n ]);\n const named = answerOf(briefAsked);\n // A ruling counts only by a signature checked against the allowed signers\n // on the base, and only once spec-brief's archive asks the plugin about it.\n const { base, signersText } = answerOf(baseAsked);\n const onBase = base.kind === 'resolved' ? signersText !== null : null;\n const signers = describeSigners(signersFile, base.kind === 'resolved' ? base.ref : null, onBase === true);\n // Which keys sign, as notes: a key that is not FIDO2 can still be one the\n // agent cannot use, and a PIV key reads as a plain one (ADR-0006).\n const read = readAllowedSigners(signersText ?? '');\n const plain = notFido2(read.signers);\n const signerNotes = [describeSignerKeys(plain), ...read.problems.map(describeSignerProblem)].filter((note): note is string => note !== null);\n const plugin = answerOf(pluginAsked);\n // The plugin and init's entries both on: Claude Code runs every guard twice\n // and registers the server twice (ADR-0012).\n const { wiring, release } = answerOf(claudeAsked);\n const claude = wiringState(wiring);\n // What the hook does with each line the settings hold for it, where there\n // is something to say: more on it than init writes, a line that turns the\n // guard off or holds every write, one only a shell can read, the writes\n // Claude Code starts it for where they are not all of them, and what\n // onFailure changes.\n const lineNotes = wiring.lines.flatMap((line) => [line.detail, line.cover, line.note]).filter((note): note is string => note !== null);\n // What stands over every line: a plugin that is turned on and is not on\n // this machine, or cannot be told to be, and disableAllHooks, which\n // switches off whatever hooks there are.\n const switchedOff = guardSwitchedOff(wiring);\n const wiringNotes = [describePresence(wiring), wiring.hooksOff === null ? null : describeHooksOff(wiring.hooksOff, switchedOff)].filter((note): note is string => note !== null);\n // How the hook runs the harness is a note: one that goes through npx guards\n // as well as one that does not, and fails nothing, --strict or not.\n const { hook, note: hookNote } = answerOf(hookAsked);\n const branch = workspace.branch === null ? '(detached)' : `${workspace.branch}${workspace.branchSource === undefined ? '' : ` (detached; ${workspace.branchSource} names it)`}`;\n if (options.format === 'json') {\n io.stdout.write(\n json('doctor', {\n root: workspace.root,\n branch: workspace.branch,\n branchSource: workspace.branchSource ?? null,\n brief: named.id,\n briefProblem: named.problem,\n base: base.kind === 'resolved' ? { ref: base.ref, source: base.source, mergeBase: base.mergeBase } : { unresolved: base.reason },\n allowedSigners: {\n file: signersFile,\n onBase,\n detail: signers,\n notFido2: plain.map(({ line, principals, keyType }) => ({ line, principals, keyType })),\n problems: read.problems,\n },\n plugin: { state: plugin.kind, file: 'file' in plugin ? plugin.file : null, detail: describePlugin(plugin) },\n claudeCode: {\n state: claude,\n ...wiring,\n detail: describeClaudeCode(wiring),\n notes: wiringNotes,\n release:\n release === null\n ? { state: 'unchecked', version: null, minimum: CLAUDE_CODE_MINIMUM, detail: 'not asked: nothing wires Claude Code to the guard here' }\n : { state: release.state, version: 'version' in release ? release.version : null, minimum: CLAUDE_CODE_MINIMUM, detail: describeClaudeRelease(release) },\n },\n gitHook: { state: hook.state, file: 'file' in hook ? hook.file : null, detail: describeGitHook(hook), note: hookNote },\n siblings: rows,\n }),\n );\n } else {\n const more = (notes: readonly string[]): string[] => notes.map((note) => ` ${note}`);\n io.stdout.write(\n [\n `root ${workspace.root}`,\n `branch ${branch}`,\n `brief ${named.problem === null ? (named.id ?? '(none named)') : `none: ${named.problem}`}`,\n `base ${describeBase(base)}`,\n `signers ${signers}`,\n ...more(signerNotes),\n `plugin ${describePlugin(plugin)}`,\n `claude ${describeClaudeCode(wiring)}`,\n ...more(wiringNotes),\n ...more(lineNotes),\n ...more(release === null ? [] : [describeClaudeRelease(release)]),\n `git ${describeGitHook(hook)}`,\n ...more(hookNote === null ? [] : [hookNote]),\n '',\n '',\n ].join('\\n'),\n );\n for (const row of rows) io.stdout.write(`${row.state.padEnd(8)} ${row.tool.padEnd(10)} ${row.detail}\\n`);\n }\n // An outdated sibling is a problem to fix, where a missing optional one is\n // a choice; with none installed, the harness can check nothing. A double\n // install is a problem too, where no Claude Code wiring at all is a choice,\n // and so are a hook whose own line turns the guard off or holds every\n // write, guard hooks that disableAllHooks switches off, a plugin that is\n // turned on and is not on this machine where no hook of init's stands in\n // for it, a Claude Code too old to run the hooks, and something at the\n // path of git's pre-commit hook that git cannot run and stops every\n // commit at. A release that cannot be told is not fine either, nor a\n // line whose reading cannot be, nor a plugin that cannot be told to be on\n // this machine: --strict fails the three.\n const outdated = rows.some((row) => row.state === 'outdated');\n const usable = rows.some((row) => row.state === 'found');\n const off = wiring.lines.some((line) => line.state === 'off' || line.state === 'held');\n const missing = wiring.presence?.state === 'absent' && wiring.hooks.length === 0;\n const tooOld = release?.state === 'outdated';\n const stopped = hook.state === 'stops';\n const untold = options.strict && (release?.state === 'unknown' || wiring.lines.some((line) => line.state === 'unknown') || wiring.presence?.state === 'unknown');\n return outdated || !usable || claude === 'both' || off || switchedOff || missing || tooOld || stopped || untold ? EXIT_FAILED : EXIT_OK;\n}\n\n/* ---------------------------------------------------------------- dispatch */\n\n/**\n * A map, because the command is the first word a person types and an object\n * answers to more names than it was given: `spec-harness constructor` ran\n * `Object` as a command and ended on a stack trace, where `spec-harness\n * construct` is an unknown command with exit 2.\n */\nconst COMMANDS: ReadonlyMap<string, (options: Options, io: CliIO) => Promise<number>> = new Map(\n // One for every command that has a shape (usage.ts), which the compiler\n // holds. A command of another module loads its module when it is the one\n // typed, and no other command's.\n Object.entries({\n guard: guardCommand,\n hook: hookCommand,\n context: async (options, io) => (await import('./commands.js')).contextCommand(options, io),\n audit: async (options, io) => (await import('./commands.js')).auditCommand(options, io),\n escalate: async (options, io) => (await import('./commands.js')).escalateCommand(options, io),\n rule: async (options, io) => (await import('./commands.js')).ruleCommand(options, io),\n rulings: async (options, io) => (await import('./commands.js')).rulingsCommand(options, io),\n probe: async (options, io) => (await import('./commands.js')).probeCommand(options, io),\n premises: async (options, io) => (await import('./premises.js')).premisesCommand(options, io),\n init: async (options, io) => (await import('./setup.js')).initCommand(options, io),\n mcp: async (options, io) => (await import('./server.js')).mcpCommand(options, io),\n doctor: doctorCommand,\n } satisfies Record<Command, (options: Options, io: CliIO) => Promise<number>>),\n);\n\nasync function dispatch(argv: readonly string[], io: CliIO): Promise<number> {\n let options: Options;\n try {\n options = parseOptions(argv);\n } catch (error) {\n // The parser throws nothing but its refusal of the line, which holds\n // whose line it was. Claude Code's hook says its own, and holds no\n // write for it.\n const refused = error as UnreadableLine;\n if (isClaudeHook(refused.words[0], refused.words[1])) return unreadLine(refused.message, io);\n io.stderr.write(`spec-harness: ${refused.message}\\n`);\n return EXIT_ERROR;\n }\n if (options.version) {\n io.stdout.write(`${version()}\\n`);\n return EXIT_OK;\n }\n if (options.help || options.command === undefined) {\n io.stdout.write(HELP);\n return options.help ? EXIT_OK : EXIT_ERROR;\n }\n const command = COMMANDS.get(options.command);\n if (command === undefined) {\n io.stderr.write(`spec-harness: unknown command \"${options.command}\"; see spec-harness --help\\n`);\n return EXIT_ERROR;\n }\n // What parsed and names nothing, before anything is read or written for it.\n const refused = refusal(options, isDirectory);\n if (refused !== null) {\n io.stderr.write(`spec-harness: ${refused}\\n`);\n return EXIT_ERROR;\n }\n return command(options, io);\n}\n\n/**\n * Runs the command line and resolves to the exit code, for an error nothing\n * below expected too.\n *\n * Such an error is neither a refusal nor a finding: the answer cannot be\n * trusted, which is exit 2 (spec-core ADR-0005). Rejected instead, it reached\n * the launcher as Node's uncaught error, exit 1, \"refused or found something\"\n * to a script, and to Claude Code a hook that failed without blocking: the\n * write the guard could not check went ahead. The stack is what makes a\n * report of it something to act on, and it goes to stderr alone: a script\n * that reads a document from stdout is handed no part of one.\n *\n * A write its reader had closed the pipe for is not such an error: the answer\n * was not delivered, which is still 2, and nothing in the harness is at\n * fault, so it is said in a line and no stack sends a person looking for a\n * defect. The process's own streams report it as an event, which the\n * launcher answers in the same words; here it is a caller's stream that\n * throws it. It is read by its code: stdout and stderr are the only pipes\n * the harness writes to.\n *\n * Nor is a module of the build that is not there. The launcher says a build\n * without its command line in a line, and a module a command asks for where\n * it runs is said in the same line: a build with a file missing is not a\n * defect a stack leads to. It is read by its code too: the harness imports\n * nothing but its own modules and Node's.\n */\nexport async function run(argv: readonly string[], io: CliIO): Promise<number> {\n try {\n return await dispatch(argv, io);\n } catch (error) {\n // A sibling's document of a shape the harness does not read is a sibling\n // that printed something it cannot read (answers.ts): exit 2. A git\n // command that failed is what git said, and no line of the harness's.\n if (\n error instanceof UsageError ||\n error instanceof ConfigError ||\n error instanceof SiblingError ||\n error instanceof SiblingOutputError ||\n error instanceof GitError\n ) {\n io.stderr.write(`spec-harness: ${error.message}\\n`);\n return EXIT_ERROR;\n }\n if (!(error instanceof Error)) io.stderr.write(`spec-harness: unexpected error: ${String(error)}\\n`);\n else if ((error as NodeJS.ErrnoException).code === 'EPIPE') io.stderr.write('spec-harness: stdout was closed before all of the output was written\\n');\n else if ((error as NodeJS.ErrnoException).code === 'ERR_MODULE_NOT_FOUND') io.stderr.write('spec-harness: build output is missing; run \"npm run build\" first, or install the published package.\\n');\n else io.stderr.write(`spec-harness: unexpected error: ${error.stack ?? error.message}\\n`);\n return EXIT_ERROR;\n }\n}\n\n// What bin/spec-harness.js runs; the suite spawns the built one, from dist/,\n// outside the sweep (tests/integration/cli.test.ts), so it survives untested\n// in-process.\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n return run(argv, { stdout: process.stdout, stderr: process.stderr, cwd: process.cwd(), env: process.env });\n}\n\n"]}
package/dist/commands.js CHANGED
@@ -10,6 +10,7 @@ import { describeMeasured } from './audit.js';
10
10
  import { briefIdFromBranch } from './branch.js';
11
11
  import { findActive } from './briefs.js';
12
12
  import { formatFindings } from './formats.js';
13
+ import { isDirectory } from './fs.js';
13
14
  import { readJUnit } from './junit.js';
14
15
  import { classify, endOfOutput, readProbes, renderEvidence, renderUnexplained, verdictOf } from './probe.js';
15
16
  import { createReader } from './reader.js';
@@ -197,16 +198,25 @@ export async function rulingsCommand(options, io) {
197
198
  * (ADR-0003).
198
199
  */
199
200
  const LEFT_RUNNING = ', and something it started was left running, holding its output';
201
+ /**
202
+ * What is read of a probe's report where a directory stands under its name,
203
+ * as a repository can hold one: no report, said in the probe's own words
204
+ * for one it cannot read. Taken away as a file or read as one, it ended the
205
+ * command on Node's EISDIR and a stack.
206
+ */
207
+ const A_DIRECTORY = { ok: false, error: 'it is a directory, not a report' };
200
208
  async function runProbe(directory, probe, runs, timeout) {
201
209
  const classified = [];
202
210
  for (let i = 0; i < runs; i += 1) {
203
211
  const report = probe.junit === null ? null : join(directory, probe.junit);
204
- if (report !== null)
212
+ // A report an earlier run left is taken away, so that what is read
213
+ // after this run is this run's. A directory is none, and is left.
214
+ if (report !== null && !isDirectory(report))
205
215
  await rm(report, { force: true });
206
216
  const run = await runCommand(probe.run, directory, timeout);
207
217
  // existsSync answers false for null, so the null check is there for the
208
218
  // type, and its mutant is equivalent.
209
- const junit = report === null || !existsSync(report) ? null : readJUnit(await readFile(report, 'utf8'));
219
+ const junit = report === null || !existsSync(report) ? null : isDirectory(report) ? A_DIRECTORY : readJUnit(await readFile(report, 'utf8'));
210
220
  const judged = classify(probe, { exitCode: run.exitCode, output: run.output, junit });
211
221
  // After whatever `classify` says of the run: red, green or stopped, it
212
222
  // is judged by its shell, and what it left is said beside the verdict.