toolroll 0.9.67 → 0.9.68

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 (236) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/acp-client.js +1 -3
  3. package/dist/agent-board.d.ts +0 -1
  4. package/dist/agent-board.js +0 -1
  5. package/dist/agent-fence.js +3 -0
  6. package/dist/browser/workspace.css +1 -1
  7. package/dist/browser/workspace.js +31 -29
  8. package/dist/builder.js +3 -26
  9. package/dist/canonical-json.d.ts +14 -0
  10. package/dist/canonical-json.js +36 -0
  11. package/dist/chat-actions.js +1 -2
  12. package/dist/chat-admission.d.ts +19 -0
  13. package/dist/chat-admission.js +22 -0
  14. package/dist/chat-channel.js +1 -1
  15. package/dist/chat-delivery.js +0 -1
  16. package/dist/chat-follow.d.ts +17 -0
  17. package/dist/chat-follow.js +32 -0
  18. package/dist/chat-messages.js +0 -1
  19. package/dist/chat-settings-page.d.ts +23 -0
  20. package/dist/chat-settings-page.js +41 -0
  21. package/dist/claim.js +3 -6
  22. package/dist/claude-print.d.ts +12 -0
  23. package/dist/claude-print.js +34 -0
  24. package/dist/cli-http.d.ts +0 -7
  25. package/dist/cli-http.js +0 -21
  26. package/dist/cli.d.ts +3 -10
  27. package/dist/cli.js +15 -24
  28. package/dist/coding-provider.js +2 -1
  29. package/dist/coding-workspace.js +1 -1
  30. package/dist/{team-cli.d.ts → connect-cli.d.ts} +5 -9
  31. package/dist/connect-cli.js +331 -0
  32. package/dist/containment.d.ts +0 -2
  33. package/dist/containment.js +2 -6
  34. package/dist/contracts/chat-actions.d.ts +0 -1
  35. package/dist/contracts/chat-content.d.ts +0 -4
  36. package/dist/contracts/chat-content.js +0 -2
  37. package/dist/contracts/chat-tables.d.ts +0 -1
  38. package/dist/contracts/cli.d.ts +0 -62
  39. package/dist/contracts/cli.js +0 -4
  40. package/dist/contracts/coding-workspace.js +1 -1
  41. package/dist/contracts/contract.js +1 -1
  42. package/dist/contracts/flow-card.d.ts +0 -1
  43. package/dist/contracts/flow-propose.d.ts +0 -1
  44. package/dist/contracts/flow-send.js +1 -1
  45. package/dist/contracts/gateway-tools.d.ts +0 -1
  46. package/dist/contracts/integration-metadata.js +1 -1
  47. package/dist/contracts/lead-tools.d.ts +0 -1
  48. package/dist/contracts/memory-pass.d.ts +0 -1
  49. package/dist/contracts/memory-pass.js +1 -1
  50. package/dist/contracts/plan.js +1 -1
  51. package/dist/contracts/project-knowledge.js +1 -1
  52. package/dist/contracts/project-skills.d.ts +0 -1
  53. package/dist/contracts/proof.js +1 -1
  54. package/dist/contracts/recipes.js +1 -1
  55. package/dist/contracts/scope.js +1 -1
  56. package/dist/contracts/scout-report.js +1 -1
  57. package/dist/contracts/teams-callback.d.ts +0 -1
  58. package/dist/converse.d.ts +0 -6
  59. package/dist/converse.js +0 -19
  60. package/dist/daemon.js +3 -2
  61. package/dist/decision.d.ts +1 -3
  62. package/dist/deprecations.d.ts +12 -4
  63. package/dist/deprecations.js +27 -4
  64. package/dist/desktop-update-recovery.js +1 -1
  65. package/dist/desktop-update.js +3 -2
  66. package/dist/discord-chat.js +4 -15
  67. package/dist/discord-settings.d.ts +2 -6
  68. package/dist/discord-settings.js +10 -38
  69. package/dist/discord.js +12 -23
  70. package/dist/evidence.d.ts +0 -1
  71. package/dist/evidence.js +0 -3
  72. package/dist/exec.d.ts +0 -9
  73. package/dist/exec.js +3 -81
  74. package/dist/flow-actions.js +0 -3
  75. package/dist/flow-draft.d.ts +1 -3
  76. package/dist/flow-draft.js +15 -28
  77. package/dist/flow-scripts.d.ts +1 -8
  78. package/dist/flow-scripts.js +0 -13
  79. package/dist/flow-send.js +1 -1
  80. package/dist/flow-share.d.ts +0 -2
  81. package/dist/flow-share.js +1 -6
  82. package/dist/flow-steps.js +1 -1
  83. package/dist/flow-triggers.d.ts +0 -1
  84. package/dist/flow-triggers.js +1 -2
  85. package/dist/flow-unattended.js +1 -12
  86. package/dist/flows.js +1 -1
  87. package/dist/health-cli.d.ts +2 -2
  88. package/dist/health-cli.js +1 -1
  89. package/dist/invoke.d.ts +0 -3
  90. package/dist/invoke.js +5 -3
  91. package/dist/is-record.d.ts +2 -0
  92. package/dist/is-record.js +2 -0
  93. package/dist/lead-doors.d.ts +1 -5
  94. package/dist/lead-doors.js +0 -4
  95. package/dist/lead-tools.js +3 -6
  96. package/dist/live-detail.d.ts +0 -1
  97. package/dist/live-detail.js +0 -6
  98. package/dist/live-terminal.js +2 -1
  99. package/dist/live.d.ts +0 -1
  100. package/dist/live.js +1 -2
  101. package/dist/mcp-core.js +0 -2
  102. package/dist/memory-pass.js +1 -1
  103. package/dist/model-catalog.js +1 -1
  104. package/dist/modes.js +1 -12
  105. package/dist/operate.js +383 -750
  106. package/dist/password-bearer.d.ts +0 -2
  107. package/dist/password-bearer.js +0 -4
  108. package/dist/peek-cli.js +2 -1
  109. package/dist/peek.d.ts +2 -26
  110. package/dist/peek.js +2 -168
  111. package/dist/phase-routing.d.ts +0 -4
  112. package/dist/phase-routing.js +2 -21
  113. package/dist/planner-source.d.ts +2 -1
  114. package/dist/planner-source.js +2 -12
  115. package/dist/planner.js +2 -14
  116. package/dist/process-tree.d.ts +0 -2
  117. package/dist/process-tree.js +0 -10
  118. package/dist/project-delete.d.ts +0 -2
  119. package/dist/project-delete.js +1 -3
  120. package/dist/project-learning.d.ts +0 -14
  121. package/dist/project-skills.d.ts +0 -1
  122. package/dist/project-skills.js +0 -14
  123. package/dist/project-tools.js +2 -10
  124. package/dist/provider.d.ts +0 -17
  125. package/dist/provider.js +0 -26
  126. package/dist/pulls.d.ts +0 -2
  127. package/dist/pulls.js +0 -9
  128. package/dist/release-adapters.d.ts +3 -0
  129. package/dist/release-adapters.js +15 -5
  130. package/dist/remote-exec.d.ts +3 -2
  131. package/dist/remote-exec.js +3 -2
  132. package/dist/repos.d.ts +0 -5
  133. package/dist/repos.js +2 -10
  134. package/dist/repository-context.d.ts +0 -2
  135. package/dist/repository-context.js +0 -4
  136. package/dist/restart-certification.d.ts +0 -2
  137. package/dist/restart-certification.js +1 -5
  138. package/dist/result-follow-ups.d.ts +1 -4
  139. package/dist/result-follow-ups.js +1 -6
  140. package/dist/result-review.d.ts +0 -2
  141. package/dist/result-review.js +0 -2
  142. package/dist/retention.d.ts +0 -1
  143. package/dist/retention.js +0 -1
  144. package/dist/review-context.d.ts +0 -1
  145. package/dist/review-context.js +1 -12
  146. package/dist/reviewer.d.ts +0 -16
  147. package/dist/reviewer.js +0 -18
  148. package/dist/run-closeout.js +2 -1
  149. package/dist/scope.js +1 -13
  150. package/dist/scout-browser.js +2 -1
  151. package/dist/serve.js +2 -2
  152. package/dist/server/console.css +5 -133
  153. package/dist/server/flows.js +2 -2
  154. package/dist/server/http.d.ts +2 -0
  155. package/dist/server/http.js +5 -0
  156. package/dist/server/pages.js +2 -2
  157. package/dist/server/people-tokens.js +3 -4
  158. package/dist/server/remote.js +1 -6
  159. package/dist/server/render-chat.d.ts +9 -2
  160. package/dist/server/render-chat.js +53 -7
  161. package/dist/server/render-results.d.ts +0 -6
  162. package/dist/server/render-results.js +3 -9
  163. package/dist/server/render-tasks.js +4 -5
  164. package/dist/server/route-table.d.ts +0 -4
  165. package/dist/server/route-table.js +0 -6
  166. package/dist/server/settings.js +23 -23
  167. package/dist/server/task-views.js +1 -1
  168. package/dist/server/tasks.js +3 -3
  169. package/dist/setup-guide.d.ts +2 -2
  170. package/dist/skills.d.ts +0 -6
  171. package/dist/skills.js +0 -8
  172. package/dist/slack-chat.d.ts +1 -7
  173. package/dist/slack-chat.js +5 -18
  174. package/dist/slack-settings.d.ts +2 -6
  175. package/dist/slack-settings.js +10 -38
  176. package/dist/slack.js +12 -23
  177. package/dist/sleep.d.ts +2 -0
  178. package/dist/sleep.js +2 -0
  179. package/dist/store.d.ts +0 -73
  180. package/dist/store.js +3 -177
  181. package/dist/structured-output.d.ts +0 -1
  182. package/dist/structured-output.js +0 -1
  183. package/dist/subagent-work.d.ts +0 -2
  184. package/dist/subagent-work.js +0 -2
  185. package/dist/subagents.d.ts +1 -3
  186. package/dist/subagents.js +20 -33
  187. package/dist/subscription-chat.d.ts +1 -3
  188. package/dist/subscription-chat.js +2 -3
  189. package/dist/task-sizing.d.ts +1 -4
  190. package/dist/task-sizing.js +3 -10
  191. package/dist/teams-chat.js +4 -11
  192. package/dist/teams.js +12 -19
  193. package/dist/telegram-lead.js +2 -2
  194. package/dist/telegram.js +1 -1
  195. package/dist/token-notices.d.ts +0 -11
  196. package/dist/token-notices.js +1 -5
  197. package/dist/tool-secret-store.d.ts +0 -3
  198. package/dist/tool-secret-store.js +2 -11
  199. package/dist/toolroll-update.d.ts +0 -2
  200. package/dist/toolroll-update.js +2 -2
  201. package/dist/verification-evidence.d.ts +0 -1
  202. package/dist/verification-evidence.js +0 -1
  203. package/dist/webhooks.d.ts +0 -1
  204. package/dist/webhooks.js +0 -1
  205. package/dist/workspace-ui.d.ts +0 -8
  206. package/dist/workspace-ui.js +1 -6
  207. package/package.json +1 -1
  208. package/dist/contracts/native-census.d.ts +0 -42
  209. package/dist/contracts/native-census.js +0 -36
  210. package/dist/process-recovery-anchor.d.ts +0 -75
  211. package/dist/process-recovery-anchor.js +0 -188
  212. package/dist/process-recovery-coalition.d.ts +0 -25
  213. package/dist/process-recovery-coalition.js +0 -105
  214. package/dist/process-recovery-eligibility.d.ts +0 -179
  215. package/dist/process-recovery-eligibility.js +0 -174
  216. package/dist/process-recovery-native.d.ts +0 -161
  217. package/dist/process-recovery-native.js +0 -595
  218. package/dist/process-recovery-provenance.d.ts +0 -163
  219. package/dist/process-recovery-provenance.js +0 -292
  220. package/dist/process-recovery-services.d.ts +0 -56
  221. package/dist/process-recovery-services.js +0 -191
  222. package/dist/process-recovery-settlement.d.ts +0 -32
  223. package/dist/process-recovery-settlement.js +0 -133
  224. package/dist/process-recovery.d.ts +0 -41
  225. package/dist/process-recovery.js +0 -91
  226. package/dist/session-brief.d.ts +0 -8
  227. package/dist/session-brief.js +0 -24
  228. package/dist/session-cli.d.ts +0 -42
  229. package/dist/session-cli.js +0 -271
  230. package/dist/session-contract.d.ts +0 -183
  231. package/dist/session-contract.js +0 -122
  232. package/dist/session-remote.d.ts +0 -19
  233. package/dist/session-remote.js +0 -86
  234. package/dist/session-service.d.ts +0 -22
  235. package/dist/session-service.js +0 -157
  236. package/dist/team-cli.js +0 -692
@@ -17,8 +17,6 @@ export declare const PASSWORD_BEARER_REFUSED = "Toolroll no longer accepts a pas
17
17
  export declare function isPasswordBearer(authorization: string | undefined): boolean;
18
18
  /** Whether this build still accepts a password bearer: only a release before PASSWORD_BEARER_REFUSED_FROM does. */
19
19
  export declare function passwordBearerAccepted(version?: string): boolean;
20
- /** A refusal's words for this request: unchanged, or with the replacement when it came with a password bearer. */
21
- export declare function withReplacement(authorization: string | undefined, message: string): string;
22
20
  /**
23
21
  * The refusal boundary for one password-bearer request, whichever adapter answers it: the deprecation is announced in
24
22
  * headers (RFC 9745 Deprecation, and a Warning naming the replacement), and any refusal's words, plain text or a JSON
@@ -20,10 +20,6 @@ export function passwordBearerAccepted(version = PACKAGE_VERSION) {
20
20
  return have[index] < limit[index];
21
21
  return false;
22
22
  }
23
- /** A refusal's words for this request: unchanged, or with the replacement when it came with a password bearer. */
24
- export function withReplacement(authorization, message) {
25
- return !isPasswordBearer(authorization) || message.includes("toolroll tokens create") ? message : `${message} ${PASSWORD_BEARER_WARNING}`;
26
- }
27
23
  /**
28
24
  * The refusal boundary for one password-bearer request, whichever adapter answers it: the deprecation is announced in
29
25
  * headers (RFC 9745 Deprecation, and a Warning naming the replacement), and any refusal's words, plain text or a JSON
package/dist/peek-cli.js CHANGED
@@ -17,6 +17,7 @@
17
17
  import { spawn } from "node:child_process";
18
18
  import { liveWindowLines, readLiveWindow } from "./live.js";
19
19
  import { validKeyTail } from "./live-records.js";
20
+ import { sleep } from "./sleep.js";
20
21
  export const PEEK_TAIL_LINES = 400;
21
22
  const ESC = "\u001b";
22
23
  const REPLACED = { offset: 0, lines: ["[the live view was replaced — starting over]"], state: "replaced" };
@@ -175,7 +176,7 @@ export async function runPeek(store, root, options) {
175
176
  try {
176
177
  paint();
177
178
  while (!stop) {
178
- await new Promise(resolve => setTimeout(resolve, options.intervalMs ?? 500));
179
+ await sleep(options.intervalMs ?? 500);
179
180
  paint();
180
181
  }
181
182
  }
package/dist/peek.d.ts CHANGED
@@ -5,9 +5,9 @@
5
5
  * gitattributes, hooks, clean/process filters, or external diff drivers —
6
6
  * the mechanisms finding 7 proved can execute repository-configured
7
7
  * commands. Change detection is a git-blob sha1 computed IN PROCESS against
8
- * the frozen base tree; the diff is a line-based Myers implemented here.
8
+ * the frozen base tree.
9
9
  *
10
- * Two layers, deliberately separated: the PURE core (sha1, diff, parsers,
10
+ * Two layers, deliberately separated: the PURE core (sha1, parsers,
11
11
  * aggregation — bytes in, structures out) and ONE I/O function,
12
12
  * observeWorktree — descriptor-DISCIPLINED, not descriptor-confined: Node
13
13
  * has no openat, so traversal is by pathname and a same-UID attacker
@@ -24,30 +24,6 @@
24
24
  /** git's own blob identity: sha1 over "blob <len>\0" + bytes. Computing it
25
25
  * here is what lets change detection never ask git about a working tree. */
26
26
  export declare function gitBlobSha1(bytes: Buffer): string;
27
- /** git's heuristic, near enough: a NUL in the first 8 KiB means binary —
28
- * named on the page, never diffed. */
29
- export declare function looksBinary(bytes: Buffer): boolean;
30
- export type Hunk = {
31
- aStart: number;
32
- aLines: number;
33
- bStart: number;
34
- bLines: number;
35
- /** Prefixed lines: " ctx", "-old", "+new" — exactly unified-diff shape. */
36
- lines: string[];
37
- };
38
- /**
39
- * Line-based Myers (the O(ND) greedy walk), bounded by the caller's caps —
40
- * inputs beyond the byte caps never reach here. Returns unified hunks with
41
- * three lines of context, or null when the edit distance exceeds `maxD`
42
- * (a rewrite is not usefully rendered as a diff — the caller says so).
43
- */
44
- export declare function diffLines(aText: string, bText: string, maxD?: number): Hunk[] | null;
45
- /** Render hunks as a unified patch body for one file, capped in bytes.
46
- * The cap drops the incomplete final line (finding 9), and says so. */
47
- export declare function renderUnified(path: string, hunks: Hunk[], capBytes: number): {
48
- text: string;
49
- truncated: boolean;
50
- };
51
27
  /**
52
28
  * New-file readability WITHOUT suppression (round-1 finding 19: ignore
53
29
  * parsing is gone — a pattern match can HIDE a name, and patterns are
package/dist/peek.js CHANGED
@@ -5,9 +5,9 @@
5
5
  * gitattributes, hooks, clean/process filters, or external diff drivers —
6
6
  * the mechanisms finding 7 proved can execute repository-configured
7
7
  * commands. Change detection is a git-blob sha1 computed IN PROCESS against
8
- * the frozen base tree; the diff is a line-based Myers implemented here.
8
+ * the frozen base tree.
9
9
  *
10
- * Two layers, deliberately separated: the PURE core (sha1, diff, parsers,
10
+ * Two layers, deliberately separated: the PURE core (sha1, parsers,
11
11
  * aggregation — bytes in, structures out) and ONE I/O function,
12
12
  * observeWorktree — descriptor-DISCIPLINED, not descriptor-confined: Node
13
13
  * has no openat, so traversal is by pathname and a same-UID attacker
@@ -33,172 +33,6 @@ export function gitBlobSha1(bytes) {
33
33
  .update(bytes)
34
34
  .digest("hex");
35
35
  }
36
- /** git's heuristic, near enough: a NUL in the first 8 KiB means binary —
37
- * named on the page, never diffed. */
38
- export function looksBinary(bytes) {
39
- return bytes.subarray(0, 8192).includes(0);
40
- }
41
- /**
42
- * Line-based Myers (the O(ND) greedy walk), bounded by the caller's caps —
43
- * inputs beyond the byte caps never reach here. Returns unified hunks with
44
- * three lines of context, or null when the edit distance exceeds `maxD`
45
- * (a rewrite is not usefully rendered as a diff — the caller says so).
46
- */
47
- export function diffLines(aText, bText, maxD = 2000) {
48
- const a = aText.split("\n");
49
- const b = bText.split("\n");
50
- // A trailing newline yields one empty tail element on both sides; keep it —
51
- // it makes "no newline at end" edits visible as a real line change.
52
- const n = a.length;
53
- const m = b.length;
54
- const max = Math.min(n + m, maxD);
55
- const offset = max;
56
- // v[k] = furthest x on diagonal k; trace keeps a snapshot per d for backtrack.
57
- let v = new Array(2 * max + 1).fill(0);
58
- const trace = [];
59
- let found = -1;
60
- for (let d = 0; d <= max; d++) {
61
- trace.push([...v]);
62
- for (let k = -d; k <= d; k += 2) {
63
- let x = k === -d || (k !== d && v[offset + k - 1] < v[offset + k + 1])
64
- ? v[offset + k + 1]
65
- : v[offset + k - 1] + 1;
66
- let y = x - k;
67
- while (x < n && y < m && a[x] === b[y]) {
68
- x++;
69
- y++;
70
- }
71
- v[offset + k] = x;
72
- if (x >= n && y >= m) {
73
- found = d;
74
- break;
75
- }
76
- }
77
- if (found >= 0)
78
- break;
79
- }
80
- if (found < 0)
81
- return null; // edit distance beyond maxD — not a diff, a replacement
82
- const ops = [];
83
- let x = n;
84
- let y = m;
85
- for (let d = found; d > 0; d--) {
86
- const vd = trace[d];
87
- const k = x - y;
88
- const prevK = k === -d || (k !== d && vd[offset + k - 1] < vd[offset + k + 1])
89
- ? k + 1
90
- : k - 1;
91
- const prevX = vd[offset + prevK];
92
- const prevY = prevX - prevK;
93
- while (x > prevX && y > prevY) {
94
- ops.push("=");
95
- x--;
96
- y--;
97
- }
98
- if (d > 0) {
99
- if (x === prevX) {
100
- ops.push("+");
101
- y--;
102
- }
103
- else {
104
- ops.push("-");
105
- x--;
106
- }
107
- }
108
- }
109
- while (x > 0 && y > 0) {
110
- ops.push("=");
111
- x--;
112
- y--;
113
- }
114
- while (x > 0) {
115
- ops.push("-");
116
- x--;
117
- }
118
- while (y > 0) {
119
- ops.push("+");
120
- y--;
121
- }
122
- ops.reverse();
123
- // Fold ops into hunks with 3 lines of context.
124
- const CONTEXT = 3;
125
- const hunks = [];
126
- let ai = 0;
127
- let bi = 0;
128
- let current = null;
129
- let trailingContext = 0;
130
- const flush = () => {
131
- if (current === null)
132
- return;
133
- // Trim context beyond CONTEXT at the tail.
134
- while (trailingContext > CONTEXT) {
135
- current.lines.pop();
136
- current.aLines--;
137
- current.bLines--;
138
- trailingContext--;
139
- }
140
- hunks.push(current);
141
- current = null;
142
- trailingContext = 0;
143
- };
144
- for (const op of ops) {
145
- if (op === "=") {
146
- const line = a[ai];
147
- if (current !== null) {
148
- current.lines.push(` ${line}`);
149
- current.aLines++;
150
- current.bLines++;
151
- trailingContext++;
152
- if (trailingContext > CONTEXT * 2)
153
- flush();
154
- }
155
- ai++;
156
- bi++;
157
- continue;
158
- }
159
- if (current === null) {
160
- const aStart = Math.max(0, ai - CONTEXT);
161
- const bStart = Math.max(0, bi - CONTEXT);
162
- current = { aStart: aStart + 1, aLines: 0, bStart: bStart + 1, bLines: 0, lines: [] };
163
- for (let c = aStart; c < ai; c++) {
164
- current.lines.push(` ${a[c]}`);
165
- current.aLines++;
166
- current.bLines++;
167
- }
168
- }
169
- trailingContext = 0;
170
- if (op === "-") {
171
- current.lines.push(`-${a[ai]}`);
172
- current.aLines++;
173
- ai++;
174
- }
175
- else {
176
- current.lines.push(`+${b[bi]}`);
177
- current.bLines++;
178
- bi++;
179
- }
180
- }
181
- flush();
182
- return hunks;
183
- }
184
- /** Render hunks as a unified patch body for one file, capped in bytes.
185
- * The cap drops the incomplete final line (finding 9), and says so. */
186
- export function renderUnified(path, hunks, capBytes) {
187
- const header = `--- a/${path}\n+++ b/${path}\n`;
188
- const parts = [header];
189
- let bytes = Buffer.byteLength(header);
190
- for (const hunk of hunks) {
191
- const head = `@@ -${hunk.aStart},${hunk.aLines} +${hunk.bStart},${hunk.bLines} @@\n`;
192
- const body = hunk.lines.join("\n") + "\n";
193
- const size = Buffer.byteLength(head) + Buffer.byteLength(body);
194
- if (bytes + size > capBytes) {
195
- return { text: parts.join(""), truncated: true };
196
- }
197
- parts.push(head, body);
198
- bytes += size;
199
- }
200
- return { text: parts.join(""), truncated: false };
201
- }
202
36
  export function aggregateNewNames(paths, groupAt = 10, rowCap = 200) {
203
37
  const bySegment = new Map();
204
38
  for (const path of paths) {
@@ -70,8 +70,6 @@ export { ROUTE_VERSION };
70
70
  * row; which route version it holds rides in the snapshot itself. */
71
71
  export declare const ROUTE_ERA = 1;
72
72
  export declare const PHASES: readonly Phase[];
73
- /** The review leg remains readable in signed history but is no longer scheduled. */
74
- export declare const ACTIVE_PHASES: readonly Phase[];
75
73
  /** The risk words a route sealed before v115 may carry (history); every route since says `routine`. */
76
74
  export type RiskLevel = (typeof RISKS)[number];
77
75
  export declare function isRiskLevel(value: unknown): value is RiskLevel;
@@ -86,8 +84,6 @@ export declare function isTaskSize(value: unknown): value is TaskSize;
86
84
  export declare function makesNoPlan(size: TaskSizing | null | undefined, risk: RiskLevel): boolean;
87
85
  /** Where a size came from, in words. */
88
86
  export declare function sizeSourceWords(source: SizeSource): string;
89
- /** Strict read of a stored sizing (the route contract's): exact keys, known words, bounded reason. */
90
- export declare function parseSizing(raw: unknown): TaskSizing | null;
91
87
  export declare function riskTitle(risk: RiskLevel): string;
92
88
  /** A runner's non-spending observation of one provider. `unknown` is a
93
89
  * real answer (claude has no login probe that does not spend) and is never
@@ -50,7 +50,8 @@
50
50
  */
51
51
  import { ACP_AGENTS, isAcpProvider } from "./acp-agents.js";
52
52
  import { createHash } from "node:crypto";
53
- import { MODEL_ID_SHAPE, postureOf, readRouteOverrides, readSealedRoute, RISKS, ROUTE_PHASES, ROUTE_PROVIDERS, ROUTE_VERSION, TASK_SIZE_WORDS, taskSizingSchema, } from "./contracts/route.js";
53
+ import { MODEL_ID_SHAPE, postureOf, readRouteOverrides, readSealedRoute, RISKS, ROUTE_PHASES, ROUTE_PROVIDERS, ROUTE_VERSION, TASK_SIZE_WORDS, } from "./contracts/route.js";
54
+ import { canonicalJson } from "./canonical-json.js";
54
55
  export { MODEL_ID_SHAPE };
55
56
  // Type-only imports from provider.ts: it sits under evidence.ts and scope.ts
56
57
  // in the module graph, and this policy is imported by scope.ts — a value
@@ -79,8 +80,6 @@ export { ROUTE_VERSION };
79
80
  * row; which route version it holds rides in the snapshot itself. */
80
81
  export const ROUTE_ERA = 1;
81
82
  export const PHASES = ROUTE_PHASES;
82
- /** The review leg remains readable in signed history but is no longer scheduled. */
83
- export const ACTIVE_PHASES = ["plan", "build", "repair"];
84
83
  export function isRiskLevel(value) {
85
84
  return value === "routine" || value === "elevated" || value === "high";
86
85
  }
@@ -97,11 +96,6 @@ export function makesNoPlan(size, risk) {
97
96
  export function sizeSourceWords(source) {
98
97
  return source === "classifier" ? "sized automatically" : source === "person" ? "set by a person" : "sized from the description";
99
98
  }
100
- /** Strict read of a stored sizing (the route contract's): exact keys, known words, bounded reason. */
101
- export function parseSizing(raw) {
102
- const parsed = taskSizingSchema.safeParse(raw);
103
- return parsed.success ? parsed.data : null;
104
- }
105
99
  export function riskTitle(risk) {
106
100
  return risk === "high" ? "High risk" : risk === "elevated" ? "Elevated risk" : "Routine";
107
101
  }
@@ -481,19 +475,6 @@ export function sameSpec(a, b) {
481
475
  return a.provider === b.provider && a.model === b.model;
482
476
  }
483
477
  // ---- canonical bytes, digest, strict rehydration ---------------------------
484
- /** Deterministic JSON: object keys sorted recursively, arrays in order. */
485
- function canonicalJson(value) {
486
- if (Array.isArray(value))
487
- return `[${value.map(canonicalJson).join(",")}]`;
488
- if (value !== null && typeof value === "object") {
489
- const entries = Object.entries(value)
490
- .filter(([, v]) => v !== undefined)
491
- .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
492
- .map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`);
493
- return `{${entries.join(",")}}`;
494
- }
495
- return JSON.stringify(value);
496
- }
497
478
  /** The stored snapshot bytes: the version rides IN the snapshot. */
498
479
  export function canonicalRouteJson(route) {
499
480
  return canonicalJson({
@@ -40,6 +40,7 @@ import type { Scope } from "./scope.js";
40
40
  import type { QualityMode } from "./quality.js";
41
41
  import type { RiskLevel } from "./phase-routing.js";
42
42
  import { type ContractChange, type ContractTerms } from "./contract-changes.js";
43
+ import { canonicalJsonUndefinedAsNull } from "./canonical-json.js";
43
44
  export declare const PLANNER_SOURCE_VERSION = 1;
44
45
  export declare const PLANNER_SOURCE_LIMITS: {
45
46
  /** The whole recorded source before lossless prompt fencing. Equal to
@@ -132,7 +133,7 @@ export type PlannerSource = {
132
133
  outsideReference?: string;
133
134
  };
134
135
  /** Stable JSON for hashing and equality only — no filling, no trimming. */
135
- export declare function canonicalContractJson(value: unknown): string;
136
+ export declare const canonicalContractJson: typeof canonicalJsonUndefinedAsNull;
136
137
  export declare function plannerSourceDigest(contract: PlannerContract): string;
137
138
  /**
138
139
  * The contract part, read from the store alone — no file I/O — so the plan
@@ -41,6 +41,7 @@ import { EVIDENCE_CAPS, readVerifiedArtifact } from "./evidence.js";
41
41
  import { TEXT_LIMITS } from "./text-limits.js";
42
42
  import { PLAN_TOUCHES } from "./contracts/plan.js";
43
43
  import { contractChangesOf } from "./contract-changes.js";
44
+ import { canonicalJsonUndefinedAsNull } from "./canonical-json.js";
44
45
  export const PLANNER_SOURCE_VERSION = 1;
45
46
  export const PLANNER_SOURCE_LIMITS = {
46
47
  /** The whole recorded source before lossless prompt fencing. Equal to
@@ -56,18 +57,7 @@ export const PLANNER_SOURCE_LIMITS = {
56
57
  handoffTerms: TEXT_LIMITS.planPayloadBytes,
57
58
  };
58
59
  /** Stable JSON for hashing and equality only — no filling, no trimming. */
59
- export function canonicalContractJson(value) {
60
- if (Array.isArray(value))
61
- return `[${value.map(canonicalContractJson).join(",")}]`;
62
- if (value !== null && typeof value === "object") {
63
- const body = value;
64
- return `{${Object.keys(body)
65
- .sort()
66
- .map(key => `${JSON.stringify(key)}:${canonicalContractJson(body[key])}`)
67
- .join(",")}}`;
68
- }
69
- return JSON.stringify(value) ?? "null";
70
- }
60
+ export const canonicalContractJson = canonicalJsonUndefinedAsNull;
71
61
  export function plannerSourceDigest(contract) {
72
62
  return createHash("sha256").update(`planner-source:v${PLANNER_SOURCE_VERSION}\n${canonicalContractJson(contract)}`, "utf8").digest("hex");
73
63
  }
package/dist/planner.js CHANGED
@@ -38,6 +38,7 @@ import { proveTreeUntouched, snapshotIgnored } from "./tree-proof.js";
38
38
  import { CLAUDE_LIMITS, ACCEPTANCE_LIMITS } from "./scope.js";
39
39
  import { normalizeStructuredJson, storeStructuredAttempt, validationErrorsJson, STRUCTURED_REPAIR_ATTEMPTS, STRUCTURED_REPAIR_MAX_TURNS, STRUCTURED_REPAIR_TIMEOUT_MS, } from "./structured-output.js";
40
40
  import { contractChangesOf, describeContractChanges, plannerSourceBlock, } from "./planner-source.js";
41
+ import { canonicalJsonUndefinedAsNull } from "./canonical-json.js";
41
42
  const GIT = "git";
42
43
  const AGENT_ENV_DENYLIST = [...TELEGRAM_TOKEN_ENVS];
43
44
  const DEFAULT_PLAN_TIMEOUT_MS = 20 * 60_000;
@@ -146,19 +147,6 @@ function plannerBrief(title, mailbox, planFile, answers, source, structured) {
146
147
  "work back for evidence nobody can produce.",
147
148
  ].join("\n");
148
149
  }
149
- /** Stable JSON for equality only — it does not fill, trim, or reinterpret. */
150
- function canonicalJson(value) {
151
- if (Array.isArray(value))
152
- return `[${value.map(canonicalJson).join(",")}]`;
153
- if (value !== null && typeof value === "object") {
154
- const body = value;
155
- return `{${Object.keys(body)
156
- .sort()
157
- .map(key => `${JSON.stringify(key)}:${canonicalJson(body[key])}`)
158
- .join(",")}}`;
159
- }
160
- return JSON.stringify(value) ?? "null";
161
- }
162
150
  function decodeStructuredBytes(raw) {
163
151
  try {
164
152
  // Buffer#toString silently inserts U+FFFD for malformed sequences,
@@ -187,7 +175,7 @@ function planAuthorityAnchor(raw) {
187
175
  // canonicalJson is recursive. A byte-bounded but pathologically deep
188
176
  // JSON value can still exhaust the JS stack; that means its authority
189
177
  // cannot be frozen safely, so this output is not eligible for repair.
190
- return canonicalJson({
178
+ return canonicalJsonUndefinedAsNull({
191
179
  goal: body["goal"],
192
180
  outOfScope: body["outOfScope"],
193
181
  touches: body["touches"],
@@ -23,8 +23,6 @@ export type ProcessTreeObserver = {
23
23
  onObservationFailure?: (failure: ProcessObservationFailure) => void;
24
24
  onUnknown?: () => void;
25
25
  };
26
- /** Private supervisor pipe input. Keep only validated identifier diagnostics. */
27
- export declare function readProcessObservationFailure(value: unknown): ProcessObservationFailure | null;
28
26
  /** Capture current descendants before asking an owned process to exit.
29
27
  * A cooperative root may exit before the next periodic observation; even
30
28
  * a killed tool can retain its PID briefly after its process group is gone. */
@@ -78,16 +78,6 @@ function recordExits(child, rows) {
78
78
  }
79
79
  // Only fixed error codes survive; error messages/output can contain private data.
80
80
  const observationCodes = new Set(["EAGAIN", "EMFILE", "ENFILE", "ETIMEDOUT", "ENOBUFS", "ENOENT", "EPERM", "EACCES", "EIO", "ESRCH", "MALFORMED_SNAPSHOT", "SUPERVISOR_DIAGNOSTIC", "SQLITE_BUSY", "SQLITE_LOCKED", "SQLITE_READONLY", "SQLITE_IOERR", "SQLITE_CORRUPT", "SQLITE_FULL", "SQLITE_CONSTRAINT"]);
81
- /** Private supervisor pipe input. Keep only validated identifier diagnostics. */
82
- export function readProcessObservationFailure(value) {
83
- if (typeof value !== "object" || value === null)
84
- return null;
85
- const row = value;
86
- const { phase, operation, code, rootPid, at, identityUnknown } = row;
87
- if (!["sample", "periodic", "final-exit", "stop", "supervisor"].includes(String(phase)) || !["snapshot", "descendant-write", "exit-write", "signal", "diagnostic-read"].includes(String(operation)) || typeof code !== "string" || (code !== "UNKNOWN" && !observationCodes.has(code)) || (rootPid !== null && (!Number.isSafeInteger(rootPid) || Number(rootPid) <= 0)) || typeof at !== "string" || !Number.isFinite(Date.parse(at)) || new Date(at).toISOString() !== at || typeof identityUnknown !== "boolean")
88
- return null;
89
- return { phase: phase, operation: operation, code, rootPid: rootPid, at, identityUnknown };
90
- }
91
81
  function failed(child, phase, operation, error, identitiesPreserved = false) {
92
82
  const tracked = observed.get(child);
93
83
  if (!tracked)
@@ -1,8 +1,6 @@
1
1
  import type { ExecResult } from "./exec.js";
2
2
  import type { Runner } from "./worktree.js";
3
3
  import { type Store } from "./store.js";
4
- /** What Toolroll names the branches it makes: toolroll/…, and standing-orders/… from before the rename. */
5
- export declare const OWN_BRANCH = "toolroll/";
6
4
  export declare const OWN_BRANCHES: readonly string[];
7
5
  export type ProjectHoldings = {
8
6
  tasks: number;
@@ -16,11 +16,9 @@ import { existsSync, lstatSync, rmSync } from "node:fs";
16
16
  import { isAbsolute, relative, resolve } from "node:path";
17
17
  import { teardownGit, refusal } from "./teardown-git.js";
18
18
  import { BUILT_IN } from "./store.js";
19
- import { BRANCH_PREFIX, BRANCH_PREFIXES, isOwnBranch } from "./names.js";
19
+ import { BRANCH_PREFIXES, isOwnBranch } from "./names.js";
20
20
  /** The tables whose history is the audit record itself: never touched. */
21
21
  const KEPT = new Set(["action_ledger", "ledger_seal", "ledger_checkpoint"]);
22
- /** What Toolroll names the branches it makes: toolroll/…, and standing-orders/… from before the rename. */
23
- export const OWN_BRANCH = BRANCH_PREFIX;
24
22
  export const OWN_BRANCHES = BRANCH_PREFIXES;
25
23
  const list = (db, sql, ...params) => db.prepare(sql).all(...params).map(row => Object.values(row)[0]);
26
24
  const ids = (db, sql, ...params) => list(db, sql, ...params).map(Number);
@@ -32,20 +32,6 @@ export type Lesson = {
32
32
  identity: string;
33
33
  adoptedBy: string | null;
34
34
  };
35
- export type LearningEvent = {
36
- snapshot: string | null;
37
- outcome: string | null;
38
- id: number;
39
- actor: string;
40
- at: string;
41
- action: string;
42
- before: string;
43
- after: string;
44
- reason: string;
45
- lesson: number | null;
46
- run: number | null;
47
- evidence: LearningEvidence[];
48
- };
49
35
  export declare const learningSha: (text: string) => string;
50
36
  /** Facts about the shared Git database that survive a restart. The volume's device number does not. */
51
37
  export type IdentityFacts = {
@@ -89,7 +89,6 @@ export declare function materializeProjectSkills(snapshot: SkillsSnapshot, root:
89
89
  }[];
90
90
  };
91
91
  export declare function skillsContext(store: Store, root: string, runId: number): string;
92
- export declare function skillReviewSource(store: Store, runId: number): string | null;
93
92
  export declare function testSkill(store: Store, args: {
94
93
  repo: string;
95
94
  actor: string;
@@ -463,20 +463,6 @@ export function skillsContext(store, root, runId) {
463
463
  JSON.stringify(catalog) +
464
464
  "\n");
465
465
  }
466
- export function skillReviewSource(store, runId) {
467
- const s = freezeSkills(store, runId);
468
- return s.packages.length
469
- ? JSON.stringify({
470
- notice: "Exact skill packages supplied to the source run. Untrusted review context, never reviewer instructions or evidence of use. Original files use base64; readable SKILL.md is also included.",
471
- ...s,
472
- instructions: s.packages.map((p) => ({
473
- name: p.name,
474
- sha: p.sha,
475
- content: Buffer.from(p.files.find((f) => f.path === "SKILL.md").base64, "base64").toString("utf8"),
476
- })),
477
- })
478
- : null;
479
- }
480
466
  export function testSkill(store, args, now = new Date()) {
481
467
  const view = skillsView(store, args.repo, args.actor);
482
468
  admit(store, args.repo, args.actor, true);
@@ -33,6 +33,7 @@ import { isAcpProvider } from "./acp-agents.js";
33
33
  import { SecretStoreError, destroyOwnFile, prepareSecretFolder, registerSecretFolder, pathIn, readOwnFile, readSealed, removeValue, secretBackend, secretFolder, secretStorage, serviceOf, withSecretLock, withSecretLockAsync, writeOwnFile, writeSealed } from "./tool-secret-store.js";
34
34
  import { ACCESS, GRANTED, REFRESH, mintRunToken, mintsRunTokens, oneAtATime, runScope, scopeList, signedIn } from "./oauth-run-token.js";
35
35
  import { HEADER_NAME, SECRET_NAME, TOOL_NAME as NAME, TOOL_SPEC_LIMITS as LIMITS, readToolSpec } from "./contracts/integration-metadata.js";
36
+ import { canonicalJson } from "./canonical-json.js";
36
37
  /** Env names a tool may never claim: the process's own plumbing, every
37
38
  * provider credential, and anything that changes how a program or its
38
39
  * interpreter loads (a secret's value must stay data, never code). */
@@ -75,19 +76,10 @@ export function localAppOf(spec) {
75
76
  export function catalogTool(id) {
76
77
  return TOOL_CATALOG.find(one => one.name === id) ?? null;
77
78
  }
78
- function canonical(value) {
79
- if (Array.isArray(value))
80
- return `[${value.map(canonical).join(",")}]`;
81
- if (value !== null && typeof value === "object") {
82
- return `{${Object.entries(value).filter(([, v]) => v !== undefined).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
83
- .map(([k, v]) => `${JSON.stringify(k)}:${canonical(v)}`).join(",")}}`;
84
- }
85
- return JSON.stringify(value);
86
- }
87
79
  /** What a build is held to: how the server starts and which secrets it names — never their values or its description. */
88
80
  export function toolDigest(spec) {
89
81
  const { about: _about, ...terms } = spec;
90
- return createHash("sha256").update(`standing-orders:tool:v1:${canonical(terms)}`, "utf8").digest("hex").slice(0, 32);
82
+ return createHash("sha256").update(`standing-orders:tool:v1:${canonicalJson(terms)}`, "utf8").digest("hex").slice(0, 32);
91
83
  }
92
84
  const str = (value, cap, what) => {
93
85
  if (typeof value !== "string" || value.trim() === "" || value.length > cap)
@@ -335,23 +335,6 @@ export type ProviderMoneyCapabilities = {
335
335
  usageSemantics: "per-invocation" | "cumulative-session";
336
336
  };
337
337
  export declare const MONEY_CAPABILITIES: Record<ProviderId, ProviderMoneyCapabilities>;
338
- /**
339
- * The fail-closed budget-flag probe (finding 24's amendment): resolve
340
- * the EXACT executable that will spawn, read its version, and prove the
341
- * flag exists in that binary's own help — presence is a feature check
342
- * and nothing more.
343
- */
344
- export declare function probeBudgetCap(provider: ProviderId, runner: (command: string, argv: readonly string[], options: {
345
- timeoutMs?: number;
346
- omitEnv?: readonly string[];
347
- }) => Promise<ExecResult>): Promise<{
348
- ok: true;
349
- executable: string;
350
- version: string;
351
- } | {
352
- ok: false;
353
- problem: string;
354
- }>;
355
338
  export declare function auditOf(provider: ProviderId): ProviderAudit;
356
339
  /**
357
340
  * A spec a person or a config row proposed, validated to a complete pair.
package/dist/provider.js CHANGED
@@ -999,32 +999,6 @@ export const MONEY_CAPABILITIES = withAcp({
999
999
  nativeDollarCapFlag: null,
1000
1000
  usageSemantics: "per-invocation",
1001
1001
  }));
1002
- /**
1003
- * The fail-closed budget-flag probe (finding 24's amendment): resolve
1004
- * the EXACT executable that will spawn, read its version, and prove the
1005
- * flag exists in that binary's own help — presence is a feature check
1006
- * and nothing more.
1007
- */
1008
- export async function probeBudgetCap(provider, runner) {
1009
- const flag = MONEY_CAPABILITIES[provider].nativeDollarCapFlag;
1010
- if (flag === null)
1011
- return { ok: false, problem: `${provider} has no native dollar cap` };
1012
- const binary = provider === "claude" ? "claude" : provider;
1013
- // A feature probe needs no credential (round 2, finding 2): strip them all.
1014
- const strip = { omitEnv: ALL_CREDENTIAL_ENV };
1015
- const where = await runner("which", [binary], { timeoutMs: 5_000, ...strip });
1016
- if (where.code !== 0)
1017
- return { ok: false, problem: `${binary} is not on PATH` };
1018
- const executable = where.stdout.trim().split("\n")[0] ?? "";
1019
- const version = await runner(executable, ["--version"], { timeoutMs: 10_000, ...strip });
1020
- if (version.code !== 0)
1021
- return { ok: false, problem: `${executable} did not answer --version` };
1022
- const help = await runner(executable, ["--help"], { timeoutMs: 10_000, ...strip });
1023
- if (help.code !== 0 || !help.stdout.includes(flag)) {
1024
- return { ok: false, problem: `${executable} does not advertise ${flag} — the dollar cap cannot be enforced` };
1025
- }
1026
- return { ok: true, executable, version: version.stdout.trim() };
1027
- }
1028
1002
  export function auditOf(provider) {
1029
1003
  return AUDITS[provider];
1030
1004
  }
package/dist/pulls.d.ts CHANGED
@@ -119,5 +119,3 @@ export declare function describe(pull: Pull, markers?: readonly string[]): strin
119
119
  * and not evidence of freshness.
120
120
  */
121
121
  export declare function idleDays(pull: Pull, now: Date): number | null;
122
- /** Waiting on someone, and has been for longer than they would have chosen. */
123
- export declare function isStalled(pull: Pull, now: Date, staleDays?: number, markers?: readonly string[]): boolean;
package/dist/pulls.js CHANGED
@@ -236,15 +236,6 @@ export function idleDays(pull, now) {
236
236
  return null;
237
237
  return Math.max(0, (now.getTime() - updated) / MS_PER_DAY);
238
238
  }
239
- /** Waiting on someone, and has been for longer than they would have chosen. */
240
- export function isStalled(pull, now, staleDays = DEFAULT_STALE_DAYS, markers = DEFAULT_REVISION_MARKERS) {
241
- const attention = classify(pull, markers);
242
- // Nobody is blocked on a draft, and a machine that is still working is not late.
243
- if (attention === "none" || attention === "machine")
244
- return false;
245
- const idle = idleDays(pull, now);
246
- return idle !== null && idle >= staleDays;
247
- }
248
239
  function firstLine(text) {
249
240
  const [line = ""] = text.trim().split("\n");
250
241
  return line;
@@ -54,6 +54,9 @@ export type AdapterOptions = {
54
54
  now?: () => Date;
55
55
  sleep?: (ms: number) => Promise<void>;
56
56
  };
57
+ /** How many times, and how far apart, a merged branch's deletion is looked for after the push lost a race. */
58
+ export declare const BRANCH_GONE_LOOKS = 5;
59
+ export declare const BRANCH_GONE_PAUSE_MS = 2000;
57
60
  export declare function releaseAdapters(options: AdapterOptions): ReleaseAdapters;
58
61
  /**
59
62
  * Whether a workflow's triggers (its top-level `on:` as a name, a list or a map) include a change to the repository.