toolroll 0.9.75 → 0.9.77

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 (129) hide show
  1. package/CHANGELOG.md +241 -0
  2. package/README.md +11 -4
  3. package/THIRD_PARTY_NOTICES.md +5 -5
  4. package/dist/agent-fence.js +36 -8
  5. package/dist/approval-authority.js +6 -2
  6. package/dist/approval-rules-ui.d.ts +11 -0
  7. package/dist/approval-rules-ui.js +13 -1
  8. package/dist/assignment.js +3 -0
  9. package/dist/batch-checks.js +3 -1
  10. package/dist/browser/THIRD_PARTY_NOTICES.txt +5 -5
  11. package/dist/browser/workspace.css +2 -2
  12. package/dist/browser/workspace.js +31 -31
  13. package/dist/builder.d.ts +14 -0
  14. package/dist/builder.js +141 -42
  15. package/dist/chat-decide.js +4 -0
  16. package/dist/check-failure.d.ts +92 -0
  17. package/dist/check-failure.js +267 -0
  18. package/dist/check-progress.d.ts +28 -1
  19. package/dist/check-progress.js +105 -6
  20. package/dist/check-report.d.ts +52 -6
  21. package/dist/check-report.js +193 -8
  22. package/dist/checkout-cleanup.js +2 -2
  23. package/dist/cli.js +8 -5
  24. package/dist/coding-handoff.d.ts +1 -0
  25. package/dist/coding-handoff.js +20 -11
  26. package/dist/coding-workspace.js +7 -5
  27. package/dist/commit-extract.d.ts +6 -0
  28. package/dist/commit-extract.js +63 -8
  29. package/dist/console-chrome.d.ts +41 -0
  30. package/dist/console-chrome.js +166 -0
  31. package/dist/contracts/console-api.d.ts +1 -0
  32. package/dist/contracts/console-api.js +1 -0
  33. package/dist/contracts/release-check.d.ts +12 -0
  34. package/dist/contracts/release-check.js +17 -0
  35. package/dist/contracts/verification-receipt.d.ts +20 -2
  36. package/dist/contracts/verification-receipt.js +15 -3
  37. package/dist/contracts/verification-view.d.ts +8 -0
  38. package/dist/controller-supervisor.d.ts +8 -0
  39. package/dist/controller-supervisor.js +33 -1
  40. package/dist/demo.js +3 -2
  41. package/dist/deploy-gate.d.ts +3 -0
  42. package/dist/deploy-gate.js +8 -2
  43. package/dist/desktop-update.d.ts +1 -1
  44. package/dist/discover.js +6 -1
  45. package/dist/dispose.d.ts +3 -0
  46. package/dist/dispose.js +6 -3
  47. package/dist/doctor.d.ts +7 -0
  48. package/dist/doctor.js +10 -2
  49. package/dist/envelope.js +2 -1
  50. package/dist/evidence.js +4 -1
  51. package/dist/exec.d.ts +7 -0
  52. package/dist/exec.js +7 -1
  53. package/dist/first-run.js +3 -1
  54. package/dist/git-floor.d.ts +16 -0
  55. package/dist/git-floor.js +36 -0
  56. package/dist/git-incident.d.ts +49 -0
  57. package/dist/git-incident.js +69 -0
  58. package/dist/git-views.d.ts +20 -0
  59. package/dist/git-views.js +120 -0
  60. package/dist/grant.js +7 -1
  61. package/dist/guides.js +4 -3
  62. package/dist/operate.d.ts +13 -0
  63. package/dist/operate.js +779 -319
  64. package/dist/planner.js +5 -1
  65. package/dist/prepared-evidence.d.ts +2 -1
  66. package/dist/prepared-evidence.js +8 -3
  67. package/dist/project-knowledge.js +6 -2
  68. package/dist/project-learning.js +23 -3
  69. package/dist/proof.js +6 -0
  70. package/dist/pull-request-flow.js +4 -0
  71. package/dist/read-executor-worker.js +8 -4
  72. package/dist/read-executor.d.ts +18 -1
  73. package/dist/read-executor.js +8 -0
  74. package/dist/release-adapters.d.ts +71 -2
  75. package/dist/release-adapters.js +471 -12
  76. package/dist/release-authority.d.ts +46 -0
  77. package/dist/release-authority.js +68 -0
  78. package/dist/release-auto.d.ts +184 -0
  79. package/dist/release-auto.js +612 -0
  80. package/dist/release-card.d.ts +15 -3
  81. package/dist/release-card.js +25 -9
  82. package/dist/release-ci-hold.d.ts +41 -0
  83. package/dist/release-ci-hold.js +53 -0
  84. package/dist/release-cli.js +77 -14
  85. package/dist/release-coverage.js +5 -2
  86. package/dist/release-recheck.d.ts +1 -1
  87. package/dist/release-recheck.js +6 -1
  88. package/dist/release.d.ts +207 -6
  89. package/dist/release.js +495 -20
  90. package/dist/repository-context.js +4 -6
  91. package/dist/result-follow-ups.js +3 -1
  92. package/dist/review-context.js +8 -6
  93. package/dist/runner.js +2 -1
  94. package/dist/sandbox-runtime.d.ts +8 -0
  95. package/dist/sandbox-runtime.js +14 -2
  96. package/dist/scope.d.ts +31 -2
  97. package/dist/scope.js +51 -4
  98. package/dist/scout.js +5 -1
  99. package/dist/secret-mint.d.ts +1 -0
  100. package/dist/secret-mint.js +14 -0
  101. package/dist/serve.js +101 -51
  102. package/dist/server/chat.js +5 -5
  103. package/dist/server/render-tasks.d.ts +12 -0
  104. package/dist/server/render-tasks.js +25 -14
  105. package/dist/server/request-context.d.ts +6 -0
  106. package/dist/server/route-table.js +3 -0
  107. package/dist/server/runtime.d.ts +2 -0
  108. package/dist/server/settings.js +29 -2
  109. package/dist/server/task-views.js +15 -2
  110. package/dist/setup-guide.d.ts +2 -2
  111. package/dist/storage.d.ts +5 -0
  112. package/dist/storage.js +28 -1
  113. package/dist/store.d.ts +11 -1
  114. package/dist/store.js +44 -5
  115. package/dist/task-base.d.ts +4 -0
  116. package/dist/task-base.js +22 -2
  117. package/dist/teardown-git.d.ts +90 -13
  118. package/dist/teardown-git.js +1027 -129
  119. package/dist/test-infra.d.ts +26 -0
  120. package/dist/test-infra.js +321 -0
  121. package/dist/up-processes.d.ts +137 -0
  122. package/dist/up-processes.js +165 -0
  123. package/dist/up-role-child.d.ts +1 -0
  124. package/dist/up-role-child.js +77 -0
  125. package/dist/verification-evidence.d.ts +1 -0
  126. package/dist/verification-evidence.js +13 -1
  127. package/dist/worktree.d.ts +4 -0
  128. package/dist/worktree.js +13 -7
  129. package/package.json +2 -1
package/dist/release.d.ts CHANGED
@@ -34,7 +34,29 @@
34
34
  */
35
35
  /** The pull-request checks a release waits for, by exact job name (.github/workflows/ci.yml). Every one must have
36
36
  * concluded `success` on the gated commit; src/ci-workflow.test.ts holds the workflow to this list. */
37
- export declare const REQUIRED_PR_CHECKS: readonly ["node 22 · ubuntu-latest", "node 24 · ubuntu-latest", "linux native containment · delegated cgroup v2", "linux fence · sandbox-runtime", "Windows Job Object containment"];
37
+ export declare const REQUIRED_PR_CHECKS: readonly ["node 22 · ubuntu-latest", "node 24 · ubuntu-latest", "linux native containment · delegated cgroup v2", "linux fence · sandbox-runtime", "Windows Job Object containment", "git 2.41 · debian trixie", "git 2.47 · debian trixie"];
38
+ /** The workflow file every REQUIRED_PR_CHECKS job belongs to: a job of that name from any other workflow (a lookalike
39
+ * added beside it) never stands for it (Codex review round 1, inherited CI limitation). */
40
+ export declare const REQUIRED_PR_CHECKS_WORKFLOW = ".github/workflows/ci.yml";
41
+ /**
42
+ * The pull-request checks main's GitHub protection is not yet required to name (eval-harness review 2, finding 1): the
43
+ * git lanes join main's protection once they have run there, so a protection without them is reported, never refused.
44
+ * A later release empties this list; from then on main's protection must name every REQUIRED_PR_CHECKS check.
45
+ */
46
+ export declare const PROTECTION_REPORT_ONLY_CHECKS: readonly string[];
47
+ /** The checks main's protection must require at minimum: every required check that isn't report-only. */
48
+ export declare const PROTECTION_MINIMUM_CHECKS: readonly string[];
49
+ /**
50
+ * Main's protection as the plane's gh reads it (release-adapters.ts readMainProtection): `effective` only when one layer
51
+ * (classic protection or one active ruleset) requires up-to-date branches, binds every PROTECTION_MINIMUM_CHECKS check to GitHub Actions,
52
+ * and nobody merging as this gh can bypass it. `missing` names each absent property; `notYetRequired` the report-only
53
+ * checks the effective layer doesn't name.
54
+ */
55
+ export type MainProtection = {
56
+ effective: boolean;
57
+ missing: string[];
58
+ notYetRequired: string[];
59
+ };
38
60
  /** The checks a release tag runs (.github/workflows/publish.yml), awaited before Homebrew moves. */
39
61
  export declare const RELEASE_TAG_CHECKS: readonly ["node 22 · macos-latest", "node 24 · macos-latest", "publish"];
40
62
  export declare const RELEASE_STEPS: readonly ["gate", "approval", "check", "complete", "quiet", "deploy", "link", "ci", "merge", "tree", "tag", "publish", "homebrew", "done"];
@@ -42,12 +64,38 @@ export type ReleaseStep = typeof RELEASE_STEPS[number];
42
64
  type WaitingStep = "gate" | "approval" | "check" | "quiet" | "deploy" | "ci" | "publish" | "homebrew";
43
65
  /** How long each waiting step may take, in minutes, before the release stops there (rerunning continues from it). */
44
66
  export declare const RELEASE_LIMITS: Readonly<Record<WaitingStep, number>>;
45
- /** One check attempt; `app` is the GitHub App that made it (github-actions for a workflow), when known. */
67
+ /** One check attempt; `app` is the GitHub App that made it (github-actions for a workflow), when known; `id` its check
68
+ * run id, `suite` its check suite (one workflow run: its re-runs stay in it) and `head` the commit GitHub filed it
69
+ * under, when known. */
46
70
  export type CheckRun = {
47
71
  name: string;
48
72
  status: string;
49
73
  conclusion: string | null;
50
74
  app?: string | null;
75
+ id?: number | null;
76
+ suite?: number | null;
77
+ head?: string | null;
78
+ /** The workflow (its id, from GitHub's workflow-run API) that this check's suite is a run of, when known. */
79
+ workflow?: number | null;
80
+ /** That workflow's file in the repository (GitHub's workflow-run `path`), when known. */
81
+ workflowPath?: string | null;
82
+ /** GitHub's own job record (its steps, read by the plane's gh) shows this unsuccessful attempt ended before any of the
83
+ * workflow's own steps ran: the runner failed, not the tests. Absent or false: nothing shows that. */
84
+ beforeTests?: boolean | null;
85
+ };
86
+ /**
87
+ * Failure classes replace a flat flake allowance (docs/plans/eval-harness.md; check-failure.ts says the classes): only a
88
+ * failure the plane itself confirmed as infrastructure is ever run again under the same approval — at most once per
89
+ * incident and twice per candidate — for a release check and for a GitHub CI job alike. A failing test, a typecheck, an
90
+ * attack test, a migration: none tolerated. An unexplained failure blocks, and a person decides.
91
+ */
92
+ export declare const INFRA_RERUNS_PER_INCIDENT = 1;
93
+ export declare const INFRA_RERUNS_PER_CANDIDATE = 2;
94
+ /** One failed attempt that a later attempt of the same job passed. */
95
+ export type CheckFailure = {
96
+ id: number;
97
+ name: string;
98
+ conclusion: string | null;
51
99
  };
52
100
  export type PullRequest = {
53
101
  number: number;
@@ -152,6 +200,18 @@ export type AuthorityView = {
152
200
  landed: LandedCommit[];
153
201
  };
154
202
  export type ReleaseAction = "dispatch" | "deploy" | "merge" | "complete";
203
+ /** The plane's answer after a failed release check: rerun (confirmed infrastructure), already rerunning, or stop. */
204
+ export type FailureClassName = "deterministic" | "infrastructure" | "unknown" | "agent-behaviour";
205
+ export type RecheckView = {
206
+ action: "rerun";
207
+ why: string;
208
+ } | {
209
+ action: "pending";
210
+ } | {
211
+ action: "stop";
212
+ class: FailureClassName | null;
213
+ why: string;
214
+ };
155
215
  export type OperationView = {
156
216
  id: string;
157
217
  kind: "deploy" | "merge";
@@ -215,6 +275,89 @@ export type ReleaseAuthorityAdapter = {
215
275
  * the authority could not be stopped (a stale epoch, a merge already reserved): the coordinator fails closed. */
216
276
  needsApproval(authority: number, reason: string, epoch: number): Promise<boolean>;
217
277
  operations(authority: number): Promise<OperationView[]>;
278
+ /** After a failed release check (check-failure.ts): the plane classifies it from its own records and, only for
279
+ * confirmed infrastructure within its limits, runs the check again on the same candidate under the same approval.
280
+ * Absent on an older plane: a failed check stops as before. */
281
+ recheck?(taskId: string): Promise<RecheckView>;
282
+ /** Whether a passing check stands given every earlier attempt on the same commit (an earlier failure that wasn't
283
+ * confirmed infrastructure isn't erased by a pass), and what passed only on a retry. */
284
+ standing?(taskId: string, run: number): Promise<{
285
+ ok: true;
286
+ retried: string[] | null;
287
+ } | {
288
+ ok: false;
289
+ why: string;
290
+ retried: string[] | null;
291
+ }>;
292
+ /** Releases that approve themselves when green (docs/plans/auto-approve-green.md): the plane's own seals, each proven
293
+ * again inside the plane. Absent: a plane that can't, and every release asks a person as before. */
294
+ auto?: AutoReleaseAdapter;
295
+ };
296
+ /** The plane's automatic release approval, as the coordinator asks it. Every answer is the plane's own: the coordinator
297
+ * hands it ids, never evidence (the plane reads GitHub CI itself for `approve`). */
298
+ export type AutoReleaseAdapter = {
299
+ /** The project's "Approve automatically when checks pass", read now (off when unreadable). */
300
+ setting(taskId: string): Promise<boolean>;
301
+ /** Seal `auto-check` so the release check runs before anyone approves. */
302
+ authorizeCheck(input: {
303
+ taskId: string;
304
+ digest: string;
305
+ candidate: string;
306
+ }): Promise<{
307
+ ok: true;
308
+ } | {
309
+ ok: false;
310
+ why: string;
311
+ }>;
312
+ /** Whether the `auto-check` seal still stands (the setting on, its evidence, the digest). */
313
+ checking(taskId: string): Promise<{
314
+ ok: true;
315
+ } | {
316
+ ok: false;
317
+ why: string;
318
+ }>;
319
+ /** Observe CI on the candidate and, when everything passed, seal `auto-green` (opening the release's authority). */
320
+ approve(input: {
321
+ taskId: string;
322
+ digest: string;
323
+ candidate: string;
324
+ run: number;
325
+ receipt: string;
326
+ }): Promise<{
327
+ ok: true;
328
+ by: string;
329
+ at: string;
330
+ ci: {
331
+ id: number;
332
+ name: string;
333
+ }[];
334
+ } | {
335
+ ok: false;
336
+ why: string;
337
+ }>;
338
+ /** The automatic road ended without a release: the task asks a person, and the owner is told why. */
339
+ giveUp(taskId: string, why: string): Promise<void>;
340
+ /** The task is filed while CI still runs on `candidate` (recorded in the plane before the task is filed): its approval
341
+ * card says so until the plane reads CI passing. It holds nothing (Alex, 2026-10-29: a person may approve during CI). */
342
+ ciRunning?(taskId: string, candidate: string): Promise<void>;
343
+ /** The plane reads CI on `candidate` itself and, when every required check passed, ends the "CI still running" note
344
+ * (and lifts a hold an older coordinator placed); `ask` tells the owner of a held release it needs them now. */
345
+ ciPassed?(taskId: string, candidate: string, ask: boolean): Promise<{
346
+ ok: true;
347
+ } | {
348
+ ok: false;
349
+ why: string;
350
+ }>;
351
+ /** The release check failed while checking automatically: the owner is told; the commit may be checked again (a
352
+ * regate of the same commit and digest, within the plane's cap on failed runs). */
353
+ checkFailed(taskId: string, why: string): Promise<void>;
354
+ /** "Released 0.9.x automatically". */
355
+ released(taskId: string, tag: string): Promise<void>;
356
+ /** CI stopped passing after the merge of an automatic release: hold its tag, publication and Homebrew until a person
357
+ * lets it go on (`toolroll release publish-ok`). Durable, in the plane. */
358
+ holdPublish(taskId: string, why: string): Promise<void>;
359
+ /** Why the release's publication waits for a person, or null. Read from the plane, whatever the journal says. */
360
+ publishHeld(taskId: string): Promise<string | null>;
218
361
  };
219
362
  export type ReleaseAdapters = {
220
363
  /** One approval per release (release-once.md); absent on a plane that can't carry. */
@@ -232,10 +375,6 @@ export type ReleaseAdapters = {
232
375
  deleteBranch(branch: string, head: string): Promise<void>;
233
376
  tree(sha: string): Promise<string>;
234
377
  fileAt(sha: string, path: string): Promise<string | null>;
235
- /** origin/main as the last sync fetched it. */
236
- mainHead(): Promise<string>;
237
- /** Whether `ancestor` is in `sha`'s history. */
238
- contains(sha: string, ancestor: string): Promise<boolean>;
239
378
  };
240
379
  toolroll: {
241
380
  /** Which runtime each launchd service and each CLI name (`toolroll`, `standing-orders`) runs from. */
@@ -304,7 +443,17 @@ export type ReleaseAdapters = {
304
443
  authenticated(): Promise<boolean>;
305
444
  pullRequest(repo: string, branch: string): Promise<PullRequest | null>;
306
445
  checks(repo: string, sha: string): Promise<CheckRun[]>;
446
+ /** Whether GitHub's check history of this commit can be read whole (fewer check suites than the check-runs
447
+ * endpoint's ceiling). Absent or false: an automatic release fails closed; a person's is unaffected. */
448
+ complete?(repo: string, sha: string): Promise<boolean>;
307
449
  merge(repo: string, pr: number, head: string, message?: string): Promise<string>;
450
+ /** main's head as GitHub's API answers now (never a local ref a build could move). */
451
+ mainHead(repo: string): Promise<string>;
452
+ /** Whether `sha` already holds `ancestor`, by GitHub's own comparison. */
453
+ contains(repo: string, sha: string, ancestor: string): Promise<boolean>;
454
+ /** Whether GitHub refuses to merge a branch that is behind main ("Require branches to be up to date before
455
+ * merging"); null when it can't be read. Read only. */
456
+ upToDateRequired(repo: string): Promise<MainProtection | null>;
308
457
  tag(repo: string, tag: string): Promise<string | null>;
309
458
  createTag(repo: string, tag: string, sha: string): Promise<void>;
310
459
  release(repo: string, tag: string): Promise<boolean>;
@@ -406,6 +555,20 @@ export type ReleaseJournal = {
406
555
  needsApproval?: boolean;
407
556
  /** This journal's task was picked fresh after a CI failure after the deploy: an id that never existed, never another. */
408
557
  freshTask?: boolean;
558
+ /** The automatic road (auto-approve-green.md): `checking` once the plane sealed `auto-check`, `approved` once it sealed
559
+ * `auto-green`, `refused` (and why) when it wouldn't — then a person approves, as before. */
560
+ auto?: {
561
+ state: "checking" | "approved" | "refused";
562
+ why?: string;
563
+ ci?: number[];
564
+ } | null;
565
+ /** The gate filed the task while the pull request's checks still ran (pipeline-speed.md, D2 and "Decision: a person's
566
+ * release asks during CI"): the release check runs beside CI. A person may approve meanwhile; the plane's automatic
567
+ * approval waits for every check to pass, and nothing deploys, merges, tags or publishes before they do. */
568
+ ciAhead?: boolean;
569
+ /** Set with ciAhead and never cleared for this commit: a person's release reads CI again, fresh, right before the
570
+ * deploy, whatever was seen while asking (a green CI may have a newer attempt failing since). */
571
+ ciBeforeDeploy?: boolean;
409
572
  /** When each step was about to change something outside this machine: what a resume must look for before acting. */
410
573
  intents: Partial<Record<ReleaseStep, string>>;
411
574
  stopped: {
@@ -476,4 +639,42 @@ export declare function checksVerdict(runs: readonly CheckRun[], required: reado
476
639
  export declare function runRelease(options: ReleaseOptions, adapters: ReleaseAdapters): Promise<ReleaseOutcome>;
477
640
  /** A probe's failure that is only the network to GitHub being slow, never a decision (a Stop) or another error. */
478
641
  export declare function transientNetworkError(error: unknown): boolean;
642
+ /**
643
+ * The pull request's checks on exactly `head`, every attempt (the adapter asks GitHub for all of them, filter=all):
644
+ * each reported attempt must be filed under `head` with a check-run id; a required check counts only from GitHub
645
+ * Actions (an app that names a check alike can't stand in for it); attempts are grouped by the job they belong to — the
646
+ * app, its check suite (a workflow run, whose re-runs stay in it) and the name — and every group is judged by its
647
+ * latest attempt; every required check needs a group. With `auto` (an automatic approval), every other failed attempt on
648
+ * the commit — an earlier attempt, or a job a newer run renamed or dropped — must be one GitHub's own job record shows ending before any workflow step ran (`beforeTests`: confirmed
649
+ * infrastructure), and at most INFRA_RERUNS_PER_CANDIDATE of them on the commit; any other earlier failure — a test,
650
+ * a typecheck, or one nothing explains — fails the verdict, so a person decides. The failures it tolerated are returned.
651
+ */
652
+ export declare function prChecksVerdict(runs: readonly CheckRun[], head: string, required: readonly string[], options?: {
653
+ auto?: true;
654
+ workflow?: string;
655
+ }): {
656
+ state: "passed";
657
+ failures: CheckFailure[];
658
+ } | {
659
+ state: "pending";
660
+ waiting: string[];
661
+ } | {
662
+ state: "failed";
663
+ failed: string[];
664
+ };
665
+ /**
666
+ * What a failed release check means and what happens next, by its class (check-failure.ts), in words. Only confirmed
667
+ * infrastructure reruns on its own; nothing else is rerun to pass.
668
+ */
669
+ export declare function checkFailedWords(input: {
670
+ sha: string;
671
+ run: number;
672
+ class: FailureClassName | null;
673
+ why: string;
674
+ branch: string;
675
+ checkout: string;
676
+ taskId: string;
677
+ }): string;
678
+ /** Whether GitHub's workflow-run `path` names exactly `file` (it may carry the ref it ran from, after an `@`). */
679
+ export declare function workflowIs(path: string | null | undefined, file: string): boolean;
479
680
  export {};