@tangle-network/agent-app 0.60.215 → 0.60.217

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 (42) hide show
  1. package/dist/chat-routes/index.js +1 -1
  2. package/dist/{chunk-QA2CBATZ.js → chunk-4QUOPWIG.js} +12 -9
  3. package/dist/chunk-4QUOPWIG.js.map +1 -0
  4. package/dist/chunk-CD2LQXY6.js +306 -0
  5. package/dist/chunk-CD2LQXY6.js.map +1 -0
  6. package/dist/chunk-LRYY3OX7.js +105 -0
  7. package/dist/chunk-LRYY3OX7.js.map +1 -0
  8. package/dist/{chunk-LLO436QO.js → chunk-QM7RTTDY.js} +27 -86
  9. package/dist/chunk-QM7RTTDY.js.map +1 -0
  10. package/dist/{chunk-KDPTXXOQ.js → chunk-WDY47GBR.js} +812 -115
  11. package/dist/chunk-WDY47GBR.js.map +1 -0
  12. package/dist/{chunk-ZRLKB4KB.js → chunk-YWLZOPDS.js} +10 -11
  13. package/dist/{chunk-ZRLKB4KB.js.map → chunk-YWLZOPDS.js.map} +1 -1
  14. package/dist/launch-invariants/catalog.d.ts +16 -0
  15. package/dist/launch-invariants/cli.js +5 -2
  16. package/dist/launch-invariants/cli.js.map +1 -1
  17. package/dist/launch-invariants/index.d.ts +1 -1
  18. package/dist/launch-invariants/index.js +13 -5
  19. package/dist/launch-invariants/index.js.map +1 -1
  20. package/dist/launch-invariants/limit-alarms.d.ts +19 -1
  21. package/dist/launch-invariants/testing.d.ts +0 -3
  22. package/dist/launch-invariants/testing.js +5 -2
  23. package/dist/sandbox/index.d.ts +3 -3
  24. package/dist/sandbox/index.js +1 -1
  25. package/dist/signoff/app-defaults.d.ts +65 -0
  26. package/dist/signoff/cache.d.ts +29 -0
  27. package/dist/signoff/cli.js +75 -4
  28. package/dist/signoff/cli.js.map +1 -1
  29. package/dist/signoff/defaults-cli.d.ts +1 -0
  30. package/dist/signoff/index.js +2 -1
  31. package/dist/signoff/store.d.ts +2 -0
  32. package/dist/signoff/types.d.ts +12 -0
  33. package/dist/signoff/worker-defaults.d.ts +8 -0
  34. package/dist/turn-health/index.js +12 -291
  35. package/dist/turn-health/index.js.map +1 -1
  36. package/dist/turn-trace/index.js +20 -3
  37. package/dist/turn-trace/index.js.map +1 -1
  38. package/dist/turn-trace/otel.d.ts +11 -4
  39. package/package.json +5 -2
  40. package/dist/chunk-KDPTXXOQ.js.map +0 -1
  41. package/dist/chunk-LLO436QO.js.map +0 -1
  42. package/dist/chunk-QA2CBATZ.js.map +0 -1
@@ -127,7 +127,7 @@ export interface LivenessProbeConfig {
127
127
  execTimeoutMs?: number;
128
128
  /**
129
129
  * Reuse a successful liveness result for this many milliseconds for the
130
- * same box id and start time. Defaults to 10 minutes; set to 0 to probe on
130
+ * same box id and identity (start time and filesystem incarnation). Defaults to 10 minutes; set to 0 to probe on
131
131
  * every reuse.
132
132
  *
133
133
  * Only the exec probe is cached. Runtime readiness, deferred-file
@@ -180,7 +180,7 @@ export interface SandboxRuntimeConfig {
180
180
  * A resume receives only the keys the platform names as required to rebuild a runtime.
181
181
  * Throw when required credentials cannot be minted; renewal failure preserves
182
182
  * the sandbox and prevents dispatch. Requires the matching Sandbox runtime.
183
- * Values equal to the last ones delivered to the same start of the box, within
183
+ * Values equal to the last ones delivered to the same box identity, within
184
184
  * 10 minutes, are resolved again but not sent again.
185
185
  */
186
186
  runtimeEnv?: (scope: SandboxScope) => Promise<Record<string, string>>;
@@ -202,7 +202,7 @@ export interface SandboxRuntimeConfig {
202
202
  * created. A reused or resumed sandbox is returned only when its explicit
203
203
  * policy already matches; existing mismatches are rejected without updating
204
204
  * or deleting the sandbox unless migration is explicitly enabled below.
205
- * A match read within 10 minutes stands for the same start of the box, except
205
+ * A match read within 10 minutes stands for the same box identity, except
206
206
  * that a `strict` or `blocked` policy is read again whenever a reuse would send
207
207
  * the box credentials (a changed {@link runtimeEnv}, or a {@link bootstrap}).
208
208
  */
@@ -100,7 +100,7 @@ import {
100
100
  warmBinOf,
101
101
  warmWeekdayOf,
102
102
  writeProfileFilesToBox
103
- } from "../chunk-QA2CBATZ.js";
103
+ } from "../chunk-4QUOPWIG.js";
104
104
  import {
105
105
  EGRESS_PROXY_RECOVERY_PHASE,
106
106
  EGRESS_PROXY_RECOVERY_REQUIRED,
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The defaults an agent app inherits from agent-app, and whether this app has them.
3
+ *
4
+ * Each proven improvement ships as a default inside agent-app, so an app gets it by construction. This report reads
5
+ * an app's checkout and says which defaults it has, which it turned off, and which it replaced with a local copy.
6
+ * It is a report: it fails only on an explicit opt-out that gives no reason, so a gap stays visible without
7
+ * blocking a merge, and an exemption is a line in the app's `signoff.config.mjs` with the reason beside it.
8
+ *
9
+ * The rows are the outcomes Drew named on 2026-10-19: the turn trace on every turn with `first_text_ms`, the shared
10
+ * prewarm route, Worker placement beside the D1 primary, limit alarms wired in the server entry, and the Worker
11
+ * upload size against Cloudflare's limit. A row is read from the source, the Wrangler config and the lockfile; it
12
+ * never runs the app.
13
+ */
14
+ /** The name the built-in step reports under; a repo cannot declare a step with it. */
15
+ export declare const APP_DEFAULTS_STEP = "agent-app defaults";
16
+ /** Defaults an app may turn off with a reason. */
17
+ export declare const EXEMPTIBLE_DEFAULTS: readonly ['turn-trace', 'first-text', 'prewarm', 'placement', 'limit-alarms'];
18
+ type ExemptibleDefault = (typeof EXEMPTIBLE_DEFAULTS)[number];
19
+ /** An app's declared opt-outs: the default and why. An empty reason is a configuration error. */
20
+ export type AppDefaultsExemptions = Readonly<Partial<Record<ExemptibleDefault, string>>>;
21
+ type DefaultStatus = 'ok' | 'gap' | 'unknown' | 'exempt' | 'opted-out' | 'na';
22
+ interface DefaultRow {
23
+ readonly id: 'pin' | 'turn-trace' | 'first-text' | 'prewarm' | 'placement' | 'tool-count' | 'limit-alarms' | 'worker-bundle';
24
+ readonly label: string;
25
+ readonly status: DefaultStatus;
26
+ readonly detail: string;
27
+ }
28
+ interface AppDefaultsReport {
29
+ /** The package name. */
30
+ readonly app: string;
31
+ /** The package directory relative to the repo root. */
32
+ readonly dir: string;
33
+ /** The `@tangle-network/agent-app` version the package pins, or null when it is not a plain version. */
34
+ readonly pin: string | null;
35
+ readonly rows: readonly DefaultRow[];
36
+ /** Opt-outs that give no reason. These alone fail the step. */
37
+ readonly findings: readonly string[];
38
+ }
39
+ export interface AppDefaultsResult {
40
+ readonly apps: readonly AppDefaultsReport[];
41
+ readonly findings: readonly string[];
42
+ }
43
+ export interface AppDefaultsOptions {
44
+ /** Declared opt-outs per package name. Applied to every app when keyed by `*`. */
45
+ readonly exemptions?: AppDefaultsExemptions;
46
+ /** Measure the Worker upload with the app's own Wrangler (default true). Needs a built app. */
47
+ readonly measureBundle?: boolean;
48
+ /** The last turn trace Intelligence accepted per Intelligence project; see {@link readLastTurnExport}. */
49
+ readonly exports?: ReadonlyMap<string, LastTurnExport | null>;
50
+ }
51
+ /** The newest `agent_app.turn` root span Intelligence holds for a project. */
52
+ interface LastTurnExport {
53
+ readonly at: number;
54
+ readonly traceId: string;
55
+ readonly firstTextMs?: number;
56
+ }
57
+ /** Report each agent app in the checkout against the defaults. Reads only tracked files; measures the Worker upload with the app's own Wrangler. */
58
+ export declare function checkAppDefaults(repoRoot: string, options?: AppDefaultsOptions): AppDefaultsResult;
59
+ export declare function formatAppDefaults(result: AppDefaultsResult): string;
60
+ /**
61
+ * The newest turn Intelligence holds for each project the apps' sinks name, read with one platform key. A project the
62
+ * key's tenant does not own, or one the ingest has never accepted, reads as null; a failed request leaves it out.
63
+ */
64
+ export declare function collectLastExports(repoRoot: string, apiKey: string): Promise<Map<string, LastTurnExport | null>>;
65
+ export {};
@@ -0,0 +1,29 @@
1
+ /** Defaults owned by signoff; callers can override only when explicitly testing. */
2
+ export declare const SIGNOFF_CACHE_MAX_AGE_MS: number;
3
+ export declare const SIGNOFF_CACHE_MAX_BYTES: number;
4
+ export interface CachePruneResult {
5
+ readonly beforeBytes: number;
6
+ readonly afterBytes: number;
7
+ readonly removed: readonly string[];
8
+ /** Active or explicitly kept entries can temporarily hold the cache above its idle cap. */
9
+ readonly overBudgetBytes: number;
10
+ }
11
+ export interface CachePruneOptions {
12
+ readonly nowMs?: number;
13
+ readonly maxAgeMs?: number;
14
+ readonly maxBytes?: number;
15
+ readonly keepPaths?: readonly string[];
16
+ }
17
+ /** One short cross-process lock protects lease transitions and deletion decisions. */
18
+ export declare function withCacheLock<T>(cacheDir: string, action: () => T | Promise<T>): Promise<T>;
19
+ export interface SignoffCacheSession {
20
+ readonly cacheDir: string;
21
+ protectStore(cacheKey: string): Promise<void>;
22
+ close(): Promise<void>;
23
+ }
24
+ /** Register before creating the tree, so a concurrent prune cannot select it. */
25
+ export declare function openSignoffCacheSession(cacheDir: string, tree: string): Promise<SignoffCacheSession>;
26
+ /** Active store keys for resolveStore's existing generation cap. Hold the lock. */
27
+ export declare function activeStoreKeys(cacheDir: string): Set<string>;
28
+ /** Bound idle trees and stores by age first, then allocated physical bytes. */
29
+ export declare function pruneSignoffCache(cacheDir: string, options?: CachePruneOptions): Promise<CachePruneResult>;
@@ -1,19 +1,84 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ checkAppDefaults,
4
+ collectLastExports,
5
+ formatAppDefaults,
3
6
  formatSignoffLine,
4
7
  formatSignoffReport,
8
+ loadSignoffConfig,
5
9
  runShellAlignmentCli,
6
10
  runSignoff,
7
11
  runSurfaceLadderCli,
8
12
  runWorkspaceSurfaceCli
9
- } from "../chunk-KDPTXXOQ.js";
13
+ } from "../chunk-WDY47GBR.js";
14
+ import "../chunk-LRYY3OX7.js";
10
15
  import {
11
16
  invokedAsScript
12
17
  } from "../chunk-C3CAYGGQ.js";
13
18
 
14
19
  // src/signoff/cli.ts
20
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
21
+ import { dirname as dirname2, resolve as resolve2 } from "path";
22
+
23
+ // src/signoff/defaults-cli.ts
15
24
  import { mkdirSync, writeFileSync } from "fs";
16
25
  import { dirname, resolve } from "path";
26
+ function defaultsUsage() {
27
+ return [
28
+ "Usage: agent-app-signoff defaults [repoDir] [options]",
29
+ "",
30
+ " --probe ask Intelligence for each app's last exported turn (needs TANGLE_INTELLIGENCE_API_KEY)",
31
+ " --no-bundle skip the Worker upload measure (it runs the app's own wrangler, so build first)",
32
+ " --json <path> write the rows"
33
+ ].join("\n");
34
+ }
35
+ async function runDefaultsCli(argv) {
36
+ let repoDir = process.cwd();
37
+ let probe = false;
38
+ let measureBundle = true;
39
+ let jsonPath;
40
+ for (let index = 0; index < argv.length; index += 1) {
41
+ const flag = argv[index];
42
+ if (flag === "--probe") probe = true;
43
+ else if (flag === "--no-bundle") measureBundle = false;
44
+ else if (flag === "--json") {
45
+ jsonPath = argv[index + 1];
46
+ index += 1;
47
+ if (jsonPath === void 0) return usageError("--json needs a path");
48
+ } else if (flag === "-h" || flag === "--help") {
49
+ process.stdout.write(`${defaultsUsage()}
50
+ `);
51
+ return 0;
52
+ } else if (flag.startsWith("-")) return usageError(`unknown option: ${flag}`);
53
+ else repoDir = resolve(flag);
54
+ }
55
+ let exemptions;
56
+ try {
57
+ exemptions = (await loadSignoffConfig({ repoRoot: repoDir })).config.agentApp?.exemptions;
58
+ } catch {
59
+ }
60
+ const apiKey = process.env.TANGLE_INTELLIGENCE_API_KEY?.trim();
61
+ if (probe && !apiKey) return usageError("--probe needs TANGLE_INTELLIGENCE_API_KEY");
62
+ const exports = probe && apiKey ? await collectLastExports(repoDir, apiKey) : void 0;
63
+ const result = checkAppDefaults(repoDir, { exemptions, measureBundle, exports });
64
+ if (jsonPath !== void 0) {
65
+ const abs = resolve(jsonPath);
66
+ mkdirSync(dirname(abs), { recursive: true });
67
+ writeFileSync(abs, `${JSON.stringify(result, null, 2)}
68
+ `);
69
+ }
70
+ process.stdout.write(formatAppDefaults(result));
71
+ return result.findings.length === 0 ? 0 : 1;
72
+ }
73
+ function usageError(message) {
74
+ process.stderr.write(`agent-app-signoff defaults: ${message}
75
+
76
+ ${defaultsUsage()}
77
+ `);
78
+ return 2;
79
+ }
80
+
81
+ // src/signoff/cli.ts
17
82
  function usage() {
18
83
  return [
19
84
  "Usage: agent-app-signoff [repoDir] [options]",
@@ -30,6 +95,7 @@ function usage() {
30
95
  " --quiet verdict only; no per-step progress",
31
96
  "",
32
97
  "Subcommands:",
98
+ " defaults report which agent-app defaults each app has (--help for options)",
33
99
  " shell-alignment measure header dividers against the rail in a browser (--help for options)",
34
100
  " surface-ladder measure card and field steps, field borders and card copy in a browser (--help for options)",
35
101
  " workspace-surface every page sits on one shared panel under an inset shell header (--help for options)"
@@ -108,6 +174,10 @@ function parseArgs(argv) {
108
174
  function progressWriter() {
109
175
  return (event) => {
110
176
  switch (event.kind) {
177
+ case "cache-prune":
178
+ process.stderr.write(`\xB7 cache ${event.beforeBytes} \u2192 ${event.afterBytes} allocated bytes; ${event.removed.length} idle entries removed${event.overBudgetBytes ? `; ${event.overBudgetBytes} bytes held by active or kept trees` : ""}
179
+ `);
180
+ break;
111
181
  case "tree":
112
182
  process.stderr.write(`\xB7 clean tree at ${event.path} (${event.head.slice(0, 12)}${event.dirty ? " + working tree" : ""})
113
183
  `);
@@ -136,15 +206,16 @@ function progressWriter() {
136
206
  };
137
207
  }
138
208
  async function runSignoffCli(argv) {
209
+ if (argv[0] === "defaults") return runDefaultsCli(argv.slice(1));
139
210
  if (argv[0] === "shell-alignment") return runShellAlignmentCli(argv.slice(1));
140
211
  if (argv[0] === "surface-ladder") return runSurfaceLadderCli(argv.slice(1));
141
212
  if (argv[0] === "workspace-surface") return runWorkspaceSurfaceCli(argv.slice(1));
142
213
  const args = parseArgs(argv);
143
214
  const report = await runSignoff({ ...args, onEvent: args.quiet ? void 0 : progressWriter() });
144
215
  if (args.jsonPath !== void 0) {
145
- const abs = resolve(args.jsonPath);
146
- mkdirSync(dirname(abs), { recursive: true });
147
- writeFileSync(abs, `${JSON.stringify(report, null, 2)}
216
+ const abs = resolve2(args.jsonPath);
217
+ mkdirSync2(dirname2(abs), { recursive: true });
218
+ writeFileSync2(abs, `${JSON.stringify(report, null, 2)}
148
219
  `);
149
220
  }
150
221
  process.stdout.write(`${args.quiet ? formatSignoffLine(report) : formatSignoffReport(report)}
@@ -1 +1 @@
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 * agent-app-signoff shell-alignment --base-url <url> --route <path> # header dividers meet the rail\n * agent-app-signoff surface-ladder --base-url <url> --route <path> # cards and fields step off their parent\n * agent-app-signoff workspace-surface --base-url <url> --route <path> # every page on the shared panel\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 { runShellAlignmentCli } from './shell-alignment-cli'\nimport { runSurfaceLadderCli } from './surface-ladder-cli'\nimport { runWorkspaceSurfaceCli } from './workspace-surface-cli'\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 '',\n 'Subcommands:',\n ' shell-alignment measure header dividers against the rail in a browser (--help for options)',\n ' surface-ladder measure card and field steps, field borders and card copy in a browser (--help for options)',\n ' workspace-surface every page sits on one shared panel under an inset shell header (--help for options)',\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 if (argv[0] === 'shell-alignment') return runShellAlignmentCli(argv.slice(1))\n if (argv[0] === 'surface-ladder') return runSurfaceLadderCli(argv.slice(1))\n if (argv[0] === 'workspace-surface') return runWorkspaceSurfaceCli(argv.slice(1))\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
+ {"version":3,"sources":["../../src/signoff/cli.ts","../../src/signoff/defaults-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 * agent-app-signoff defaults [repoDir] # which agent-app defaults each app has\n * agent-app-signoff shell-alignment --base-url <url> --route <path> # header dividers meet the rail\n * agent-app-signoff surface-ladder --base-url <url> --route <path> # cards and fields step off their parent\n * agent-app-signoff workspace-surface --base-url <url> --route <path> # every page on the shared panel\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { runDefaultsCli } from './defaults-cli'\nimport { invokedAsScript } from './invoked-as-script'\nimport { formatSignoffLine, formatSignoffReport } from './report'\nimport { runSignoff, type RunSignoffOptions } from './run'\nimport { runShellAlignmentCli } from './shell-alignment-cli'\nimport { runSurfaceLadderCli } from './surface-ladder-cli'\nimport { runWorkspaceSurfaceCli } from './workspace-surface-cli'\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 '',\n 'Subcommands:',\n ' defaults report which agent-app defaults each app has (--help for options)',\n ' shell-alignment measure header dividers against the rail in a browser (--help for options)',\n ' surface-ladder measure card and field steps, field borders and card copy in a browser (--help for options)',\n ' workspace-surface every page sits on one shared panel under an inset shell header (--help for options)',\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 'cache-prune':\n process.stderr.write(`· cache ${event.beforeBytes} → ${event.afterBytes} allocated bytes; ` +\n `${event.removed.length} idle entries removed${event.overBudgetBytes ? `; ${event.overBudgetBytes} bytes held by active or kept trees` : ''}\\n`)\n break\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 if (argv[0] === 'defaults') return runDefaultsCli(argv.slice(1))\n if (argv[0] === 'shell-alignment') return runShellAlignmentCli(argv.slice(1))\n if (argv[0] === 'surface-ladder') return runSurfaceLadderCli(argv.slice(1))\n if (argv[0] === 'workspace-surface') return runWorkspaceSurfaceCli(argv.slice(1))\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","/**\n * `agent-app-signoff defaults` — report which agent-app defaults each app in a checkout has.\n *\n * agent-app-signoff defaults [repoDir] # the matrix for the apps in repoDir\n * agent-app-signoff defaults --probe # also ask Intelligence for each app's last exported turn\n * agent-app-signoff defaults --json matrix.json # the same rows, machine-readable\n *\n * Exit 0 unless an app turns a default off without a reason (1), or the usage is wrong (2). `--probe` reads the\n * Intelligence key from `TANGLE_INTELLIGENCE_API_KEY`; it reads the traces of the tenant that owns the apps' export keys.\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { checkAppDefaults, collectLastExports, formatAppDefaults } from './app-defaults'\nimport { loadSignoffConfig } from './config'\n\nfunction defaultsUsage(): string {\n return [\n 'Usage: agent-app-signoff defaults [repoDir] [options]',\n '',\n ' --probe ask Intelligence for each app\\'s last exported turn (needs TANGLE_INTELLIGENCE_API_KEY)',\n ' --no-bundle skip the Worker upload measure (it runs the app\\'s own wrangler, so build first)',\n ' --json <path> write the rows',\n ].join('\\n')\n}\n\nexport async function runDefaultsCli(argv: readonly string[]): Promise<number> {\n let repoDir = process.cwd()\n let probe = false\n let measureBundle = true\n let jsonPath: string | undefined\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] as string\n if (flag === '--probe') probe = true\n else if (flag === '--no-bundle') measureBundle = false\n else if (flag === '--json') {\n jsonPath = argv[index + 1]\n index += 1\n if (jsonPath === undefined) return usageError('--json needs a path')\n } else if (flag === '-h' || flag === '--help') {\n process.stdout.write(`${defaultsUsage()}\\n`)\n return 0\n } else if (flag.startsWith('-')) return usageError(`unknown option: ${flag}`)\n else repoDir = resolve(flag)\n }\n let exemptions\n try {\n exemptions = (await loadSignoffConfig({ repoRoot: repoDir })).config.agentApp?.exemptions\n } catch {\n // A checkout with no signoff config, or one that does not load here, declares no exemptions.\n }\n const apiKey = process.env.TANGLE_INTELLIGENCE_API_KEY?.trim()\n if (probe && !apiKey) return usageError('--probe needs TANGLE_INTELLIGENCE_API_KEY')\n const exports = probe && apiKey ? await collectLastExports(repoDir, apiKey) : undefined\n const result = checkAppDefaults(repoDir, { exemptions, measureBundle, exports })\n if (jsonPath !== undefined) {\n const abs = resolve(jsonPath)\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, `${JSON.stringify(result, null, 2)}\\n`)\n }\n process.stdout.write(formatAppDefaults(result))\n return result.findings.length === 0 ? 0 : 1\n}\n\nfunction usageError(message: string): number {\n process.stderr.write(`agent-app-signoff defaults: ${message}\\n\\n${defaultsUsage()}\\n`)\n return 2\n}\n"],"mappings":"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","names":["mkdirSync","writeFileSync","dirname","resolve","resolve","mkdirSync","dirname","writeFileSync"]}
@@ -0,0 +1 @@
1
+ export declare function runDefaultsCli(argv: readonly string[]): Promise<number>;
@@ -41,7 +41,8 @@ import {
41
41
  runWorkspaceSurfaceCli,
42
42
  summarizeSurfacePage,
43
43
  surfaceDeltaL
44
- } from "../chunk-KDPTXXOQ.js";
44
+ } from "../chunk-WDY47GBR.js";
45
+ import "../chunk-LRYY3OX7.js";
45
46
  export {
46
47
  HEADER_TOP_TOLERANCE_PX,
47
48
  NETWORK_OVER_BUDGET_EXIT,
@@ -14,6 +14,8 @@ export interface ResolveStoreOptions {
14
14
  readonly cacheDir: string;
15
15
  /** Generations to keep. Default 4. */
16
16
  readonly generations?: number;
17
+ /** Keys held by other active signoff runs; they cannot be evicted. */
18
+ readonly protectedStoreKeys?: ReadonlySet<string>;
17
19
  }
18
20
  /** Every manifest in the tree, repo-relative and sorted. */
19
21
  export declare function manifestFiles(treePath: string): string[];
@@ -10,6 +10,7 @@
10
10
  * install filter, step list, language (one has a Python step) and repo-specific
11
11
  * gates.
12
12
  */
13
+ import type { AppDefaultsExemptions } from './app-defaults';
13
14
  /** Which bytes get verified. */
14
15
  export type SignoffSource =
15
16
  /** Exactly the commit that would merge. Uncommitted work is NOT included. */
@@ -99,6 +100,11 @@ export interface SignoffConfig {
99
100
  * every tracked `wrangler.{toml,json,jsonc}`. Each is checked against the
100
101
  * agent-app Worker defaults (`worker-defaults.ts`). */
101
102
  readonly workerConfigs?: readonly string[];
103
+ /** What this app declares about the agent-app defaults (`app-defaults.ts`). */
104
+ readonly agentApp?: {
105
+ /** Defaults the app turns off, each with the reason. An empty reason is a configuration error. */
106
+ readonly exemptions?: AppDefaultsExemptions;
107
+ };
102
108
  }
103
109
  /** Where a config came from. Printed in the proof — a run against a derived
104
110
  * default is a weaker claim than one against a declared step list. */
@@ -206,6 +212,12 @@ export interface SignoffReport {
206
212
  }
207
213
  /** Progress, for a CLI that prints as it goes rather than at the end. */
208
214
  export type SignoffEvent = {
215
+ readonly kind: 'cache-prune';
216
+ readonly beforeBytes: number;
217
+ readonly afterBytes: number;
218
+ readonly removed: readonly string[];
219
+ readonly overBudgetBytes: number;
220
+ } | {
209
221
  readonly kind: 'tree';
210
222
  readonly path: string;
211
223
  readonly head: string;
@@ -41,6 +41,14 @@ export interface WorkerDefaultsResult {
41
41
  }[];
42
42
  readonly findings: readonly WorkerDefaultsFinding[];
43
43
  }
44
+ /** Every file the repo tracks, repo-relative. Generated output is gitignored, so this is the complete source list without a hand-kept exclude list. */
45
+ export declare function trackedFiles(repoRoot: string): string[];
46
+ /**
47
+ * Wrangler configs the repo tracks. Generated output (`.wrangler/`, build
48
+ * directories) is gitignored, so `git ls-files` is the complete source list
49
+ * without a hand-kept exclude list.
50
+ */
51
+ export declare function trackedWorkerConfigs(repoRoot: string): string[];
44
52
  /**
45
53
  * Check each Worker config, and every environment it deploys, against the
46
54
  * defaults. `configs` are repo-relative paths; omit them to check every tracked