@tangle-network/agent-app 0.45.24 → 0.45.26

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.
@@ -0,0 +1,233 @@
1
+ /**
2
+ * The vocabulary of a local sign-off run: what a repo declares, and what the
3
+ * run produces as proof.
4
+ *
5
+ * A sign-off gate replaces CI as the merge gate, so it has to reproduce what CI
6
+ * does structurally (a pristine dependency tree) and then do more than CI does
7
+ * (randomized suite order, recorded seeds, a dependency graph run in parallel).
8
+ * Both halves are declared here rather than hardcoded, because the three
9
+ * workflows this must express — agent-app, legal-agent, tax-agent — differ in
10
+ * install filter, step list, language (one has a Python step) and repo-specific
11
+ * gates.
12
+ */
13
+ /** Which bytes get verified. */
14
+ type SignoffSource =
15
+ /** Exactly the commit that would merge. Uncommitted work is NOT included. */
16
+ 'head'
17
+ /** HEAD plus the working tree: tracked modifications applied as a patch and
18
+ * untracked, non-ignored files copied in. What you are about to commit. */
19
+ | 'working-tree';
20
+ /**
21
+ * How a step is re-run under different suite orders.
22
+ *
23
+ * CI runs one arbitrary order. The `node:sqlite` bundling failure that started
24
+ * this was scheduling-dependent: it reproduced in CI's clean install under CI's
25
+ * worker sharding and not in a warm local run, so a single fixed order can miss
26
+ * it in either direction. Every seed used is recorded in the report, which is
27
+ * what makes a shuffled failure reproducible rather than folklore.
28
+ */
29
+ interface SignoffShuffleSpec {
30
+ /** How many times to run the step, each with its own seed. Default 2. */
31
+ readonly runs?: number;
32
+ /** Exact seeds to use. Wins over `runs`; use it to replay a known failure. */
33
+ readonly seeds?: readonly number[];
34
+ /** Arguments appended to the command, with `{seed}` substituted. Defaults to
35
+ * vitest's file-order shuffle; override for another runner. */
36
+ readonly args?: readonly string[];
37
+ }
38
+ /** One verification step — a CI step, declared by the repo. */
39
+ interface SignoffStepSpec {
40
+ /** Unique within the config. Names the failure in the report. */
41
+ readonly name: string;
42
+ /** Shell command, run from `cwd` inside the clean tree. */
43
+ readonly run: string;
44
+ /** Relative to the clean tree root. Defaults to the root. */
45
+ readonly cwd?: string;
46
+ /** Extra environment for this step only. */
47
+ readonly env?: Readonly<Record<string, string>>;
48
+ /** Step names that must pass first. Anything not named here may run in
49
+ * parallel with this step — that is the whole speed lever, so an omitted
50
+ * dependency is a correctness bug, not a tuning knob. */
51
+ readonly needs?: readonly string[];
52
+ /** Kill the step after this long. No default — an unbounded step is the
53
+ * repo's choice to make. */
54
+ readonly timeoutMs?: number;
55
+ /** `true` for the default shuffle spec, or an explicit one. */
56
+ readonly shuffle?: boolean | SignoffShuffleSpec;
57
+ }
58
+ /** The hermetic install that precedes every step. */
59
+ interface SignoffInstallSpec {
60
+ /** Default `pnpm install --frozen-lockfile`. tax-agent needs
61
+ * `--filter web...` because `server/` depends on a sibling repo by `file:`. */
62
+ readonly run?: string;
63
+ /** Flag used to point the package manager at the pristine store. Default
64
+ * `--store-dir`. `null` passes no flag (the env var still applies). */
65
+ readonly storeDirFlag?: string | null;
66
+ /** Env var used for the same. Default `NPM_CONFIG_STORE_DIR`, which is what
67
+ * the tax-agent and legal-agent workflows set. `null` sets none. */
68
+ readonly storeEnv?: string | null;
69
+ /** Relative to the clean tree root. Defaults to the root. */
70
+ readonly cwd?: string;
71
+ readonly timeoutMs?: number;
72
+ /** Extra environment for the install only. */
73
+ readonly env?: Readonly<Record<string, string>>;
74
+ }
75
+ /** What a repo declares in `signoff.config.mjs` or a package.json `signoff` key. */
76
+ interface SignoffConfig {
77
+ readonly install?: SignoffInstallSpec;
78
+ readonly steps: readonly SignoffStepSpec[];
79
+ /** Cap on concurrently running steps. Defaults to the host's parallelism. */
80
+ readonly maxParallel?: number;
81
+ /** Environment applied to every step and the install. */
82
+ readonly env?: Readonly<Record<string, string>>;
83
+ /** Node version the product ships on, e.g. `'22'`. Falls back to `.nvmrc`.
84
+ * A mismatch REFUSES the run — see `node-version.ts`. */
85
+ readonly nodeVersion?: string;
86
+ /** Gitignored files the run genuinely needs (a private-registry `.npmrc`).
87
+ * Explicit and fail-loud: a missing one aborts rather than installing from
88
+ * a different registry than the developer thinks. */
89
+ readonly carryFiles?: readonly string[];
90
+ /** Root for the clean tree and the pristine stores. Default
91
+ * `~/.cache/agent-app-signoff`. Both live under it so they share a
92
+ * filesystem — pnpm hardlinks from the store into `node_modules`, and a
93
+ * cross-device store silently degrades to copying. */
94
+ readonly cacheDir?: string;
95
+ /** Pristine store generations to keep. Default 4, so flipping between a
96
+ * branch and main stays warm on both. */
97
+ readonly storeGenerations?: number;
98
+ }
99
+ /** Where a config came from. Printed in the proof — a run against a derived
100
+ * default is a weaker claim than one against a declared step list. */
101
+ type SignoffConfigOrigin = {
102
+ readonly kind: 'file';
103
+ readonly path: string;
104
+ } | {
105
+ readonly kind: 'package-json';
106
+ readonly path: string;
107
+ } | {
108
+ readonly kind: 'derived';
109
+ readonly path: string;
110
+ readonly scripts: readonly string[];
111
+ };
112
+ interface LoadedSignoffConfig {
113
+ readonly config: SignoffConfig;
114
+ readonly origin: SignoffConfigOrigin;
115
+ }
116
+ /** One execution of a step's command. A shuffled step has several. */
117
+ interface SignoffAttempt {
118
+ readonly command: string;
119
+ /** The suite-order seed, or `null` for an unshuffled step. */
120
+ readonly seed: number | null;
121
+ readonly exitCode: number;
122
+ readonly signal: string | null;
123
+ readonly durationMs: number;
124
+ readonly timedOut: boolean;
125
+ /** Captured stdout+stderr, interleaved. Retained on failure; on success only
126
+ * the tail is kept, so a passing 3,000-test run does not bloat the proof. */
127
+ readonly output: string;
128
+ readonly outputTruncated: boolean;
129
+ }
130
+ type SignoffStepStatus = 'passed' | 'failed'
131
+ /** Never started — an earlier failure stopped the schedule. */
132
+ | 'skipped'
133
+ /** Started, then killed when another step failed under fail-fast. */
134
+ | 'cancelled'
135
+ /** A dependency failed, so this step could not be judged. */
136
+ | 'blocked';
137
+ interface SignoffStepResult {
138
+ readonly name: string;
139
+ readonly status: SignoffStepStatus;
140
+ readonly attempts: readonly SignoffAttempt[];
141
+ readonly durationMs: number;
142
+ /** Milliseconds from schedule start, so the report can show the real overlap
143
+ * rather than asserting a speedup it did not measure. */
144
+ readonly startedAtMs: number | null;
145
+ readonly finishedAtMs: number | null;
146
+ }
147
+ interface SignoffInstallResult {
148
+ readonly command: string;
149
+ readonly storeDir: string;
150
+ readonly cacheKey: string;
151
+ readonly cacheHit: boolean;
152
+ /** The files whose bytes produced `cacheKey`. Named so a surprise cold
153
+ * install is explainable rather than mysterious. */
154
+ readonly keyedOn: readonly string[];
155
+ readonly exitCode: number;
156
+ readonly durationMs: number;
157
+ readonly output: string;
158
+ readonly outputTruncated: boolean;
159
+ }
160
+ interface SignoffRepoFacts {
161
+ readonly root: string;
162
+ readonly head: string;
163
+ readonly branch: string;
164
+ readonly source: SignoffSource;
165
+ readonly dirty: boolean;
166
+ /** sha256 of the applied working-tree patch, `null` when nothing was applied.
167
+ * This is what makes the proof specific to the bytes that were verified. */
168
+ readonly diffSha256: string | null;
169
+ readonly untrackedFiles: readonly string[];
170
+ readonly carriedFiles: readonly string[];
171
+ }
172
+ interface SignoffHostFacts {
173
+ readonly node: string;
174
+ /** The pin the repo declares, and where it came from. `null` when the repo
175
+ * pins nothing — stated in the proof, because an unpinned runtime is a
176
+ * weaker claim than a pinned one. */
177
+ readonly nodePinned: string | null;
178
+ readonly nodePinSource: string | null;
179
+ readonly packageManager: string;
180
+ readonly platform: string;
181
+ readonly arch: string;
182
+ readonly cpus: number;
183
+ }
184
+ interface SignoffReport {
185
+ readonly ok: boolean;
186
+ readonly startedAt: string;
187
+ readonly repo: SignoffRepoFacts;
188
+ readonly configOrigin: SignoffConfigOrigin;
189
+ readonly workspace: string;
190
+ readonly workspaceRetained: boolean;
191
+ readonly host: SignoffHostFacts;
192
+ readonly install: SignoffInstallResult;
193
+ readonly steps: readonly SignoffStepResult[];
194
+ /** Base seed. Passing it back via `--seed` reproduces every step's seeds. */
195
+ readonly seedBase: number;
196
+ readonly wallClockMs: number;
197
+ /** Install + the sum of step durations: what the same work costs in series. */
198
+ readonly serialMs: number;
199
+ readonly keepGoing: boolean;
200
+ /** The exact command that reproduces this run. */
201
+ readonly reproduce: string;
202
+ }
203
+ /** Progress, for a CLI that prints as it goes rather than at the end. */
204
+ type SignoffEvent = {
205
+ readonly kind: 'tree';
206
+ readonly path: string;
207
+ readonly head: string;
208
+ readonly dirty: boolean;
209
+ } | {
210
+ readonly kind: 'store';
211
+ readonly storeDir: string;
212
+ readonly cacheHit: boolean;
213
+ readonly cacheKey: string;
214
+ } | {
215
+ readonly kind: 'install-start';
216
+ readonly command: string;
217
+ } | {
218
+ readonly kind: 'install-end';
219
+ readonly exitCode: number;
220
+ readonly durationMs: number;
221
+ } | {
222
+ readonly kind: 'step-start';
223
+ readonly name: string;
224
+ readonly command: string;
225
+ readonly seed: number | null;
226
+ } | {
227
+ readonly kind: 'step-end';
228
+ readonly name: string;
229
+ readonly status: SignoffStepStatus;
230
+ readonly durationMs: number;
231
+ };
232
+
233
+ export type { LoadedSignoffConfig as L, SignoffSource as S, SignoffEvent as a, SignoffReport as b, SignoffConfig as c, SignoffStepResult as d, SignoffStepSpec as e, SignoffRepoFacts as f, SignoffAttempt as g, SignoffConfigOrigin as h, SignoffHostFacts as i, SignoffInstallResult as j, SignoffInstallSpec as k, SignoffShuffleSpec as l, SignoffStepStatus as m };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.45.24",
3
+ "version": "0.45.26",
4
4
  "packageManager": "pnpm@11.17.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [
@@ -35,10 +35,22 @@
35
35
  "agent-app-theme-check": "./dist/theme-contract/cli.js",
36
36
  "agent-app-legibility-check": "./dist/legibility/cli.js",
37
37
  "agent-app-preflight": "./dist/preflight/cli.js",
38
- "agent-app-peer-check": "./dist/peer-floors/cli.js"
38
+ "agent-app-peer-check": "./dist/peer-floors/cli.js",
39
+ "agent-app-signoff": "./dist/signoff/cli.js",
40
+ "agent-app-verify-proof": "./dist/signoff/proof-cli.js"
39
41
  },
40
42
  "exports": {
41
43
  "./package.json": "./package.json",
44
+ "./signoff": {
45
+ "types": "./dist/signoff/index.d.ts",
46
+ "import": "./dist/signoff/index.js",
47
+ "default": "./dist/signoff/index.js"
48
+ },
49
+ "./signoff/proof": {
50
+ "types": "./dist/signoff/proof.d.ts",
51
+ "import": "./dist/signoff/proof.js",
52
+ "default": "./dist/signoff/proof.js"
53
+ },
42
54
  "./tools": {
43
55
  "types": "./dist/tools/index.d.ts",
44
56
  "import": "./dist/tools/index.js",
@@ -482,7 +494,8 @@
482
494
  "test:watch": "vitest",
483
495
  "typecheck": "tsc --noEmit",
484
496
  "docs:gen": "agent-docs",
485
- "knip": "knip"
497
+ "knip": "knip",
498
+ "signoff": "node dist/signoff/cli.js"
486
499
  },
487
500
  "devDependencies": {
488
501
  "@cloudflare/workers-types": "5.20260722.1",