toolroll 0.9.93 → 0.9.94

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 (328) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/activity-line.d.ts +7 -4
  3. package/dist/activity-line.js +9 -7
  4. package/dist/agent-fence.d.ts +4 -0
  5. package/dist/agent-fence.js +4 -1
  6. package/dist/approval-authority.d.ts +7 -1
  7. package/dist/approval-authority.js +11 -2
  8. package/dist/approval-password.d.ts +31 -0
  9. package/dist/approval-password.js +26 -0
  10. package/dist/assignment-ui.js +1 -1
  11. package/dist/assignment.js +5 -0
  12. package/dist/boot-identity.d.ts +2 -1
  13. package/dist/boot-identity.js +6 -4
  14. package/dist/bounded-spawn.d.ts +57 -0
  15. package/dist/bounded-spawn.js +220 -0
  16. package/dist/browser/terminal.js +42 -42
  17. package/dist/browser/workspace.css +1 -1
  18. package/dist/browser/workspace.js +32 -32
  19. package/dist/browser-shell.d.ts +1 -1
  20. package/dist/browser-shell.js +2 -2
  21. package/dist/browser-workspace.d.ts +45 -2
  22. package/dist/browser-workspace.js +3 -3
  23. package/dist/builder-restart.d.ts +21 -0
  24. package/dist/builder-restart.js +50 -0
  25. package/dist/builder.d.ts +4 -0
  26. package/dist/builder.js +53 -24
  27. package/dist/chat-acceptance.js +1 -1
  28. package/dist/chat-actions.d.ts +12 -2
  29. package/dist/chat-actions.js +25 -2
  30. package/dist/chat-channel.js +11 -0
  31. package/dist/chat-decide.d.ts +7 -2
  32. package/dist/chat-decide.js +37 -9
  33. package/dist/chat-quiet.js +3 -3
  34. package/dist/chat-voice.d.ts +1 -1
  35. package/dist/chat-voice.js +2 -2
  36. package/dist/check-facts.d.ts +3 -1
  37. package/dist/check-facts.js +57 -11
  38. package/dist/check-failure.d.ts +22 -3
  39. package/dist/check-failure.js +57 -13
  40. package/dist/check-levels-ui.d.ts +4 -0
  41. package/dist/check-levels-ui.js +10 -1
  42. package/dist/check-load.d.ts +85 -0
  43. package/dist/check-load.js +147 -0
  44. package/dist/check-only-standing.d.ts +36 -0
  45. package/dist/check-only-standing.js +39 -0
  46. package/dist/check-only.d.ts +15 -0
  47. package/dist/check-only.js +99 -0
  48. package/dist/check-report.d.ts +2 -0
  49. package/dist/check-report.js +1 -1
  50. package/dist/check-stamp.d.ts +46 -0
  51. package/dist/check-stamp.js +93 -0
  52. package/dist/checkout-cleanup.d.ts +36 -5
  53. package/dist/checkout-cleanup.js +166 -14
  54. package/dist/cli-help.d.ts +4 -1
  55. package/dist/cli-help.js +47 -30
  56. package/dist/cli.js +11 -1
  57. package/dist/code-extract.d.ts +44 -0
  58. package/dist/code-extract.js +88 -0
  59. package/dist/code-map-acts.d.ts +24 -0
  60. package/dist/code-map-acts.js +53 -0
  61. package/dist/code-map-admission.d.ts +52 -0
  62. package/dist/code-map-admission.js +295 -0
  63. package/dist/code-map-build.d.ts +63 -0
  64. package/dist/code-map-build.js +415 -0
  65. package/dist/code-map-cli.d.ts +153 -0
  66. package/dist/code-map-cli.js +103 -0
  67. package/dist/code-map-main.d.ts +1 -0
  68. package/dist/code-map-main.js +48 -0
  69. package/dist/code-map-read.d.ts +106 -0
  70. package/dist/code-map-read.js +171 -0
  71. package/dist/code-map-report.d.ts +37 -0
  72. package/dist/code-map-report.js +95 -0
  73. package/dist/code-map-shape.d.ts +172 -0
  74. package/dist/code-map-shape.js +327 -0
  75. package/dist/code-map-store.d.ts +136 -0
  76. package/dist/code-map-store.js +233 -0
  77. package/dist/coding-provider.d.ts +2 -0
  78. package/dist/coding-provider.js +3 -2
  79. package/dist/coding-update.js +3 -2
  80. package/dist/coding-workspace.js +4 -4
  81. package/dist/console-chrome.js +2 -2
  82. package/dist/containment.d.ts +5 -0
  83. package/dist/containment.js +14 -1
  84. package/dist/contracts/chat-actions.d.ts +9 -0
  85. package/dist/contracts/chat-actions.js +2 -0
  86. package/dist/contracts/cli.d.ts +52 -0
  87. package/dist/contracts/cli.js +4 -0
  88. package/dist/contracts/console-api.d.ts +10 -3
  89. package/dist/contracts/console-api.js +10 -3
  90. package/dist/contracts/gateway-tools.d.ts +17 -0
  91. package/dist/contracts/gateway-tools.js +3 -1
  92. package/dist/contracts/lead-tools.d.ts +61 -0
  93. package/dist/contracts/lead-tools.js +10 -1
  94. package/dist/contracts/project-knowledge.d.ts +38 -5
  95. package/dist/contracts/project-knowledge.js +11 -5
  96. package/dist/contracts/project-memory.d.ts +3 -1
  97. package/dist/contracts/project-memory.js +3 -2
  98. package/dist/contracts/storage.d.ts +14 -0
  99. package/dist/contracts/storage.js +3 -1
  100. package/dist/contracts/store-json.d.ts +2 -0
  101. package/dist/contracts/youiyoux-request.d.ts +1 -1
  102. package/dist/contracts/youiyoux-request.js +1 -1
  103. package/dist/desktop-access.js +6 -2
  104. package/dist/dispatch.js +18 -15
  105. package/dist/dispose.js +8 -2
  106. package/dist/easy-start.js +2 -3
  107. package/dist/evals.js +2 -1
  108. package/dist/fast-start.d.ts +136 -0
  109. package/dist/fast-start.js +431 -0
  110. package/dist/fast-terms.d.ts +9 -0
  111. package/dist/fast-terms.js +23 -0
  112. package/dist/fenced-check-coverage.d.ts +62 -0
  113. package/dist/fenced-check-coverage.js +54 -0
  114. package/dist/first-run.js +1 -1
  115. package/dist/flaky-ci.d.ts +31 -0
  116. package/dist/flaky-ci.js +149 -0
  117. package/dist/flaky-cli.d.ts +60 -0
  118. package/dist/flaky-cli.js +60 -0
  119. package/dist/flaky.d.ts +75 -9
  120. package/dist/flaky.js +255 -0
  121. package/dist/flow-card-task.js +3 -0
  122. package/dist/flow-triggers.d.ts +1 -1
  123. package/dist/flow-triggers.js +1 -1
  124. package/dist/github-import.d.ts +62 -0
  125. package/dist/github-import.js +146 -0
  126. package/dist/guides.js +15 -10
  127. package/dist/invoke.d.ts +5 -1
  128. package/dist/invoke.js +49 -14
  129. package/dist/job-object-helper.ps1 +10 -3
  130. package/dist/keymap.d.ts +41 -0
  131. package/dist/keymap.js +51 -0
  132. package/dist/knowledge-cli.js +1 -1
  133. package/dist/knowledge-ui.d.ts +21 -4
  134. package/dist/knowledge-ui.js +75 -7
  135. package/dist/laptop-background.d.ts +16 -0
  136. package/dist/laptop-background.js +108 -2
  137. package/dist/lead-context.js +1 -1
  138. package/dist/lead-contract.d.ts +1 -1
  139. package/dist/lead-contract.js +2 -2
  140. package/dist/lead-progress.js +3 -0
  141. package/dist/lead-status.d.ts +2 -0
  142. package/dist/lead-status.js +6 -2
  143. package/dist/lead-tools.js +51 -2
  144. package/dist/lead.js +1 -1
  145. package/dist/lesson-notes.d.ts +81 -0
  146. package/dist/lesson-notes.js +336 -0
  147. package/dist/limits-ui.js +1 -1
  148. package/dist/local-owner.d.ts +1 -1
  149. package/dist/local-owner.js +11 -0
  150. package/dist/machine-check.d.ts +16 -0
  151. package/dist/machine-check.js +26 -0
  152. package/dist/machine-identity.d.ts +75 -0
  153. package/dist/machine-identity.js +170 -0
  154. package/dist/mcp-core.js +11 -1
  155. package/dist/memory-cli.d.ts +300 -1
  156. package/dist/memory-cli.js +62 -9
  157. package/dist/memory-pass.d.ts +16 -0
  158. package/dist/memory-pass.js +67 -3
  159. package/dist/memory-tidy.d.ts +181 -0
  160. package/dist/memory-tidy.js +523 -0
  161. package/dist/memory-use.d.ts +35 -0
  162. package/dist/memory-use.js +109 -0
  163. package/dist/merge-checklist.d.ts +55 -0
  164. package/dist/merge-checklist.js +182 -0
  165. package/dist/needs-you.d.ts +27 -8
  166. package/dist/needs-you.js +96 -39
  167. package/dist/nightly-github.d.ts +2 -0
  168. package/dist/nightly-github.js +4 -4
  169. package/dist/operate-remote-arguments.js +6 -1
  170. package/dist/operate-remote.js +3 -1
  171. package/dist/operate.d.ts +6 -1
  172. package/dist/operate.js +402 -52
  173. package/dist/phase-routing.js +2 -2
  174. package/dist/plain-schema.d.ts +23 -0
  175. package/dist/plain-schema.js +94 -0
  176. package/dist/plain-words.d.ts +20 -0
  177. package/dist/plain-words.js +66 -0
  178. package/dist/planner.js +2 -1
  179. package/dist/process-liveness.d.ts +2 -0
  180. package/dist/process-liveness.js +61 -17
  181. package/dist/project-delete-ui.d.ts +7 -2
  182. package/dist/project-delete-ui.js +12 -1
  183. package/dist/project-delete.js +8 -1
  184. package/dist/project-knowledge.d.ts +18 -11
  185. package/dist/project-knowledge.js +39 -9
  186. package/dist/project-learning.d.ts +2 -1
  187. package/dist/project-learning.js +15 -45
  188. package/dist/project-memory.d.ts +5 -0
  189. package/dist/project-memory.js +22 -2
  190. package/dist/proof.js +30 -5
  191. package/dist/provider-auth.js +1 -1
  192. package/dist/publish.js +9 -1
  193. package/dist/pull-request-flow.js +5 -0
  194. package/dist/push.d.ts +18 -2
  195. package/dist/push.js +40 -16
  196. package/dist/release-adapters.d.ts +9 -0
  197. package/dist/release-adapters.js +76 -0
  198. package/dist/release-auto.js +13 -13
  199. package/dist/release-card.d.ts +1 -2
  200. package/dist/release-card.js +11 -0
  201. package/dist/release-carry.d.ts +7 -2
  202. package/dist/release-carry.js +39 -9
  203. package/dist/release-cli.d.ts +4 -0
  204. package/dist/release-cli.js +29 -22
  205. package/dist/release-coverage.js +1 -1
  206. package/dist/release-next.d.ts +48 -0
  207. package/dist/release-next.js +161 -0
  208. package/dist/release.d.ts +20 -1
  209. package/dist/release.js +76 -8
  210. package/dist/remote-destination.d.ts +36 -0
  211. package/dist/remote-destination.js +217 -0
  212. package/dist/remote-main.d.ts +48 -0
  213. package/dist/remote-main.js +84 -5
  214. package/dist/repository-context.d.ts +3 -2
  215. package/dist/repository-context.js +112 -70
  216. package/dist/restart-certification.d.ts +1 -0
  217. package/dist/restart-certification.js +8 -6
  218. package/dist/result-acts.d.ts +27 -19
  219. package/dist/result-acts.js +36 -25
  220. package/dist/result-follow-ups.d.ts +2 -2
  221. package/dist/result-follow-ups.js +18 -4
  222. package/dist/result-review.d.ts +1 -1
  223. package/dist/route-change-check.d.ts +4 -0
  224. package/dist/route-change-check.js +13 -0
  225. package/dist/route-change.d.ts +22 -0
  226. package/dist/route-change.js +89 -0
  227. package/dist/route-hooks.js +3 -2
  228. package/dist/route-results.d.ts +6 -1
  229. package/dist/route-results.js +14 -5
  230. package/dist/run-closeout.d.ts +1 -1
  231. package/dist/run-closeout.js +7 -5
  232. package/dist/runner-process.js +3 -2
  233. package/dist/runner.js +2 -1
  234. package/dist/scope.d.ts +6 -1
  235. package/dist/scope.js +22 -9
  236. package/dist/serve.d.ts +1 -1
  237. package/dist/serve.js +24 -18
  238. package/dist/server/chat.js +14 -12
  239. package/dist/server/chrome.d.ts +1 -1
  240. package/dist/server/chrome.js +26 -35
  241. package/dist/server/console.css +23 -0
  242. package/dist/server/guards.js +3 -0
  243. package/dist/server/home.d.ts +6 -0
  244. package/dist/server/home.js +21 -13
  245. package/dist/server/http.js +1 -1
  246. package/dist/server/kit.js +1 -1
  247. package/dist/server/merge-ready-view.d.ts +10 -0
  248. package/dist/server/merge-ready-view.js +30 -0
  249. package/dist/server/pages-assets.d.ts +1 -0
  250. package/dist/server/pages-assets.js +8 -5
  251. package/dist/server/pages.js +103 -82
  252. package/dist/server/render-chat.js +2 -2
  253. package/dist/server/render-code-map.d.ts +30 -0
  254. package/dist/server/render-code-map.js +137 -0
  255. package/dist/server/render-flaky.d.ts +20 -0
  256. package/dist/server/render-flaky.js +59 -0
  257. package/dist/server/render-history.js +1 -1
  258. package/dist/server/render-new-task.d.ts +26 -1
  259. package/dist/server/render-new-task.js +30 -5
  260. package/dist/server/render-pages.d.ts +1 -175
  261. package/dist/server/render-pages.js +38 -313
  262. package/dist/server/render-projects.d.ts +2 -1
  263. package/dist/server/render-projects.js +9 -7
  264. package/dist/server/render-release.d.ts +2 -0
  265. package/dist/server/render-release.js +3 -3
  266. package/dist/server/render-results.d.ts +2 -0
  267. package/dist/server/render-results.js +67 -67
  268. package/dist/server/render-tasks.d.ts +13 -2
  269. package/dist/server/render-tasks.js +153 -136
  270. package/dist/server/retired-routes.d.ts +17 -0
  271. package/dist/server/retired-routes.js +53 -0
  272. package/dist/server/route-table.d.ts +3 -0
  273. package/dist/server/route-table.js +45 -12
  274. package/dist/server/settings.js +129 -22
  275. package/dist/server/task-views.js +61 -26
  276. package/dist/server/tasks.d.ts +2 -6
  277. package/dist/server/tasks.js +174 -321
  278. package/dist/server/welcome.js +1 -1
  279. package/dist/settings-groups-ui.js +1 -1
  280. package/dist/setup-guide.d.ts +2 -2
  281. package/dist/stop-proof.js +6 -4
  282. package/dist/storage-sweep-process.js +1 -1
  283. package/dist/storage-sweep.d.ts +5 -3
  284. package/dist/storage-sweep.js +30 -9
  285. package/dist/storage-ui.js +28 -17
  286. package/dist/storage.d.ts +27 -2
  287. package/dist/storage.js +39 -2
  288. package/dist/store.d.ts +80 -5
  289. package/dist/store.js +296 -87
  290. package/dist/surface.js +45 -4
  291. package/dist/sweep-quarantine.d.ts +1 -0
  292. package/dist/sweep-quarantine.js +6 -4
  293. package/dist/tamper-scan.d.ts +4 -0
  294. package/dist/tamper-scan.js +90 -0
  295. package/dist/task-aliases.d.ts +5 -0
  296. package/dist/task-aliases.js +9 -0
  297. package/dist/task-control.js +4 -1
  298. package/dist/task-outcome-cli.d.ts +2 -0
  299. package/dist/task-outcome-cli.js +17 -17
  300. package/dist/task-sizing.d.ts +5 -0
  301. package/dist/task-sizing.js +2 -0
  302. package/dist/task-source.d.ts +7 -0
  303. package/dist/task-source.js +14 -0
  304. package/dist/task-status.d.ts +9 -0
  305. package/dist/task-status.js +40 -49
  306. package/dist/teardown-git.d.ts +16 -0
  307. package/dist/teardown-git.js +63 -5
  308. package/dist/telegram-progress.js +5 -3
  309. package/dist/telegram-status.js +6 -4
  310. package/dist/test-infra.d.ts +8 -0
  311. package/dist/test-infra.js +18 -0
  312. package/dist/tidy.js +1 -1
  313. package/dist/toolroll-update.js +17 -5
  314. package/dist/tui-contract.d.ts +24 -0
  315. package/dist/tui-source.js +67 -8
  316. package/dist/tui.js +51 -51
  317. package/dist/vanished-retry.d.ts +30 -0
  318. package/dist/vanished-retry.js +174 -0
  319. package/dist/work-index.d.ts +2 -0
  320. package/dist/work-index.js +76 -62
  321. package/dist/work-summary.js +2 -0
  322. package/dist/workspace-ui.d.ts +4 -2
  323. package/dist/workspace-ui.js +28 -22
  324. package/dist/worktree.d.ts +12 -3
  325. package/dist/worktree.js +68 -13
  326. package/package.json +1 -1
  327. package/dist/server/render-next.d.ts +0 -63
  328. package/dist/server/render-next.js +0 -109
@@ -11,7 +11,7 @@
11
11
  import { z } from "zod";
12
12
  import { TEXT_LIMITS } from "../text-limits.js";
13
13
  import { envelopeSchema } from "./cli.js";
14
- import { catchUpOutput, decisionOutput, decisionsOutput, LISTED_TASK_STATES, queueColumnsOutput, recapOutput, repositoryContextOutput, scopeText, touches } from "./lead-tools.js";
14
+ import { catchUpOutput, CODE_MAP_VIEWS, codeMapOutput, decisionOutput, decisionsOutput, LISTED_TASK_STATES, queueColumnsOutput, recapOutput, repositoryContextOutput, scopeText, touches } from "./lead-tools.js";
15
15
  const text = (key) => z.string().max(TEXT_LIMITS[key]);
16
16
  const ref = z.string().min(1).max(TEXT_LIMITS.taskRef);
17
17
  const projectPath = text("projectPath").min(1);
@@ -30,6 +30,7 @@ export const ASSIGNMENT_INPUTS = {
30
30
  };
31
31
  export const GATEWAY_TOOL_INPUTS = {
32
32
  get_project_context: z.strictObject({ repo: projectPath, query: text("contextQuery").min(1), mode: z.enum(["search", "impact"]).optional() }),
33
+ get_code_map: z.strictObject({ repo: projectPath, version: z.int().min(1).optional(), view: z.enum(CODE_MAP_VIEWS), id: text("projectPath").optional(), query: text("contextQuery").optional(), cursor: z.string().max(40).optional() }),
33
34
  get_assignment: ASSIGNMENT_INPUTS.show,
34
35
  list_assignment_updates: ASSIGNMENT_INPUTS.updates,
35
36
  claim_assignment: ASSIGNMENT_INPUTS.claim,
@@ -68,6 +69,7 @@ const proposed = z.looseObject({ proposal: int, kind: z.enum(["next", "reserve",
68
69
  const assignmentOutput = z.looseObject({ version: z.literal(1), rootId: str, activeTaskId: str, title: str, state: str, detail: str, attention: z.array(str) });
69
70
  export const GATEWAY_TOOL_OUTPUTS = {
70
71
  get_project_context: repositoryContextOutput,
72
+ get_code_map: codeMapOutput,
71
73
  get_assignment: assignmentOutput,
72
74
  list_assignment_updates: z.looseObject({ events: list, nextCursor: int, hasMore: z.boolean() }),
73
75
  claim_assignment: assignmentOutput,
@@ -30,6 +30,7 @@ export declare const acceptance: z.ZodArray<z.ZodObject<{
30
30
  screenshot: "screenshot";
31
31
  }>>;
32
32
  }, z.core.$strict>>;
33
+ export declare const CODE_MAP_VIEWS: readonly ["overview", "area", "file", "search"];
33
34
  /** Task states a list filters by. */
34
35
  export declare const LISTED_TASK_STATES: readonly ["queued", "running", "done", "failed", "cancelled"];
35
36
  export declare const LEAD_TOOL_INPUTS: {
@@ -48,6 +49,22 @@ export declare const LEAD_TOOL_INPUTS: {
48
49
  search: "search";
49
50
  }>>;
50
51
  }, z.core.$strict>;
52
+ readonly get_code_map: z.ZodObject<{
53
+ repo: z.ZodString;
54
+ version: z.ZodOptional<z.ZodInt>;
55
+ view: z.ZodEnum<{
56
+ area: "area";
57
+ file: "file";
58
+ overview: "overview";
59
+ search: "search";
60
+ }>;
61
+ id: z.ZodOptional<z.ZodString>;
62
+ query: z.ZodOptional<z.ZodString>;
63
+ cursor: z.ZodOptional<z.ZodString>;
64
+ }, z.core.$strict>;
65
+ readonly refresh_code_map: z.ZodObject<{
66
+ repo: z.ZodString;
67
+ }, z.core.$strict>;
51
68
  readonly get_action_status: z.ZodObject<{
52
69
  proposal: z.ZodInt;
53
70
  }, z.core.$strict>;
@@ -74,6 +91,7 @@ export declare const LEAD_TOOL_INPUTS: {
74
91
  url: z.ZodOptional<z.ZodString>;
75
92
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
76
93
  about: z.ZodOptional<z.ZodString>;
94
+ on: z.ZodOptional<z.ZodBoolean>;
77
95
  }, z.core.$strict>;
78
96
  readonly propose_task_action: z.ZodObject<{
79
97
  task: z.ZodString;
@@ -537,6 +555,10 @@ export declare const LEAD_TOOL_INPUTS: {
537
555
  reference: z.ZodOptional<z.ZodString>;
538
556
  decision: z.ZodOptional<z.ZodInt>;
539
557
  }, z.core.$strict>;
558
+ readonly get_flaky_tests: z.ZodObject<{
559
+ repo: z.ZodString;
560
+ row: z.ZodOptional<z.ZodString>;
561
+ }, z.core.$strict>;
540
562
  readonly get_task_conversation: z.ZodObject<{
541
563
  task: z.ZodString;
542
564
  limit: z.ZodOptional<z.ZodInt>;
@@ -785,6 +807,22 @@ export declare const LEAD_TOOL_READ_INPUTS: {
785
807
  search: "search";
786
808
  }>>;
787
809
  }, z.core.$strict>;
810
+ readonly get_code_map: z.ZodObject<{
811
+ repo: z.ZodString;
812
+ version: z.ZodOptional<z.ZodInt>;
813
+ view: z.ZodEnum<{
814
+ area: "area";
815
+ file: "file";
816
+ overview: "overview";
817
+ search: "search";
818
+ }>;
819
+ id: z.ZodOptional<z.ZodString>;
820
+ query: z.ZodOptional<z.ZodString>;
821
+ cursor: z.ZodOptional<z.ZodString>;
822
+ }, z.core.$strict>;
823
+ readonly refresh_code_map: z.ZodObject<{
824
+ repo: z.ZodString;
825
+ }, z.core.$strict>;
788
826
  readonly get_action_status: z.ZodObject<{
789
827
  proposal: z.ZodInt;
790
828
  }, z.core.$strict>;
@@ -811,6 +849,7 @@ export declare const LEAD_TOOL_READ_INPUTS: {
811
849
  url: z.ZodOptional<z.ZodString>;
812
850
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
813
851
  about: z.ZodOptional<z.ZodString>;
852
+ on: z.ZodOptional<z.ZodBoolean>;
814
853
  }, z.core.$strict>;
815
854
  readonly propose_task_action: z.ZodObject<{
816
855
  task: z.ZodString;
@@ -1267,6 +1306,10 @@ export declare const LEAD_TOOL_READ_INPUTS: {
1267
1306
  reference: z.ZodOptional<z.ZodString>;
1268
1307
  decision: z.ZodOptional<z.ZodInt>;
1269
1308
  }, z.core.$strict>;
1309
+ readonly get_flaky_tests: z.ZodObject<{
1310
+ repo: z.ZodString;
1311
+ row: z.ZodOptional<z.ZodString>;
1312
+ }, z.core.$strict>;
1270
1313
  readonly commit_to: z.ZodObject<{
1271
1314
  what: z.ZodString;
1272
1315
  when: z.ZodEnum<{
@@ -1503,6 +1546,11 @@ export declare const LEAD_TOOL_READ_INPUTS: {
1503
1546
  export type LeadToolInput<N extends LeadToolName> = z.infer<(typeof LEAD_TOOL_READ_INPUTS)[N]>;
1504
1547
  /** How a tool's call names a key it doesn't know: propose_flow suggests the flow vocabulary's own words. */
1505
1548
  export declare const LEAD_TOOL_OPTIONS: Partial<Record<LeadToolName, ContractOptions>>;
1549
+ /** One bounded answer from the shared code map reader (code-map-read.ts `MapAnswer`). */
1550
+ export declare const codeMapOutput: z.ZodObject<{
1551
+ v: z.ZodLiteral<1>;
1552
+ ok: z.ZodBoolean;
1553
+ }, z.core.$loose>;
1506
1554
  /** A repository-context read (repository-context.ts `RepositoryContext`). */
1507
1555
  export declare const repositoryContextOutput: z.ZodObject<{
1508
1556
  version: z.ZodLiteral<1>;
@@ -1609,6 +1657,16 @@ export declare const LEAD_TOOL_OUTPUTS: {
1609
1657
  asOf: z.ZodString;
1610
1658
  excerpts: z.ZodArray<z.ZodUnknown>;
1611
1659
  }, z.core.$loose>;
1660
+ readonly get_code_map: z.ZodObject<{
1661
+ v: z.ZodLiteral<1>;
1662
+ ok: z.ZodBoolean;
1663
+ }, z.core.$loose>;
1664
+ readonly refresh_code_map: z.ZodObject<{
1665
+ request: z.ZodEnum<{
1666
+ "already-queued": "already-queued";
1667
+ queued: "queued";
1668
+ }>;
1669
+ }, z.core.$loose>;
1612
1670
  readonly get_action_status: z.ZodObject<{
1613
1671
  proposal: z.ZodNumber;
1614
1672
  operation: z.ZodString;
@@ -1824,6 +1882,9 @@ export declare const LEAD_TOOL_OUTPUTS: {
1824
1882
  readonly get_project_knowledge: z.ZodObject<{
1825
1883
  revision: z.ZodNumber;
1826
1884
  }, z.core.$loose>;
1885
+ readonly get_flaky_tests: z.ZodObject<{
1886
+ notice: z.ZodString;
1887
+ }, z.core.$loose>;
1827
1888
  readonly get_task_conversation: z.ZodObject<{
1828
1889
  task: z.ZodString;
1829
1890
  messages: z.ZodArray<z.ZodObject<{
@@ -46,6 +46,7 @@ export const touches = z.array(text("taskTouch")).max(50);
46
46
  export const acceptance = z.array(acceptanceCriterionSchema).min(1).max(ACCEPTANCE_LIMITS.criteria);
47
47
  /** A note the operator's own words fill (revise feedback, steering, a flow card's note). */
48
48
  const note = z.string().max(LIMITS.note, { error: issue => overBy(LIMITS.note, issue.input) }).describe(`At most ${LIMITS.note} characters; longer is refused with its length, not cut.`);
49
+ export const CODE_MAP_VIEWS = ["overview", "area", "file", "search"];
49
50
  /** Task states a list filters by. */
50
51
  export const LISTED_TASK_STATES = ["queued", "running", "done", "failed", "cancelled"];
51
52
  /** The shared actions the lead proposes with propose_action; flows and subagents have their own tools. */
@@ -54,6 +55,8 @@ export const LEAD_TOOL_INPUTS = {
54
55
  get_brief: z.strictObject({ repo: repoId.optional() }),
55
56
  get_project_activity: z.strictObject({ repo: repoId, offset: offset.optional() }),
56
57
  get_project_context: z.strictObject({ repo: repoId, query: text("contextQuery").min(1), mode: z.enum(["search", "impact"]).optional() }),
58
+ get_code_map: z.strictObject({ repo: repoId, version: id.optional(), view: z.enum(CODE_MAP_VIEWS), id: text("projectPath").optional(), query: text("contextQuery").optional(), cursor: z.string().max(40).optional() }),
59
+ refresh_code_map: z.strictObject({ repo: repoId }),
57
60
  get_action_status: z.strictObject({ proposal: id }),
58
61
  get_actions: z.strictObject({}),
59
62
  propose_action: z.strictObject({
@@ -61,7 +64,7 @@ export const LEAD_TOOL_INPUTS = {
61
64
  sample: text("actionSample").optional(), content: text("actionContent").optional(), instructions: text("flowInstructions").optional(),
62
65
  title: text("actionTitle").optional(), id: z.string().optional(), run: id.optional(), note: note.optional(), catalog: text("actionName").optional(),
63
66
  name: text("actionName").optional(), command: text("actionCommand").optional(), args: z.array(text("actionCommand")).max(40).optional(),
64
- url: text("actionUrl").optional(), secrets: z.array(text("actionSecret")).max(12).optional(), about: text("actionAbout").optional(),
67
+ url: text("actionUrl").optional(), secrets: z.array(text("actionSecret")).max(12).optional(), about: text("actionAbout").optional(), on: z.boolean().optional(),
65
68
  }),
66
69
  propose_task_action: z.strictObject({ task: taskRef, operation: enumOf(Object.keys(CHAT_TASK_ACTIONS)), dependency: taskRef.optional(), run: id.optional() }),
67
70
  get_controls: z.strictObject({}),
@@ -100,6 +103,7 @@ export const LEAD_TOOL_INPUTS = {
100
103
  get_flow_insights: z.strictObject({ repo: repoId.optional(), flow: id.optional(), days: z.int().min(1).max(90).optional(), card: id.optional(), entry: id.optional() }),
101
104
  get_skills: z.strictObject({ repo: repoId, version: z.string().regex(/^[a-f0-9]{20}$/).optional(), offset: offset.optional() }),
102
105
  get_project_knowledge: z.strictObject({ repo: repoId, reference: text("knowledgeReference").optional(), decision: id.optional() }),
106
+ get_flaky_tests: z.strictObject({ repo: repoId, row: text("knowledgeReference").optional() }),
103
107
  get_task_conversation: z.strictObject({ task: taskRef, limit: z.int().min(1).max(30).optional() }),
104
108
  commit_to: z.strictObject({
105
109
  what: text("promise").min(3), when: z.enum(["task", "run", "check", "time"]), task: taskRef.optional(), run: id.optional(),
@@ -185,6 +189,8 @@ const rows = (shape) => z.array(z.looseObject(shape));
185
189
  const cardDrafted = z.looseObject({ proposal: int, label: str, awaiting: str, executed: z.literal(false) });
186
190
  /** A proposal row drafted by one of the queue, hold, scope and answer tools. */
187
191
  const proposed = (kind, shape = {}) => z.looseObject({ proposal: int, kind: z.literal(kind), awaiting: str, ...shape });
192
+ /** One bounded answer from the shared code map reader (code-map-read.ts `MapAnswer`). */
193
+ export const codeMapOutput = z.looseObject({ v: z.literal(1), ok: z.boolean() });
188
194
  /** A repository-context read (repository-context.ts `RepositoryContext`). */
189
195
  export const repositoryContextOutput = z.looseObject({ version: z.literal(1), readOnly: z.boolean(), query: str, mode: z.enum(["search", "impact"]), asOf: str, excerpts: list });
190
196
  /** The local catch-up (assignment-brief.ts `AssignmentCatchUp`). */
@@ -201,6 +207,8 @@ export const LEAD_TOOL_OUTPUTS = {
201
207
  get_brief: catchUpOutput,
202
208
  get_project_activity: z.looseObject({ asOf: str, since: str, days: int, limit: int, truncated: z.boolean(), ready: z.object({ count: int, oldestFinishedAgeMs: nullable(int), dated: int }), completed: z.looseObject({ count: int }), families: list, familiesTotal: int, familiesOffset: int, nextOffset: nullable(int), incompleteHistory: int }),
203
209
  get_project_context: repositoryContextOutput,
210
+ get_code_map: codeMapOutput,
211
+ refresh_code_map: z.looseObject({ request: z.enum(["queued", "already-queued"]) }),
204
212
  get_action_status: z.looseObject({ proposal: int, operation: str, state: str, outcome: z.unknown(), finishedAt: nullable(str) }),
205
213
  get_actions: z.looseObject({ actions: rows({ operation: str, label: str, secureReview: z.boolean(), inputs: z.array(str) }), notice: str }),
206
214
  propose_action: cardDrafted,
@@ -241,6 +249,7 @@ export const LEAD_TOOL_OUTPUTS = {
241
249
  z.looseObject({ skills: list, nextOffset: nullable(int) }),
242
250
  ]),
243
251
  get_project_knowledge: z.looseObject({ revision: int }),
252
+ get_flaky_tests: z.looseObject({ notice: z.string() }),
244
253
  get_task_conversation: z.looseObject({ task: str, messages: rows({ from: z.enum(["operator", "lead"]), text: str, at: str }), notice: nullable(str) }),
245
254
  commit_to: z.looseObject({ commitment: int, condition: str, expires: str, report: str }),
246
255
  release_commitment: z.looseObject({ commitment: int, state: z.literal("cancelled") }),
@@ -68,10 +68,12 @@ export declare const knowledgeOmissionSchema: z.ZodObject<{
68
68
  title: z.ZodString;
69
69
  reason: z.ZodString;
70
70
  }, z.core.$strict>;
71
- export declare const KNOWLEDGE_SELECTION_VERSION = 1;
71
+ /** Version 2 (docs/plans/learning-loops.md, "Versioned snapshots"): a selection says when it was frozen, and its decision
72
+ * lines their revision. Version 1 stays readable exactly as it was frozen, its fields as they are. */
73
+ export declare const KNOWLEDGE_SELECTION_VERSION = 2;
72
74
  /** The selection a run is given, as it is frozen. The keys are in the order a selection has always been written. */
73
75
  export declare const knowledgeSelectionSchema: z.ZodObject<{
74
- version: z.ZodLiteral<1>;
76
+ version: z.ZodLiteral<2>;
75
77
  revision: z.ZodInt;
76
78
  instructions: z.ZodString;
77
79
  references: z.ZodArray<z.ZodObject<{
@@ -91,11 +93,39 @@ export declare const knowledgeSelectionSchema: z.ZodObject<{
91
93
  id: z.ZodInt;
92
94
  claim: z.ZodString;
93
95
  decidedAt: z.ZodString;
96
+ revision: z.ZodOptional<z.ZodInt>;
94
97
  }, z.core.$strict>>>;
95
98
  repository: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
99
+ capturedAt: z.ZodString;
96
100
  }, z.core.$strict>;
97
- /** A frozen selection as it is read back. */
101
+ /** A frozen selection as it is read back: the version it was frozen under. */
98
102
  export declare const savedKnowledgeSelectionSchema: z.ZodObject<{
103
+ version: z.ZodLiteral<2>;
104
+ revision: z.ZodInt;
105
+ instructions: z.ZodString;
106
+ references: z.ZodArray<z.ZodObject<{
107
+ id: z.ZodString;
108
+ title: z.ZodString;
109
+ content: z.ZodString;
110
+ path: z.ZodNullable<z.ZodString>;
111
+ sourceSha: z.ZodNullable<z.ZodString>;
112
+ sourceRevision: z.ZodNullable<z.ZodString>;
113
+ }, z.core.$strict>>;
114
+ omitted: z.ZodArray<z.ZodObject<{
115
+ title: z.ZodString;
116
+ reason: z.ZodString;
117
+ }, z.core.$strict>>;
118
+ inheritedFrom: z.ZodNullable<z.ZodInt>;
119
+ decisions: z.ZodOptional<z.ZodArray<z.ZodObject<{
120
+ id: z.ZodInt;
121
+ claim: z.ZodString;
122
+ decidedAt: z.ZodString;
123
+ revision: z.ZodOptional<z.ZodInt>;
124
+ }, z.core.$strict>>>;
125
+ repository: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
126
+ capturedAt: z.ZodString;
127
+ }, z.core.$strict>;
128
+ export declare const savedKnowledgeSelectionV1Schema: z.ZodObject<{
99
129
  version: z.ZodLiteral<1>;
100
130
  revision: z.ZodInt;
101
131
  instructions: z.ZodString;
@@ -116,11 +146,14 @@ export declare const savedKnowledgeSelectionSchema: z.ZodObject<{
116
146
  id: z.ZodInt;
117
147
  claim: z.ZodString;
118
148
  decidedAt: z.ZodString;
149
+ revision: z.ZodOptional<z.ZodInt>;
119
150
  }, z.core.$strict>>>;
120
151
  repository: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
121
152
  }, z.core.$strict>;
122
- export type KnowledgeSelection = Omit<z.infer<typeof knowledgeSelectionSchema>, "repository"> & {
153
+ export type KnowledgeSelection = Omit<z.infer<typeof knowledgeSelectionSchema>, "repository" | "version" | "capturedAt"> & {
154
+ version: 1 | 2;
155
+ capturedAt?: string;
123
156
  repository?: RepositoryContext;
124
157
  };
125
- /** Read a frozen selection: version 1 (every selection ever frozen) as itself, a newer one refused plainly. */
158
+ /** Read a frozen selection: version 1 and 2 each as themselves, a newer one refused plainly. */
126
159
  export declare function readKnowledgeSelection(input: unknown): ContractResult<KnowledgeSelection>;
@@ -82,12 +82,18 @@ const selectionShape = (text) => ({
82
82
  /** Source excerpts from the crew's checkout (repository-context.ts owns their shape); absent when not captured. */
83
83
  repository: z.looseObject({}).optional(),
84
84
  });
85
- export const KNOWLEDGE_SELECTION_VERSION = 1;
85
+ /** Version 2 (docs/plans/learning-loops.md, "Versioned snapshots"): a selection says when it was frozen, and its decision
86
+ * lines their revision. Version 1 stays readable exactly as it was frozen, its fields as they are. */
87
+ export const KNOWLEDGE_SELECTION_VERSION = 2;
86
88
  /** The selection a run is given, as it is frozen. The keys are in the order a selection has always been written. */
87
- export const knowledgeSelectionSchema = versioned(KNOWLEDGE_SELECTION_VERSION, selectionShape(written));
88
- /** A frozen selection as it is read back. */
89
- export const savedKnowledgeSelectionSchema = versioned(KNOWLEDGE_SELECTION_VERSION, selectionShape(saved));
90
- /** Read a frozen selection: version 1 (every selection ever frozen) as itself, a newer one refused plainly. */
89
+ export const knowledgeSelectionSchema = versioned(KNOWLEDGE_SELECTION_VERSION, { ...selectionShape(written), capturedAt: z.string() });
90
+ /** A frozen selection as it is read back: the version it was frozen under. */
91
+ export const savedKnowledgeSelectionSchema = versioned(KNOWLEDGE_SELECTION_VERSION, { ...selectionShape(saved), capturedAt: z.string() });
92
+ export const savedKnowledgeSelectionV1Schema = versioned(1, selectionShape(saved));
93
+ /** Read a frozen selection: version 1 and 2 each as themselves, a newer one refused plainly. */
91
94
  export function readKnowledgeSelection(input) {
95
+ const version = input !== null && typeof input === "object" ? input.version : undefined;
96
+ if (version === 1)
97
+ return readVersioned(savedKnowledgeSelectionV1Schema, input);
92
98
  return readVersioned(savedKnowledgeSelectionSchema, input);
93
99
  }
@@ -75,11 +75,13 @@ export declare const decisionDraftSchema: z.ZodObject<{
75
75
  supersedes: z.ZodOptional<z.ZodNullable<z.ZodInt>>;
76
76
  }, z.core.$strict>;
77
77
  export type DecisionDraft = z.infer<typeof decisionDraftSchema>;
78
- /** One decision in a brief: its id, the choice and when; the why loads on demand by id. */
78
+ /** One decision in a brief: its id, the choice and when (the revision on snapshots from version 2 on); the why loads on
79
+ * demand by id. */
79
80
  export declare const decisionLineSchema: z.ZodObject<{
80
81
  id: z.ZodInt;
81
82
  claim: z.ZodString;
82
83
  decidedAt: z.ZodString;
84
+ revision: z.ZodOptional<z.ZodInt>;
83
85
  }, z.core.$strict>;
84
86
  export type DecisionLine = z.infer<typeof decisionLineSchema>;
85
87
  export declare const DECISION_CHANGE_VERSION = 1;
@@ -38,8 +38,9 @@ export const decisionDraftSchema = z.strictObject({
38
38
  sourceRef: z.string().nullable().optional(),
39
39
  supersedes: z.int().nullable().optional(),
40
40
  });
41
- /** One decision in a brief: its id, the choice and when; the why loads on demand by id. */
42
- export const decisionLineSchema = z.strictObject({ id: z.int(), claim: z.string(), decidedAt: z.string() });
41
+ /** One decision in a brief: its id, the choice and when (the revision on snapshots from version 2 on); the why loads on
42
+ * demand by id. */
43
+ export const decisionLineSchema = z.strictObject({ id: z.int(), claim: z.string(), decidedAt: z.string(), revision: z.int().min(1).optional() });
43
44
  export const DECISION_CHANGE_VERSION = 1;
44
45
  /**
45
46
  * One entry of a decision's history (`decision_change.payload`): the record when it was made, or the reason its status
@@ -11,6 +11,13 @@ export declare const checkoutCleanupSchema: z.ZodEnum<{
11
11
  finished: "finished";
12
12
  never: "never";
13
13
  }>;
14
+ /** How long a task stays idle before its clean folder goes (v151, checkout-cleanup.ts). A saved row's NULL is the default. */
15
+ export declare const checkoutIdleSchema: z.ZodEnum<{
16
+ "14d": "14d";
17
+ "30d": "30d";
18
+ "7d": "7d";
19
+ never: "never";
20
+ }>;
14
21
  /** A saved `checkout_cleanup_setting` row (at most one; none means the default), unknown columns ignored. */
15
22
  export declare const checkoutCleanupRowSchema: z.ZodObject<{
16
23
  cleanup: z.ZodEnum<{
@@ -19,5 +26,12 @@ export declare const checkoutCleanupRowSchema: z.ZodObject<{
19
26
  finished: "finished";
20
27
  never: "never";
21
28
  }>;
29
+ idle: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
30
+ "14d": "14d";
31
+ "30d": "30d";
32
+ "7d": "7d";
33
+ never: "never";
34
+ }>>>;
22
35
  }, z.core.$strip>;
23
36
  export type CheckoutCleanup = z.infer<typeof checkoutCleanupSchema>;
37
+ export type CheckoutIdle = z.infer<typeof checkoutIdleSchema>;
@@ -6,5 +6,7 @@
6
6
  */
7
7
  import { z } from "zod";
8
8
  export const checkoutCleanupSchema = z.enum(["finished", "2d", "7d", "never"]);
9
+ /** How long a task stays idle before its clean folder goes (v151, checkout-cleanup.ts). A saved row's NULL is the default. */
10
+ export const checkoutIdleSchema = z.enum(["7d", "14d", "30d", "never"]);
9
11
  /** A saved `checkout_cleanup_setting` row (at most one; none means the default), unknown columns ignored. */
10
- export const checkoutCleanupRowSchema = z.object({ cleanup: checkoutCleanupSchema });
12
+ export const checkoutCleanupRowSchema = z.object({ cleanup: checkoutCleanupSchema, idle: checkoutIdleSchema.nullable().optional() });
@@ -166,6 +166,8 @@ declare const STORE_COLUMN_VALUES: {
166
166
  readonly "lead_proposal.payload_json": z.ZodUnion<readonly [z.ZodObject<{
167
167
  version: z.ZodLiteral<1>;
168
168
  operation: z.ZodEnum<{
169
+ code_map_holdout_end: "code_map_holdout_end";
170
+ code_map_switch: "code_map_switch";
169
171
  decision_record: "decision_record";
170
172
  decision_retire: "decision_retire";
171
173
  flow_browser: "flow_browser";
@@ -15,7 +15,7 @@ export declare const YOUIYOUX_FILED_VIA = "youiyoux";
15
15
  * Approve all and each one's own Approve and Open. */
16
16
  export declare const YOUIYOUX_CARD_KIND = "youiyoux-requests";
17
17
  /** Where a person sees and approves everything waiting on them in the console (flow-triggers.ts NEEDS_YOU_HREF). */
18
- export declare const YOUIYOUX_HOME_PATH = "/work?view=needs-you";
18
+ export declare const YOUIYOUX_HOME_PATH = "/tasks?view=needs-you";
19
19
  export declare const YOUIYOUX_EVIDENCE: readonly ["screenshot", "check", "changed-path", "manual-review"];
20
20
  /** What an options request offers its agent: the one file to write (`.youi/proposals/<proposal>.json`), the props an
21
21
  * option may set (enum values from `values`), and whether it may give the component new text. */
@@ -15,7 +15,7 @@ export const YOUIYOUX_FILED_VIA = "youiyoux";
15
15
  * Approve all and each one's own Approve and Open. */
16
16
  export const YOUIYOUX_CARD_KIND = "youiyoux-requests";
17
17
  /** Where a person sees and approves everything waiting on them in the console (flow-triggers.ts NEEDS_YOU_HREF). */
18
- export const YOUIYOUX_HOME_PATH = "/work?view=needs-you";
18
+ export const YOUIYOUX_HOME_PATH = "/tasks?view=needs-you";
19
19
  const text = (max) => z.string().min(1).max(max);
20
20
  const who = z.object({ kind: z.enum(["person", "agent"]), name: text(100) });
21
21
  // The published schema's date-time: an ISO timestamp with a zone.
@@ -2,8 +2,8 @@
2
2
  import { mkdtempSync, readFileSync, writeFileSync, unlinkSync, rmdirSync, opendirSync, realpathSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { execFileSync } from "node:child_process";
6
5
  import { run } from "./exec.js";
6
+ import { checkoutGitSync, checkoutTop } from "./teardown-git.js";
7
7
  export function accessFailure(repo, code) {
8
8
  if (code === "EROFS")
9
9
  return { repo, state: "permission-needed", message: "This project is on a read-only drive. Choose a writable copy; Privacy Settings cannot make a read-only drive writable." };
@@ -23,7 +23,11 @@ export function probeDesktopProject(repo) {
23
23
  const directory = opendirSync(repo);
24
24
  directory.readSync();
25
25
  directory.closeSync();
26
- const common = execFileSync("git", ["-C", repo, "rev-parse", "--path-format=absolute", "--git-common-dir"], { encoding: "utf8", timeout: 4000, stdio: ["ignore", "pipe", "pipe"] }).trim();
26
+ // The project's own repository, read through a frozen view: a build's include naming a FIFO can't hang the probe.
27
+ const top = checkoutTop(repo, 4000);
28
+ if (top === null)
29
+ throw Error("Not a readable Git checkout");
30
+ const common = checkoutGitSync(top, ["rev-parse", "--path-format=absolute", "--git-common-dir"], { timeoutMs: 4000, binding: { repo: top } }).trim();
27
31
  scratch = mkdtempSync(join(realpathSync(common), "standing-orders-access-"));
28
32
  const file = join(scratch, "check");
29
33
  writeFileSync(file, "Toolroll access check\n", { flag: "wx", mode: 0o600 });
package/dist/dispatch.js CHANGED
@@ -16,6 +16,8 @@ import { REVIEW_TOKENS, resultStatusOf, reviewFactsOf } from "./workspace-ui.js"
16
16
  import { replacedWords } from "./task-status.js";
17
17
  import { failedAttemptSentence, latestFinishedAttempt } from "./needs-you.js";
18
18
  import { buildReviewOf } from "./review-switch.js";
19
+ import { vanishedStopOf, vanishedStopSentence } from "./vanished-retry.js";
20
+ import { routeChangeOf } from "./route-change.js";
19
21
  import { BUILT_IN, refArchived, parseCapabilityKey } from "./store.js";
20
22
  import { shortWhen } from "./when-html.js";
21
23
  export const DEFAULT_MAX_OPEN_DECISIONS = 5;
@@ -81,7 +83,7 @@ export function scopeApprovedForDispatch(store, taskRef, now) {
81
83
  JOIN task_ref ON task_ref.id = ? AND task_scope.task_id = task_ref.external_id
82
84
  WHERE task_scope.approved_digest = task_scope.digest AND task_scope.approved_at IS NOT NULL
83
85
  AND ${authorityStandsSql("task_scope", "task_ref.repo", "?")}`)
84
- .get(taskRef, now.toISOString(), now.toISOString(), now.toISOString());
86
+ .get(taskRef, now.toISOString(), now.toISOString(), now.toISOString(), now.toISOString());
85
87
  return row !== undefined;
86
88
  }
87
89
  /** The phase the ordinary dispatch loop would choose before it resolves an
@@ -229,9 +231,9 @@ export function diagnoseTaskDispatch(store, taskId, now, readableRepos = null) {
229
231
  return answer(code, code === "reviewing" ? "running" : "waiting", status.label, status.detail, { action: retry.state === "retryable" ? "retry-review" : "open-result", review });
230
232
  }
231
233
  if (!accepted && proof?.verdict === "refuted")
232
- return answer("proof-refuted", "waiting", status.label, `${status.detail} Review the evidence to correct it, or record an explicit acceptance.`, { action: "open-result", review });
234
+ return answer("proof-refuted", "waiting", status.label, `${status.detail} Open the result to send it back, or accept it with a reason.`, { action: "open-result", review });
233
235
  if (!accepted && proof?.verdict === "short")
234
- return answer("needs-verification", "waiting", status.label, `${status.detail} Open the result for the exact criteria still needing verification.`, { action: "open-result", review });
236
+ return answer("needs-verification", "waiting", status.label, `${status.detail} Open the result to see which requirements still need checking.`, { action: "open-result", review });
235
237
  if (!accepted && proof === null && noChangeRecord !== true)
236
238
  return answer("needs-verification", "waiting", status.label, status.detail, { action: "open-result", review });
237
239
  return answer("complete", "terminal", status.label, review?.state === "succeeded" && review.attempt !== null && review.attempt > 1
@@ -248,12 +250,13 @@ export function diagnoseTaskDispatch(store, taskId, now, readableRepos = null) {
248
250
  // The family's latest finished attempt's own recorded reason, or that none was recorded: never "review its incident".
249
251
  const family = store.taskFamilyOf(taskId, ref.repo === null ? [] : [ref.repo], ref.repo === null);
250
252
  const runs = family === null || family.problem !== null ? store.runsFor(ref.id) : family.versions.flatMap(version => store.runsFor(version.refId));
251
- return answer("failed", "terminal", "Needs a retry", failedAttemptSentence(latestFinishedAttempt(runs)?.reason), { action: "retry-task" });
253
+ const stopped = vanishedStopOf(store, ref.id);
254
+ return answer("failed", "terminal", "Needs a retry", stopped === null ? failedAttemptSentence(latestFinishedAttempt(runs)?.reason) : vanishedStopSentence(stopped), { action: "retry-task" });
252
255
  }
253
256
  if (store.hasLiveClaim(ref.id, now))
254
- return answer("running", "running", "Running now", "A worker owns the current live claim.");
257
+ return answer("running", "running", "Running now", "A builder is working on it now.");
255
258
  if (task.state === "running")
256
- return answer("vanished-run", "waiting", "Build vanished", "The task says running, but no current claim owns it; reconcile it before retrying.", { action: "retry-task" });
259
+ return answer("vanished-run", "waiting", "Build vanished", "The build stopped unexpectedly. Retry it.", { action: "retry-task" });
257
260
  if (updateAdmissionPaused(store.raw()))
258
261
  return answer("updating", "waiting", "Waiting for app update", UPDATE_PAUSED);
259
262
  const local = taskReadinessBlocker(store, ref.id, now);
@@ -270,7 +273,7 @@ export function diagnoseTaskDispatch(store, taskId, now, readableRepos = null) {
270
273
  if (local.ownerKind === "decision")
271
274
  return answer("waiting-decision", "waiting", "Waiting on your answer", "An agent parked a question; answering it resumes the task.", { action: "answer-decision" });
272
275
  if (local.ownerKind === "incident")
273
- return answer("waiting-incident", "waiting", "Needs a retry", "An unresolved incident holds the next attempt.", { action: "retry-task" });
276
+ return answer("waiting-incident", "waiting", "Needs a retry", "The last attempts failed the same way. Retry, or change the plan.", { action: "retry-task" });
274
277
  if (local.ownerKind === "stop")
275
278
  return answer("stopped", "waiting", "Paused", `${local.message.replace(/^held:\s*/, "")}. The attempt's work is preserved; resuming that exact attempt lifts this pause.`, { action: "resume-run" });
276
279
  return answer("held", "waiting", "On hold", local.message.replace(/^held:\s*/, ""), { action: local.ownerKind === "operator" ? "unhold" : "inspect-hold" });
@@ -288,14 +291,14 @@ export function diagnoseTaskDispatch(store, taskId, now, readableRepos = null) {
288
291
  const role = dispatchRoleFor(store, ref.id, now);
289
292
  const scope = store.getScope(taskId);
290
293
  if (ref.repo === null)
291
- return answer("needs-project", "waiting", "Needs a project", "Place this task in a repository before a worker can claim it.", { action: "place-task", role });
294
+ return answer("needs-project", "waiting", "Needs a project", "Choose a project for this task so a builder can start it.", { action: "place-task", role });
292
295
  if (role !== "planner") {
293
296
  if (scope === null)
294
- return answer("needs-scope", "waiting", "Needs a scope", "Write the success contract or ask the planner to draft it.", { action: "write-scope", role });
297
+ return answer("needs-scope", "waiting", "Needs a plan", "Write the plan, or ask the planner to draft it.", { action: "write-scope", role });
295
298
  if (scope.profileState === "unresolved")
296
299
  return answer("needs-agent-profile", "waiting", "Needs an agent profile", scope.unresolvedReason ?? "Choose an available provider and model.", { action: "select-agent", role });
297
300
  if (!scopeApprovedForDispatch(store, ref.id, now) || !approvalOf(scope).approved) {
298
- return answer("needs-approval", "waiting", "Needs your approval", "Review and sign the current scope before a worker can claim it.", { action: "approve-scope", role });
301
+ return answer("needs-approval", "waiting", "Needs your approval", routeChangeOf(store, taskId) ?? "Review the plan and approve it so a builder can start.", { action: "approve-scope", role });
299
302
  }
300
303
  }
301
304
  const gap = missingCapability(store, ref.id, ref.repo, now);
@@ -315,14 +318,14 @@ export function diagnoseTaskDispatch(store, taskId, now, readableRepos = null) {
315
318
  }
316
319
  const available = alive.filter(one => store.liveClaimCount(one.name, now) < one.capacity);
317
320
  if (available.length === 0)
318
- return answer("worker-at-capacity", "retrying", "Waiting for worker capacity", "Every eligible worker is busy; this task starts when a slot is released.", { role });
321
+ return answer("worker-at-capacity", "retrying", "Waiting its turn", "Builders are busy; it starts when one is free.", { role });
319
322
  const profile = approvedProfile(scope);
320
323
  if (profile !== null) {
321
324
  const exhausted = available.map(one => store.readQuotaState(one.name, profile.provider, profile.model, now)).filter(one => one?.state === "exhausted");
322
325
  if (exhausted.length === available.length) {
323
326
  const resets = exhausted.map(one => one?.resetAt ?? null).filter((one) => one !== null).sort();
324
327
  const nextAt = resets[0] ?? null;
325
- return answer("provider-quota", "retrying", "Provider quota exhausted", nextAt === null ? "The provider has not supplied a reset time; this needs operator attention." : `The next recorded reset is ${nextAt}.`, { action: nextAt === null ? "select-agent" : null, nextAt, role });
328
+ return answer("provider-quota", "retrying", "Provider quota exhausted", nextAt === null ? "The provider gave no reset time. Choose another agent, or wait for the limit to reset." : `The next recorded reset is ${nextAt}.`, { action: nextAt === null ? "select-agent" : null, nextAt, role });
326
329
  }
327
330
  }
328
331
  // The sign-in pause: the task's provider stopped working; nothing it would
@@ -343,11 +346,11 @@ export function diagnoseTaskDispatch(store, taskId, now, readableRepos = null) {
343
346
  const sourceProblem = plannerSourceProblemOf(store, taskId);
344
347
  if (sourceProblem !== null)
345
348
  return answer("planner-source", "waiting", sourceProblem.title, sourceProblem.detail, { action: "write-scope", role });
346
- return answer("planning-ready", "retrying", "Planner ready", "An eligible worker can draft the scope on the next pass.", { role });
349
+ return answer("planning-ready", "retrying", "Waiting to plan", "A builder can draft the plan next.", { role });
347
350
  }
348
351
  if (role === "scout")
349
- return answer("scouting-ready", "retrying", "Scout ready", "An eligible worker can produce the report on the next pass.", { role });
350
- return answer("ready", "retrying", "Ready to run", "An eligible worker has capacity and every dispatch gate currently passes.", { role });
352
+ return answer("scouting-ready", "retrying", "Waiting to research", "A builder can write the report next.", { role });
353
+ return answer("ready", "retrying", "Ready to run", "A builder is free and nothing is in the way.", { role });
351
354
  }
352
355
  export function diagnosisIsDispatchable(diagnosis) {
353
356
  return diagnosis?.code === "ready" || diagnosis?.code === "planning-ready" || diagnosis?.code === "scouting-ready";
package/dist/dispose.js CHANGED
@@ -1,4 +1,6 @@
1
1
  // Assignment tracking grants no repair authority or attempts.
2
+ import { authorizeCheckOnly } from "./check-only.js";
3
+ import { proposeNewRoute } from "./route-change.js";
2
4
  import { originalTaskBase, focusedTestCommandSupported } from "./observations.js";
3
5
  /**
4
6
  * The build disposition service (Parity II Phase 2, v4 Q2 / v6 W1): the
@@ -158,6 +160,8 @@ function disposeBuildOutcomeLocked(context, result) {
158
160
  });
159
161
  // A stated no-change publishes nothing.
160
162
  if (result.noChange !== true && result.committed) {
163
+ // The approval that built this commit allows one automatic recheck of it, should its verdict go missing.
164
+ authorizeCheckOnly(store, runId, clock());
161
165
  const grant = store.publicationGrantFor(repo);
162
166
  const headSha = store.getRun(runId)?.headRevision ?? null;
163
167
  if (grant !== null &&
@@ -357,6 +361,8 @@ function disposeBuildOutcomeLocked(context, result) {
357
361
  */
358
362
  export function holdStaleApproval(store, args, now) {
359
363
  const scope = store.getScope(args.taskId);
364
+ // Toolroll proposes the new exact route itself (route-change.ts): the person's one act is Approve, on one line.
365
+ const proposed = proposeNewRoute(store, args.taskRef, args.taskId, now);
360
366
  store.holdOwned({
361
367
  taskRef: args.taskRef,
362
368
  ownerKind: "backoff",
@@ -370,8 +376,8 @@ export function holdStaleApproval(store, args, now) {
370
376
  kind: "stale-approval",
371
377
  pushClass: "attention",
372
378
  link: `/t/${encodeURIComponent(args.taskId)}`,
373
- subject: `${args.taskId}: its approval no longer matches the build routing — approve it again`,
374
- body: `${args.message}\nNothing runs on it until the scope is approved again; the hold lifts with the yes.`,
379
+ subject: `${args.taskId}: its agents changed — approve it again`,
380
+ body: `${proposed?.words ?? args.message}\nNothing runs on it until it's approved again.`,
375
381
  }, now);
376
382
  }
377
383
  // ---- the bounded repair loop (v40, evidence-review-v1) --------------------
@@ -284,9 +284,8 @@ export function defaultEasyStartSeams(options) {
284
284
  }
285
285
  },
286
286
  findRepo: async (dir) => {
287
- const { run } = await import("./exec.js");
288
- const top = await run("git", ["rev-parse", "--show-toplevel"], { cwd: dir, timeoutMs: 10_000 });
289
- return top.code === 0 ? top.stdout.trim() : null;
287
+ const { checkoutTop } = await import("./teardown-git.js");
288
+ return checkoutTop(dir);
290
289
  },
291
290
  enrolled: async (repo) => {
292
291
  const { loadRepos } = await import("./repos.js");
package/dist/evals.js CHANGED
@@ -27,6 +27,7 @@ import { createHash, randomBytes } from "node:crypto";
27
27
  import { closeSync, constants, lstatSync, mkdirSync, mkdtempSync, openSync, readdirSync, realpathSync, rmSync, writeSync } from "node:fs";
28
28
  import { dirname, join, relative, sep } from "node:path";
29
29
  import { homedir, hostname } from "node:os";
30
+ import { sameMachineHost } from "./machine-identity.js";
30
31
  import { fileURLToPath } from "node:url";
31
32
  import { createRequire } from "node:module";
32
33
  import { readVerifiedCommit, verifiedBlobs } from "./commit-extract.js";
@@ -840,7 +841,7 @@ export function recoverEvalCampaigns(store, now, options = {}) {
840
841
  const out = [];
841
842
  for (const campaign of store.handle.prepare("SELECT id, runner_host, runner_pid, runner_started FROM eval_campaign WHERE state = 'running' ORDER BY admitted_at").all()) {
842
843
  const id = String(campaign["id"]);
843
- if (String(campaign["runner_host"]) !== host) {
844
+ if (!sameMachineHost(String(campaign["runner_host"]), host)) {
844
845
  out.push({ id, recovered: false, why: `its runner is on ${String(campaign["runner_host"])}` });
845
846
  continue;
846
847
  }