toolroll 0.9.70 → 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 (91) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/dist/agent-fence.d.ts +7 -0
  3. package/dist/agent-fence.js +10 -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-report.d.ts +109 -0
  11. package/dist/check-report.js +204 -0
  12. package/dist/claim.js +1 -1
  13. package/dist/commit-extract.d.ts +94 -0
  14. package/dist/commit-extract.js +436 -0
  15. package/dist/contracts/console-api.d.ts +1 -1
  16. package/dist/contracts/console-api.js +1 -0
  17. package/dist/contracts/flow.d.ts +16 -0
  18. package/dist/contracts/flow.js +3 -0
  19. package/dist/contracts/release-check.d.ts +335 -0
  20. package/dist/contracts/release-check.js +159 -0
  21. package/dist/contracts/release-terms.d.ts +60 -0
  22. package/dist/contracts/release-terms.js +70 -0
  23. package/dist/contracts/verification-receipt.d.ts +42 -8
  24. package/dist/contracts/verification-receipt.js +24 -7
  25. package/dist/contracts/verification-view.d.ts +1 -0
  26. package/dist/deploy-gate.d.ts +17 -0
  27. package/dist/deploy-gate.js +68 -0
  28. package/dist/dispatch.js +3 -10
  29. package/dist/dispose.js +4 -1
  30. package/dist/evidence-pack.d.ts +1 -1
  31. package/dist/evidence-pack.js +20 -2
  32. package/dist/evidence.d.ts +1 -0
  33. package/dist/evidence.js +2 -1
  34. package/dist/flow-engine.js +5 -1
  35. package/dist/flow-pull-request.d.ts +5 -2
  36. package/dist/flow-pull-request.js +14 -5
  37. package/dist/flow-schedule.js +25 -6
  38. package/dist/flows-ui.js +7 -1
  39. package/dist/invoke.d.ts +19 -1
  40. package/dist/invoke.js +49 -2
  41. package/dist/lead-status.js +5 -2
  42. package/dist/live-terminal.d.ts +10 -6
  43. package/dist/live-terminal.js +55 -14
  44. package/dist/nightly-check.d.ts +104 -0
  45. package/dist/nightly-check.js +362 -0
  46. package/dist/operate.js +39 -2
  47. package/dist/person-proof.d.ts +2 -0
  48. package/dist/person-proof.js +14 -0
  49. package/dist/plan-auto.js +4 -4
  50. package/dist/planner-source.d.ts +1 -1
  51. package/dist/proof.js +2 -0
  52. package/dist/publish.js +156 -144
  53. package/dist/pull-request-flow.d.ts +2 -0
  54. package/dist/pull-request-flow.js +24 -2
  55. package/dist/release-adapters.d.ts +8 -0
  56. package/dist/release-adapters.js +212 -15
  57. package/dist/release-authority.d.ts +112 -0
  58. package/dist/release-authority.js +126 -0
  59. package/dist/release-carry.d.ts +233 -0
  60. package/dist/release-carry.js +645 -0
  61. package/dist/release-cli.d.ts +3 -0
  62. package/dist/release-cli.js +124 -5
  63. package/dist/release-coverage.js +3 -0
  64. package/dist/release-recheck.d.ts +146 -0
  65. package/dist/release-recheck.js +657 -0
  66. package/dist/release-view.d.ts +34 -0
  67. package/dist/release-view.js +27 -0
  68. package/dist/release.d.ts +131 -1
  69. package/dist/release.js +562 -244
  70. package/dist/remote-main.d.ts +2 -0
  71. package/dist/remote-main.js +1 -1
  72. package/dist/result-completion.d.ts +6 -0
  73. package/dist/result-completion.js +15 -1
  74. package/dist/result-follow-ups.js +29 -1
  75. package/dist/sandbox-runtime.d.ts +59 -1
  76. package/dist/sandbox-runtime.js +159 -5
  77. package/dist/scope.d.ts +115 -5
  78. package/dist/scope.js +219 -7
  79. package/dist/server/render-tasks.d.ts +8 -0
  80. package/dist/server/render-tasks.js +50 -9
  81. package/dist/server/route-table.js +1 -0
  82. package/dist/server/task-views.js +4 -0
  83. package/dist/server/tasks.js +12 -0
  84. package/dist/store.d.ts +227 -5
  85. package/dist/store.js +727 -37
  86. package/dist/task-outcome-cli.js +7 -3
  87. package/dist/toolroll-update.js +2 -2
  88. package/dist/verification-evidence.d.ts +25 -1
  89. package/dist/verification-evidence.js +57 -2
  90. package/dist/work-index.js +3 -6
  91. package/package.json +1 -1
@@ -0,0 +1,34 @@
1
+ import { type Store } from "./store.js";
2
+ export type LandedView = {
3
+ sha: string;
4
+ task: string;
5
+ files: {
6
+ path: string;
7
+ added: number;
8
+ deleted: number;
9
+ }[];
10
+ };
11
+ export type ReleaseView = {
12
+ kind: "anchor" | "carried";
13
+ authority: number;
14
+ version: string;
15
+ pr: number;
16
+ state: string;
17
+ /** Whether the release still carries later commits, and why not. */
18
+ carrying: boolean;
19
+ why: string | null;
20
+ approver: string | null;
21
+ anchorTask: string;
22
+ tipTask: string;
23
+ expiresAt: string;
24
+ landed: LandedView[];
25
+ /** Identities a later check of this release must run again and pass (release-recheck.ts). */
26
+ obligations: string[];
27
+ nightly: {
28
+ at: string;
29
+ sha: string;
30
+ outcome: string | null;
31
+ } | null;
32
+ openMainFailures: number;
33
+ };
34
+ export declare function releaseViewOf(store: Store, taskId: string, now: Date, obligations?: (authority: number) => string[]): ReleaseView | null;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What a release task's page shows (docs/plans/release-once.md, "What people see"): for the approved task, the release
3
+ * it's approved for, every later commit carried under it, the open check obligations and the last nightly result for
4
+ * main; for a carried task, whose release approval it was carried from. Read-only, from the store.
5
+ */
6
+ import { liveReleaseOf } from "./scope.js";
7
+ import { releaseAuthorityOfTask, releaseCarries } from "./store.js";
8
+ export function releaseViewOf(store, taskId, now, obligations = () => []) {
9
+ const found = releaseAuthorityOfTask(store, taskId);
10
+ if (found === null)
11
+ return null;
12
+ const a = found.authority;
13
+ const live = liveReleaseOf(store, a.tipTask, "dispatch", now);
14
+ const anchor = store.getScope(a.anchorTask);
15
+ const nightly = store.handle.prepare("SELECT sha, outcome, at FROM nightly_check WHERE repo = ? ORDER BY id DESC LIMIT 1").get(a.repo);
16
+ const open = Number(store.handle.prepare("SELECT COUNT(*) AS n FROM main_check_failure WHERE repo = ? AND cleared_at IS NULL").get(a.repo)?.["n"] ?? 0);
17
+ return {
18
+ kind: found.carry === null ? "anchor" : "carried",
19
+ authority: a.id, version: a.version, pr: a.pr, state: a.state,
20
+ carrying: a.state === "open" && live.applies && live.ok, why: live.applies && !live.ok ? live.why : null,
21
+ approver: anchor?.approvedBy ?? null, anchorTask: a.anchorTask, tipTask: a.tipTask, expiresAt: a.expiresAt,
22
+ landed: releaseCarries(store, a.id).flatMap(carry => carry.commits.map(commit => ({ sha: commit.sha, task: carry.taskId, files: commit.files }))),
23
+ obligations: obligations(a.id),
24
+ nightly: nightly === undefined ? null : { at: String(nightly["at"]), sha: String(nightly["sha"]), outcome: nightly["outcome"] == null ? null : String(nightly["outcome"]) },
25
+ openMainFailures: open,
26
+ };
27
+ }
package/dist/release.d.ts CHANGED
@@ -65,6 +65,15 @@ export type GateState = {
65
65
  basis: string | null;
66
66
  role: string | null;
67
67
  active: boolean;
68
+ /** The plane's own answer to "did a person give this approval, with a person's proof recorded?" (approval policy
69
+ * §1.5). Absent from a plane too old to say, which is no person's approval. */
70
+ person?: {
71
+ ok: true;
72
+ method: string;
73
+ } | {
74
+ ok: false;
75
+ why: string;
76
+ };
68
77
  } | null;
69
78
  /** The newest finished build of the task: its sealed result and check. */
70
79
  result: {
@@ -115,7 +124,94 @@ export type HomebrewState = {
115
124
  } | {
116
125
  kind: "missing";
117
126
  };
127
+ /** One commit that landed after the approval, with its files and line counts (release_carry). */
128
+ export type LandedCommit = {
129
+ sha: string;
130
+ files: {
131
+ path: string;
132
+ added: number;
133
+ deleted: number;
134
+ }[];
135
+ };
136
+ /** A release's authority record as the coordinator reads it (store.ts release_authority). */
137
+ export type AuthorityView = {
138
+ id: number;
139
+ generation: number;
140
+ state: string;
141
+ tipSha: string;
142
+ tipTask: string;
143
+ version: string;
144
+ pr: number;
145
+ landed: LandedCommit[];
146
+ };
147
+ export type ReleaseAction = "dispatch" | "deploy" | "merge" | "complete";
148
+ export type OperationView = {
149
+ id: string;
150
+ kind: "deploy" | "merge";
151
+ state: "reserved" | "running" | "succeeded" | "failed" | "unknown";
152
+ candidate: string;
153
+ externalRef: string | null;
154
+ reservedAt: string;
155
+ /** Reserved by a person's own deploy run (deploy-browser.mjs), not a coordinator. */
156
+ direct: boolean;
157
+ /** Whether the process that issued it is proven gone (store.ts releaseIssuerGone): read when the view is made. */
158
+ issuerGone: boolean;
159
+ /** A direct deploy's staging folder. */
160
+ stage: string | null;
161
+ };
162
+ /** The release's authority record, through the plane's store (release-once.md). Absent: a plane too old to carry, and
163
+ * every commit asks for a person as before. */
164
+ export type ReleaseAuthorityAdapter = {
165
+ authority(taskId: string): Promise<AuthorityView | null>;
166
+ live(taskId: string, action: ReleaseAction): Promise<{
167
+ applies: boolean;
168
+ ok: boolean;
169
+ why: string | null;
170
+ }>;
171
+ lease(authority: number, owner: string): Promise<{
172
+ ok: true;
173
+ epoch: number;
174
+ } | {
175
+ ok: false;
176
+ why: string;
177
+ }>;
178
+ renew(authority: number, owner: string, epoch: number): Promise<boolean>;
179
+ carry(authority: number, to: string, requestId: string, epoch: number): Promise<{
180
+ ok: true;
181
+ taskId: string;
182
+ } | {
183
+ ok: false;
184
+ message: string;
185
+ }>;
186
+ /** `secret`: proves a deploy run is this reservation's (handed to deploy-browser on stdin). */
187
+ reserve(input: {
188
+ authority: number;
189
+ kind: "deploy" | "merge";
190
+ taskId: string;
191
+ candidate: string;
192
+ epoch: number;
193
+ }): Promise<{
194
+ ok: true;
195
+ operation: string;
196
+ secret?: string;
197
+ } | {
198
+ ok: false;
199
+ why: string;
200
+ }>;
201
+ start(operation: string, epoch: number): Promise<boolean>;
202
+ /** Settle an operation at the epoch this coordinator holds; false: it no longer holds the release. */
203
+ finish(operation: string, outcome: "succeeded" | "failed" | "unknown", facts: {
204
+ detail?: string | null;
205
+ externalRef?: string | null;
206
+ }, epoch: number): Promise<boolean>;
207
+ /** A CI failure after the deploy (Alex's decision): the release stops and needs a person's fresh approval. False when
208
+ * the authority could not be stopped (a stale epoch, a merge already reserved): the coordinator fails closed. */
209
+ needsApproval(authority: number, reason: string, epoch: number): Promise<boolean>;
210
+ operations(authority: number): Promise<OperationView[]>;
211
+ };
118
212
  export type ReleaseAdapters = {
213
+ /** One approval per release (release-once.md); absent on a plane that can't carry. */
214
+ release?: ReleaseAuthorityAdapter;
119
215
  now(): Date;
120
216
  sleep(ms: number): Promise<void>;
121
217
  say(line: string): void;
@@ -147,6 +243,13 @@ export type ReleaseAdapters = {
147
243
  candidate: string;
148
244
  goal: string;
149
245
  acceptance: string;
246
+ /** Release terms to file with the scope (task scope --release): the version, pull request and branch. */
247
+ release?: {
248
+ version: string;
249
+ pr: number;
250
+ branch: string;
251
+ noCarry: boolean;
252
+ };
150
253
  }): Promise<{
151
254
  scopeDigest: string;
152
255
  }>;
@@ -165,6 +268,10 @@ export type ReleaseAdapters = {
165
268
  run: number;
166
269
  worktree: string;
167
270
  stage: string;
271
+ operation?: {
272
+ id: string;
273
+ secret: string;
274
+ };
168
275
  }): Promise<{
169
276
  ok: true;
170
277
  runtime: string;
@@ -177,6 +284,9 @@ export type ReleaseAdapters = {
177
284
  }): Promise<{
178
285
  ok: true;
179
286
  } | DeployStop>;
287
+ /** Whether no deployment is at work or half done: no deploy-browser process, no update pause held, and `stage`'s
288
+ * journal (when given) unlocked and at a phase that changed nothing or finished. Null stage: unknown, so false. */
289
+ deploymentIdle(stage: string | null): Promise<boolean>;
180
290
  /** Where both CLI names are on PATH now. */
181
291
  cliLinks(): Promise<SavedLink[]>;
182
292
  /** Point every saved link at `bin` and check each answers `version`; on any failure every link goes back to its
@@ -187,7 +297,7 @@ export type ReleaseAdapters = {
187
297
  authenticated(): Promise<boolean>;
188
298
  pullRequest(repo: string, branch: string): Promise<PullRequest | null>;
189
299
  checks(repo: string, sha: string): Promise<CheckRun[]>;
190
- merge(repo: string, pr: number, head: string): Promise<string>;
300
+ merge(repo: string, pr: number, head: string, message?: string): Promise<string>;
191
301
  tag(repo: string, tag: string): Promise<string | null>;
192
302
  createTag(repo: string, tag: string, sha: string): Promise<void>;
193
303
  release(repo: string, tag: string): Promise<boolean>;
@@ -273,6 +383,22 @@ export type ReleaseJournal = {
273
383
  head: string | null;
274
384
  merged: boolean;
275
385
  } | null;
386
+ /** The release's authority record (release-once.md), once a person approved terms: the id and generation. */
387
+ authority?: {
388
+ id: number;
389
+ generation: number;
390
+ } | null;
391
+ /** Commits that landed after the approval, carried under it: each with its files and line counts. */
392
+ landed?: LandedCommit[];
393
+ /** The deploy and merge operations this coordinator reserved (store.ts release_operation). */
394
+ operations?: {
395
+ deploy?: string;
396
+ merge?: string;
397
+ };
398
+ /** A pull request check failed after the deploy: nothing continues until a person approves again (--new). */
399
+ needsApproval?: boolean;
400
+ /** This journal's task was picked fresh after a CI failure after the deploy: an id that never existed, never another. */
401
+ freshTask?: boolean;
276
402
  /** When each step was about to change something outside this machine: what a resume must look for before acting. */
277
403
  intents: Partial<Record<ReleaseStep, string>>;
278
404
  stopped: {
@@ -307,7 +433,11 @@ export type ReleaseOptions = {
307
433
  /** Start over for a new commit on the branch, keeping the old journal aside. Refused once merging began. */
308
434
  fresh?: boolean;
309
435
  pollMs?: number;
436
+ /** File the release without carrying later commits: each one asks again. */
437
+ noCarry?: boolean;
310
438
  };
439
+ /** Every commit that landed after the approval, in words: the summary and the merge message list them all. */
440
+ export declare function landedWords(landed: readonly LandedCommit[]): string[];
311
441
  export declare const journalFile: (stateDir: string, branch: string) => string;
312
442
  export declare const resumeCommand: (branch: string, checkout: string) => string;
313
443
  /** Whole or not at all: a private temp file, synced, renamed into place, its folder synced. */