@tangle-network/agent-app 0.45.27 → 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.
- package/dist/assistant/index.d.ts +1 -0
- package/dist/assistant/index.js +1 -1
- package/dist/chunk-C3CAYGGQ.js +18 -0
- package/dist/chunk-C3CAYGGQ.js.map +1 -0
- package/dist/chunk-EMLGWEHV.js +33 -0
- package/dist/chunk-EMLGWEHV.js.map +1 -0
- package/dist/{chunk-XEA5EG6P.js → chunk-EPZYYWCT.js} +8 -30
- package/dist/chunk-EPZYYWCT.js.map +1 -0
- package/dist/{chunk-WD2B6HGY.js → chunk-K4RA5T3A.js} +11 -32
- package/dist/chunk-K4RA5T3A.js.map +1 -0
- package/dist/{chunk-RT5RKAFX.js → chunk-QGSVF6DZ.js} +8 -18
- package/dist/chunk-QGSVF6DZ.js.map +1 -0
- package/dist/{chunk-ODYE4A7L.js → chunk-WC43OQMR.js} +40 -29
- package/dist/chunk-WC43OQMR.js.map +1 -0
- package/dist/{chunk-N3G3FSM4.js → chunk-YXA3U4JZ.js} +9 -47
- package/dist/chunk-YXA3U4JZ.js.map +1 -0
- package/dist/legibility/cli.js +14 -8
- package/dist/legibility/cli.js.map +1 -1
- package/dist/legibility/index.js +2 -1
- package/dist/peer-floors/cli.js +14 -8
- package/dist/peer-floors/cli.js.map +1 -1
- package/dist/preflight/cli.js +4 -2
- package/dist/preflight/cli.js.map +1 -1
- package/dist/{run-tEsZUhAf.d.ts → run-D80hoLKh.d.ts} +1 -1
- package/dist/signoff/cli.d.ts +2 -2
- package/dist/signoff/cli.js +6 -18
- package/dist/signoff/cli.js.map +1 -1
- package/dist/signoff/index.d.ts +4 -420
- package/dist/signoff/index.js +3 -55
- package/dist/signoff/proof-cli.js +11 -6
- package/dist/signoff/proof-cli.js.map +1 -1
- package/dist/signoff/proof.d.ts +70 -271
- package/dist/signoff/proof.js +3 -73
- package/dist/signoff/proof.js.map +1 -1
- package/dist/theme-contract/cli.js +6 -2
- package/dist/theme-contract/cli.js.map +1 -1
- package/dist/theme-contract/index.js +2 -1
- package/dist/{types-U7Nz-txa.d.ts → types-Bd6uW9vQ.d.ts} +1 -1
- package/dist/web-react/index.d.ts +28 -40
- package/dist/web-react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-N3G3FSM4.js.map +0 -1
- package/dist/chunk-ODYE4A7L.js.map +0 -1
- package/dist/chunk-RT5RKAFX.js.map +0 -1
- package/dist/chunk-WD2B6HGY.js.map +0 -1
- package/dist/chunk-XEA5EG6P.js.map +0 -1
package/dist/signoff/proof.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { b as SignoffReport } from '../types-
|
|
2
|
+
import { b as SignoffReport } from '../types-Bd6uW9vQ.js';
|
|
3
3
|
|
|
4
|
-
/** Bumped when the canonical body shape changes; a verifier refuses versions it does not know. */
|
|
5
|
-
declare const SIGNOFF_PROOF_VERSION = 1;
|
|
6
4
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* A status is carried alongside the exit code because they answer different
|
|
10
|
-
* questions and only one of them is safe on its own: a step that was `skipped`,
|
|
11
|
-
* `cancelled` or `blocked` never produced an exit code at all, and defaulting
|
|
12
|
-
* that to `0` is precisely how a run that did not happen reads as a pass.
|
|
13
|
-
*
|
|
14
|
-
* The `satisfies` and the `Exclude` below pin this list to the runner's own
|
|
15
|
-
* union in BOTH directions, so a status added there fails this file's typecheck
|
|
16
|
-
* instead of quietly arriving as an unmodelled string.
|
|
5
|
+
* Is `ancestor` reachable from `descendant`? A port rather than a direct call so
|
|
6
|
+
* the verifier stays a pure function over facts a caller supplies.
|
|
17
7
|
*/
|
|
18
|
-
|
|
8
|
+
type IsAncestorFn = (ancestor: string, descendant: string) => boolean;
|
|
9
|
+
interface CommitFacts {
|
|
10
|
+
/** 40-hex commit id. */
|
|
11
|
+
readonly commit: string;
|
|
12
|
+
/** 40-hex id of the tree the COMMIT points at. */
|
|
13
|
+
readonly commitTree: string;
|
|
14
|
+
readonly parents: readonly string[];
|
|
15
|
+
/** Committer date, UTC ISO-8601 with a `Z` suffix. */
|
|
16
|
+
readonly committedAt: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
19
|
declare const signoffProofStepSchema: z.ZodObject<{
|
|
20
20
|
id: z.ZodString;
|
|
21
21
|
command: z.ZodString;
|
|
@@ -168,69 +168,71 @@ type SignoffProofSubject = z.infer<typeof signoffProofSubjectSchema>;
|
|
|
168
168
|
type SignoffProofBody = z.infer<typeof signoffProofBodySchema>;
|
|
169
169
|
type SignoffProofSeal = z.infer<typeof signoffProofSealSchema>;
|
|
170
170
|
type SignoffProof = z.infer<typeof signoffProofSchema>;
|
|
171
|
-
type CanonicalValue = string | number | boolean | null | readonly CanonicalValue[] | {
|
|
172
|
-
readonly [key: string]: CanonicalValue;
|
|
173
|
-
};
|
|
174
|
-
/**
|
|
175
|
-
* Deterministic JSON: object keys sorted, array order preserved, no whitespace.
|
|
176
|
-
*
|
|
177
|
-
* The seal is a hash over this string, so two readers must produce byte-identical
|
|
178
|
-
* bytes from the same record. `undefined` throws rather than vanishing — a field
|
|
179
|
-
* that silently disappears is a field the hash stops covering.
|
|
180
|
-
*/
|
|
181
|
-
declare function canonicalJson(value: CanonicalValue): string;
|
|
182
|
-
declare function canonicalizeProofBody(body: SignoffProofBody): string;
|
|
183
|
-
declare function hashProofBody(body: SignoffProofBody): string;
|
|
184
|
-
/** The digest a runner records for a step's combined output. Shared so both halves agree. */
|
|
185
|
-
declare function hashStepOutput(output: string): string;
|
|
186
|
-
declare function signoffKeyId(key: Uint8Array): string;
|
|
187
171
|
/** Read the local sign-off key. Throws when absent — an unreadable key is never a silent downgrade to unsealed. */
|
|
188
172
|
declare function readSignoffKey(path: string): Uint8Array;
|
|
189
|
-
declare function sealProof(body: SignoffProofBody, key?: Uint8Array): SignoffProof;
|
|
190
|
-
/** Constant-time comparison of two hex digests of equal length. */
|
|
191
|
-
declare function macMatches(expected: string, actual: string): boolean;
|
|
192
|
-
interface ToolingFactsInput {
|
|
193
|
-
readonly repoDir: string;
|
|
194
|
-
/** Package names whose resolved on-disk version belongs in the proof. */
|
|
195
|
-
readonly peerNames: readonly string[];
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* The versions that actually resolved on disk — the field CI's clean install
|
|
199
|
-
* makes trustworthy and a warm local `node_modules` does not. A below-floor peer
|
|
200
|
-
* is invisible to typecheck and to a green suite (it fails at the wire call), so
|
|
201
|
-
* the proof records what was really there rather than what the manifest asks for.
|
|
202
|
-
*/
|
|
203
|
-
declare function collectToolingFacts(input: ToolingFactsInput): SignoffProofBody['tooling'];
|
|
204
|
-
/** Resolved version from the consumer's own `node_modules`, or `null` when the package is not there. */
|
|
205
|
-
declare function readInstalledVersion(repoDir: string, packageName: string): string | null;
|
|
206
|
-
/** Every `@tangle-network/*` name the repo declares as a peer or a dependency. */
|
|
207
|
-
declare function tangleDependencyNames(repoDir: string): readonly string[];
|
|
208
|
-
interface BuildSignoffProofInput {
|
|
209
|
-
readonly repoDir: string;
|
|
210
|
-
/** Repo identity the verifier's required-step table is keyed on. */
|
|
211
|
-
readonly repo: string;
|
|
212
|
-
/** Revision the sign-off is for; defaults to `HEAD`. */
|
|
213
|
-
readonly rev?: string;
|
|
214
|
-
readonly steps: readonly SignoffProofStep[];
|
|
215
|
-
/** Measured elapsed time for the run. Required — it is not derivable from the steps. */
|
|
216
|
-
readonly wallClockMs: number;
|
|
217
|
-
/** Step ids this run treated as required. Checked against the verifier's table. */
|
|
218
|
-
readonly declaredRequired: readonly string[];
|
|
219
|
-
readonly seeds: Readonly<Record<string, string | number>>;
|
|
220
|
-
readonly peerNames?: readonly string[];
|
|
221
|
-
readonly key?: Uint8Array;
|
|
222
|
-
readonly now?: Date;
|
|
223
|
-
}
|
|
224
|
-
declare function buildSignoffProof(input: BuildSignoffProofInput): SignoffProof;
|
|
225
173
|
/** Parse an untrusted proof document, failing loud on any shape the verifier cannot reason about. */
|
|
226
174
|
declare function parseSignoffProof(json: string): SignoffProof;
|
|
227
|
-
declare function serializeSignoffProof(proof: SignoffProof): string;
|
|
228
175
|
/**
|
|
229
176
|
* The single line an operator pastes into a PR or a merge commit: how many steps
|
|
230
177
|
* ran, how long it took, the seeds, and the verdict.
|
|
231
178
|
*/
|
|
232
179
|
declare function formatSignoffSummary(proof: SignoffProof): string;
|
|
233
180
|
|
|
181
|
+
/**
|
|
182
|
+
* `verify-proof` — the half a reader runs, on a machine that did not produce
|
|
183
|
+
* the proof, to decide whether a commit was really signed off.
|
|
184
|
+
*
|
|
185
|
+
* The verifier never believes the document. Every claim it can re-derive, it
|
|
186
|
+
* re-derives from git and compares; every claim it cannot re-derive is reported
|
|
187
|
+
* as recorded, not as checked. The one field the proof is deliberately not
|
|
188
|
+
* allowed to own is **which steps were required**: a run that declares its own
|
|
189
|
+
* bar can declare an empty one, so the authoritative table lives here and a
|
|
190
|
+
* proof declaring fewer requirements than its repo's table fails as
|
|
191
|
+
* `lowered-bar`.
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
type SignoffFailureCode = 'unsupported-version' | 'body-tampered' | 'mac-missing' | 'mac-invalid' | 'unknown-repo' | 'repo-mismatch' | 'tree-mismatch' | 'dirty-worktree' | 'commit-unbound' | 'missing-required-step' | 'lowered-bar' | 'duplicate-step' | 'step-failed' | 'verdict-fail' | 'stale-proof';
|
|
195
|
+
interface SignoffFailure {
|
|
196
|
+
readonly code: SignoffFailureCode;
|
|
197
|
+
readonly detail: string;
|
|
198
|
+
}
|
|
199
|
+
/** How the proof attaches to the commit that was asked about. */
|
|
200
|
+
type SignoffCommitBinding =
|
|
201
|
+
/** The proof names this exact commit. */
|
|
202
|
+
'exact'
|
|
203
|
+
/** A different commit id, but byte-identical content — a rebase or a squash of what was verified. */
|
|
204
|
+
| 'tree-equivalent'
|
|
205
|
+
/** Neither. The proof does not describe this commit. */
|
|
206
|
+
| 'none';
|
|
207
|
+
interface SignoffVerification {
|
|
208
|
+
readonly ok: boolean;
|
|
209
|
+
readonly commitBinding: SignoffCommitBinding;
|
|
210
|
+
/** True only when a key was supplied AND the mac over the canonical body matched. */
|
|
211
|
+
readonly macChecked: boolean;
|
|
212
|
+
readonly failures: readonly SignoffFailure[];
|
|
213
|
+
readonly proof: SignoffProof;
|
|
214
|
+
readonly target: CommitFacts;
|
|
215
|
+
readonly requiredSteps: readonly string[];
|
|
216
|
+
}
|
|
217
|
+
interface VerifySignoffProofOptions {
|
|
218
|
+
/** The commit the reader is asking about, read from git — never from the proof. */
|
|
219
|
+
readonly target: CommitFacts;
|
|
220
|
+
/**
|
|
221
|
+
* Reachability in the target's history. Required, because the clock cannot
|
|
222
|
+
* answer staleness on its own: git records committer time to the SECOND, so a
|
|
223
|
+
* proof and the commit it is being replayed onto routinely share a timestamp.
|
|
224
|
+
* Ancestry is exact and clock-free.
|
|
225
|
+
*/
|
|
226
|
+
readonly isAncestor: IsAncestorFn;
|
|
227
|
+
/** Local HMAC key. Omitted, the mac is reported unchecked rather than assumed good. */
|
|
228
|
+
readonly key?: Uint8Array;
|
|
229
|
+
/** Overrides the built-in table. Supplying `[]` is a deliberate no-bar check, and says so. */
|
|
230
|
+
readonly requiredSteps?: readonly string[];
|
|
231
|
+
/** Repo identity the caller expects; a mismatch against the proof is a failure, not a rename. */
|
|
232
|
+
readonly expectRepo?: string;
|
|
233
|
+
}
|
|
234
|
+
declare function verifySignoffProof(proof: SignoffProof, options: VerifySignoffProofOptions): SignoffVerification;
|
|
235
|
+
|
|
234
236
|
/**
|
|
235
237
|
* The join between the runner and the proof: one sign-off run produces one
|
|
236
238
|
* report, and this turns that report into the signed, attachable record.
|
|
@@ -240,14 +242,6 @@ declare function formatSignoffSummary(proof: SignoffProof): string;
|
|
|
240
242
|
* is what stops a second, drifting idea of "which steps ran" from appearing.
|
|
241
243
|
*/
|
|
242
244
|
|
|
243
|
-
/**
|
|
244
|
-
* A step that never executed has no exit code, so it is recorded as one no
|
|
245
|
-
* process can produce. `status` is what a reader and the verifier judge on;
|
|
246
|
-
* this exists so the field is never a plausible-looking `0`.
|
|
247
|
-
*/
|
|
248
|
-
declare const NO_EXIT_CODE = -1;
|
|
249
|
-
/** The `command` of a step that never executed. A skipped step had no command line. */
|
|
250
|
-
declare const NOT_EXECUTED_COMMAND = "(never executed)";
|
|
251
245
|
interface ProofFromReportInput {
|
|
252
246
|
readonly report: SignoffReport;
|
|
253
247
|
/** Repo identity the verifier's required-step table is keyed on. */
|
|
@@ -259,8 +253,6 @@ interface ProofFromReportInput {
|
|
|
259
253
|
readonly key?: Uint8Array;
|
|
260
254
|
readonly now?: Date;
|
|
261
255
|
}
|
|
262
|
-
/** Every seed the run used, keyed so a reader can replay one step rather than the whole run. */
|
|
263
|
-
declare function seedsFromReport(report: SignoffReport): Record<string, string | number>;
|
|
264
256
|
declare function proofFromSignoffReport(input: ProofFromReportInput): SignoffProof;
|
|
265
257
|
|
|
266
258
|
/**
|
|
@@ -305,13 +297,6 @@ declare function proofFromSignoffReport(input: ProofFromReportInput): SignoffPro
|
|
|
305
297
|
* `not-found`, never as a pass.
|
|
306
298
|
*/
|
|
307
299
|
|
|
308
|
-
declare const SIGNOFF_NOTES_REF = "refs/notes/signoff";
|
|
309
|
-
/**
|
|
310
|
-
* The git configuration a repo needs for notes to travel. Emitted by the CLI
|
|
311
|
-
* when a proof cannot be found, because the usual cause is an unconfigured repo
|
|
312
|
-
* rather than an unsigned commit.
|
|
313
|
-
*/
|
|
314
|
-
declare const SIGNOFF_NOTES_GIT_CONFIG: readonly string[];
|
|
315
300
|
interface AttachSignoffProofInput {
|
|
316
301
|
readonly repoDir: string;
|
|
317
302
|
readonly proof: SignoffProof;
|
|
@@ -325,191 +310,5 @@ interface AttachedSignoffProof {
|
|
|
325
310
|
readonly ref: string;
|
|
326
311
|
}
|
|
327
312
|
declare function attachSignoffProof(input: AttachSignoffProofInput): AttachedSignoffProof;
|
|
328
|
-
type SignoffProofLookup = {
|
|
329
|
-
readonly found: true;
|
|
330
|
-
readonly proof: SignoffProof;
|
|
331
|
-
readonly commit: string;
|
|
332
|
-
readonly binding: 'exact' | 'tree-equivalent';
|
|
333
|
-
} | {
|
|
334
|
-
readonly found: false;
|
|
335
|
-
readonly commit: string;
|
|
336
|
-
};
|
|
337
|
-
/** The note attached to exactly this commit, or `found: false`. Never searches. */
|
|
338
|
-
declare function readSignoffProofNote(repoDir: string, rev: string): SignoffProofLookup;
|
|
339
|
-
/** Every proof stored under the notes ref, paired with the commit it annotates. */
|
|
340
|
-
declare function listSignoffProofs(repoDir: string): readonly {
|
|
341
|
-
readonly commit: string;
|
|
342
|
-
readonly proof: SignoffProof;
|
|
343
|
-
}[];
|
|
344
|
-
/**
|
|
345
|
-
* Answer "was this SHA signed off" for any commit, including one produced by a
|
|
346
|
-
* rebase or a squash-merge of the branch that was actually verified.
|
|
347
|
-
*
|
|
348
|
-
* Exact note first. Then the tree scan — a proof whose `commitTree` equals this
|
|
349
|
-
* commit's tree verified byte-identical content, which is the strongest claim
|
|
350
|
-
* available once the SHA has been rewritten. The binding is returned so a caller
|
|
351
|
-
* can tell the two apart; nothing here treats them as the same thing.
|
|
352
|
-
*/
|
|
353
|
-
declare function resolveSignoffProof(repoDir: string, rev: string): SignoffProofLookup;
|
|
354
|
-
|
|
355
|
-
/** A git invocation that exited non-zero, carrying stderr so the caller can act. */
|
|
356
|
-
declare class SignoffGitError extends Error {
|
|
357
|
-
readonly args: readonly string[];
|
|
358
|
-
readonly status: number | null;
|
|
359
|
-
readonly stderr: string;
|
|
360
|
-
constructor(args: readonly string[], status: number | null, stderr: string);
|
|
361
|
-
}
|
|
362
|
-
interface GitResult {
|
|
363
|
-
readonly status: number | null;
|
|
364
|
-
readonly stdout: string;
|
|
365
|
-
readonly stderr: string;
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Run git and hand back the raw result. `GIT_OPTIONAL_LOCKS=0` keeps a read
|
|
369
|
-
* from touching the index while another agent works the same worktree — this
|
|
370
|
-
* repo is shared by concurrent sessions.
|
|
371
|
-
*/
|
|
372
|
-
declare function runGit(repoDir: string, args: readonly string[], options?: {
|
|
373
|
-
readonly input?: string;
|
|
374
|
-
readonly env?: Readonly<Record<string, string>>;
|
|
375
|
-
}): GitResult;
|
|
376
|
-
/** Run git, or throw. Trailing newline is stripped — every caller wants the value, not the line. */
|
|
377
|
-
declare function gitText(repoDir: string, args: readonly string[], options?: {
|
|
378
|
-
readonly input?: string;
|
|
379
|
-
readonly env?: Readonly<Record<string, string>>;
|
|
380
|
-
}): string;
|
|
381
|
-
/**
|
|
382
|
-
* Is `ancestor` reachable from `descendant`? A port rather than a direct call so
|
|
383
|
-
* the verifier stays a pure function over facts a caller supplies.
|
|
384
|
-
*/
|
|
385
|
-
type IsAncestorFn = (ancestor: string, descendant: string) => boolean;
|
|
386
|
-
declare function gitIsAncestor(repoDir: string): IsAncestorFn;
|
|
387
|
-
interface CommitFacts {
|
|
388
|
-
/** 40-hex commit id. */
|
|
389
|
-
readonly commit: string;
|
|
390
|
-
/** 40-hex id of the tree the COMMIT points at. */
|
|
391
|
-
readonly commitTree: string;
|
|
392
|
-
readonly parents: readonly string[];
|
|
393
|
-
/** Committer date, UTC ISO-8601 with a `Z` suffix. */
|
|
394
|
-
readonly committedAt: string;
|
|
395
|
-
}
|
|
396
|
-
/** Resolve a revision to the commit it names, failing loud on an unknown rev. */
|
|
397
|
-
declare function resolveCommit(repoDir: string, rev: string): string;
|
|
398
|
-
declare function readCommitFacts(repoDir: string, rev: string): CommitFacts;
|
|
399
|
-
/**
|
|
400
|
-
* Hash the tree the checks actually ran against, including uncommitted and
|
|
401
|
-
* untracked (non-ignored) files.
|
|
402
|
-
*
|
|
403
|
-
* This is the field that makes drift detectable. A sign-off that ran over an
|
|
404
|
-
* edited worktree produces a tree id no commit carries, so it cannot verify
|
|
405
|
-
* against the commit it claims — which is the intended outcome, not a bug.
|
|
406
|
-
*
|
|
407
|
-
* Written through a throwaway index (`GIT_INDEX_FILE`) so a concurrent agent's
|
|
408
|
-
* staged work in the real index is neither read nor disturbed. `git add -A`
|
|
409
|
-
* honours `.gitignore`, so `node_modules` / `dist` stay out.
|
|
410
|
-
*/
|
|
411
|
-
declare function computeWorktreeTree(repoDir: string): string;
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* `verify-proof` — the half a reader runs, on a machine that did not produce
|
|
415
|
-
* the proof, to decide whether a commit was really signed off.
|
|
416
|
-
*
|
|
417
|
-
* The verifier never believes the document. Every claim it can re-derive, it
|
|
418
|
-
* re-derives from git and compares; every claim it cannot re-derive is reported
|
|
419
|
-
* as recorded, not as checked. The one field the proof is deliberately not
|
|
420
|
-
* allowed to own is **which steps were required**: a run that declares its own
|
|
421
|
-
* bar can declare an empty one, so the authoritative table lives here and a
|
|
422
|
-
* proof declaring fewer requirements than its repo's table fails as
|
|
423
|
-
* `lowered-bar`.
|
|
424
|
-
*/
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* The steps a repo's sign-off MUST cover, transcribed from each repo's CI job.
|
|
428
|
-
* A runner is free to run more; it may never run fewer.
|
|
429
|
-
*
|
|
430
|
-
* agent-app .github/workflows/ci.yml
|
|
431
|
-
* tax-agent .github/workflows/deploy.yml (the `ci` job)
|
|
432
|
-
* legal-agent .github/workflows/deploy.yml (the `ci` job)
|
|
433
|
-
*/
|
|
434
|
-
declare const SIGNOFF_REQUIRED_STEPS: Readonly<Record<string, readonly string[]>>;
|
|
435
|
-
/** Throws for a repo with no table — an unrecognised repo has no bar, and no bar is not a pass. */
|
|
436
|
-
declare function requiredStepsFor(repo: string): readonly string[];
|
|
437
|
-
type SignoffFailureCode = 'unsupported-version' | 'body-tampered' | 'mac-missing' | 'mac-invalid' | 'unknown-repo' | 'repo-mismatch' | 'tree-mismatch' | 'dirty-worktree' | 'commit-unbound' | 'missing-required-step' | 'lowered-bar' | 'duplicate-step' | 'step-failed' | 'verdict-fail' | 'stale-proof';
|
|
438
|
-
interface SignoffFailure {
|
|
439
|
-
readonly code: SignoffFailureCode;
|
|
440
|
-
readonly detail: string;
|
|
441
|
-
}
|
|
442
|
-
/** How the proof attaches to the commit that was asked about. */
|
|
443
|
-
type SignoffCommitBinding =
|
|
444
|
-
/** The proof names this exact commit. */
|
|
445
|
-
'exact'
|
|
446
|
-
/** A different commit id, but byte-identical content — a rebase or a squash of what was verified. */
|
|
447
|
-
| 'tree-equivalent'
|
|
448
|
-
/** Neither. The proof does not describe this commit. */
|
|
449
|
-
| 'none';
|
|
450
|
-
interface SignoffVerification {
|
|
451
|
-
readonly ok: boolean;
|
|
452
|
-
readonly commitBinding: SignoffCommitBinding;
|
|
453
|
-
/** True only when a key was supplied AND the mac over the canonical body matched. */
|
|
454
|
-
readonly macChecked: boolean;
|
|
455
|
-
readonly failures: readonly SignoffFailure[];
|
|
456
|
-
readonly proof: SignoffProof;
|
|
457
|
-
readonly target: CommitFacts;
|
|
458
|
-
readonly requiredSteps: readonly string[];
|
|
459
|
-
}
|
|
460
|
-
interface VerifySignoffProofOptions {
|
|
461
|
-
/** The commit the reader is asking about, read from git — never from the proof. */
|
|
462
|
-
readonly target: CommitFacts;
|
|
463
|
-
/**
|
|
464
|
-
* Reachability in the target's history. Required, because the clock cannot
|
|
465
|
-
* answer staleness on its own: git records committer time to the SECOND, so a
|
|
466
|
-
* proof and the commit it is being replayed onto routinely share a timestamp.
|
|
467
|
-
* Ancestry is exact and clock-free.
|
|
468
|
-
*/
|
|
469
|
-
readonly isAncestor: IsAncestorFn;
|
|
470
|
-
/** Local HMAC key. Omitted, the mac is reported unchecked rather than assumed good. */
|
|
471
|
-
readonly key?: Uint8Array;
|
|
472
|
-
/** Overrides the built-in table. Supplying `[]` is a deliberate no-bar check, and says so. */
|
|
473
|
-
readonly requiredSteps?: readonly string[];
|
|
474
|
-
/** Repo identity the caller expects; a mismatch against the proof is a failure, not a rename. */
|
|
475
|
-
readonly expectRepo?: string;
|
|
476
|
-
}
|
|
477
|
-
declare function verifySignoffProof(proof: SignoffProof, options: VerifySignoffProofOptions): SignoffVerification;
|
|
478
|
-
interface VerifySignoffAtRevInput {
|
|
479
|
-
readonly repoDir: string;
|
|
480
|
-
readonly rev: string;
|
|
481
|
-
readonly key?: Uint8Array;
|
|
482
|
-
readonly requiredSteps?: readonly string[];
|
|
483
|
-
readonly expectRepo?: string;
|
|
484
|
-
}
|
|
485
|
-
type SignoffLookupFailure = {
|
|
486
|
-
readonly found: false;
|
|
487
|
-
readonly commit: string;
|
|
488
|
-
readonly hint: readonly string[];
|
|
489
|
-
};
|
|
490
|
-
type SignoffVerifyOutcome = ({
|
|
491
|
-
readonly found: true;
|
|
492
|
-
} & SignoffVerification) | SignoffLookupFailure;
|
|
493
|
-
/** Verify by revision: find the proof attached to that SHA (or to its content), then check it. */
|
|
494
|
-
declare function verifySignoffAtRev(input: VerifySignoffAtRevInput): SignoffVerifyOutcome;
|
|
495
|
-
interface VerifySignoffFileInput {
|
|
496
|
-
readonly repoDir: string;
|
|
497
|
-
readonly file: string;
|
|
498
|
-
/**
|
|
499
|
-
* The commit to check the file against. REQUIRED, and deliberately not
|
|
500
|
-
* defaulted to the commit the proof names: a proof checked against its own
|
|
501
|
-
* subject can never fail the commit binding, which is a check that reads as
|
|
502
|
-
* strong and cannot catch anything. The reader always states what they are
|
|
503
|
-
* asking about.
|
|
504
|
-
*/
|
|
505
|
-
readonly rev: string;
|
|
506
|
-
readonly key?: Uint8Array;
|
|
507
|
-
readonly requiredSteps?: readonly string[];
|
|
508
|
-
readonly expectRepo?: string;
|
|
509
|
-
}
|
|
510
|
-
/** Verify a proof document on disk. The repo is still required — "matches the tree it claims" is not answerable without it. */
|
|
511
|
-
declare function verifySignoffProofFile(input: VerifySignoffFileInput): SignoffVerification;
|
|
512
|
-
/** One line per failure, prefixed by its code, in the order the checks ran. */
|
|
513
|
-
declare function formatSignoffVerification(result: SignoffVerification): string;
|
|
514
313
|
|
|
515
|
-
export { type AttachSignoffProofInput, type AttachedSignoffProof, type
|
|
314
|
+
export { type AttachSignoffProofInput, type AttachedSignoffProof, type CommitFacts, type IsAncestorFn, type ProofFromReportInput, type SignoffCommitBinding, type SignoffFailure, type SignoffFailureCode, type SignoffProof, type SignoffProofBody, type SignoffProofPeer, type SignoffProofSeal, type SignoffProofStep, type SignoffProofSubject, type SignoffVerification, type VerifySignoffProofOptions, attachSignoffProof, formatSignoffSummary, parseSignoffProof, proofFromSignoffReport, readSignoffKey, verifySignoffProof };
|
package/dist/signoff/proof.js
CHANGED
|
@@ -1,45 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
SIGNOFF_NOTES_GIT_CONFIG,
|
|
3
|
-
SIGNOFF_NOTES_REF,
|
|
4
|
-
SIGNOFF_PROOF_VERSION,
|
|
5
|
-
SIGNOFF_REQUIRED_STEPS,
|
|
6
|
-
SIGNOFF_STEP_STATUSES,
|
|
7
|
-
SignoffGitError,
|
|
8
2
|
attachSignoffProof,
|
|
9
3
|
buildSignoffProof,
|
|
10
|
-
canonicalJson,
|
|
11
|
-
canonicalizeProofBody,
|
|
12
|
-
collectToolingFacts,
|
|
13
|
-
computeWorktreeTree,
|
|
14
4
|
formatSignoffSummary,
|
|
15
|
-
formatSignoffVerification,
|
|
16
|
-
gitIsAncestor,
|
|
17
|
-
gitText,
|
|
18
|
-
hashProofBody,
|
|
19
5
|
hashStepOutput,
|
|
20
|
-
listSignoffProofs,
|
|
21
|
-
macMatches,
|
|
22
6
|
parseSignoffProof,
|
|
23
7
|
readCommitFacts,
|
|
24
|
-
readInstalledVersion,
|
|
25
8
|
readSignoffKey,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
resolveCommit,
|
|
29
|
-
resolveSignoffProof,
|
|
30
|
-
runGit,
|
|
31
|
-
sealProof,
|
|
32
|
-
serializeSignoffProof,
|
|
33
|
-
signoffKeyId,
|
|
34
|
-
signoffProofBodySchema,
|
|
35
|
-
signoffProofSchema,
|
|
36
|
-
signoffProofSealSchema,
|
|
37
|
-
signoffProofStepSchema,
|
|
38
|
-
tangleDependencyNames,
|
|
39
|
-
verifySignoffAtRev,
|
|
40
|
-
verifySignoffProof,
|
|
41
|
-
verifySignoffProofFile
|
|
42
|
-
} from "../chunk-N3G3FSM4.js";
|
|
9
|
+
verifySignoffProof
|
|
10
|
+
} from "../chunk-YXA3U4JZ.js";
|
|
43
11
|
|
|
44
12
|
// src/signoff/proof-from-report.ts
|
|
45
13
|
var NO_EXIT_CODE = -1;
|
|
@@ -100,49 +68,11 @@ function proofFromSignoffReport(input) {
|
|
|
100
68
|
});
|
|
101
69
|
}
|
|
102
70
|
export {
|
|
103
|
-
NOT_EXECUTED_COMMAND,
|
|
104
|
-
NO_EXIT_CODE,
|
|
105
|
-
SIGNOFF_NOTES_GIT_CONFIG,
|
|
106
|
-
SIGNOFF_NOTES_REF,
|
|
107
|
-
SIGNOFF_PROOF_VERSION,
|
|
108
|
-
SIGNOFF_REQUIRED_STEPS,
|
|
109
|
-
SIGNOFF_STEP_STATUSES,
|
|
110
|
-
SignoffGitError,
|
|
111
71
|
attachSignoffProof,
|
|
112
|
-
buildSignoffProof,
|
|
113
|
-
canonicalJson,
|
|
114
|
-
canonicalizeProofBody,
|
|
115
|
-
collectToolingFacts,
|
|
116
|
-
computeWorktreeTree,
|
|
117
72
|
formatSignoffSummary,
|
|
118
|
-
formatSignoffVerification,
|
|
119
|
-
gitIsAncestor,
|
|
120
|
-
gitText,
|
|
121
|
-
hashProofBody,
|
|
122
|
-
hashStepOutput,
|
|
123
|
-
listSignoffProofs,
|
|
124
|
-
macMatches,
|
|
125
73
|
parseSignoffProof,
|
|
126
74
|
proofFromSignoffReport,
|
|
127
|
-
readCommitFacts,
|
|
128
|
-
readInstalledVersion,
|
|
129
75
|
readSignoffKey,
|
|
130
|
-
|
|
131
|
-
requiredStepsFor,
|
|
132
|
-
resolveCommit,
|
|
133
|
-
resolveSignoffProof,
|
|
134
|
-
runGit,
|
|
135
|
-
sealProof,
|
|
136
|
-
seedsFromReport,
|
|
137
|
-
serializeSignoffProof,
|
|
138
|
-
signoffKeyId,
|
|
139
|
-
signoffProofBodySchema,
|
|
140
|
-
signoffProofSchema,
|
|
141
|
-
signoffProofSealSchema,
|
|
142
|
-
signoffProofStepSchema,
|
|
143
|
-
tangleDependencyNames,
|
|
144
|
-
verifySignoffAtRev,
|
|
145
|
-
verifySignoffProof,
|
|
146
|
-
verifySignoffProofFile
|
|
76
|
+
verifySignoffProof
|
|
147
77
|
};
|
|
148
78
|
//# sourceMappingURL=proof.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/signoff/proof-from-report.ts"],"sourcesContent":["/**\n * The join between the runner and the proof: one sign-off run produces one\n * report, and this turns that report into the signed, attachable record.\n *\n * Nothing here re-runs or re-judges anything. The runner owns what happened; the\n * proof owns what is provable about it later. Keeping the two in one direction\n * is what stops a second, drifting idea of \"which steps ran\" from appearing.\n */\nimport { hashStepOutput, buildSignoffProof, type SignoffProof, type SignoffProofStep } from './proof-record'\nimport { readCommitFacts } from './proof-git'\nimport type { SignoffReport, SignoffStepResult } from './types'\n\n/**\n * A step that never executed has no exit code, so it is recorded as one no\n * process can produce. `status` is what a reader and the verifier judge on;\n * this exists so the field is never a plausible-looking `0`.\n */\
|
|
1
|
+
{"version":3,"sources":["../../src/signoff/proof-from-report.ts"],"sourcesContent":["/**\n * The join between the runner and the proof: one sign-off run produces one\n * report, and this turns that report into the signed, attachable record.\n *\n * Nothing here re-runs or re-judges anything. The runner owns what happened; the\n * proof owns what is provable about it later. Keeping the two in one direction\n * is what stops a second, drifting idea of \"which steps ran\" from appearing.\n */\nimport { hashStepOutput, buildSignoffProof, type SignoffProof, type SignoffProofStep } from './proof-record'\nimport { readCommitFacts } from './proof-git'\nimport type { SignoffReport, SignoffStepResult } from './types'\n\n/**\n * A step that never executed has no exit code, so it is recorded as one no\n * process can produce. `status` is what a reader and the verifier judge on;\n * this exists so the field is never a plausible-looking `0`.\n */\nconst NO_EXIT_CODE = -1\n\n/** The `command` of a step that never executed. A skipped step had no command line. */\nconst NOT_EXECUTED_COMMAND = '(never executed)'\n\nexport interface ProofFromReportInput {\n readonly report: SignoffReport\n /** Repo identity the verifier's required-step table is keyed on. */\n readonly repo: string\n /** Source repository. Defaults to the root the run recorded. */\n readonly repoDir?: string\n /** Step ids the run treated as required. Defaults to every step the report carries. */\n readonly declaredRequired?: readonly string[]\n readonly key?: Uint8Array\n readonly now?: Date\n}\n\nfunction stepFromResult(result: SignoffStepResult, startedAtEpochMs: number): SignoffProofStep {\n const attempts = result.attempts\n const worst = attempts.reduce<number>((worstSoFar, attempt) => (attempt.exitCode !== 0 ? attempt.exitCode : worstSoFar), 0)\n return {\n id: result.name,\n command: attempts[0]?.command ?? NOT_EXECUTED_COMMAND,\n cwd: '.',\n status: result.status,\n exitCode: attempts.length === 0 ? NO_EXIT_CODE : worst,\n durationMs: Math.max(0, Math.round(result.durationMs)),\n startedAt: new Date(startedAtEpochMs + (result.startedAtMs ?? 0)).toISOString(),\n // Every attempt's output, in order — a shuffled step that failed on the\n // second seed must not digest to the same value as one that passed twice.\n outputSha256: hashStepOutput(attempts.map((attempt) => attempt.output).join('\\n')),\n }\n}\n\n/** Every seed the run used, keyed so a reader can replay one step rather than the whole run. */\nfunction seedsFromReport(report: SignoffReport): Record<string, string | number> {\n const seeds: Record<string, string | number> = { base: report.seedBase }\n for (const step of report.steps) {\n step.attempts.forEach((attempt, index) => {\n if (attempt.seed !== null) seeds[`${step.name}#${index}`] = attempt.seed\n })\n }\n return seeds\n}\n\nexport function proofFromSignoffReport(input: ProofFromReportInput): SignoffProof {\n const { report } = input\n const repoDir = input.repoDir ?? report.repo.root\n\n // HEAD moving during a run makes every later claim ambiguous — the checks ran\n // over one commit and the proof would name another. Refused, not reconciled.\n const facts = readCommitFacts(repoDir, 'HEAD')\n if (facts.commit !== report.repo.head) {\n throw new Error(`HEAD moved during the sign-off: the run verified ${report.repo.head}, ${repoDir} is now at ${facts.commit}`)\n }\n\n const startedAtEpochMs = Date.parse(report.startedAt)\n const install: SignoffProofStep = {\n id: 'install',\n command: report.install.command,\n cwd: report.workspace,\n status: report.install.exitCode === 0 ? 'passed' : 'failed',\n exitCode: report.install.exitCode,\n durationMs: Math.max(0, Math.round(report.install.durationMs)),\n startedAt: new Date(startedAtEpochMs).toISOString(),\n outputSha256: hashStepOutput(report.install.output),\n }\n const steps = [install, ...report.steps.map((step) => stepFromResult(step, startedAtEpochMs))]\n\n return buildSignoffProof({\n repoDir,\n repo: input.repo,\n steps,\n wallClockMs: report.wallClockMs,\n declaredRequired: input.declaredRequired ?? steps.map((step) => step.id),\n seeds: seedsFromReport(report),\n key: input.key,\n now: input.now,\n })\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,IAAM,eAAe;AAGrB,IAAM,uBAAuB;AAc7B,SAAS,eAAe,QAA2B,kBAA4C;AAC7F,QAAM,WAAW,OAAO;AACxB,QAAM,QAAQ,SAAS,OAAe,CAAC,YAAY,YAAa,QAAQ,aAAa,IAAI,QAAQ,WAAW,YAAa,CAAC;AAC1H,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX,SAAS,SAAS,CAAC,GAAG,WAAW;AAAA,IACjC,KAAK;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,UAAU,SAAS,WAAW,IAAI,eAAe;AAAA,IACjD,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,UAAU,CAAC;AAAA,IACrD,WAAW,IAAI,KAAK,oBAAoB,OAAO,eAAe,EAAE,EAAE,YAAY;AAAA;AAAA;AAAA,IAG9E,cAAc,eAAe,SAAS,IAAI,CAAC,YAAY,QAAQ,MAAM,EAAE,KAAK,IAAI,CAAC;AAAA,EACnF;AACF;AAGA,SAAS,gBAAgB,QAAwD;AAC/E,QAAM,QAAyC,EAAE,MAAM,OAAO,SAAS;AACvE,aAAW,QAAQ,OAAO,OAAO;AAC/B,SAAK,SAAS,QAAQ,CAAC,SAAS,UAAU;AACxC,UAAI,QAAQ,SAAS,KAAM,OAAM,GAAG,KAAK,IAAI,IAAI,KAAK,EAAE,IAAI,QAAQ;AAAA,IACtE,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,OAA2C;AAChF,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,UAAU,MAAM,WAAW,OAAO,KAAK;AAI7C,QAAM,QAAQ,gBAAgB,SAAS,MAAM;AAC7C,MAAI,MAAM,WAAW,OAAO,KAAK,MAAM;AACrC,UAAM,IAAI,MAAM,oDAAoD,OAAO,KAAK,IAAI,KAAK,OAAO,cAAc,MAAM,MAAM,EAAE;AAAA,EAC9H;AAEA,QAAM,mBAAmB,KAAK,MAAM,OAAO,SAAS;AACpD,QAAM,UAA4B;AAAA,IAChC,IAAI;AAAA,IACJ,SAAS,OAAO,QAAQ;AAAA,IACxB,KAAK,OAAO;AAAA,IACZ,QAAQ,OAAO,QAAQ,aAAa,IAAI,WAAW;AAAA,IACnD,UAAU,OAAO,QAAQ;AAAA,IACzB,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,QAAQ,UAAU,CAAC;AAAA,IAC7D,WAAW,IAAI,KAAK,gBAAgB,EAAE,YAAY;AAAA,IAClD,cAAc,eAAe,OAAO,QAAQ,MAAM;AAAA,EACpD;AACA,QAAM,QAAQ,CAAC,SAAS,GAAG,OAAO,MAAM,IAAI,CAAC,SAAS,eAAe,MAAM,gBAAgB,CAAC,CAAC;AAE7F,SAAO,kBAAkB;AAAA,IACvB;AAAA,IACA,MAAM,MAAM;AAAA,IACZ;AAAA,IACA,aAAa,OAAO;AAAA,IACpB,kBAAkB,MAAM,oBAAoB,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,IACvE,OAAO,gBAAgB,MAAM;AAAA,IAC7B,KAAK,MAAM;AAAA,IACX,KAAK,MAAM;AAAA,EACb,CAAC;AACH;","names":[]}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
checkThemeContract
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-QGSVF6DZ.js";
|
|
5
|
+
import "../chunk-EMLGWEHV.js";
|
|
6
|
+
import {
|
|
7
|
+
invokedAsScript
|
|
8
|
+
} from "../chunk-C3CAYGGQ.js";
|
|
5
9
|
|
|
6
10
|
// src/theme-contract/cli.ts
|
|
7
11
|
function parseArgs(argv) {
|
|
@@ -75,5 +79,5 @@ function main() {
|
|
|
75
79
|
);
|
|
76
80
|
process.exit(1);
|
|
77
81
|
}
|
|
78
|
-
main();
|
|
82
|
+
if (invokedAsScript(import.meta.url, process.argv[1])) main();
|
|
79
83
|
//# sourceMappingURL=cli.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/theme-contract/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * agent-app-theme-check — CI guard against the invisible-surface incident class.\n *\n * A consumer app runs this over its own source; it fails (exit 1) when a\n * component references a theme token — `var(--popover)` or a preset-mapped\n * utility like `bg-surface-container-high` — that the app's shipped CSS never\n * defines, which would paint that surface transparent with no error at runtime.\n *\n * agent-app-theme-check --src src --src packages/ui/src \\\n * --extra-css src/app-tokens.css\n *\n * Flags (all repeatable except --tokens):\n * --src <dir> source dir to scan for token references (required, 1+)\n * --extra-css <file> extra CSS whose --name: definitions also count as defined\n * --tokens <file> override the base tokens.css (defaults to the one\n * agent-app ships as `@tangle-network/agent-app/styles`)\n * --allow <--var> suppress a token name from the missing report\n *\n * Wire it as a CI step: `\"theme-check\": \"agent-app-theme-check --src src\"`.\n */\n\nimport { checkThemeContract } from './index'\n\ninterface ParsedArgs {\n srcDirs: string[]\n extraCss: string[]\n allow: string[]\n tokens?: string\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { srcDirs: [], extraCss: [], allow: [] }\n for (let i = 0; i < argv.length; i++) {\n const flag = argv[i]\n const take = () => {\n const v = argv[++i]\n if (v === undefined) fail(`${flag} needs a value`)\n return v!\n }\n switch (flag) {\n case '--src':\n out.srcDirs.push(take())\n break\n case '--extra-css':\n out.extraCss.push(take())\n break\n case '--allow':\n out.allow.push(take())\n break\n case '--tokens':\n out.tokens = take()\n break\n case '-h':\n case '--help':\n printUsage()\n process.exit(0)\n break\n default:\n fail(`unknown argument: ${flag}`)\n }\n }\n return out\n}\n\nfunction printUsage(): void {\n process.stdout.write(\n 'Usage: agent-app-theme-check --src <dir> [--src <dir>…] ' +\n '[--extra-css <file>…] [--tokens <file>] [--allow <--var>…]\\n',\n )\n}\n\nfunction fail(msg: string): never {\n process.stderr.write(`agent-app-theme-check: ${msg}\\n`)\n printUsage()\n process.exit(2)\n}\n\nfunction main(): void {\n const args = parseArgs(process.argv.slice(2))\n if (args.srcDirs.length === 0) fail('at least one --src <dir> is required')\n\n const { ok, missing } = checkThemeContract({\n srcDirs: args.srcDirs,\n tokensCss: args.tokens,\n extraTokensCss: args.extraCss,\n allowlist: args.allow,\n })\n\n if (ok) {\n process.stdout.write(`theme contract OK — every referenced token is defined (${args.srcDirs.join(', ')})\\n`)\n process.exit(0)\n }\n\n process.stderr.write(\n `theme contract FAILED — ${missing.length} token reference(s) resolve to nothing (surface ships transparent):\\n\\n`,\n )\n for (const m of missing) process.stderr.write(` ${m.varName}\\n referenced in ${m.referencedIn}\\n`)\n process.stderr.write(\n '\\nDefine these in your tokens.css (or `import \\'@tangle-network/agent-app/styles\\'`),\\n' +\n 'pass the defining CSS via --extra-css, or suppress a deliberately-external one with --allow.\\n',\n )\n process.exit(1)\n}\n\
|
|
1
|
+
{"version":3,"sources":["../../src/theme-contract/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * agent-app-theme-check — CI guard against the invisible-surface incident class.\n *\n * A consumer app runs this over its own source; it fails (exit 1) when a\n * component references a theme token — `var(--popover)` or a preset-mapped\n * utility like `bg-surface-container-high` — that the app's shipped CSS never\n * defines, which would paint that surface transparent with no error at runtime.\n *\n * agent-app-theme-check --src src --src packages/ui/src \\\n * --extra-css src/app-tokens.css\n *\n * Flags (all repeatable except --tokens):\n * --src <dir> source dir to scan for token references (required, 1+)\n * --extra-css <file> extra CSS whose --name: definitions also count as defined\n * --tokens <file> override the base tokens.css (defaults to the one\n * agent-app ships as `@tangle-network/agent-app/styles`)\n * --allow <--var> suppress a token name from the missing report\n *\n * Wire it as a CI step: `\"theme-check\": \"agent-app-theme-check --src src\"`.\n */\n\nimport { checkThemeContract } from './index'\nimport { invokedAsScript } from '../signoff/invoked-as-script'\n\ninterface ParsedArgs {\n srcDirs: string[]\n extraCss: string[]\n allow: string[]\n tokens?: string\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { srcDirs: [], extraCss: [], allow: [] }\n for (let i = 0; i < argv.length; i++) {\n const flag = argv[i]\n const take = () => {\n const v = argv[++i]\n if (v === undefined) fail(`${flag} needs a value`)\n return v!\n }\n switch (flag) {\n case '--src':\n out.srcDirs.push(take())\n break\n case '--extra-css':\n out.extraCss.push(take())\n break\n case '--allow':\n out.allow.push(take())\n break\n case '--tokens':\n out.tokens = take()\n break\n case '-h':\n case '--help':\n printUsage()\n process.exit(0)\n break\n default:\n fail(`unknown argument: ${flag}`)\n }\n }\n return out\n}\n\nfunction printUsage(): void {\n process.stdout.write(\n 'Usage: agent-app-theme-check --src <dir> [--src <dir>…] ' +\n '[--extra-css <file>…] [--tokens <file>] [--allow <--var>…]\\n',\n )\n}\n\nfunction fail(msg: string): never {\n process.stderr.write(`agent-app-theme-check: ${msg}\\n`)\n printUsage()\n process.exit(2)\n}\n\nfunction main(): void {\n const args = parseArgs(process.argv.slice(2))\n if (args.srcDirs.length === 0) fail('at least one --src <dir> is required')\n\n const { ok, missing } = checkThemeContract({\n srcDirs: args.srcDirs,\n tokensCss: args.tokens,\n extraTokensCss: args.extraCss,\n allowlist: args.allow,\n })\n\n if (ok) {\n process.stdout.write(`theme contract OK — every referenced token is defined (${args.srcDirs.join(', ')})\\n`)\n process.exit(0)\n }\n\n process.stderr.write(\n `theme contract FAILED — ${missing.length} token reference(s) resolve to nothing (surface ships transparent):\\n\\n`,\n )\n for (const m of missing) process.stderr.write(` ${m.varName}\\n referenced in ${m.referencedIn}\\n`)\n process.stderr.write(\n '\\nDefine these in your tokens.css (or `import \\'@tangle-network/agent-app/styles\\'`),\\n' +\n 'pass the defining CSS via --extra-css, or suppress a deliberately-external one with --allow.\\n',\n )\n process.exit(1)\n}\n\n/* c8 ignore start — process wiring, exercised by the bin itself */\nif (invokedAsScript(import.meta.url, process.argv[1])) main()\n/* c8 ignore stop */\n"],"mappings":";;;;;;;;;;AAgCA,SAAS,UAAU,MAA4B;AAC7C,QAAM,MAAkB,EAAE,SAAS,CAAC,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,EAAE;AAC/D,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,OAAO,KAAK,CAAC;AACnB,UAAM,OAAO,MAAM;AACjB,YAAM,IAAI,KAAK,EAAE,CAAC;AAClB,UAAI,MAAM,OAAW,MAAK,GAAG,IAAI,gBAAgB;AACjD,aAAO;AAAA,IACT;AACA,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,YAAI,QAAQ,KAAK,KAAK,CAAC;AACvB;AAAA,MACF,KAAK;AACH,YAAI,SAAS,KAAK,KAAK,CAAC;AACxB;AAAA,MACF,KAAK;AACH,YAAI,MAAM,KAAK,KAAK,CAAC;AACrB;AAAA,MACF,KAAK;AACH,YAAI,SAAS,KAAK;AAClB;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,mBAAW;AACX,gBAAQ,KAAK,CAAC;AACd;AAAA,MACF;AACE,aAAK,qBAAqB,IAAI,EAAE;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAmB;AAC1B,UAAQ,OAAO;AAAA,IACb;AAAA,EAEF;AACF;AAEA,SAAS,KAAK,KAAoB;AAChC,UAAQ,OAAO,MAAM,0BAA0B,GAAG;AAAA,CAAI;AACtD,aAAW;AACX,UAAQ,KAAK,CAAC;AAChB;AAEA,SAAS,OAAa;AACpB,QAAM,OAAO,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAC5C,MAAI,KAAK,QAAQ,WAAW,EAAG,MAAK,sCAAsC;AAE1E,QAAM,EAAE,IAAI,QAAQ,IAAI,mBAAmB;AAAA,IACzC,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,IAChB,gBAAgB,KAAK;AAAA,IACrB,WAAW,KAAK;AAAA,EAClB,CAAC;AAED,MAAI,IAAI;AACN,YAAQ,OAAO,MAAM,+DAA0D,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,CAAK;AAC3G,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,OAAO;AAAA,IACb,gCAA2B,QAAQ,MAAM;AAAA;AAAA;AAAA,EAC3C;AACA,aAAW,KAAK,QAAS,SAAQ,OAAO,MAAM,KAAK,EAAE,OAAO;AAAA,oBAAuB,EAAE,YAAY;AAAA,CAAI;AACrG,UAAQ,OAAO;AAAA,IACb;AAAA,EAEF;AACA,UAAQ,KAAK,CAAC;AAChB;AAGA,IAAI,gBAAgB,YAAY,KAAK,QAAQ,KAAK,CAAC,CAAC,EAAG,MAAK;","names":[]}
|
|
@@ -230,4 +230,4 @@ type SignoffEvent = {
|
|
|
230
230
|
readonly durationMs: number;
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
-
export type { LoadedSignoffConfig as L, SignoffSource as S, SignoffEvent as a, SignoffReport as b,
|
|
233
|
+
export type { LoadedSignoffConfig as L, SignoffSource as S, SignoffEvent as a, SignoffReport as b, SignoffAttempt as c, SignoffConfig as d, SignoffConfigOrigin as e, SignoffHostFacts as f, SignoffInstallResult as g, SignoffInstallSpec as h, SignoffRepoFacts as i, SignoffShuffleSpec as j, SignoffStepResult as k, SignoffStepSpec as l, SignoffStepStatus as m };
|