toolroll 0.9.71 → 0.9.72

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 (93) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/agent-fence.d.ts +5 -2
  3. package/dist/agent-fence.js +5 -2
  4. package/dist/approval-authority.d.ts +20 -0
  5. package/dist/approval-authority.js +67 -0
  6. package/dist/assignment.js +26 -4
  7. package/dist/browser/workspace.css +1 -1
  8. package/dist/builder.js +48 -6
  9. package/dist/chat-decide.js +17 -2
  10. package/dist/check-access.js +2 -2
  11. package/dist/check-report.d.ts +109 -0
  12. package/dist/check-report.js +204 -0
  13. package/dist/claim.js +1 -1
  14. package/dist/commit-extract.d.ts +94 -0
  15. package/dist/commit-extract.js +436 -0
  16. package/dist/contracts/console-api.d.ts +1 -1
  17. package/dist/contracts/console-api.js +1 -0
  18. package/dist/contracts/flow.d.ts +16 -0
  19. package/dist/contracts/flow.js +3 -0
  20. package/dist/contracts/release-check.d.ts +335 -0
  21. package/dist/contracts/release-check.js +159 -0
  22. package/dist/contracts/release-terms.d.ts +60 -0
  23. package/dist/contracts/release-terms.js +70 -0
  24. package/dist/contracts/verification-receipt.d.ts +42 -8
  25. package/dist/contracts/verification-receipt.js +24 -7
  26. package/dist/contracts/verification-view.d.ts +1 -0
  27. package/dist/deploy-gate.d.ts +17 -0
  28. package/dist/deploy-gate.js +68 -0
  29. package/dist/dispatch.js +3 -10
  30. package/dist/dispose.js +4 -1
  31. package/dist/evidence-pack.d.ts +1 -1
  32. package/dist/evidence-pack.js +20 -2
  33. package/dist/evidence.d.ts +1 -0
  34. package/dist/evidence.js +2 -1
  35. package/dist/flow-engine.js +5 -1
  36. package/dist/flow-pull-request.d.ts +5 -2
  37. package/dist/flow-pull-request.js +14 -5
  38. package/dist/flow-schedule.js +25 -6
  39. package/dist/flows-ui.js +7 -1
  40. package/dist/invoke.d.ts +17 -6
  41. package/dist/invoke.js +48 -18
  42. package/dist/lead-status.js +5 -2
  43. package/dist/live-terminal.d.ts +10 -6
  44. package/dist/live-terminal.js +55 -14
  45. package/dist/nightly-check.d.ts +104 -0
  46. package/dist/nightly-check.js +362 -0
  47. package/dist/operate.js +39 -2
  48. package/dist/person-proof.d.ts +2 -0
  49. package/dist/person-proof.js +14 -0
  50. package/dist/plan-auto.js +4 -4
  51. package/dist/planner-source.d.ts +1 -1
  52. package/dist/project-delete-ui.js +1 -1
  53. package/dist/proof.js +2 -0
  54. package/dist/publish.js +156 -144
  55. package/dist/pull-request-flow.d.ts +2 -0
  56. package/dist/pull-request-flow.js +24 -2
  57. package/dist/release-adapters.d.ts +8 -0
  58. package/dist/release-adapters.js +212 -15
  59. package/dist/release-authority.d.ts +112 -0
  60. package/dist/release-authority.js +126 -0
  61. package/dist/release-carry.d.ts +233 -0
  62. package/dist/release-carry.js +645 -0
  63. package/dist/release-cli.d.ts +3 -0
  64. package/dist/release-cli.js +124 -5
  65. package/dist/release-coverage.js +3 -0
  66. package/dist/release-recheck.d.ts +146 -0
  67. package/dist/release-recheck.js +657 -0
  68. package/dist/release-view.d.ts +34 -0
  69. package/dist/release-view.js +27 -0
  70. package/dist/release.d.ts +131 -1
  71. package/dist/release.js +562 -244
  72. package/dist/remote-main.d.ts +2 -0
  73. package/dist/remote-main.js +1 -1
  74. package/dist/result-completion.d.ts +6 -0
  75. package/dist/result-completion.js +15 -1
  76. package/dist/result-follow-ups.js +29 -1
  77. package/dist/sandbox-runtime.d.ts +16 -5
  78. package/dist/sandbox-runtime.js +19 -6
  79. package/dist/scope.d.ts +115 -5
  80. package/dist/scope.js +219 -7
  81. package/dist/server/render-tasks.d.ts +8 -0
  82. package/dist/server/render-tasks.js +50 -9
  83. package/dist/server/route-table.js +1 -0
  84. package/dist/server/task-views.js +4 -0
  85. package/dist/server/tasks.js +12 -0
  86. package/dist/store.d.ts +227 -5
  87. package/dist/store.js +727 -37
  88. package/dist/task-outcome-cli.js +7 -3
  89. package/dist/toolroll-update.js +2 -2
  90. package/dist/verification-evidence.d.ts +25 -1
  91. package/dist/verification-evidence.js +57 -2
  92. package/dist/work-index.js +3 -6
  93. package/package.json +1 -1
@@ -0,0 +1,233 @@
1
+ import { type TreeChange, type VerifiedCommit } from "./commit-extract.js";
2
+ import { type ReleasePolicy, type ReleaseTerms } from "./contracts/release-terms.js";
3
+ import { type ExecResult } from "./exec.js";
4
+ import { type ReleaseAuthority, type ReleaseCarry, type Store } from "./store.js";
5
+ /** The journey scripts: tests, by Alex's decision (they carry). */
6
+ export declare const JOURNEY_SCRIPTS: readonly string[];
7
+ /** What carries (version 1). Everything else asks again — including every other `test/**` or `scripts/**` file (the
8
+ * harness, what it imports, helpers and fixtures), so no harness file can slip in under a class. */
9
+ export declare const CARRY_RULES: Readonly<{
10
+ version: 1;
11
+ classes: readonly {
12
+ name: string;
13
+ matches: (path: string) => boolean;
14
+ }[];
15
+ /** Never carry, even when a class above matches them. */
16
+ never: readonly {
17
+ why: string;
18
+ matches: (path: string) => boolean;
19
+ }[];
20
+ }>;
21
+ /** The limits (Alex, 2026-10-25): 400 changed lines and 20 files after the approval, 800 lines of churn. */
22
+ export declare const CARRY_LIMITS: Readonly<{
23
+ lines: 400;
24
+ files: 20;
25
+ churn: 800;
26
+ }>;
27
+ /** "Ask for every release commit": a project setting, newest choice wins (a ledger row each); off by default. */
28
+ export declare const ASK_EVERY_COMMIT_ACTION = "release carrying changed";
29
+ export declare function asksEveryReleaseCommit(store: Store, repo: string): boolean;
30
+ export declare function setAskEveryReleaseCommit(store: Store, repo: string, ask: boolean, by: string, now: Date): void;
31
+ /** The effective policy now: the runtime rules, the project's protected paths and the limits. */
32
+ export declare function effectivePolicy(store: Store, repo: string, options?: {
33
+ noCarry?: boolean;
34
+ }): ReleasePolicy;
35
+ /** The stricter of two policies: what either protects asks again, the lower limit wins, either one's "ask" asks. Null
36
+ * when either is a policy this runtime doesn't know (then nothing carries). */
37
+ export declare function stricterOf(a: ReleasePolicy | null, b: ReleasePolicy | null): ReleasePolicy | null;
38
+ /**
39
+ * A path as the rules compare it: lower case (a case-insensitive file system reads docs/Plans as docs/plans), each part
40
+ * without the trailing dots and spaces Windows drops, and no empty or `.` parts (a verified tree never holds them, but
41
+ * the rules don't rely on that).
42
+ */
43
+ export declare function rulePath(path: string): string;
44
+ /** Why one changed path doesn't carry, in words, or null when it does. Every rule reads the normalized path. */
45
+ export declare function changeRefusal(change: TreeChange, policy: ReleasePolicy): string | null;
46
+ /**
47
+ * A release scope's terms, from the plane's own records: the project's repository, the approved commit and its
48
+ * verified tree, the effective policy, the live release check grant and the check access (only the fence), and the
49
+ * expiry. Null with why when the release can't carry at all (it then asks for every commit, as before).
50
+ */
51
+ export declare function releaseTermsFor(store: Store, input: {
52
+ repo: string;
53
+ version: string;
54
+ branch: string;
55
+ pr: number;
56
+ candidate: string;
57
+ now: Date;
58
+ noCarry?: boolean;
59
+ }): {
60
+ ok: true;
61
+ terms: ReleaseTerms;
62
+ } | {
63
+ ok: false;
64
+ why: string;
65
+ };
66
+ /** One carried commit, as the summary and the merge message list it. */
67
+ export type LandedCommit = {
68
+ sha: string;
69
+ files: {
70
+ path: string;
71
+ added: number;
72
+ deleted: number;
73
+ }[];
74
+ };
75
+ export type CarryRefusal = {
76
+ ok: false;
77
+ reason: "authority" | "ancestry" | "shape" | "rules" | "limits" | "build" | "artifact" | "stale";
78
+ message: string;
79
+ path?: string;
80
+ };
81
+ export type PreflightPlan = {
82
+ authority: ReleaseAuthority;
83
+ to: string;
84
+ toTree: string;
85
+ commits: LandedCommit[];
86
+ changedLines: number;
87
+ files: number;
88
+ churn: number;
89
+ policy: ReleasePolicy;
90
+ currentPolicyDigest: string;
91
+ };
92
+ /**
93
+ * Step 2, read-only: nothing from the candidate is installed, built or run here. Objects come from the project's own
94
+ * Git directory as Toolroll records it, hashed here; the authority is read live.
95
+ */
96
+ export declare function preflightCarry(store: Store, input: {
97
+ authority: number;
98
+ to: string;
99
+ epoch?: number | null;
100
+ now: Date;
101
+ }): {
102
+ ok: true;
103
+ plan: PreflightPlan;
104
+ } | CarryRefusal;
105
+ /** How a build step runs: the fenced default, or a test's stand-in. */
106
+ export type BuildRunner = (file: string, args: readonly string[], options: {
107
+ cwd: string;
108
+ env: Record<string, string>;
109
+ writable: readonly string[];
110
+ timeoutMs: number;
111
+ }) => Promise<ExecResult>;
112
+ /** The default build runner: the OS fence, writes only where named, and no network — its only way out is a proxy of its
113
+ * own that allows no host. No fence on this machine, no build. */
114
+ export declare function fencedBuildRunner(store: Store): BuildRunner;
115
+ /** What the writer scan reads from the OS: injectable so each refusal shape can be shown (tests), real by default. */
116
+ export type WriterScanIO = {
117
+ platform: NodeJS.Platform;
118
+ /** This process: its pid, and the user the build runs as (its effective uid). */
119
+ pid: number;
120
+ uid: number;
121
+ /** Linux: the numeric entries of /proc. Throws when /proc can't be listed. */
122
+ procPids(): string[];
123
+ /** Linux: readlink /proc/<pid>/cwd. Throws with the errno code. */
124
+ procCwd(pid: string): string;
125
+ /** Linux: a process's real and effective uid (/proc/<pid>/status, readable even when its folder isn't) and its start
126
+ * time in clock ticks since boot (/proc/<pid>/stat). Throws with the errno code. Never the owner of its /proc files:
127
+ * a process can make those root's (PR_SET_DUMPABLE 0). */
128
+ procIdentity(pid: string): {
129
+ uids: number[];
130
+ startTicks: number;
131
+ };
132
+ /** Linux: now, in clock ticks since boot (from /proc/uptime), and the ticks in a second; null when unreadable. */
133
+ nowTicks(): {
134
+ ticks: number;
135
+ hz: number;
136
+ } | null;
137
+ /** macOS: each process's pid, effective uid and whether it is a zombie (ps), or null when ps failed. */
138
+ processes(): {
139
+ pid: number;
140
+ uid: number;
141
+ zombie: boolean;
142
+ }[] | null;
143
+ /** macOS: lsof's cwd listing, its stdout and how it ended. */
144
+ lsof(): {
145
+ stdout: string;
146
+ status: number | null;
147
+ signal: string | null;
148
+ code: string | null;
149
+ };
150
+ /** macOS: a second look at these pids (ps): each one still there, with its uid, whether it is a zombie and when it
151
+ * started (ms, whole seconds); a pid missing from the map is gone. Null when ps failed. */
152
+ describe(pids: readonly number[]): Map<number, {
153
+ uid: number;
154
+ zombie: boolean;
155
+ startedMs: number | null;
156
+ }> | null;
157
+ /** Whether a pid is gone (ESRCH). */
158
+ gone(pid: number): boolean;
159
+ };
160
+ /** When the build began: wall-clock ms, and on Linux the clock ticks since boot. */
161
+ export type BuildStart = {
162
+ ms: number;
163
+ ticks: {
164
+ ticks: number;
165
+ hz: number;
166
+ } | null;
167
+ };
168
+ /**
169
+ * Pids whose working folder is inside `root` (lsof on macOS, /proc on Linux), or null when that can't be shown (the
170
+ * caller refuses: nothing is digested unless it is shown that no writer remains). A process is passed over only when
171
+ * it is gone, or provably runs as another user than the build; one of the build's own user that can't be read refuses.
172
+ *
173
+ * On Linux a fenced build can't leave one at all: the sandbox runtime starts every launch in a PID namespace of its own
174
+ * (bwrap --unshare-pid, --die-with-parent), and when the build's process ends the kernel kills everything left in that
175
+ * namespace, a detached or new-session child included, before the launch returns. The scan is the check for whatever
176
+ * runs outside such a namespace (an unfenced runner) and the proof on macOS, where Seatbelt has no PID namespace.
177
+ */
178
+ export declare function processesInside(root: string, since: BuildStart | null, io?: WriterScanIO): number[] | null;
179
+ /** Files left out of the artifact digest and listed as doc changes instead. */
180
+ export declare const ARTIFACT_EXCLUDED: readonly string[];
181
+ /**
182
+ * The digest of one built tree's production artifacts, read as untrusted: every entry walked with lstat, opened with
183
+ * O_NOFOLLOW and checked again on the descriptor; only regular files inside `root` count; a symlink, a special file or a
184
+ * path that escapes refuses. Each entry records path, mode and sha256.
185
+ */
186
+ export declare function digestTree(root: string, paths: readonly string[]): {
187
+ ok: true;
188
+ digest: string;
189
+ entries: number;
190
+ } | {
191
+ ok: false;
192
+ message: string;
193
+ };
194
+ /**
195
+ * Step 3 for one commit: extract it (verified objects, regular files only) into a fresh folder, install from its
196
+ * lockfile with no scripts and no network (npm checks every package against the lockfile's integrity hash), build it,
197
+ * list what `npm pack` would ship, wait until nothing runs from the folder any more, and digest dist/ plus the packed
198
+ * files twice — a difference means something is still writing, and refuses.
199
+ */
200
+ export declare function artifactDigest(gitDir: string, sha: string, runner: BuildRunner, options?: {
201
+ timeoutMs?: number;
202
+ npmCache?: string;
203
+ }): Promise<{
204
+ ok: true;
205
+ digest: string;
206
+ } | {
207
+ ok: false;
208
+ message: string;
209
+ }>;
210
+ /** The release task's id for a commit (release.ts gateTaskId's naming). */
211
+ export declare const carriedTaskId: (version: string, sha: string) => string;
212
+ export type CarryResult = {
213
+ ok: true;
214
+ taskId: string;
215
+ carry: ReleaseCarry;
216
+ retried: boolean;
217
+ } | CarryRefusal;
218
+ /**
219
+ * Carry a person's release approval to commit `to`, or say exactly why not. The lead may ask; only these rules decide.
220
+ * A refusal seals nothing and writes no row.
221
+ */
222
+ export declare function proveCarry(store: Store, input: {
223
+ authority: number;
224
+ to: string;
225
+ requestId?: string;
226
+ epoch?: number | null;
227
+ now: Date;
228
+ runner?: BuildRunner;
229
+ runtime?: string;
230
+ }): Promise<CarryResult>;
231
+ /** The words a refused carry ends with: the commit, the path and the rule, and that a person approves it instead. */
232
+ export declare function carryRefusalWords(refusal: CarryRefusal, to: string): string;
233
+ export type { VerifiedCommit };