@tangle-network/agent-app 0.45.26 → 0.45.28

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 (70) hide show
  1. package/dist/assistant/index.d.ts +1 -0
  2. package/dist/assistant/index.js +5 -5
  3. package/dist/chat-routes/index.js +21 -21
  4. package/dist/chat-store/index.js +2 -2
  5. package/dist/{chunk-B2UEW62O.js → chunk-5ZTFZBS6.js} +4 -4
  6. package/dist/{chunk-AGCRCOQH.js → chunk-AWPK7ZDS.js} +1 -1
  7. package/dist/chunk-C3CAYGGQ.js +18 -0
  8. package/dist/chunk-C3CAYGGQ.js.map +1 -0
  9. package/dist/chunk-EMLGWEHV.js +33 -0
  10. package/dist/chunk-EMLGWEHV.js.map +1 -0
  11. package/dist/{chunk-XEA5EG6P.js → chunk-EPZYYWCT.js} +8 -30
  12. package/dist/chunk-EPZYYWCT.js.map +1 -0
  13. package/dist/{chunk-WD2B6HGY.js → chunk-K4RA5T3A.js} +11 -32
  14. package/dist/chunk-K4RA5T3A.js.map +1 -0
  15. package/dist/chunk-NEJ7OMQS.js +351 -0
  16. package/dist/chunk-NEJ7OMQS.js.map +1 -0
  17. package/dist/{chunk-7V2I3JGZ.js → chunk-OTLEYHOG.js} +50 -12
  18. package/dist/chunk-OTLEYHOG.js.map +1 -0
  19. package/dist/{chunk-RT5RKAFX.js → chunk-QGSVF6DZ.js} +8 -18
  20. package/dist/chunk-QGSVF6DZ.js.map +1 -0
  21. package/dist/{chunk-KOMP6NDW.js → chunk-WC43OQMR.js} +45 -34
  22. package/dist/chunk-WC43OQMR.js.map +1 -0
  23. package/dist/{chunk-N3G3FSM4.js → chunk-YXA3U4JZ.js} +9 -47
  24. package/dist/chunk-YXA3U4JZ.js.map +1 -0
  25. package/dist/design-canvas-react/index.js +4 -4
  26. package/dist/design-canvas-react/lazy.js +1 -1
  27. package/dist/legibility/cli.js +14 -8
  28. package/dist/legibility/cli.js.map +1 -1
  29. package/dist/legibility/index.js +2 -1
  30. package/dist/peer-floors/cli.js +14 -8
  31. package/dist/peer-floors/cli.js.map +1 -1
  32. package/dist/preflight/cli.js +4 -2
  33. package/dist/preflight/cli.js.map +1 -1
  34. package/dist/{run-tEsZUhAf.d.ts → run-D80hoLKh.d.ts} +1 -1
  35. package/dist/sandbox/index.d.ts +53 -1
  36. package/dist/sandbox/index.js +1 -1
  37. package/dist/signoff/cli.d.ts +2 -2
  38. package/dist/signoff/cli.js +6 -18
  39. package/dist/signoff/cli.js.map +1 -1
  40. package/dist/signoff/index.d.ts +4 -420
  41. package/dist/signoff/index.js +3 -55
  42. package/dist/signoff/proof-cli.js +11 -6
  43. package/dist/signoff/proof-cli.js.map +1 -1
  44. package/dist/signoff/proof.d.ts +70 -271
  45. package/dist/signoff/proof.js +3 -73
  46. package/dist/signoff/proof.js.map +1 -1
  47. package/dist/spend/cli.d.ts +1 -0
  48. package/dist/spend/cli.js +119 -0
  49. package/dist/spend/cli.js.map +1 -0
  50. package/dist/spend/index.d.ts +640 -0
  51. package/dist/spend/index.js +196 -0
  52. package/dist/spend/index.js.map +1 -0
  53. package/dist/stream/index.js +14 -14
  54. package/dist/teams/index.js +9 -9
  55. package/dist/teams/invitations-api.js +7 -7
  56. package/dist/theme-contract/cli.js +6 -2
  57. package/dist/theme-contract/cli.js.map +1 -1
  58. package/dist/theme-contract/index.js +2 -1
  59. package/dist/{types-U7Nz-txa.d.ts → types-Bd6uW9vQ.d.ts} +1 -1
  60. package/dist/web-react/index.d.ts +28 -40
  61. package/dist/web-react/index.js +11 -11
  62. package/package.json +7 -1
  63. package/dist/chunk-7V2I3JGZ.js.map +0 -1
  64. package/dist/chunk-KOMP6NDW.js.map +0 -1
  65. package/dist/chunk-N3G3FSM4.js.map +0 -1
  66. package/dist/chunk-RT5RKAFX.js.map +0 -1
  67. package/dist/chunk-WD2B6HGY.js.map +0 -1
  68. package/dist/chunk-XEA5EG6P.js.map +0 -1
  69. /package/dist/{chunk-B2UEW62O.js.map → chunk-5ZTFZBS6.js.map} +0 -0
  70. /package/dist/{chunk-AGCRCOQH.js.map → chunk-AWPK7ZDS.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/signoff/cli.ts","../../src/signoff/invoked-as-script.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-signoff` — run the local sign-off gate and print the proof.\n *\n * Exits 0 only when every declared step passed in a pristine tree. Exit 1 is a\n * real failure; exit 2 is a usage or config error, so a script can tell \"your\n * code is broken\" from \"your gate is misconfigured\".\n *\n * agent-app-signoff # this repo, working tree, default config\n * agent-app-signoff --source head # exactly the commit that would merge\n * agent-app-signoff --seed 12345 # reproduce a previous run's orders\n * agent-app-signoff --keep-going # run every step, full picture\n * agent-app-signoff --json proof.json # machine-readable record\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { invokedAsScript } from './invoked-as-script'\nimport { formatSignoffReport } from './report'\nimport { runSignoff, type RunSignoffOptions } from './run'\nimport type { SignoffEvent, SignoffSource } from './types'\n\ninterface ParsedArgs extends RunSignoffOptions {\n readonly jsonPath?: string\n readonly quiet?: boolean\n}\n\nfunction usage(): string {\n return [\n 'Usage: agent-app-signoff [repoDir] [options]',\n '',\n ' --source head|working-tree bytes to verify (default working-tree)',\n ' --config <path> config module (default signoff.config.mjs)',\n ' --seed <n> base seed; reproduces a previous run',\n ' --shuffle-runs <n> override every shuffled step\\'s run count',\n ' --max-parallel <n> cap concurrent steps',\n ' --cache-dir <path> clean trees + pristine stores live here',\n ' --keep-going run every step even after one fails',\n ' --keep-workspace leave the clean tree on disk to inspect',\n ' --json <path> write the machine-readable report',\n ' --quiet verdict only; no per-step progress',\n ].join('\\n')\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`agent-app-signoff: ${message}\\n\\n${usage()}\\n`)\n process.exit(2)\n}\n\nfunction positiveInt(raw: string, flag: string): number {\n const value = Number.parseInt(raw, 10)\n if (!Number.isFinite(value) || value < 0) fail(`${flag} needs a non-negative integer, got \"${raw}\"`)\n return value\n}\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const parsed: {\n repoDir?: string\n configPath?: string\n source?: SignoffSource\n seed?: number\n shuffleRuns?: number\n maxParallel?: number\n cacheDir?: string\n keepGoing?: boolean\n keepWorkspace?: boolean\n jsonPath?: string\n quiet?: boolean\n } = {}\n\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] as string\n const take = (): string => {\n const value = argv[index + 1]\n if (value === undefined) fail(`${flag} needs a value`)\n index += 1\n return value\n }\n switch (flag) {\n case '--source': {\n const value = take()\n if (value !== 'head' && value !== 'working-tree') fail(`--source must be head or working-tree, got \"${value}\"`)\n parsed.source = value\n break\n }\n case '--config': parsed.configPath = take(); break\n case '--seed': parsed.seed = positiveInt(take(), '--seed'); break\n case '--shuffle-runs': parsed.shuffleRuns = positiveInt(take(), '--shuffle-runs'); break\n case '--max-parallel': parsed.maxParallel = positiveInt(take(), '--max-parallel'); break\n case '--cache-dir': parsed.cacheDir = take(); break\n case '--keep-going': parsed.keepGoing = true; break\n case '--keep-workspace': parsed.keepWorkspace = true; break\n case '--json': parsed.jsonPath = take(); break\n case '--quiet': parsed.quiet = true; break\n case '-h':\n case '--help':\n process.stdout.write(`${usage()}\\n`)\n process.exit(0)\n break\n default:\n if (flag.startsWith('-')) fail(`unknown option: ${flag}`)\n if (parsed.repoDir !== undefined) fail(`unexpected second directory: ${flag}`)\n parsed.repoDir = flag\n }\n }\n return parsed\n}\n\nfunction progressWriter(): (event: SignoffEvent) => void {\n return (event) => {\n switch (event.kind) {\n case 'tree':\n process.stderr.write(`· clean tree at ${event.path} (${event.head.slice(0, 12)}${event.dirty ? ' + working tree' : ''})\\n`)\n break\n case 'store':\n process.stderr.write(`· store ${event.cacheHit ? 'warm' : 'COLD'} ${event.cacheKey.slice(0, 16)}\\n`)\n break\n case 'install-start':\n process.stderr.write(`· ${event.command}\\n`)\n break\n case 'install-end':\n process.stderr.write(`· install exit ${event.exitCode} in ${event.durationMs}ms\\n`)\n break\n case 'step-start':\n process.stderr.write(`· start ${event.name}${event.seed === null ? '' : ` (seed ${event.seed})`}\\n`)\n break\n case 'step-end':\n process.stderr.write(`· ${event.status === 'passed' ? 'ok' : event.status} ${event.name} ${event.durationMs}ms\\n`)\n break\n }\n }\n}\n\nexport async function runSignoffCli(argv: readonly string[]): Promise<number> {\n const args = parseArgs(argv)\n const report = await runSignoff({ ...args, onEvent: args.quiet ? undefined : progressWriter() })\n\n if (args.jsonPath !== undefined) {\n const abs = resolve(args.jsonPath)\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, `${JSON.stringify(report, null, 2)}\\n`)\n }\n\n process.stdout.write(`${formatSignoffReport(report)}\\n`)\n return report.ok ? 0 : 1\n}\n\n/* c8 ignore start — process wiring, exercised by the bin itself */\nif (invokedAsScript(import.meta.url, process.argv[1])) {\n runSignoffCli(process.argv.slice(2))\n .then((code) => process.exit(code))\n .catch((err: unknown) => {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(2)\n })\n}\n/* c8 ignore stop */\n","import { realpathSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\n\n/**\n * Is this module the script the process was started with?\n *\n * The obvious spelling — `import.meta.url === pathToFileURL(process.argv[1]).href`\n * — is wrong for every packaged bin, and wrong in the silent direction: the\n * module decides it was imported rather than executed, so the CLI does nothing\n * and exits 0.\n *\n * The two sides are not the same kind of path. `import.meta.url` is the module\n * URL Node resolved, and Node resolves a module's realpath unless started with\n * `--preserve-symlinks`. `process.argv[1]` is the path as SPELLED on the\n * command line. A package manager's bin shim spells it through symlinked\n * directories:\n *\n * argv[1] …/node_modules/.bin/../@scope/pkg/dist/cli.js\n * import.meta.url …/node_modules/.pnpm/pkg@1.2.3/node_modules/@scope/pkg/dist/cli.js\n *\n * Same file, two strings, and a `===` between them is false.\n *\n * So the entry path is resolved the same way Node resolved the module before\n * the comparison. A missing or unresolvable entry is not this function's\n * business to explain — it is simply not this module, which is the honest\n * answer and keeps an importer from executing a CLI.\n */\nexport function invokedAsScript(moduleUrl: string, entry: string | undefined): boolean {\n if (entry === undefined || entry.length === 0) return false\n let resolved: string\n try {\n resolved = realpathSync(entry)\n } catch {\n return false\n }\n return moduleUrl === pathToFileURL(resolved).href\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/signoff/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-signoff` — run the local sign-off gate and print the proof.\n *\n * Exits 0 only when every declared step passed in a pristine tree. Exit 1 is a\n * real failure; exit 2 is a usage or config error, so a script can tell \"your\n * code is broken\" from \"your gate is misconfigured\".\n *\n * agent-app-signoff # this repo, working tree, default config\n * agent-app-signoff --source head # exactly the commit that would merge\n * agent-app-signoff --seed 12345 # reproduce a previous run's orders\n * agent-app-signoff --keep-going # run every step, full picture\n * agent-app-signoff --json proof.json # machine-readable record\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { invokedAsScript } from './invoked-as-script'\nimport { formatSignoffLine, formatSignoffReport } from './report'\nimport { runSignoff, type RunSignoffOptions } from './run'\nimport type { SignoffEvent, SignoffSource } from './types'\n\ninterface ParsedArgs extends RunSignoffOptions {\n readonly jsonPath?: string\n readonly quiet?: boolean\n}\n\nfunction usage(): string {\n return [\n 'Usage: agent-app-signoff [repoDir] [options]',\n '',\n ' --source head|working-tree bytes to verify (default working-tree)',\n ' --config <path> config module (default signoff.config.mjs)',\n ' --seed <n> base seed; reproduces a previous run',\n ' --shuffle-runs <n> override every shuffled step\\'s run count',\n ' --max-parallel <n> cap concurrent steps',\n ' --cache-dir <path> clean trees + pristine stores live here',\n ' --keep-going run every step even after one fails',\n ' --keep-workspace leave the clean tree on disk to inspect',\n ' --json <path> write the machine-readable report',\n ' --quiet verdict only; no per-step progress',\n ].join('\\n')\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`agent-app-signoff: ${message}\\n\\n${usage()}\\n`)\n process.exit(2)\n}\n\nfunction positiveInt(raw: string, flag: string): number {\n const value = Number.parseInt(raw, 10)\n if (!Number.isFinite(value) || value < 0) fail(`${flag} needs a non-negative integer, got \"${raw}\"`)\n return value\n}\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const parsed: {\n repoDir?: string\n configPath?: string\n source?: SignoffSource\n seed?: number\n shuffleRuns?: number\n maxParallel?: number\n cacheDir?: string\n keepGoing?: boolean\n keepWorkspace?: boolean\n jsonPath?: string\n quiet?: boolean\n } = {}\n\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] as string\n const take = (): string => {\n const value = argv[index + 1]\n if (value === undefined) fail(`${flag} needs a value`)\n index += 1\n return value\n }\n switch (flag) {\n case '--source': {\n const value = take()\n if (value !== 'head' && value !== 'working-tree') fail(`--source must be head or working-tree, got \"${value}\"`)\n parsed.source = value\n break\n }\n case '--config': parsed.configPath = take(); break\n case '--seed': parsed.seed = positiveInt(take(), '--seed'); break\n case '--shuffle-runs': parsed.shuffleRuns = positiveInt(take(), '--shuffle-runs'); break\n case '--max-parallel': parsed.maxParallel = positiveInt(take(), '--max-parallel'); break\n case '--cache-dir': parsed.cacheDir = take(); break\n case '--keep-going': parsed.keepGoing = true; break\n case '--keep-workspace': parsed.keepWorkspace = true; break\n case '--json': parsed.jsonPath = take(); break\n case '--quiet': parsed.quiet = true; break\n case '-h':\n case '--help':\n process.stdout.write(`${usage()}\\n`)\n process.exit(0)\n break\n default:\n if (flag.startsWith('-')) fail(`unknown option: ${flag}`)\n if (parsed.repoDir !== undefined) fail(`unexpected second directory: ${flag}`)\n parsed.repoDir = flag\n }\n }\n return parsed\n}\n\nfunction progressWriter(): (event: SignoffEvent) => void {\n return (event) => {\n switch (event.kind) {\n case 'tree':\n process.stderr.write(`· clean tree at ${event.path} (${event.head.slice(0, 12)}${event.dirty ? ' + working tree' : ''})\\n`)\n break\n case 'store':\n process.stderr.write(`· store ${event.cacheHit ? 'warm' : 'COLD'} ${event.cacheKey.slice(0, 16)}\\n`)\n break\n case 'install-start':\n process.stderr.write(`· ${event.command}\\n`)\n break\n case 'install-end':\n process.stderr.write(`· install exit ${event.exitCode} in ${event.durationMs}ms\\n`)\n break\n case 'step-start':\n process.stderr.write(`· start ${event.name}${event.seed === null ? '' : ` (seed ${event.seed})`}\\n`)\n break\n case 'step-end':\n process.stderr.write(`· ${event.status === 'passed' ? 'ok' : event.status} ${event.name} ${event.durationMs}ms\\n`)\n break\n }\n }\n}\n\nexport async function runSignoffCli(argv: readonly string[]): Promise<number> {\n const args = parseArgs(argv)\n const report = await runSignoff({ ...args, onEvent: args.quiet ? undefined : progressWriter() })\n\n if (args.jsonPath !== undefined) {\n const abs = resolve(args.jsonPath)\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, `${JSON.stringify(report, null, 2)}\\n`)\n }\n\n // `--quiet` is documented as \"verdict only\", and CLAUDE.md names the one-line\n // `signoff PASS <sha> …` summary as an accepted PR proof. Printing the full\n // report here contradicted both, and left the only producer of that summary\n // with no caller.\n process.stdout.write(`${args.quiet ? formatSignoffLine(report) : formatSignoffReport(report)}\\n`)\n return report.ok ? 0 : 1\n}\n\n/* c8 ignore start — process wiring, exercised by the bin itself */\nif (invokedAsScript(import.meta.url, process.argv[1])) {\n runSignoffCli(process.argv.slice(2))\n .then((code) => process.exit(code))\n .catch((err: unknown) => {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(2)\n })\n}\n/* c8 ignore stop */\n"],"mappings":"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","names":[]}
@@ -1,32 +1,7 @@
1
- export { R as RunSignoffOptions, r as runSignoff } from '../run-tEsZUhAf.js';
2
- import { c as SignoffConfig, L as LoadedSignoffConfig, b as SignoffReport, d as SignoffStepResult, e as SignoffStepSpec, f as SignoffRepoFacts, S as SignoffSource } from '../types-U7Nz-txa.js';
3
- export { g as SignoffAttempt, h as SignoffConfigOrigin, a as SignoffEvent, i as SignoffHostFacts, j as SignoffInstallResult, k as SignoffInstallSpec, l as SignoffShuffleSpec, m as SignoffStepStatus } from '../types-U7Nz-txa.js';
1
+ export { R as RunSignoffOptions, r as runSignoff } from '../run-D80hoLKh.js';
2
+ import { L as LoadedSignoffConfig, b as SignoffReport } from '../types-Bd6uW9vQ.js';
3
+ export { c as SignoffAttempt, d as SignoffConfig, e as SignoffConfigOrigin, a as SignoffEvent, f as SignoffHostFacts, g as SignoffInstallResult, h as SignoffInstallSpec, i as SignoffRepoFacts, j as SignoffShuffleSpec, S as SignoffSource, k as SignoffStepResult, l as SignoffStepSpec, m as SignoffStepStatus } from '../types-Bd6uW9vQ.js';
4
4
 
5
- /**
6
- * Where the step list comes from.
7
- *
8
- * It is declared by the repo, never hardcoded here, because the three workflows
9
- * this has to reproduce do not share a shape: tax-agent filters its install to
10
- * one workspace package and runs a Python toolkit suite; legal-agent runs a
11
- * react-router typegen and a Worker startup check; agent-app runs a named
12
- * incident-class gate, a generated-project test and knip. A checker that
13
- * hardcodes any one of those is wrong for the other two.
14
- *
15
- * Three sources, in order:
16
- * 1. `signoff.config.mjs` (or `.js`) — the full surface, including per-step
17
- * `env`, `needs` and shuffle specs.
18
- * 2. a `signoff` key in `package.json` — the same shape, JSON-only.
19
- * 3. derived from the repo's own `scripts`, so a repo gets a real gate before
20
- * anyone writes a config. The derivation is documented below and its origin
21
- * is stamped into the proof, because a derived run is a weaker claim than a
22
- * declared one.
23
- */
24
- declare const SIGNOFF_CONFIG_FILES: readonly string[];
25
- declare function parseSignoffConfig(value: unknown, where: string): SignoffConfig;
26
- declare function deriveSignoffConfig(scripts: Readonly<Record<string, string>>): {
27
- readonly config: SignoffConfig;
28
- readonly used: readonly string[];
29
- };
30
5
  interface LoadSignoffConfigOptions {
31
6
  readonly repoRoot: string;
32
7
  /** Explicit config path. Missing file is an error, never a silent fallback. */
@@ -34,397 +9,6 @@ interface LoadSignoffConfigOptions {
34
9
  }
35
10
  declare function loadSignoffConfig(options: LoadSignoffConfigOptions): Promise<LoadedSignoffConfig>;
36
11
 
37
- /** Concurrency actually achieved, measured from the step windows rather than
38
- * asserted from the config. A claimed speedup nobody measured is a wish. */
39
- declare function peakConcurrency(steps: readonly SignoffStepResult[]): number;
40
12
  declare function formatSignoffReport(report: SignoffReport): string;
41
- /** One line for a commit message, a PR comment, or a chat handoff. */
42
- declare function formatSignoffLine(report: SignoffReport): string;
43
13
 
44
- /**
45
- * Refuse to sign off on a runtime the product does not ship.
46
- *
47
- * CI pins its Node version (`actions/setup-node` with `node-version: 22` in all
48
- * three fleet workflows). A developer's shell does not — this host runs 24. A
49
- * local gate that inherits whatever is on `PATH` therefore verifies a runtime
50
- * nobody deploys, and reports it as the runtime that ships. That is the same
51
- * failure shape as a number measured in a narrower context than it is
52
- * presented in, and it is not acceptable in the thing that replaces the merge
53
- * gate.
54
- *
55
- * So the pin is read from the repo and enforced, or it is absent and the report
56
- * says so. Three sources, in order:
57
- *
58
- * - `signoff.config.mjs`'s `nodeVersion` — the explicit declaration.
59
- * - `.nvmrc` — the pin a repo already keeps for humans.
60
- * - the `pull_request` workflows' `node-version` (`./workflow-pin`) — the pin
61
- * CI itself runs on.
62
- *
63
- * **The third source was added because the first two were empty on the entire
64
- * fleet, and that produced a false PASS.** legal-agent `4c0d688` failed CI on
65
- * `Cannot bundle Node.js built-in "node:sqlite"` and this gate signed it off.
66
- * Reproduced in one installed tree, same bytes: Node 22 fails both files, Node
67
- * 24 passes both, every time. No `.nvmrc` exists in tax-agent, legal-agent or
68
- * agent-app; all three pin `node-version: 22` in the workflow being replaced.
69
- * A gate that replaces a workflow has to read the runtime that workflow pins.
70
- *
71
- * A `.nvmrc` and a workflow that disagree is not resolved by preference — it is
72
- * a refusal, because it means the local gate and CI verify different runtimes,
73
- * which is the exact defect this module exists to prevent.
74
- *
75
- * **`engines.node` is deliberately NOT read.** It is a floor (`">=18"`), not a
76
- * pin, so treating it as one manufactures refusals on every version above the
77
- * floor — and an unsatisfiable gate does not stop bad work, it gets waived.
78
- */
79
- interface NodeVersionRequirement {
80
- /** The declared major, e.g. `22`. */
81
- readonly major: number;
82
- readonly declared: string;
83
- /** Where it came from, for the proof. */
84
- readonly source: string;
85
- }
86
- declare function resolveNodeRequirement(repoRoot: string, configured?: string): NodeVersionRequirement | null;
87
- /**
88
- * Throw when the running Node cannot stand in for the declared one.
89
- *
90
- * Major-only: a patch difference is not a different runtime, and demanding an
91
- * exact patch would refuse every host that has not just re-installed.
92
- */
93
- declare function assertNodeVersion(requirement: NodeVersionRequirement | null, running?: string): void;
94
-
95
- /**
96
- * The dependency graph, and running it as wide as the graph allows.
97
- *
98
- * CI runs these steps in a line because a YAML `steps:` list is a line. Nothing
99
- * about the work requires that: typecheck, the suite, the build and knip all
100
- * read source and none reads another's output. On a 32-core host, running them
101
- * concurrently is free wall-clock, and it is the only reason a strictly larger
102
- * verification can still finish faster than the CI it replaces.
103
- *
104
- * The graph is declared per step (`needs`), validated here, and the schedule is
105
- * derived from it — so an omitted edge is a correctness bug the repo owns, and
106
- * a cycle is named rather than deadlocking.
107
- */
108
- interface GraphNode {
109
- readonly name: string;
110
- readonly needs?: readonly string[];
111
- }
112
- /** Throws on a duplicate name, a dangling `needs`, or a cycle. */
113
- declare function validateGraph(nodes: readonly GraphNode[]): void;
114
- type TaskStatus = 'passed' | 'failed' | 'skipped' | 'cancelled' | 'blocked';
115
- interface TaskOutcome<T> {
116
- readonly name: string;
117
- readonly status: TaskStatus;
118
- /** Present for anything that actually ran, including a cancelled task. */
119
- readonly value: T | null;
120
- readonly startedAtMs: number | null;
121
- readonly finishedAtMs: number | null;
122
- }
123
- interface RunGraphOptions<TNode extends GraphNode, TValue> {
124
- readonly nodes: readonly TNode[];
125
- readonly maxParallel: number;
126
- /** `false` stops scheduling after the first failure and kills what is running. */
127
- readonly keepGoing: boolean;
128
- /** Runs one node. Resolves `{ ok }` for pass/fail; must not throw for a
129
- * failing command — a non-zero exit is data. */
130
- readonly run: (node: TNode, signal: AbortSignal) => Promise<{
131
- readonly ok: boolean;
132
- readonly value: TValue;
133
- }>;
134
- /** Wall-clock origin, so outcomes are comparable across the whole run. */
135
- readonly now?: () => number;
136
- }
137
- /**
138
- * Run the graph, honouring dependencies and the parallelism cap.
139
- *
140
- * Failure semantics, stated because they are the difference between a gate you
141
- * trust and one you argue with:
142
- * - fail-fast (default): nothing new is scheduled, everything in flight is
143
- * aborted and reported as `cancelled`, everything unstarted as `skipped`.
144
- * - `keepGoing`: independent work continues, but a step whose dependency
145
- * failed is reported `blocked`. It is never reported as passed, and never
146
- * silently omitted.
147
- */
148
- declare function runGraph<TNode extends GraphNode, TValue>(options: RunGraphOptions<TNode, TValue>): Promise<TaskOutcome<TValue>[]>;
149
-
150
- /**
151
- * Suite-order randomization — the half of this gate that CI does not have.
152
- *
153
- * CI runs one arbitrary file order, so a scheduling-dependent failure is a coin
154
- * flip it happens to win or lose. The `node:sqlite` bundling failure that
155
- * started this was exactly that shape: it reproduced under CI's clean install
156
- * and worker sharding and not under a warm local run, and a single fixed order
157
- * could have missed it in either direction.
158
- *
159
- * Two rules make randomization useful rather than merely noisy:
160
- *
161
- * 1. **Every seed is recorded.** A shuffled failure that cannot be replayed is
162
- * a rumour. The report carries the base seed and every derived seed, and the
163
- * derivation is a pure function of `(base, step, index)` — so `--seed <base>`
164
- * reproduces the whole run, and a single seed replays one step.
165
- * 2. **Files are shuffled; tests inside a file are not.** File order is what
166
- * module-graph and worker-scheduling failures depend on. Shuffling the tests
167
- * within a file mostly finds intentional ordering in a `describe` block,
168
- * which is a false alarm, and a gate that cries wolf gets waived.
169
- */
170
- /**
171
- * Vitest file-order shuffle. `{seed}` is substituted per attempt.
172
- *
173
- * **No `--` separator, and that is measured, not assumed.** The habit is to
174
- * write `pnpm run test -- --flag`, and it silently breaks this: pnpm forwards
175
- * script arguments verbatim without needing the separator, so the `--` reaches
176
- * vitest, whose CLI treats it as end-of-options and drops everything after it.
177
- * Measured on this repo, four test files, `--reporter=verbose`:
178
- *
179
- * | invocation | seed 1 order | seed 2 order |
180
- * |---|---|---|
181
- * | `vitest run -- --sequence.shuffle.files=true --sequence.seed=N` | schedule, store, seeds, config | schedule, store, seeds, config |
182
- * | `vitest run --sequence.shuffle.files=true --sequence.seed=N` | schedule, config, store, seeds | seeds, schedule, config, store |
183
- *
184
- * The first row is the failure this gate exists to prevent, applied to itself:
185
- * a run that reports "2 orders, seeds recorded" while running one fixed order
186
- * twice. If a runner ever does need a separator, its config declares its own
187
- * `shuffle.args`.
188
- */
189
- declare const DEFAULT_SHUFFLE_ARGS: readonly string[];
190
- declare const DEFAULT_SHUFFLE_RUNS = 2;
191
- /** A fresh base seed. Random, then recorded — never a fixed constant, or the
192
- * "randomized" order is one more fixed order. */
193
- declare function newSeedBase(): number;
194
- /**
195
- * Derive a step's Nth seed from the base.
196
- *
197
- * A hash rather than `base + n`: adjacent seeds produce correlated orders in
198
- * some runners, and the point is independent samples of the order space.
199
- */
200
- declare function deriveSeed(base: number, stepName: string, index: number): number;
201
- /**
202
- * Refuse a shuffled step whose command cannot receive the appended flags.
203
- *
204
- * pnpm only forwards extra arguments to a script through `run`, `exec` or
205
- * `dlx`. The shorthand form puts pnpm's own option parser in front of them, and
206
- * what happens next is a version lottery. Measured on this host, appending
207
- * `--sequence.shuffle.files=true --sequence.seed=7` to a script that prints its
208
- * `process.argv`:
209
- *
210
- * | command | pnpm 9.15.9 | pnpm 10.22.0 |
211
- * |---|---|---|
212
- * | `pnpm run t <flags>` | forwarded, exit 0 | forwarded, exit 0 |
213
- * | `pnpm exec node probe.mjs <flags>` | forwarded, exit 0 | forwarded, exit 0 |
214
- * | `pnpm t <flags>` | `Unknown options`, exit 1 | exit 254, script never ran |
215
- * | `pnpm --filter web t <flags>` | `Unknown options`, exit 1 | **exit 0, script never ran** |
216
- *
217
- * That last cell is the reason this is a refusal and not a note. tax-agent's CI
218
- * runs `pnpm --filter web test`, and a config that copied the line verbatim
219
- * would, on pnpm 10, report a green "unit tests" step that executed zero tests.
220
- * A gate reporting safety it did not provide is the exact failure this module
221
- * exists to prevent, and the shorthand makes it silent.
222
- *
223
- * This is a static approximation — it checks the invocation SHAPE, not what the
224
- * runner received — so it is deliberately narrow: it fires only on commands
225
- * that invoke pnpm, and only on steps that get arguments appended.
226
- */
227
- declare function assertShuffleArgsReachTheRunner(steps: readonly SignoffStepSpec[]): void;
228
- interface StepAttemptPlan {
229
- readonly command: string;
230
- readonly seed: number | null;
231
- }
232
- /**
233
- * Expand one step into the commands that will actually run.
234
- *
235
- * An unshuffled step is one attempt with no seed. A shuffled step is one
236
- * attempt per seed, each with the seed substituted into the appended arguments.
237
- */
238
- declare function planAttempts(step: SignoffStepSpec, seedBase: number, overrideRuns?: number): StepAttemptPlan[];
239
-
240
- /**
241
- * Read the Node pin out of the workflows that gate a merge.
242
- *
243
- * This exists because of a measured false PASS. legal-agent `4c0d688` was red
244
- * in CI on two test files — `Cannot bundle Node.js built-in "node:sqlite"` —
245
- * and the sign-off gate signed it off. Same bytes, same lockfile, same
246
- * hermetic tree: on Node 22 both files fail, on Node 24 both pass, 100% of the
247
- * time. The runtime was the whole difference, and the gate never saw it because
248
- * it looked for a pin in exactly two places the fleet does not keep one.
249
- *
250
- * None of tax-agent, legal-agent or agent-app has a `.nvmrc`. All three pin
251
- * `node-version: 22` in the workflow that IS the merge gate. So the pin the
252
- * gate is replacing was sitting in the file it is replacing, unread.
253
- *
254
- * Scope is deliberate: only workflows that trigger on `pull_request`. Those are
255
- * the merge gate. agent-app's `publish.yml` runs Node 24.18.0 for its release
256
- * jobs and triggers on push, and reading it would put the gate in permanent
257
- * conflict with `ci.yml`'s Node 22.
258
- *
259
- * Nothing here guesses. An expression (`${{ matrix.node }}`) is not a version,
260
- * a `node-version-file` that does not exist is not a pin, and two merge-gate
261
- * workflows on different majors is a question this module cannot answer — each
262
- * one refuses and names the config key that settles it.
263
- */
264
- interface WorkflowNodePin {
265
- /** Repo-relative workflow path, for the proof. */
266
- readonly file: string;
267
- /** The version as written: `22`, `24.18.0`, `v20`. */
268
- readonly value: string;
269
- /** `node-version`, or the `node-version-file` path it was read through. */
270
- readonly via: string;
271
- }
272
- /**
273
- * Does this workflow run on `pull_request`?
274
- *
275
- * Both spellings the fleet uses are handled: the block form every workflow here
276
- * writes, and the inline form (`on: [push, pull_request]`). `on` is quoted in
277
- * some repos because YAML 1.1 reads a bare `on` as the boolean true, so the
278
- * quoted keys are matched too.
279
- */
280
- declare function triggersOnPullRequest(source: string): boolean;
281
- /** Node pins declared by every workflow that gates a merge, in filename order. */
282
- declare function scanMergeGateNodePins(repoRoot: string): WorkflowNodePin[];
283
- interface ResolvedWorkflowPin {
284
- readonly major: number;
285
- readonly declared: string;
286
- readonly source: string;
287
- }
288
- /**
289
- * One Node major for the whole merge gate, or a refusal that names why not.
290
- *
291
- * `majorOf` is injected rather than imported to keep the direction of the
292
- * dependency one-way: `node-version.ts` owns what a version string means, this
293
- * module owns where the string lives.
294
- */
295
- declare function resolveWorkflowNodePin(repoRoot: string, majorOf: (raw: string) => number | null): ResolvedWorkflowPin | null;
296
-
297
- /**
298
- * The pristine package store, cached on the lockfile so speed is not paid for
299
- * with a stale module graph.
300
- *
301
- * The whole mechanical difference between "green locally" and "red in CI" is
302
- * that CI installs `--frozen-lockfile` into an isolated store with no
303
- * `node_modules` and no framework cache, and a local run reuses both. Only one
304
- * of those two is safe to keep:
305
- *
306
- * - `node_modules` and any build/framework cache are **never** reused. They are
307
- * what masked the failure this gate exists to catch, and they are recreated
308
- * for every run inside a fresh `git worktree`.
309
- * - The **store** is reused, keyed on the bytes that decide what gets installed.
310
- * A pnpm store is content-addressed: every entry is named by the hash of what
311
- * is in it, so a reused entry cannot be a different version of a package than
312
- * the lockfile asked for. Reusing it skips downloads, not resolution.
313
- *
314
- * The key covers every manifest in the tree — lockfile, workspace file, every
315
- * `package.json`, `.npmrc`. Change any of them and the key changes, so the next
316
- * run installs into an empty store and pays the honest cold cost. Generations
317
- * are kept (default 4) rather than one, so moving between a branch and `main`
318
- * finds both warm instead of thrashing.
319
- */
320
- /** Basenames whose bytes decide what an install resolves to. */
321
- declare const MANIFEST_FILES: readonly string[];
322
- interface StoreResolution {
323
- readonly storeDir: string;
324
- readonly cacheKey: string;
325
- /** True when a store for this key already had content. */
326
- readonly hit: boolean;
327
- /** Repo-relative manifest paths, sorted — the inputs to `cacheKey`. */
328
- readonly keyedOn: readonly string[];
329
- /** Store directories removed by the generation cap. */
330
- readonly pruned: readonly string[];
331
- }
332
- interface ResolveStoreOptions {
333
- /** The clean tree whose manifests are hashed. */
334
- readonly treePath: string;
335
- readonly cacheDir: string;
336
- /** Generations to keep. Default 4. */
337
- readonly generations?: number;
338
- }
339
- /** Every manifest in the tree, repo-relative and sorted. */
340
- declare function manifestFiles(treePath: string): string[];
341
- /** sha256 over each manifest's path and content — order-independent by sorting. */
342
- declare function manifestCacheKey(treePath: string, files: readonly string[]): string;
343
- declare function resolveStore(options: ResolveStoreOptions): StoreResolution;
344
-
345
- /**
346
- * Materialize the pristine checkout every step runs against.
347
- *
348
- * **The decision, and the measurement behind it: a `git worktree` of HEAD, not
349
- * a filtered copy.** Both were timed on two real repos on this host:
350
- *
351
- * | repo | `git worktree add --detach` | `rsync -a --exclude node_modules --exclude .git` |
352
- * |---|---|---|
353
- * | agent-app (931 tracked files) | **0.04 s / 11 MB** | 0.12 s / 25 MB |
354
- * | legal-agent (753 tracked files) | **0.06 s / 24 MB** | **3.97 s / 2.7 GB** |
355
- *
356
- * The 2.7 GB is the argument. The copy carried `build/`, `.react-router/` and
357
- * `.wrangler/` — generated output and framework caches — because an exclude
358
- * list is a hand-maintained enumeration of things to leave behind, and it is
359
- * never complete. A warm Vite cache is precisely what made the `node:sqlite`
360
- * bundling failure invisible locally while CI saw it, so a materializer that
361
- * can leak one has defeated its own purpose. `git` already knows what is source
362
- * and what is generated, and `.gitignore` is that list, maintained by the repo.
363
- *
364
- * The overlay on top is what keeps the gate usable before you commit:
365
- * `source: 'working-tree'` applies `git diff HEAD` (staged and unstaged) as a
366
- * patch and copies untracked, non-ignored files in. `source: 'head'` verifies
367
- * exactly the commit that would merge.
368
- */
369
- interface MaterializeOptions {
370
- readonly repoDir: string;
371
- readonly dest: string;
372
- readonly source: SignoffSource;
373
- /** Gitignored files the run genuinely needs. Missing ones abort. */
374
- readonly carryFiles?: readonly string[];
375
- }
376
- interface CleanTree extends SignoffRepoFacts {
377
- /** Absolute path of the materialized checkout. */
378
- readonly path: string;
379
- }
380
- declare function repoRootOf(dir: string): string;
381
- declare function materializeCleanTree(options: MaterializeOptions): CleanTree;
382
- /** Unregister and delete a materialized tree. */
383
- declare function removeCleanTree(tree: CleanTree): void;
384
-
385
- /**
386
- * The subprocess primitive every sign-off step runs through.
387
- *
388
- * Three properties the gate depends on, none of which `execSync` gives:
389
- *
390
- * 1. **Cancellable.** Under fail-fast, a build still running when typecheck
391
- * fails is killed rather than waited out — otherwise the "faster than CI"
392
- * claim is spent waiting for work whose verdict no longer matters.
393
- * 2. **Process-group kill.** Steps run through `sh -c`, so killing the shell
394
- * leaves `vitest`'s forks and `tsup`'s dts worker orphaned and holding CPU.
395
- * The child is spawned as a group leader and the whole group is signalled.
396
- * 3. **Bounded, non-silent capture.** Output is capped, and when the cap is hit
397
- * the elision is stated in the captured text. A gate that quietly drops the
398
- * middle of a failure log is a gate that hides the failure.
399
- */
400
- interface CommandResult {
401
- readonly command: string;
402
- readonly cwd: string;
403
- readonly exitCode: number;
404
- readonly signal: string | null;
405
- readonly durationMs: number;
406
- readonly output: string;
407
- readonly truncated: boolean;
408
- readonly timedOut: boolean;
409
- }
410
- interface RunCommandOptions {
411
- readonly command: string;
412
- readonly cwd: string;
413
- readonly env?: Readonly<Record<string, string | undefined>>;
414
- readonly timeoutMs?: number;
415
- readonly signal?: AbortSignal;
416
- /** Retained bytes before elision. Default 2 MiB. */
417
- readonly maxOutputBytes?: number;
418
- /** Grace between SIGTERM and SIGKILL. Default 5 s. */
419
- readonly killGraceMs?: number;
420
- readonly onData?: (chunk: string) => void;
421
- }
422
- /**
423
- * Run one shell command to completion and report what happened.
424
- *
425
- * Never throws on a non-zero exit — a failing step is data, not an exception.
426
- * It throws only when the process could not be started at all.
427
- */
428
- declare function runCommand(options: RunCommandOptions): Promise<CommandResult>;
429
-
430
- export { type CleanTree, type CommandResult, DEFAULT_SHUFFLE_ARGS, DEFAULT_SHUFFLE_RUNS, type GraphNode, type LoadSignoffConfigOptions, LoadedSignoffConfig, MANIFEST_FILES, type MaterializeOptions, type NodeVersionRequirement, type ResolveStoreOptions, type ResolvedWorkflowPin, type RunCommandOptions, type RunGraphOptions, SIGNOFF_CONFIG_FILES, SignoffConfig, SignoffRepoFacts, SignoffReport, SignoffSource, SignoffStepResult, SignoffStepSpec, type StepAttemptPlan, type StoreResolution, type TaskOutcome, type TaskStatus, type WorkflowNodePin, assertNodeVersion, assertShuffleArgsReachTheRunner, deriveSeed, deriveSignoffConfig, formatSignoffLine, formatSignoffReport, loadSignoffConfig, manifestCacheKey, manifestFiles, materializeCleanTree, newSeedBase, parseSignoffConfig, peakConcurrency, planAttempts, removeCleanTree, repoRootOf, resolveNodeRequirement, resolveStore, resolveWorkflowNodePin, runCommand, runGraph, scanMergeGateNodePins, triggersOnPullRequest, validateGraph };
14
+ export { type LoadSignoffConfigOptions, LoadedSignoffConfig, SignoffReport, formatSignoffReport, loadSignoffConfig };
@@ -1,63 +1,11 @@
1
1
  import {
2
- DEFAULT_SHUFFLE_ARGS,
3
- DEFAULT_SHUFFLE_RUNS,
4
- MANIFEST_FILES,
5
- SIGNOFF_CONFIG_FILES,
6
- assertNodeVersion,
7
- assertShuffleArgsReachTheRunner,
8
- deriveSeed,
9
- deriveSignoffConfig,
10
- formatSignoffLine,
11
2
  formatSignoffReport,
12
3
  loadSignoffConfig,
13
- manifestCacheKey,
14
- manifestFiles,
15
- materializeCleanTree,
16
- newSeedBase,
17
- parseSignoffConfig,
18
- peakConcurrency,
19
- planAttempts,
20
- removeCleanTree,
21
- repoRootOf,
22
- resolveNodeRequirement,
23
- resolveStore,
24
- resolveWorkflowNodePin,
25
- runCommand,
26
- runGraph,
27
- runSignoff,
28
- scanMergeGateNodePins,
29
- triggersOnPullRequest,
30
- validateGraph
31
- } from "../chunk-WD2B6HGY.js";
4
+ runSignoff
5
+ } from "../chunk-K4RA5T3A.js";
32
6
  export {
33
- DEFAULT_SHUFFLE_ARGS,
34
- DEFAULT_SHUFFLE_RUNS,
35
- MANIFEST_FILES,
36
- SIGNOFF_CONFIG_FILES,
37
- assertNodeVersion,
38
- assertShuffleArgsReachTheRunner,
39
- deriveSeed,
40
- deriveSignoffConfig,
41
- formatSignoffLine,
42
7
  formatSignoffReport,
43
8
  loadSignoffConfig,
44
- manifestCacheKey,
45
- manifestFiles,
46
- materializeCleanTree,
47
- newSeedBase,
48
- parseSignoffConfig,
49
- peakConcurrency,
50
- planAttempts,
51
- removeCleanTree,
52
- repoRootOf,
53
- resolveNodeRequirement,
54
- resolveStore,
55
- resolveWorkflowNodePin,
56
- runCommand,
57
- runGraph,
58
- runSignoff,
59
- scanMergeGateNodePins,
60
- triggersOnPullRequest,
61
- validateGraph
9
+ runSignoff
62
10
  };
63
11
  //# sourceMappingURL=index.js.map
@@ -5,7 +5,10 @@ import {
5
5
  readSignoffKey,
6
6
  verifySignoffAtRev,
7
7
  verifySignoffProofFile
8
- } from "../chunk-N3G3FSM4.js";
8
+ } from "../chunk-YXA3U4JZ.js";
9
+ import {
10
+ invokedAsScript
11
+ } from "../chunk-C3CAYGGQ.js";
9
12
 
10
13
  // src/signoff/proof-cli.ts
11
14
  function parseArgs(argv) {
@@ -82,11 +85,13 @@ ${outcome.hint.map((line) => ` ${line}`).join("\n")}
82
85
  }
83
86
  return report(outcome, options);
84
87
  }
85
- try {
86
- process.exit(main());
87
- } catch (error) {
88
- process.stderr.write(`agent-app-verify-proof failed: ${error instanceof Error ? error.message : String(error)}
88
+ if (invokedAsScript(import.meta.url, process.argv[1])) {
89
+ try {
90
+ process.exit(main());
91
+ } catch (error) {
92
+ process.stderr.write(`agent-app-verify-proof failed: ${error instanceof Error ? error.message : String(error)}
89
93
  `);
90
- process.exit(1);
94
+ process.exit(1);
95
+ }
91
96
  }
92
97
  //# sourceMappingURL=proof-cli.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/signoff/proof-cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-verify-proof` — the command a reader runs to decide whether a\n * commit was signed off, by what, and whether it passed.\n *\n * agent-app-verify-proof <sha|rev> # look the proof up by commit\n * agent-app-verify-proof --file proof.json # check a proof document\n *\n * Exits 0 only when every check passes. Exits 1 on any failure, and on a commit\n * with no proof at all — \"nobody signed this off\" is a rejection, not a pass.\n */\nimport { formatSignoffSummary, readSignoffKey } from './proof-record'\nimport { formatSignoffVerification, verifySignoffAtRev, verifySignoffProofFile, type SignoffVerification } from './proof-verify'\n\ninterface CliOptions {\n readonly rev: string\n readonly file: string | null\n readonly dir: string\n readonly keyPath: string | null\n readonly repo: string | null\n readonly json: boolean\n}\n\nfunction parseArgs(argv: readonly string[]): CliOptions {\n let rev = 'HEAD'\n let file: string | null = null\n let dir = process.cwd()\n let keyPath: string | null = null\n let repo: string | null = null\n let json = false\n let sawRev = false\n\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index] as string\n const next = (): string => {\n const value = argv[index + 1]\n if (value === undefined) throw new Error(`${arg} requires a value`)\n index += 1\n return value\n }\n if (arg === '--file') file = next()\n else if (arg === '--dir') dir = next()\n else if (arg === '--key') keyPath = next()\n else if (arg === '--repo') repo = next()\n else if (arg === '--json') json = true\n else if (arg.startsWith('-')) throw new Error(`unknown flag ${arg}`)\n else {\n if (sawRev) throw new Error(`unexpected second revision ${arg}`)\n rev = arg\n sawRev = true\n }\n }\n return { rev, file, dir, keyPath, repo, json }\n}\n\nfunction report(result: SignoffVerification, options: CliOptions): number {\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify(\n {\n ok: result.ok,\n commitBinding: result.commitBinding,\n macChecked: result.macChecked,\n failures: result.failures,\n requiredSteps: result.requiredSteps,\n summary: formatSignoffSummary(result.proof),\n proof: result.proof,\n },\n null,\n 2,\n )}\\n`,\n )\n } else {\n process.stdout.write(`${formatSignoffVerification(result)}\\n${formatSignoffSummary(result.proof)}\\n`)\n }\n return result.ok ? 0 : 1\n}\n\nfunction main(): number {\n const options = parseArgs(process.argv.slice(2))\n const key = options.keyPath === null ? undefined : readSignoffKey(options.keyPath)\n\n if (options.file !== null) {\n return report(verifySignoffProofFile({ repoDir: options.dir, file: options.file, rev: options.rev, key, expectRepo: options.repo ?? undefined }), options)\n }\n\n const outcome = verifySignoffAtRev({ repoDir: options.dir, rev: options.rev, key, expectRepo: options.repo ?? undefined })\n if (!outcome.found) {\n process.stdout.write(\n `NO PROOF ${outcome.commit}\\n nothing is attached under refs/notes/signoff, and no proof covers this commit's tree\\n if notes exist upstream, this repo may not fetch them:\\n${outcome.hint.map((line) => ` ${line}`).join('\\n')}\\n`,\n )\n return 1\n }\n return report(outcome, options)\n}\n\ntry {\n process.exit(main())\n} catch (error) {\n process.stderr.write(`agent-app-verify-proof failed: ${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n}\n"],"mappings":";;;;;;;;;;AAuBA,SAAS,UAAU,MAAqC;AACtD,MAAI,MAAM;AACV,MAAI,OAAsB;AAC1B,MAAI,MAAM,QAAQ,IAAI;AACtB,MAAI,UAAyB;AAC7B,MAAI,OAAsB;AAC1B,MAAI,OAAO;AACX,MAAI,SAAS;AAEb,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AACtB,UAAM,OAAO,MAAc;AACzB,YAAM,QAAQ,KAAK,QAAQ,CAAC;AAC5B,UAAI,UAAU,OAAW,OAAM,IAAI,MAAM,GAAG,GAAG,mBAAmB;AAClE,eAAS;AACT,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,SAAU,QAAO,KAAK;AAAA,aACzB,QAAQ,QAAS,OAAM,KAAK;AAAA,aAC5B,QAAQ,QAAS,WAAU,KAAK;AAAA,aAChC,QAAQ,SAAU,QAAO,KAAK;AAAA,aAC9B,QAAQ,SAAU,QAAO;AAAA,aACzB,IAAI,WAAW,GAAG,EAAG,OAAM,IAAI,MAAM,gBAAgB,GAAG,EAAE;AAAA,SAC9D;AACH,UAAI,OAAQ,OAAM,IAAI,MAAM,8BAA8B,GAAG,EAAE;AAC/D,YAAM;AACN,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO,EAAE,KAAK,MAAM,KAAK,SAAS,MAAM,KAAK;AAC/C;AAEA,SAAS,OAAO,QAA6B,SAA6B;AACxE,MAAI,QAAQ,MAAM;AAChB,YAAQ,OAAO;AAAA,MACb,GAAG,KAAK;AAAA,QACN;AAAA,UACE,IAAI,OAAO;AAAA,UACX,eAAe,OAAO;AAAA,UACtB,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB,eAAe,OAAO;AAAA,UACtB,SAAS,qBAAqB,OAAO,KAAK;AAAA,UAC1C,OAAO,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA;AAAA,IACH;AAAA,EACF,OAAO;AACL,YAAQ,OAAO,MAAM,GAAG,0BAA0B,MAAM,CAAC;AAAA,EAAK,qBAAqB,OAAO,KAAK,CAAC;AAAA,CAAI;AAAA,EACtG;AACA,SAAO,OAAO,KAAK,IAAI;AACzB;AAEA,SAAS,OAAe;AACtB,QAAM,UAAU,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAC/C,QAAM,MAAM,QAAQ,YAAY,OAAO,SAAY,eAAe,QAAQ,OAAO;AAEjF,MAAI,QAAQ,SAAS,MAAM;AACzB,WAAO,OAAO,uBAAuB,EAAE,SAAS,QAAQ,KAAK,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,KAAK,YAAY,QAAQ,QAAQ,OAAU,CAAC,GAAG,OAAO;AAAA,EAC3J;AAEA,QAAM,UAAU,mBAAmB,EAAE,SAAS,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,YAAY,QAAQ,QAAQ,OAAU,CAAC;AACzH,MAAI,CAAC,QAAQ,OAAO;AAClB,YAAQ,OAAO;AAAA,MACb,YAAY,QAAQ,MAAM;AAAA;AAAA;AAAA,EAAuJ,QAAQ,KAAK,IAAI,CAAC,SAAS,OAAO,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,IACvO;AACA,WAAO;AAAA,EACT;AACA,SAAO,OAAO,SAAS,OAAO;AAChC;AAEA,IAAI;AACF,UAAQ,KAAK,KAAK,CAAC;AACrB,SAAS,OAAO;AACd,UAAQ,OAAO,MAAM,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACjH,UAAQ,KAAK,CAAC;AAChB;","names":[]}
1
+ {"version":3,"sources":["../../src/signoff/proof-cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-verify-proof` — the command a reader runs to decide whether a\n * commit was signed off, by what, and whether it passed.\n *\n * agent-app-verify-proof <sha|rev> # look the proof up by commit\n * agent-app-verify-proof --file proof.json # check a proof document\n *\n * Exits 0 only when every check passes. Exits 1 on any failure, and on a commit\n * with no proof at all — \"nobody signed this off\" is a rejection, not a pass.\n */\nimport { invokedAsScript } from './invoked-as-script'\nimport { formatSignoffSummary, readSignoffKey } from './proof-record'\nimport { formatSignoffVerification, verifySignoffAtRev, verifySignoffProofFile, type SignoffVerification } from './proof-verify'\n\ninterface CliOptions {\n readonly rev: string\n readonly file: string | null\n readonly dir: string\n readonly keyPath: string | null\n readonly repo: string | null\n readonly json: boolean\n}\n\nfunction parseArgs(argv: readonly string[]): CliOptions {\n let rev = 'HEAD'\n let file: string | null = null\n let dir = process.cwd()\n let keyPath: string | null = null\n let repo: string | null = null\n let json = false\n let sawRev = false\n\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index] as string\n const next = (): string => {\n const value = argv[index + 1]\n if (value === undefined) throw new Error(`${arg} requires a value`)\n index += 1\n return value\n }\n if (arg === '--file') file = next()\n else if (arg === '--dir') dir = next()\n else if (arg === '--key') keyPath = next()\n else if (arg === '--repo') repo = next()\n else if (arg === '--json') json = true\n else if (arg.startsWith('-')) throw new Error(`unknown flag ${arg}`)\n else {\n if (sawRev) throw new Error(`unexpected second revision ${arg}`)\n rev = arg\n sawRev = true\n }\n }\n return { rev, file, dir, keyPath, repo, json }\n}\n\nfunction report(result: SignoffVerification, options: CliOptions): number {\n if (options.json) {\n process.stdout.write(\n `${JSON.stringify(\n {\n ok: result.ok,\n commitBinding: result.commitBinding,\n macChecked: result.macChecked,\n failures: result.failures,\n requiredSteps: result.requiredSteps,\n summary: formatSignoffSummary(result.proof),\n proof: result.proof,\n },\n null,\n 2,\n )}\\n`,\n )\n } else {\n process.stdout.write(`${formatSignoffVerification(result)}\\n${formatSignoffSummary(result.proof)}\\n`)\n }\n return result.ok ? 0 : 1\n}\n\nfunction main(): number {\n const options = parseArgs(process.argv.slice(2))\n const key = options.keyPath === null ? undefined : readSignoffKey(options.keyPath)\n\n if (options.file !== null) {\n return report(verifySignoffProofFile({ repoDir: options.dir, file: options.file, rev: options.rev, key, expectRepo: options.repo ?? undefined }), options)\n }\n\n const outcome = verifySignoffAtRev({ repoDir: options.dir, rev: options.rev, key, expectRepo: options.repo ?? undefined })\n if (!outcome.found) {\n process.stdout.write(\n `NO PROOF ${outcome.commit}\\n nothing is attached under refs/notes/signoff, and no proof covers this commit's tree\\n if notes exist upstream, this repo may not fetch them:\\n${outcome.hint.map((line) => ` ${line}`).join('\\n')}\\n`,\n )\n return 1\n }\n return report(outcome, options)\n}\n\n/* c8 ignore start — process wiring, exercised by the bin itself */\nif (invokedAsScript(import.meta.url, process.argv[1])) {\n try {\n process.exit(main())\n } catch (error) {\n process.stderr.write(`agent-app-verify-proof failed: ${error instanceof Error ? error.message : String(error)}\\n`)\n process.exit(1)\n }\n}\n/* c8 ignore stop */\n"],"mappings":";;;;;;;;;;;;;AAwBA,SAAS,UAAU,MAAqC;AACtD,MAAI,MAAM;AACV,MAAI,OAAsB;AAC1B,MAAI,MAAM,QAAQ,IAAI;AACtB,MAAI,UAAyB;AAC7B,MAAI,OAAsB;AAC1B,MAAI,OAAO;AACX,MAAI,SAAS;AAEb,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACnD,UAAM,MAAM,KAAK,KAAK;AACtB,UAAM,OAAO,MAAc;AACzB,YAAM,QAAQ,KAAK,QAAQ,CAAC;AAC5B,UAAI,UAAU,OAAW,OAAM,IAAI,MAAM,GAAG,GAAG,mBAAmB;AAClE,eAAS;AACT,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,SAAU,QAAO,KAAK;AAAA,aACzB,QAAQ,QAAS,OAAM,KAAK;AAAA,aAC5B,QAAQ,QAAS,WAAU,KAAK;AAAA,aAChC,QAAQ,SAAU,QAAO,KAAK;AAAA,aAC9B,QAAQ,SAAU,QAAO;AAAA,aACzB,IAAI,WAAW,GAAG,EAAG,OAAM,IAAI,MAAM,gBAAgB,GAAG,EAAE;AAAA,SAC9D;AACH,UAAI,OAAQ,OAAM,IAAI,MAAM,8BAA8B,GAAG,EAAE;AAC/D,YAAM;AACN,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO,EAAE,KAAK,MAAM,KAAK,SAAS,MAAM,KAAK;AAC/C;AAEA,SAAS,OAAO,QAA6B,SAA6B;AACxE,MAAI,QAAQ,MAAM;AAChB,YAAQ,OAAO;AAAA,MACb,GAAG,KAAK;AAAA,QACN;AAAA,UACE,IAAI,OAAO;AAAA,UACX,eAAe,OAAO;AAAA,UACtB,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB,eAAe,OAAO;AAAA,UACtB,SAAS,qBAAqB,OAAO,KAAK;AAAA,UAC1C,OAAO,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA;AAAA,IACH;AAAA,EACF,OAAO;AACL,YAAQ,OAAO,MAAM,GAAG,0BAA0B,MAAM,CAAC;AAAA,EAAK,qBAAqB,OAAO,KAAK,CAAC;AAAA,CAAI;AAAA,EACtG;AACA,SAAO,OAAO,KAAK,IAAI;AACzB;AAEA,SAAS,OAAe;AACtB,QAAM,UAAU,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAC/C,QAAM,MAAM,QAAQ,YAAY,OAAO,SAAY,eAAe,QAAQ,OAAO;AAEjF,MAAI,QAAQ,SAAS,MAAM;AACzB,WAAO,OAAO,uBAAuB,EAAE,SAAS,QAAQ,KAAK,MAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,KAAK,YAAY,QAAQ,QAAQ,OAAU,CAAC,GAAG,OAAO;AAAA,EAC3J;AAEA,QAAM,UAAU,mBAAmB,EAAE,SAAS,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,YAAY,QAAQ,QAAQ,OAAU,CAAC;AACzH,MAAI,CAAC,QAAQ,OAAO;AAClB,YAAQ,OAAO;AAAA,MACb,YAAY,QAAQ,MAAM;AAAA;AAAA;AAAA,EAAuJ,QAAQ,KAAK,IAAI,CAAC,SAAS,OAAO,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,IACvO;AACA,WAAO;AAAA,EACT;AACA,SAAO,OAAO,SAAS,OAAO;AAChC;AAGA,IAAI,gBAAgB,YAAY,KAAK,QAAQ,KAAK,CAAC,CAAC,GAAG;AACrD,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AAAA,EACrB,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACjH,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}