toolroll 0.9.67 → 0.9.69

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 (250) hide show
  1. package/CHANGELOG.md +70 -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.d.ts +58 -0
  6. package/dist/agent-fence.js +214 -19
  7. package/dist/agentconfig.d.ts +1 -1
  8. package/dist/agentconfig.js +6 -2
  9. package/dist/batch-checks.js +14 -26
  10. package/dist/browser/workspace.css +1 -1
  11. package/dist/browser/workspace.js +31 -29
  12. package/dist/builder.d.ts +9 -0
  13. package/dist/builder.js +30 -27
  14. package/dist/canonical-json.d.ts +14 -0
  15. package/dist/canonical-json.js +36 -0
  16. package/dist/chat-actions.js +1 -2
  17. package/dist/chat-admission.d.ts +19 -0
  18. package/dist/chat-admission.js +22 -0
  19. package/dist/chat-channel.js +1 -1
  20. package/dist/chat-delivery.js +0 -1
  21. package/dist/chat-follow.d.ts +17 -0
  22. package/dist/chat-follow.js +32 -0
  23. package/dist/chat-messages.js +0 -1
  24. package/dist/chat-settings-page.d.ts +23 -0
  25. package/dist/chat-settings-page.js +41 -0
  26. package/dist/check-access.d.ts +54 -0
  27. package/dist/check-access.js +80 -0
  28. package/dist/claim.js +3 -6
  29. package/dist/claude-print.d.ts +12 -0
  30. package/dist/claude-print.js +34 -0
  31. package/dist/cli-http.d.ts +0 -7
  32. package/dist/cli-http.js +0 -21
  33. package/dist/cli.d.ts +3 -10
  34. package/dist/cli.js +15 -24
  35. package/dist/coding-provider.js +2 -1
  36. package/dist/coding-workspace.js +1 -1
  37. package/dist/{team-cli.d.ts → connect-cli.d.ts} +5 -9
  38. package/dist/connect-cli.js +331 -0
  39. package/dist/containment.d.ts +0 -2
  40. package/dist/containment.js +2 -6
  41. package/dist/contracts/chat-actions.d.ts +0 -1
  42. package/dist/contracts/chat-content.d.ts +0 -4
  43. package/dist/contracts/chat-content.js +0 -2
  44. package/dist/contracts/chat-tables.d.ts +0 -1
  45. package/dist/contracts/cli.d.ts +0 -62
  46. package/dist/contracts/cli.js +0 -4
  47. package/dist/contracts/coding-workspace.js +1 -1
  48. package/dist/contracts/console-api.d.ts +1 -0
  49. package/dist/contracts/console-api.js +1 -0
  50. package/dist/contracts/contract.js +1 -1
  51. package/dist/contracts/flow-card.d.ts +0 -1
  52. package/dist/contracts/flow-propose.d.ts +0 -1
  53. package/dist/contracts/flow-send.js +1 -1
  54. package/dist/contracts/gateway-tools.d.ts +0 -1
  55. package/dist/contracts/integration-metadata.js +1 -1
  56. package/dist/contracts/lead-tools.d.ts +0 -1
  57. package/dist/contracts/memory-pass.d.ts +0 -1
  58. package/dist/contracts/memory-pass.js +1 -1
  59. package/dist/contracts/plan.js +1 -1
  60. package/dist/contracts/project-knowledge.js +1 -1
  61. package/dist/contracts/project-skills.d.ts +0 -1
  62. package/dist/contracts/proof.js +1 -1
  63. package/dist/contracts/recipes.js +1 -1
  64. package/dist/contracts/scope.js +1 -1
  65. package/dist/contracts/scout-report.js +1 -1
  66. package/dist/contracts/teams-callback.d.ts +0 -1
  67. package/dist/converse.d.ts +0 -6
  68. package/dist/converse.js +0 -19
  69. package/dist/daemon.js +3 -2
  70. package/dist/decision.d.ts +1 -3
  71. package/dist/deprecations.d.ts +12 -4
  72. package/dist/deprecations.js +27 -4
  73. package/dist/desktop-update-recovery.js +1 -1
  74. package/dist/desktop-update.js +3 -2
  75. package/dist/discord-chat.js +4 -15
  76. package/dist/discord-settings.d.ts +2 -6
  77. package/dist/discord-settings.js +10 -38
  78. package/dist/discord.js +12 -23
  79. package/dist/evidence.d.ts +0 -1
  80. package/dist/evidence.js +0 -3
  81. package/dist/exec.d.ts +0 -9
  82. package/dist/exec.js +3 -81
  83. package/dist/flow-actions.js +0 -3
  84. package/dist/flow-draft.d.ts +1 -3
  85. package/dist/flow-draft.js +15 -28
  86. package/dist/flow-scripts.d.ts +1 -8
  87. package/dist/flow-scripts.js +0 -13
  88. package/dist/flow-send.js +1 -1
  89. package/dist/flow-share.d.ts +0 -2
  90. package/dist/flow-share.js +1 -6
  91. package/dist/flow-steps.js +1 -1
  92. package/dist/flow-triggers.d.ts +0 -1
  93. package/dist/flow-triggers.js +1 -2
  94. package/dist/flow-unattended.js +1 -12
  95. package/dist/flows.js +1 -1
  96. package/dist/health-cli.d.ts +2 -2
  97. package/dist/health-cli.js +1 -1
  98. package/dist/invoke.d.ts +39 -5
  99. package/dist/invoke.js +181 -24
  100. package/dist/is-record.d.ts +2 -0
  101. package/dist/is-record.js +2 -0
  102. package/dist/lead-doors.d.ts +1 -5
  103. package/dist/lead-doors.js +0 -4
  104. package/dist/lead-tools.js +3 -6
  105. package/dist/live-detail.d.ts +0 -1
  106. package/dist/live-detail.js +0 -6
  107. package/dist/live-terminal.js +2 -1
  108. package/dist/live.d.ts +0 -1
  109. package/dist/live.js +1 -2
  110. package/dist/mcp-core.js +0 -2
  111. package/dist/memory-pass.js +1 -1
  112. package/dist/model-catalog.js +1 -1
  113. package/dist/modes.js +1 -12
  114. package/dist/operate.d.ts +4 -0
  115. package/dist/operate.js +456 -750
  116. package/dist/password-bearer.d.ts +0 -2
  117. package/dist/password-bearer.js +0 -4
  118. package/dist/peek-cli.js +2 -1
  119. package/dist/peek.d.ts +2 -26
  120. package/dist/peek.js +2 -168
  121. package/dist/phase-routing.d.ts +0 -4
  122. package/dist/phase-routing.js +2 -21
  123. package/dist/planner-source.d.ts +2 -1
  124. package/dist/planner-source.js +2 -12
  125. package/dist/planner.js +2 -14
  126. package/dist/process-tree.d.ts +0 -2
  127. package/dist/process-tree.js +0 -10
  128. package/dist/project-delete-ui.d.ts +16 -0
  129. package/dist/project-delete-ui.js +60 -1
  130. package/dist/project-delete.d.ts +0 -2
  131. package/dist/project-delete.js +1 -3
  132. package/dist/project-learning.d.ts +0 -14
  133. package/dist/project-skills.d.ts +0 -1
  134. package/dist/project-skills.js +0 -14
  135. package/dist/project-tools.js +2 -10
  136. package/dist/provider.d.ts +0 -17
  137. package/dist/provider.js +0 -26
  138. package/dist/pulls.d.ts +0 -2
  139. package/dist/pulls.js +0 -9
  140. package/dist/release-adapters.d.ts +3 -0
  141. package/dist/release-adapters.js +15 -5
  142. package/dist/remote-exec.d.ts +3 -2
  143. package/dist/remote-exec.js +3 -2
  144. package/dist/repos.d.ts +0 -5
  145. package/dist/repos.js +2 -10
  146. package/dist/repository-context.d.ts +0 -2
  147. package/dist/repository-context.js +0 -4
  148. package/dist/restart-certification.d.ts +0 -2
  149. package/dist/restart-certification.js +1 -5
  150. package/dist/result-follow-ups.d.ts +1 -4
  151. package/dist/result-follow-ups.js +11 -21
  152. package/dist/result-review.d.ts +0 -2
  153. package/dist/result-review.js +0 -2
  154. package/dist/retention.d.ts +0 -1
  155. package/dist/retention.js +0 -1
  156. package/dist/review-context.d.ts +0 -1
  157. package/dist/review-context.js +1 -12
  158. package/dist/reviewer.d.ts +0 -16
  159. package/dist/reviewer.js +0 -18
  160. package/dist/run-closeout.js +2 -1
  161. package/dist/scope.d.ts +9 -0
  162. package/dist/scope.js +13 -18
  163. package/dist/scout-browser.js +2 -1
  164. package/dist/serve.js +11 -2
  165. package/dist/server/console.css +5 -133
  166. package/dist/server/flows.js +2 -2
  167. package/dist/server/http.d.ts +4 -0
  168. package/dist/server/http.js +5 -0
  169. package/dist/server/pages.js +2 -2
  170. package/dist/server/people-tokens.js +3 -4
  171. package/dist/server/remote.js +1 -6
  172. package/dist/server/render-chat.d.ts +9 -2
  173. package/dist/server/render-chat.js +53 -7
  174. package/dist/server/render-results.d.ts +3 -6
  175. package/dist/server/render-results.js +4 -9
  176. package/dist/server/render-tasks.js +6 -6
  177. package/dist/server/route-table.d.ts +0 -4
  178. package/dist/server/route-table.js +1 -6
  179. package/dist/server/settings.js +60 -23
  180. package/dist/server/task-views.js +1 -1
  181. package/dist/server/tasks.js +5 -3
  182. package/dist/setup-guide.d.ts +2 -2
  183. package/dist/skills.d.ts +0 -6
  184. package/dist/skills.js +0 -8
  185. package/dist/slack-chat.d.ts +1 -7
  186. package/dist/slack-chat.js +5 -18
  187. package/dist/slack-settings.d.ts +2 -6
  188. package/dist/slack-settings.js +10 -38
  189. package/dist/slack.js +12 -23
  190. package/dist/sleep.d.ts +2 -0
  191. package/dist/sleep.js +2 -0
  192. package/dist/store.d.ts +29 -75
  193. package/dist/store.js +89 -180
  194. package/dist/structured-output.d.ts +0 -1
  195. package/dist/structured-output.js +0 -1
  196. package/dist/subagent-work.d.ts +0 -2
  197. package/dist/subagent-work.js +0 -2
  198. package/dist/subagents.d.ts +1 -3
  199. package/dist/subagents.js +20 -33
  200. package/dist/subscription-chat.d.ts +1 -3
  201. package/dist/subscription-chat.js +2 -3
  202. package/dist/surface.js +2 -1
  203. package/dist/task-sizing.d.ts +1 -4
  204. package/dist/task-sizing.js +3 -10
  205. package/dist/teams-chat.js +4 -11
  206. package/dist/teams.js +12 -19
  207. package/dist/telegram-lead.js +2 -2
  208. package/dist/telegram.js +1 -1
  209. package/dist/token-notices.d.ts +0 -11
  210. package/dist/token-notices.js +1 -5
  211. package/dist/tool-secret-store.d.ts +0 -3
  212. package/dist/tool-secret-store.js +2 -11
  213. package/dist/toolroll-update.d.ts +0 -2
  214. package/dist/toolroll-update.js +2 -2
  215. package/dist/verification-evidence.d.ts +0 -1
  216. package/dist/verification-evidence.js +0 -1
  217. package/dist/webhooks.d.ts +0 -1
  218. package/dist/webhooks.js +0 -1
  219. package/dist/workspace-ui.d.ts +0 -8
  220. package/dist/workspace-ui.js +1 -6
  221. package/package.json +1 -1
  222. package/dist/contracts/native-census.d.ts +0 -42
  223. package/dist/contracts/native-census.js +0 -36
  224. package/dist/process-recovery-anchor.d.ts +0 -75
  225. package/dist/process-recovery-anchor.js +0 -188
  226. package/dist/process-recovery-coalition.d.ts +0 -25
  227. package/dist/process-recovery-coalition.js +0 -105
  228. package/dist/process-recovery-eligibility.d.ts +0 -179
  229. package/dist/process-recovery-eligibility.js +0 -174
  230. package/dist/process-recovery-native.d.ts +0 -161
  231. package/dist/process-recovery-native.js +0 -595
  232. package/dist/process-recovery-provenance.d.ts +0 -163
  233. package/dist/process-recovery-provenance.js +0 -292
  234. package/dist/process-recovery-services.d.ts +0 -56
  235. package/dist/process-recovery-services.js +0 -191
  236. package/dist/process-recovery-settlement.d.ts +0 -32
  237. package/dist/process-recovery-settlement.js +0 -133
  238. package/dist/process-recovery.d.ts +0 -41
  239. package/dist/process-recovery.js +0 -91
  240. package/dist/session-brief.d.ts +0 -8
  241. package/dist/session-brief.js +0 -24
  242. package/dist/session-cli.d.ts +0 -42
  243. package/dist/session-cli.js +0 -271
  244. package/dist/session-contract.d.ts +0 -183
  245. package/dist/session-contract.js +0 -122
  246. package/dist/session-remote.d.ts +0 -19
  247. package/dist/session-remote.js +0 -86
  248. package/dist/session-service.d.ts +0 -22
  249. package/dist/session-service.js +0 -157
  250. package/dist/team-cli.js +0 -692
@@ -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.
@@ -11,6 +11,7 @@ import { homedir } from "node:os";
11
11
  import { basename, delimiter, dirname, join } from "node:path";
12
12
  import { createRequire } from "node:module";
13
13
  import { parse as parseYaml } from "yaml";
14
+ import { sleep } from "./sleep.js";
14
15
  // Loaded on first use, like the store: a static import prints Node's SQLite warning before the CLI can quiet it.
15
16
  const sqlite = () => createRequire(import.meta.url)("node:sqlite");
16
17
  import { activeUpdateWork } from "./desktop-update-gate.js";
@@ -148,6 +149,9 @@ export function stageGate(stage, owner) {
148
149
  const id = textOr(journal["id"]), phase = textOr(journal["phase"]);
149
150
  return id !== null && phase !== null && BEFORE_SWAP.includes(phase) && owner() === id ? { id, phase } : null;
150
151
  }
152
+ /** How many times, and how far apart, a merged branch's deletion is looked for after the push lost a race. */
153
+ export const BRANCH_GONE_LOOKS = 5;
154
+ export const BRANCH_GONE_PAUSE_MS = 2_000;
151
155
  export function releaseAdapters(options) {
152
156
  const run = options.run ?? exec;
153
157
  const get = options.fetch ?? fetch;
@@ -155,6 +159,7 @@ export function releaseAdapters(options) {
155
159
  const tap = options.tap ?? "ap9000/homebrew-toolroll";
156
160
  const formula = options.formula ?? "Formula/toolroll.rb";
157
161
  const git = (...args) => run("git", ["-C", checkout, ...args]);
162
+ const pause = options.sleep ?? ((ms) => new Promise(done => setTimeout(done, ms)));
158
163
  const gh = (...args) => run("gh", args);
159
164
  const ghJson = async (what, ...args) => JSON.parse(await must(gh(...args), what));
160
165
  const toolroll = async (...args) => {
@@ -190,7 +195,7 @@ export function releaseAdapters(options) {
190
195
  });
191
196
  return {
192
197
  now: options.now ?? (() => new Date()),
193
- sleep: options.sleep ?? (ms => new Promise(done => setTimeout(done, ms))),
198
+ sleep: options.sleep ?? sleep,
194
199
  say: options.say ?? (line => process.stdout.write(`${line}\n`)),
195
200
  repo: {
196
201
  async github() {
@@ -229,10 +234,15 @@ export function releaseAdapters(options) {
229
234
  const pushed = await git("push", `--force-with-lease=${ref}:${head}`, "origin", `:${ref}`);
230
235
  if (pushed.code === 0)
231
236
  return;
232
- // GitHub may delete a merged branch itself between the look and the push; gone is what was wanted.
233
- const after = (await must(git("ls-remote", "origin", ref), "git ls-remote")).trim().split(/\s+/)[0] || null;
234
- if (after === null)
235
- return;
237
+ // GitHub may delete a merged branch itself between the look and the push; gone is what was wanted. Its refs can
238
+ // lag the deletion by a few seconds, so look a few times before calling it a failure.
239
+ for (let look = 0; look < BRANCH_GONE_LOOKS; look++) {
240
+ if (look > 0)
241
+ await pause(BRANCH_GONE_PAUSE_MS);
242
+ const after = (await must(git("ls-remote", "origin", ref), "git ls-remote")).trim().split(/\s+/)[0] || null;
243
+ if (after === null)
244
+ return;
245
+ }
236
246
  throw new Error(`deleting merged branch ${branch} failed: ${pushed.stderr.trim() || `exit ${pushed.code}`}`);
237
247
  },
238
248
  async tree(sha) { return (await must(git("rev-parse", `${sha}^{tree}`), `git rev-parse ${sha.slice(0, 7)}^{tree}`)).trim(); },
@@ -1,8 +1,9 @@
1
- import { type TeamCliOptions } from './team-cli.js';
1
+ import { type ConnectOptions } from './connect-cli.js';
2
2
  import { type CliRequest } from './cli-http.js';
3
3
  import { type RemoteCommandLookup } from './remote-command.js';
4
4
  export { contractRow, STEP_UP_MESSAGE, type RemoteMode } from './remote-command.js';
5
- export type RemoteExecOptions = TeamCliOptions & {
5
+ export type RemoteExecOptions = ConnectOptions & {
6
+ sleep?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
6
7
  cwd?: string;
7
8
  /** Raw output streams; remote bytes are written exactly as the server returned them. */
8
9
  stdout?: (chunk: string) => void;
@@ -12,13 +12,14 @@ import { resolve } from 'node:path';
12
12
  import { setTimeout as delay } from 'node:timers/promises';
13
13
  import { envelopeJson } from './envelope.js';
14
14
  import { COMMAND_GUIDE } from './surface.js';
15
- import { centralProfile, UsageError } from './team-cli.js';
15
+ import { centralProfile, UsageError } from './connect-cli.js';
16
16
  import { CLI_FILES_BYTES, CLI_WAIT_SECONDS } from './cli-http.js';
17
17
  import { TOKEN_REPLACEMENT } from './password-bearer.js';
18
18
  import { contractRow, fileArguments, STEP_UP_MESSAGE } from './remote-command.js';
19
19
  export { contractRow, STEP_UP_MESSAGE } from './remote-command.js';
20
20
  const EXIT = { ok: 0, failed: 1, usage: 2, refused: 3 };
21
- /** Team commands own their own central path (team-cli.ts); `session` sends its own checked request (session-cli.ts). */
21
+ /** Never sent remotely: `connect` saves the profile itself, the lead's commands are this computer's, and the removed
22
+ * central team and session verbs answer with their removal notice (removed-commands.ts). */
22
23
  const TEAM_COMMANDS = new Set(['connect', 'lead', 'conversation', 'chat', 'brief', 'session']);
23
24
  const RESPONSE_BYTES = 16 * 1024 * 1024;
24
25
  const REQUEST_TIMEOUT_MS = (CLI_WAIT_SECONDS + 35) * 1_000;
package/dist/repos.d.ts CHANGED
@@ -50,11 +50,6 @@ export declare function updateRepos(file: string, transform: (repos: string[]) =
50
50
  ok: true;
51
51
  repos: string[];
52
52
  } | RegistryUpdateFailure>;
53
- /** Persist project roots through the same lock as repo enrollment. */
54
- export declare function updateProjectRoots(file: string, transform: (roots: string[]) => string[]): Promise<{
55
- ok: true;
56
- roots: string[];
57
- } | RegistryUpdateFailure>;
58
53
  /** Atomically update repositories and roots without either writer erasing the other. */
59
54
  export declare function updateProjectRegistry(file: string, transform: (registry: ProjectRegistry) => ProjectRegistry): Promise<{
60
55
  ok: true;
package/dist/repos.js CHANGED
@@ -11,8 +11,9 @@
11
11
  * untrusted input and gets validated like any other.
12
12
  */
13
13
  import { mkdir, readFile, writeFile } from "node:fs/promises";
14
- import { dirname, join } from "node:path";
14
+ import { dirname } from "node:path";
15
15
  import { configBase, namedPath } from "./names.js";
16
+ import { sleep } from "./sleep.js";
16
17
  export const CONFIG_VERSION = 2;
17
18
  const FILE_NAME = "repos.json";
18
19
  export function configPath(env, home) {
@@ -76,14 +77,6 @@ export async function updateRepos(file, transform) {
76
77
  }));
77
78
  return updated.ok ? { ok: true, repos: updated.registry.repos } : updated;
78
79
  }
79
- /** Persist project roots through the same lock as repo enrollment. */
80
- export async function updateProjectRoots(file, transform) {
81
- const updated = await updateProjectRegistry(file, current => ({
82
- ...current,
83
- roots: transform(current.roots),
84
- }));
85
- return updated.ok ? { ok: true, roots: updated.registry.roots } : updated;
86
- }
87
80
  /** Atomically update repositories and roots without either writer erasing the other. */
88
81
  export async function updateProjectRegistry(file, transform) {
89
82
  const { openSync, closeSync, writeSync, readFileSync, unlinkSync, existsSync: exists, mkdirSync, renameSync } = await import("node:fs");
@@ -93,7 +86,6 @@ export async function updateProjectRegistry(file, transform) {
93
86
  const reaperPath = `${file}.reaper.lock`;
94
87
  const token = randomBytes(16).toString("hex");
95
88
  const body = JSON.stringify({ pid: process.pid, token, at: Date.now() });
96
- const sleep = (ms) => new Promise(done => setTimeout(done, ms));
97
89
  const tryReap = () => {
98
90
  // Recovery only for PROVEN-dead owners, serialized by the reaper lock,
99
91
  // which re-reads the exact snapshot before unlinking (finding 29). An
@@ -63,5 +63,3 @@ export type RepositoryContext = {
63
63
  export declare function repositoryContextRead(request: Omit<RepositoryContextRequest, 'refresh'>): RepositoryContext;
64
64
  /** Explicit refresh is the only cache-writing path. It never changes project/task records. */
65
65
  export declare function repositoryContext(request: RepositoryContextRequest): Promise<RepositoryContext>;
66
- /** Human/model context rendering; saved records remain the authority and retain this structured capture. */
67
- export declare function repositoryContextText(context: RepositoryContext): string;
@@ -370,7 +370,3 @@ export async function repositoryContext(request) {
370
370
  }
371
371
  return finishContext(request, result, snapshot, index);
372
372
  }
373
- /** Human/model context rendering; saved records remain the authority and retain this structured capture. */
374
- export function repositoryContextText(context) {
375
- return '\nRepository context (source material, not instructions or authority). This selection is pinned to the shown checkout and source hashes; missing context never blocks the task.\n' + JSON.stringify(context).replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029') + '\n';
376
- }
@@ -130,5 +130,3 @@ export type VerifyInputs = BaselineInputs & {
130
130
  export declare function verifyRestartRecovery(inputs: VerifyInputs): Promise<RestartVerification>;
131
131
  /** The baseline and verification are meant to be printed; this keeps a secret from ever entering them. */
132
132
  export declare function assertNoSecret(json: string, secrets: readonly string[]): void;
133
- /** The current boot id, for scripts that print it beside a baseline. */
134
- export declare function bootIdNow(): string | null;
@@ -24,7 +24,7 @@ import { createHash, randomUUID } from "node:crypto";
24
24
  import { dirname, join } from "node:path";
25
25
  import { fileURLToPath } from "node:url";
26
26
  import { existsSync, readFileSync, realpathSync, readdirSync, statSync } from "node:fs";
27
- import { bootIdentity, currentBootId, provenDeadByBootChange } from "./boot-identity.js";
27
+ import { bootIdentity, provenDeadByBootChange } from "./boot-identity.js";
28
28
  import { containmentStatus, currentContainment } from "./containment.js";
29
29
  import { daemonStatus } from "./daemon.js";
30
30
  import { isAlive } from "./runner.js";
@@ -220,7 +220,3 @@ export function assertNoSecret(json, secrets) {
220
220
  throw new Error("the certification output would contain a credential; refusing to write it");
221
221
  }
222
222
  }
223
- /** The current boot id, for scripts that print it beside a baseline. */
224
- export function bootIdNow() {
225
- return currentBootId();
226
- }
@@ -1,5 +1,5 @@
1
1
  import type { Runner } from "./backend.js";
2
- import type { Store, VerifyCommand } from "./store.js";
2
+ import type { Store } from "./store.js";
3
3
  import { type CheckLevel } from "./check-levels.js";
4
4
  export declare const CHECKS_REQUESTED = "checks requested";
5
5
  export declare const CHECKS_STARTED = "checks started";
@@ -93,8 +93,6 @@ export declare function withFollowUps(original: CheckReading, followUps: readonl
93
93
  /** The level a result's checks stand at now: the build's own level, raised by
94
94
  * a follow-up that passed on the same commit. null for results from before levels. */
95
95
  export declare function resultCheckLevel(store: Store, runId: number, now: Date): CheckLevel | null;
96
- /** Whether this result's commit has passed the project's full check, here or in a follow-up. */
97
- export declare function fullCheckPassed(reading: CheckReading): boolean;
98
96
  /** Before a Quick or Off result merges: the project's full check on its exact
99
97
  * commit. Clear when the build already ran the full check, when the project has
100
98
  * no full command (its CI covers it), or when a follow-up full check passed. */
@@ -105,7 +103,6 @@ export type FullCheckGate = {
105
103
  message: string;
106
104
  };
107
105
  export declare function fullCheckGate(store: Store, runId: number, now: Date): FullCheckGate;
108
- export declare const isQuickCommand: (command: VerifyCommand | null, repo: string) => boolean;
109
106
  /** File a small task to write tests for a result's change. It is filed like any
110
107
  * other task: nothing runs until a person approves it. */
111
108
  export declare function fileAddTestsTask(store: Store, root: string | null, input: {
@@ -1,15 +1,4 @@
1
- /** Follow-ups on any result: "Run checks" and "Add tests".
2
- *
3
- * Run checks runs the project's quick or full check on the result's exact
4
- * commit, in a fresh checkout, after the build has finished. A person (or a
5
- * pull request opening) asks; the ask is a ledger entry; a worker runs it
6
- * once and seals its log and a receipt beside the result. A pass upgrades
7
- * what the result's Checks row says; a failure stays visible. Nothing here
8
- * rewrites the build's own check or reruns crew work.
9
- *
10
- * Add tests files a small task, unapproved like any other filing, to write
11
- * tests for that change. */
12
- import { fencedCheckoutCommands } from "./invoke.js";
1
+ import { checkoutRunner, ranAtLine, widestRan } from "./invoke.js";
13
2
  import { mkdtempSync, rmSync } from "node:fs";
14
3
  import { tmpdir } from "node:os";
15
4
  import { join } from "node:path";
@@ -17,7 +6,7 @@ import { run as execRun } from "./exec.js";
17
6
  import { approvedCommandShell, SETUP_ENV_ALLOWLIST, SETUP_ENV_DENYLIST } from "./builder.js";
18
7
  import { runWithIsolatedDatabase } from "./child-database.js";
19
8
  import { boundStreamHeadTail, readVerifiedArtifact, redactSecretLines, scanForSecrets, storeEvidence } from "./evidence.js";
20
- import { CHECK_LEVEL_WORDS, checkCommandFor, quickVerifyKey, repoClause, repoOfRun, runCheckLevel } from "./check-levels.js";
9
+ import { CHECK_LEVEL_WORDS, checkCommandFor, repoClause, repoOfRun, runCheckLevel } from "./check-levels.js";
21
10
  import { fileTaskProposal } from "./proposal.js";
22
11
  export const CHECKS_REQUESTED = "checks requested";
23
12
  export const CHECKS_STARTED = "checks started";
@@ -188,6 +177,8 @@ export async function runFollowUpCheck(store, root, request, deps = {}) {
188
177
  const folder = mkdtempSync(join(deps.scratch ?? tmpdir(), "toolroll-checks-"));
189
178
  const checkout = join(folder, "checkout");
190
179
  const log = [];
180
+ // How each command actually ran (check-access.ts): the widest is on the receipt and in the log.
181
+ const ranAt = [];
191
182
  const bound = (text) => { const hits = scanForSecrets(text); return boundStreamHeadTail(hits.length > 0 ? redactSecretLines(text, hits) : text, 24 * 1024); };
192
183
  const note = (label, command, result) => log.push(`=== ${label} ===\n$ ${command}\n(exit ${result.code}${result.notFound ? ", could not start" : ""}${result.timedOut ? ", timed out" : ""})\n\n--- stdout ---\n${bound(result.stdout)}\n\n--- stderr ---\n${bound(result.stderr)}`);
193
184
  let result;
@@ -199,10 +190,11 @@ export async function runFollowUpCheck(store, root, request, deps = {}) {
199
190
  }
200
191
  else {
201
192
  const setup = store.liveWorktreeSetup(target.repo);
193
+ // Worked out again right before each command (check-access.ts): a narrowing meanwhile applies to the next one.
202
194
  let ready = true;
203
195
  if (setup !== null) {
204
196
  const shell = approvedCommandShell(setup.command);
205
- const prepared = await runWithIsolatedDatabase(fencedCheckoutCommands(store, target.repo, checkout, runner), shell.file, shell.args, { cwd: checkout, timeoutMs: setup.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
197
+ const prepared = await runWithIsolatedDatabase(checkoutRunner(store, target.repo, checkout, runner, [runId], level => ranAt.push(level)), shell.file, shell.args, { cwd: checkout, timeoutMs: setup.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
206
198
  note("Approved project setup", setup.command, prepared);
207
199
  if (prepared.code !== 0 || prepared.timedOut || prepared.notFound) {
208
200
  ready = false;
@@ -217,7 +209,7 @@ export async function runFollowUpCheck(store, root, request, deps = {}) {
217
209
  }
218
210
  else {
219
211
  const shell = approvedCommandShell(live.command);
220
- const ran = await runWithIsolatedDatabase(fencedCheckoutCommands(store, target.repo, checkout, runner), shell.file, shell.args, { cwd: checkout, timeoutMs: live.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
212
+ const ran = await runWithIsolatedDatabase(checkoutRunner(store, target.repo, checkout, runner, [runId], level => ranAt.push(level)), shell.file, shell.args, { cwd: checkout, timeoutMs: live.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
221
213
  note(`${CHECK_LEVEL_WORDS[target.level]} check`, live.command, ran);
222
214
  result = ran.timedOut ? { ran: false, failure: "The check ran out of time." } : ran.notFound ? { ran: false, failure: "The check couldn't start." } : { ran: true, exitCode: ran.code };
223
215
  }
@@ -231,10 +223,13 @@ export async function runFollowUpCheck(store, root, request, deps = {}) {
231
223
  rmSync(folder, { recursive: true, force: true });
232
224
  }
233
225
  const at = now();
226
+ const ranLine = ranAtLine(widestRan(ranAt));
227
+ if (ranLine !== null)
228
+ log.push(ranLine);
234
229
  const text = log.length === 0 ? "No command started." : log.join("\n\n");
235
230
  const logId = storeEvidence(store, root, runId, "structured-output", `follow-up-check-${request}.log`, Buffer.from(text, "utf8"), FOLLOW_UP_LOG, at, { captureStatus: "ok" });
236
231
  const logArtifact = store.getArtifact(logId);
237
- const receipt = JSON.stringify({ version: 1, request, run: runId, head: target.head, tested: target.head, level: target.level,
232
+ const receipt = JSON.stringify({ version: 1, request, run: runId, head: target.head, tested: target.head, level: target.level, checkAccess: widestRan(ranAt),
238
233
  command: { repo: target.command.repo, command: target.command.command, digest: target.command.digest, approvedBy: target.command.approvedBy },
239
234
  result, log: { artifactId: logArtifact.id, sha256: logArtifact.sha256, bytesStored: logArtifact.bytesStored, truncated: logArtifact.truncated } }, null, 1);
240
235
  storeEvidence(store, root, runId, "structured-output", `follow-up-check-${request}.json`, Buffer.from(receipt, "utf8"), FOLLOW_UP_RECEIPT, at, { captureStatus: "ok" });
@@ -284,10 +279,6 @@ export function resultCheckLevel(store, runId, now) {
284
279
  const read = withFollowUps({ status: level === "off" ? "not-run" : "passed", level, exitCode: null, head: run?.headRevision ?? null }, follows);
285
280
  return read.level;
286
281
  }
287
- /** Whether this result's commit has passed the project's full check, here or in a follow-up. */
288
- export function fullCheckPassed(reading) {
289
- return reading.status === "passed" && (reading.level === "full" || reading.level === null);
290
- }
291
282
  export function fullCheckGate(store, runId, now) {
292
283
  const level = runCheckLevel(store, runId);
293
284
  const repo = repoOfRun(store, runId);
@@ -310,7 +301,6 @@ export function fullCheckGate(store, runId, now) {
310
301
  return { state: "not-run", message: `The full check didn't finish on this commit${last.note === null ? "" : `: ${last.note}`} Run it again, or merge anyway.` };
311
302
  return { state: "waiting", message: "The full check is still running on this commit. Merge once it passes, or merge anyway." };
312
303
  }
313
- export const isQuickCommand = (command, repo) => command !== null && command.repo === quickVerifyKey(repo);
314
304
  // ---- Add tests --------------------------------------------------------------
315
305
  /** File a small task to write tests for a result's change. It is filed like any
316
306
  * other task: nothing runs until a person approves it. */
@@ -182,8 +182,6 @@ export declare function parseRevisionBatch(raw: string | null | undefined): numb
182
182
  /** The source binding the revision form carries: the scope digest the
183
183
  * page was rendered against, or "none". */
184
184
  export declare function revisionSourceOf(scopeDigest: string | null): string;
185
- export declare const REVIEW_DRAFT_PREFIX = "standing-orders:review-draft:";
186
- export declare const RESULT_SCROLL_PREFIX = "standing-orders:result-scroll:";
187
185
  /** The in-page half of the result presentation. Everything it does is
188
186
  * presentational or a bounded draft: no fetch, no endpoint, no submit.
189
187
  *
@@ -210,8 +210,6 @@ export function parseRevisionBatch(raw) {
210
210
  export function revisionSourceOf(scopeDigest) {
211
211
  return scopeDigest === null ? "none" : scopeDigest;
212
212
  }
213
- export const REVIEW_DRAFT_PREFIX = "standing-orders:review-draft:";
214
- export const RESULT_SCROLL_PREFIX = "standing-orders:result-scroll:";
215
213
  /** The in-page half of the result presentation. Everything it does is
216
214
  * presentational or a bounded draft: no fetch, no endpoint, no submit.
217
215
  *
@@ -12,7 +12,6 @@ export declare const RETENTION_KINDS: readonly {
12
12
  }[];
13
13
  export declare const PERIOD_CHOICES: Readonly<Record<RetentionKind, readonly (number | null)[]>>;
14
14
  export declare const MIN_DAYS: 1;
15
- export declare const MAX_DAYS: 3650;
16
15
  /** A sweep is due once a day. */
17
16
  export declare const SWEEP_EVERY_MS = 86400000;
18
17
  /** At most this many runs, messages, notifications or records go per kind per sweep; the next sweep takes the rest. */
package/dist/retention.js CHANGED
@@ -69,7 +69,6 @@ export const PERIOD_CHOICES = {
69
69
  evidence: [1, 7, 14, 28, null], checkouts: LONG_CHOICES, chat: LONG_CHOICES, notifications: LONG_CHOICES,
70
70
  };
71
71
  export const MIN_DAYS = RETENTION_DAYS.min;
72
- export const MAX_DAYS = RETENTION_DAYS.max;
73
72
  const DAY_MS = 86_400_000;
74
73
  /** A sweep is due once a day. */
75
74
  export const SWEEP_EVERY_MS = DAY_MS;
@@ -32,7 +32,6 @@ export declare const REVIEW_CONTEXT_LIMITS: {
32
32
  /** Only this compact projection enters prompts. Full bytes remain sealed in
33
33
  * the artifact and are materialized under generated, flat scratch names. */
34
34
  export declare function reviewContextFileName(id: string): string;
35
- export declare function reviewContextManifest(inventory: ReviewContextInventory): string;
36
35
  export type ContextGapReason = "source-missing" | "source-unverified" | "source-proof-missing" | "source-scope-changed" | "criterion-changed" | "stale-ancestry" | "missing-at-head" | "not-a-file" | "binary" | "over-limit" | "aggregate-limit" | "item-cap" | "secret-redacted" | "capture-failed";
37
36
  export type ContextItemWhy = "source-criterion-evidence" | "source-changed-path" | "candidate-changed-path";
38
37
  export type ReviewContextItem = {
@@ -1,5 +1,5 @@
1
1
  // Assignment direct assessments reuse custody checks; gaps remain explicit.
2
- import { readObservationEvidence, OBSERVATION_CAPTURE, OBSERVATION_FILE } from "./observations.js";
2
+ import { readObservationEvidence, OBSERVATION_CAPTURE } from "./observations.js";
3
3
  import { isVerificationReceipt } from "./verification-evidence.js";
4
4
  /**
5
5
  * Inherited review context (v51, contract handoff task 3): the bounded,
@@ -75,17 +75,6 @@ export function reviewContextFileName(id) {
75
75
  throw new Error("invalid context item id");
76
76
  return `REVIEW-CONTEXT-${id}.txt`;
77
77
  }
78
- export function reviewContextManifest(inventory) {
79
- return JSON.stringify({
80
- ...inventory,
81
- ...(inventory.handoff === undefined ? {} : { handoff: { artifact: inventory.handoff.artifact, sha256: inventory.handoff.sha256, file: "REVIEW-BUILDER-NOTES.json" } }),
82
- ...(inventory.observations === undefined ? {} : { observations: { artifact: inventory.observations.artifact, sha256: inventory.observations.sha256, file: OBSERVATION_FILE } }),
83
- format: "review-context-manifest-v1",
84
- items: inventory.items.map(({ content: _content, ...item }) => ({
85
- ...item, file: reviewContextFileName(item.id),
86
- })),
87
- });
88
- }
89
78
  const CONTEXT_INPUT_KINDS = new Set(["terminal-diff", "diff-stat", "proof", "check-log", "screenshot", "review-context"]);
90
79
  /** A shortened check log is the exact bounded log the reviewer saw.
91
80
  * Completeness of patches, proofs and other structured inputs is still
@@ -8,22 +8,6 @@ import { type BuildFinding } from "./contracts/review-findings.js";
8
8
  * screenshots only when this run actually has one (v40) — a grandfathered
9
9
  * run (no rubric) writes exactly what it always has, byte for byte. */
10
10
  export declare const REVIEW_PATCH_NAME = "REVIEW-DIFF.patch";
11
- export declare const REVIEW_RUBRIC_NAME = "REVIEW-RUBRIC.json";
12
- export declare const REVIEW_PROOF_NAME = "REVIEW-PROOF.json";
13
- /** Audit hardening (still evidence-review-v1, unreleased): the repository's
14
- * approved verification command's own captured stdout/stderr — a
15
- * criterion citing `check` evidence was previously judged from the proof's
16
- * bare claim, never the actual output. */
17
- export declare const REVIEW_CHECK_LOG_NAME = "REVIEW-CHECK-LOG.txt";
18
- /** v51 (inherited review context): a REVISION's sealed source-and-ancestry
19
- * inventory — bounded files at the exact sealed head, bound to the source
20
- * run, plus prior review provenance as context. Materialized only when
21
- * the run captured one; every other run writes exactly what it always has. */
22
- export declare const REVIEW_CONTEXT_NAME = "REVIEW-CONTEXT.json";
23
- /** One claimed screenshot's name in the scratch — stable per artifact id,
24
- * so a reviewer's own tool output naming it is reproducible across a
25
- * retried materialization within the same pass. */
26
- export declare function reviewScreenshotName(artifactId: number, kind: "png" | "jpeg"): string;
27
11
  export declare const REVIEW_LIMITS: {
28
12
  readonly comments: 40;
29
13
  readonly criteria: 12;
package/dist/reviewer.js CHANGED
@@ -6,24 +6,6 @@ import { readBuildFindings } from "./contracts/review-findings.js";
6
6
  * screenshots only when this run actually has one (v40) — a grandfathered
7
7
  * run (no rubric) writes exactly what it always has, byte for byte. */
8
8
  export const REVIEW_PATCH_NAME = "REVIEW-DIFF.patch";
9
- export const REVIEW_RUBRIC_NAME = "REVIEW-RUBRIC.json";
10
- export const REVIEW_PROOF_NAME = "REVIEW-PROOF.json";
11
- /** Audit hardening (still evidence-review-v1, unreleased): the repository's
12
- * approved verification command's own captured stdout/stderr — a
13
- * criterion citing `check` evidence was previously judged from the proof's
14
- * bare claim, never the actual output. */
15
- export const REVIEW_CHECK_LOG_NAME = "REVIEW-CHECK-LOG.txt";
16
- /** v51 (inherited review context): a REVISION's sealed source-and-ancestry
17
- * inventory — bounded files at the exact sealed head, bound to the source
18
- * run, plus prior review provenance as context. Materialized only when
19
- * the run captured one; every other run writes exactly what it always has. */
20
- export const REVIEW_CONTEXT_NAME = "REVIEW-CONTEXT.json";
21
- /** One claimed screenshot's name in the scratch — stable per artifact id,
22
- * so a reviewer's own tool output naming it is reproducible across a
23
- * retried materialization within the same pass. */
24
- export function reviewScreenshotName(artifactId, kind) {
25
- return `REVIEW-SCREENSHOT-${artifactId}.${kind === "png" ? "png" : "jpg"}`;
26
- }
27
9
  export const REVIEW_LIMITS = {
28
10
  ...REVIEW_OUTPUT_LIMITS,
29
11
  /** The mailbox read cap: 40 maximal comments plus 12 judgements fit with headroom. */
@@ -18,6 +18,7 @@ import { existsSync, readdirSync, readlinkSync, realpathSync } from "node:fs";
18
18
  import { hostname } from "node:os";
19
19
  import { basename, sep } from "node:path";
20
20
  import { ownedProcessCount, runOwnerTag } from "./exec.js";
21
+ import { sleep as defaultSleep } from "./sleep.js";
21
22
  /** How long a process has after SIGTERM before SIGKILL. */
22
23
  export const STOP_GRACE_MS = 10_000;
23
24
  /** `ps` reports age in whole seconds: a process born this close after the run saw its pid is still that process. */
@@ -86,7 +87,7 @@ export async function stopProcesses(targets, options = {}) {
86
87
  const graceMs = options.graceMs ?? STOP_GRACE_MS;
87
88
  const census = options.census ?? (() => processCensus());
88
89
  const signal = options.signal ?? ((pid, name) => process.kill(pid, name));
89
- const sleep = options.sleep ?? (ms => new Promise(done => setTimeout(done, ms)));
90
+ const sleep = options.sleep ?? defaultSleep;
90
91
  const send = (rows, name) => {
91
92
  for (const row of rows) {
92
93
  try {
package/dist/scope.d.ts CHANGED
@@ -4,6 +4,7 @@ import { isAcpProfile, type AcpProviderId } from "./acp-agents.js";
4
4
  export { isAcpProfile };
5
5
  import { type NetworkProfile } from "./egress.js";
6
6
  import { type WritesMode } from "./writes-mode.js";
7
+ import { type CheckAccess } from "./check-access.js";
7
8
  import { type EvidenceKind } from "./contracts/acceptance-terms.js";
8
9
  import { type AcceptanceCriterion, type AcceptanceProblem, type ScopeTerms } from "./contracts/scope.js";
9
10
  import type { Store, Mutation } from "./store.js";
@@ -78,6 +79,8 @@ export type ClaudeProfile = {
78
79
  /** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
79
80
  * write allowlists, which keep writing anywhere their fence allows. */
80
81
  writes?: WritesMode;
82
+ /** How far its checks reach beyond the check fence (check-access.ts), sealed when wider than sandboxed; absent: sandboxed. */
83
+ checkAccess?: Exclude<CheckAccess, "sandboxed">;
81
84
  };
82
85
  export type CodexShapedProfile = {
83
86
  provider: "codex" | "openrouter";
@@ -98,6 +101,8 @@ export type CodexShapedProfile = {
98
101
  /** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
99
102
  * write allowlists, which keep writing anywhere their fence allows. */
100
103
  writes?: WritesMode;
104
+ /** How far its checks reach beyond the check fence (check-access.ts), sealed when wider than sandboxed; absent: sandboxed. */
105
+ checkAccess?: Exclude<CheckAccess, "sandboxed">;
101
106
  };
102
107
  export type GeminiProfile = {
103
108
  provider: "gemini";
@@ -120,6 +125,8 @@ export type GeminiProfile = {
120
125
  /** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
121
126
  * write allowlists, which keep writing anywhere their fence allows. */
122
127
  writes?: WritesMode;
128
+ /** How far its checks reach beyond the check fence (check-access.ts), sealed when wider than sandboxed; absent: sandboxed. */
129
+ checkAccess?: Exclude<CheckAccess, "sandboxed">;
123
130
  };
124
131
  /**
125
132
  * An agent over the Agent Client Protocol (acp-agents.ts, docs/plans/acp-adapter.md).
@@ -143,6 +150,8 @@ export type AcpProfile = {
143
150
  /** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
144
151
  * write allowlists, which keep writing anywhere their fence allows. */
145
152
  writes?: WritesMode;
153
+ /** How far its checks reach beyond the check fence (check-access.ts), sealed when wider than sandboxed; absent: sandboxed. */
154
+ checkAccess?: Exclude<CheckAccess, "sandboxed">;
146
155
  };
147
156
  export type ExecutionProfile = ClaudeProfile | CodexShapedProfile | GeminiProfile | AcpProfile;
148
157
  /** Whether a profile's clock is a no-progress window (an ACP profile has both clocks; its overall one is a deadline). */