toolroll 0.9.93 → 0.9.95

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 (436) hide show
  1. package/CHANGELOG.md +79 -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 +10 -0
  5. package/dist/agent-fence.js +6 -3
  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-status.d.ts +1 -1
  11. package/dist/assignment-ui.js +3 -1
  12. package/dist/assignment.js +5 -0
  13. package/dist/attest.d.ts +3 -0
  14. package/dist/attest.js +10 -0
  15. package/dist/boot-identity.d.ts +2 -1
  16. package/dist/boot-identity.js +6 -4
  17. package/dist/bounded-spawn.d.ts +57 -0
  18. package/dist/bounded-spawn.js +220 -0
  19. package/dist/browser/terminal.js +42 -42
  20. package/dist/browser/workspace.css +1 -1
  21. package/dist/browser/workspace.js +32 -32
  22. package/dist/browser-crew.js +2 -0
  23. package/dist/browser-shell.d.ts +1 -1
  24. package/dist/browser-shell.js +2 -2
  25. package/dist/browser-workspace.d.ts +50 -2
  26. package/dist/browser-workspace.js +3 -3
  27. package/dist/build-review.js +2 -0
  28. package/dist/builder-restart.d.ts +21 -0
  29. package/dist/builder-restart.js +50 -0
  30. package/dist/builder.d.ts +11 -2
  31. package/dist/builder.js +234 -101
  32. package/dist/card-catalog.d.ts +209 -0
  33. package/dist/card-catalog.js +133 -0
  34. package/dist/card-cli.d.ts +43 -0
  35. package/dist/card-cli.js +44 -0
  36. package/dist/card-render.d.ts +26 -0
  37. package/dist/card-render.js +223 -0
  38. package/dist/card-sources.d.ts +68 -0
  39. package/dist/card-sources.js +234 -0
  40. package/dist/chat-acceptance.js +1 -1
  41. package/dist/chat-actions.d.ts +106 -9
  42. package/dist/chat-actions.js +473 -46
  43. package/dist/chat-approval.d.ts +13 -0
  44. package/dist/chat-approval.js +39 -9
  45. package/dist/chat-card-part.d.ts +11 -0
  46. package/dist/chat-card-part.js +18 -0
  47. package/dist/chat-card.d.ts +46 -0
  48. package/dist/chat-card.js +99 -0
  49. package/dist/chat-channel.d.ts +2 -0
  50. package/dist/chat-channel.js +37 -14
  51. package/dist/chat-controls.d.ts +4 -0
  52. package/dist/chat-controls.js +4 -0
  53. package/dist/chat-decide.d.ts +10 -16
  54. package/dist/chat-decide.js +79 -62
  55. package/dist/chat-delivery.js +13 -4
  56. package/dist/chat-flow.d.ts +0 -27
  57. package/dist/chat-flow.js +31 -2
  58. package/dist/chat-quiet.js +4 -4
  59. package/dist/chat-task-actions.d.ts +3 -2
  60. package/dist/chat-task-actions.js +19 -5
  61. package/dist/chat-terms.d.ts +14 -2
  62. package/dist/chat-terms.js +35 -0
  63. package/dist/chat-voice.d.ts +1 -1
  64. package/dist/chat-voice.js +2 -2
  65. package/dist/check-facts.d.ts +3 -1
  66. package/dist/check-facts.js +57 -11
  67. package/dist/check-failure.d.ts +24 -3
  68. package/dist/check-failure.js +89 -13
  69. package/dist/check-levels-ui.d.ts +4 -0
  70. package/dist/check-levels-ui.js +10 -1
  71. package/dist/check-load.d.ts +85 -0
  72. package/dist/check-load.js +147 -0
  73. package/dist/check-only-standing.d.ts +36 -0
  74. package/dist/check-only-standing.js +39 -0
  75. package/dist/check-only.d.ts +15 -0
  76. package/dist/check-only.js +99 -0
  77. package/dist/check-repair.d.ts +47 -0
  78. package/dist/check-repair.js +240 -0
  79. package/dist/check-report.d.ts +2 -0
  80. package/dist/check-report.js +1 -1
  81. package/dist/check-stamp.d.ts +46 -0
  82. package/dist/check-stamp.js +93 -0
  83. package/dist/checkout-cleanup.d.ts +36 -5
  84. package/dist/checkout-cleanup.js +166 -14
  85. package/dist/claim.d.ts +6 -0
  86. package/dist/claim.js +13 -2
  87. package/dist/cli-help.d.ts +4 -1
  88. package/dist/cli-help.js +49 -30
  89. package/dist/cli.js +15 -1
  90. package/dist/code-extract.d.ts +44 -0
  91. package/dist/code-extract.js +88 -0
  92. package/dist/code-map-acts.d.ts +24 -0
  93. package/dist/code-map-acts.js +53 -0
  94. package/dist/code-map-admission.d.ts +52 -0
  95. package/dist/code-map-admission.js +295 -0
  96. package/dist/code-map-build.d.ts +63 -0
  97. package/dist/code-map-build.js +415 -0
  98. package/dist/code-map-cli.d.ts +153 -0
  99. package/dist/code-map-cli.js +103 -0
  100. package/dist/code-map-main.d.ts +1 -0
  101. package/dist/code-map-main.js +48 -0
  102. package/dist/code-map-read.d.ts +106 -0
  103. package/dist/code-map-read.js +171 -0
  104. package/dist/code-map-report.d.ts +37 -0
  105. package/dist/code-map-report.js +95 -0
  106. package/dist/code-map-shape.d.ts +172 -0
  107. package/dist/code-map-shape.js +327 -0
  108. package/dist/code-map-store.d.ts +136 -0
  109. package/dist/code-map-store.js +233 -0
  110. package/dist/coding-provider.d.ts +3 -1
  111. package/dist/coding-provider.js +12 -7
  112. package/dist/coding-update.js +3 -2
  113. package/dist/coding-workspace.d.ts +1 -1
  114. package/dist/coding-workspace.js +8 -8
  115. package/dist/console-chrome.js +2 -2
  116. package/dist/containment.d.ts +5 -0
  117. package/dist/containment.js +14 -1
  118. package/dist/contracts/chat-actions.d.ts +92 -0
  119. package/dist/contracts/chat-actions.js +20 -0
  120. package/dist/contracts/chat-card.d.ts +91 -0
  121. package/dist/contracts/chat-card.js +54 -0
  122. package/dist/contracts/chat-content.d.ts +191 -0
  123. package/dist/contracts/chat-content.js +4 -0
  124. package/dist/contracts/cli.d.ts +52 -0
  125. package/dist/contracts/cli.js +4 -0
  126. package/dist/contracts/console-api.d.ts +12 -3
  127. package/dist/contracts/console-api.js +12 -3
  128. package/dist/contracts/flow-propose.d.ts +8 -1
  129. package/dist/contracts/flow-propose.js +3 -1
  130. package/dist/contracts/flow-send.d.ts +126 -0
  131. package/dist/contracts/flow-send.js +3 -0
  132. package/dist/contracts/gateway-tools.d.ts +17 -0
  133. package/dist/contracts/gateway-tools.js +3 -1
  134. package/dist/contracts/lead-tools.d.ts +234 -0
  135. package/dist/contracts/lead-tools.js +25 -1
  136. package/dist/contracts/project-knowledge.d.ts +38 -5
  137. package/dist/contracts/project-knowledge.js +11 -5
  138. package/dist/contracts/project-memory.d.ts +3 -1
  139. package/dist/contracts/project-memory.js +3 -2
  140. package/dist/contracts/storage.d.ts +14 -0
  141. package/dist/contracts/storage.js +3 -1
  142. package/dist/contracts/store-json.d.ts +18 -0
  143. package/dist/contracts/youiyoux-request.d.ts +1 -1
  144. package/dist/contracts/youiyoux-request.js +1 -1
  145. package/dist/desktop-access.js +6 -2
  146. package/dist/discord-chat.js +14 -0
  147. package/dist/dispatch.d.ts +1 -1
  148. package/dist/dispatch.js +25 -16
  149. package/dist/dispose.d.ts +19 -0
  150. package/dist/dispose.js +55 -9
  151. package/dist/easy-start.js +2 -3
  152. package/dist/eval-oracle.js +4 -1
  153. package/dist/evals.js +2 -1
  154. package/dist/evidence-pair.d.ts +53 -0
  155. package/dist/evidence-pair.js +128 -0
  156. package/dist/exhaustion.d.ts +17 -4
  157. package/dist/exhaustion.js +44 -4
  158. package/dist/export.js +1 -1
  159. package/dist/failing-first.d.ts +31 -0
  160. package/dist/failing-first.js +44 -0
  161. package/dist/fallback-schema.d.ts +8 -0
  162. package/dist/fallback-schema.js +40 -0
  163. package/dist/fallback.d.ts +138 -0
  164. package/dist/fallback.js +605 -0
  165. package/dist/fast-start.d.ts +136 -0
  166. package/dist/fast-start.js +431 -0
  167. package/dist/fast-terms.d.ts +9 -0
  168. package/dist/fast-terms.js +23 -0
  169. package/dist/fenced-check-coverage.d.ts +62 -0
  170. package/dist/fenced-check-coverage.js +54 -0
  171. package/dist/findings.d.ts +224 -0
  172. package/dist/findings.js +449 -0
  173. package/dist/first-run.js +1 -1
  174. package/dist/flaky-ci.d.ts +31 -0
  175. package/dist/flaky-ci.js +149 -0
  176. package/dist/flaky-cli.d.ts +60 -0
  177. package/dist/flaky-cli.js +60 -0
  178. package/dist/flaky.d.ts +75 -9
  179. package/dist/flaky.js +255 -0
  180. package/dist/fleet-schema.d.ts +17 -0
  181. package/dist/fleet-schema.js +135 -0
  182. package/dist/flow-browser.js +2 -2
  183. package/dist/flow-card-task.js +3 -0
  184. package/dist/flow-code.d.ts +2 -2
  185. package/dist/flow-code.js +9 -5
  186. package/dist/flow-result-card.d.ts +22 -0
  187. package/dist/flow-result-card.js +55 -0
  188. package/dist/flow-send.js +12 -9
  189. package/dist/flow-steps.js +1 -1
  190. package/dist/flow-triggers.d.ts +1 -1
  191. package/dist/flow-triggers.js +2 -2
  192. package/dist/flow-unattended.d.ts +26 -0
  193. package/dist/flow-unattended.js +12 -3
  194. package/dist/flows-ui.js +10 -2
  195. package/dist/follow-through-brief.d.ts +12 -0
  196. package/dist/follow-through-brief.js +31 -0
  197. package/dist/follow-through-cli.d.ts +23 -0
  198. package/dist/follow-through-cli.js +153 -0
  199. package/dist/git-incident.d.ts +16 -0
  200. package/dist/git-incident.js +69 -6
  201. package/dist/github-import.d.ts +62 -0
  202. package/dist/github-import.js +146 -0
  203. package/dist/guides.js +15 -10
  204. package/dist/handover-note.d.ts +33 -0
  205. package/dist/handover-note.js +106 -0
  206. package/dist/invoke.d.ts +25 -2
  207. package/dist/invoke.js +157 -58
  208. package/dist/job-object-helper.ps1 +10 -3
  209. package/dist/keymap.d.ts +41 -0
  210. package/dist/keymap.js +51 -0
  211. package/dist/knowledge-cli.js +1 -1
  212. package/dist/knowledge-ui.d.ts +21 -4
  213. package/dist/knowledge-ui.js +75 -7
  214. package/dist/laptop-background.d.ts +16 -0
  215. package/dist/laptop-background.js +108 -2
  216. package/dist/lead-cli.js +26 -24
  217. package/dist/lead-context.js +1 -1
  218. package/dist/lead-contract.d.ts +1 -1
  219. package/dist/lead-contract.js +3 -2
  220. package/dist/lead-doors.d.ts +4 -0
  221. package/dist/lead-doors.js +2 -2
  222. package/dist/lead-progress.js +5 -0
  223. package/dist/lead-status.d.ts +2 -0
  224. package/dist/lead-status.js +6 -2
  225. package/dist/lead-tools.js +162 -34
  226. package/dist/lead.js +2 -2
  227. package/dist/lesson-notes.d.ts +81 -0
  228. package/dist/lesson-notes.js +336 -0
  229. package/dist/limits-ui.js +1 -1
  230. package/dist/local-owner.d.ts +1 -1
  231. package/dist/local-owner.js +16 -0
  232. package/dist/machine-check.d.ts +16 -0
  233. package/dist/machine-check.js +26 -0
  234. package/dist/machine-identity.d.ts +75 -0
  235. package/dist/machine-identity.js +170 -0
  236. package/dist/mcp-core.js +11 -1
  237. package/dist/memory-cli.d.ts +300 -1
  238. package/dist/memory-cli.js +62 -9
  239. package/dist/memory-pass.d.ts +16 -0
  240. package/dist/memory-pass.js +67 -3
  241. package/dist/memory-tidy.d.ts +181 -0
  242. package/dist/memory-tidy.js +523 -0
  243. package/dist/memory-use.d.ts +35 -0
  244. package/dist/memory-use.js +109 -0
  245. package/dist/merge-checklist.d.ts +55 -0
  246. package/dist/merge-checklist.js +182 -0
  247. package/dist/modes.d.ts +6 -6
  248. package/dist/modes.js +3 -1
  249. package/dist/needs-you.d.ts +31 -9
  250. package/dist/needs-you.js +110 -41
  251. package/dist/nightly-github.d.ts +2 -0
  252. package/dist/nightly-github.js +4 -4
  253. package/dist/operate-remote-arguments.js +7 -1
  254. package/dist/operate-remote.js +3 -1
  255. package/dist/operate.d.ts +6 -1
  256. package/dist/operate.js +565 -64
  257. package/dist/phase-routing.js +2 -2
  258. package/dist/plain-schema.d.ts +23 -0
  259. package/dist/plain-schema.js +94 -0
  260. package/dist/plain-words.d.ts +20 -0
  261. package/dist/plain-words.js +66 -0
  262. package/dist/plan-login.d.ts +14 -0
  263. package/dist/plan-login.js +58 -0
  264. package/dist/planner.d.ts +1 -1
  265. package/dist/planner.js +4 -2
  266. package/dist/process-liveness.d.ts +2 -0
  267. package/dist/process-liveness.js +61 -17
  268. package/dist/project-delete-ui.d.ts +19 -2
  269. package/dist/project-delete-ui.js +29 -1
  270. package/dist/project-delete.js +14 -1
  271. package/dist/project-knowledge.d.ts +18 -11
  272. package/dist/project-knowledge.js +39 -9
  273. package/dist/project-learning.d.ts +2 -1
  274. package/dist/project-learning.js +15 -45
  275. package/dist/project-memory.d.ts +5 -0
  276. package/dist/project-memory.js +22 -2
  277. package/dist/project-tools.d.ts +4 -4
  278. package/dist/project-tools.js +23 -7
  279. package/dist/proof.js +30 -5
  280. package/dist/protected-storage-look.d.ts +1 -0
  281. package/dist/protected-storage-look.js +13 -0
  282. package/dist/protected-storage.d.ts +70 -39
  283. package/dist/protected-storage.js +196 -147
  284. package/dist/provider-auth.js +1 -1
  285. package/dist/provider-capture.d.ts +34 -0
  286. package/dist/provider-capture.js +53 -0
  287. package/dist/publish.js +9 -1
  288. package/dist/pull-request-flow.js +5 -0
  289. package/dist/push.d.ts +18 -2
  290. package/dist/push.js +40 -16
  291. package/dist/release-adapters.d.ts +9 -0
  292. package/dist/release-adapters.js +76 -0
  293. package/dist/release-auto.js +13 -13
  294. package/dist/release-card.d.ts +1 -2
  295. package/dist/release-card.js +11 -0
  296. package/dist/release-carry.d.ts +7 -2
  297. package/dist/release-carry.js +49 -10
  298. package/dist/release-cli.d.ts +4 -0
  299. package/dist/release-cli.js +29 -22
  300. package/dist/release-coverage.js +1 -1
  301. package/dist/release-next.d.ts +48 -0
  302. package/dist/release-next.js +161 -0
  303. package/dist/release.d.ts +20 -1
  304. package/dist/release.js +85 -9
  305. package/dist/remote-destination.d.ts +36 -0
  306. package/dist/remote-destination.js +217 -0
  307. package/dist/remote-main.d.ts +48 -0
  308. package/dist/remote-main.js +84 -5
  309. package/dist/repository-context.d.ts +3 -2
  310. package/dist/repository-context.js +112 -70
  311. package/dist/restart-certification.d.ts +1 -0
  312. package/dist/restart-certification.js +8 -6
  313. package/dist/result-acts.d.ts +27 -19
  314. package/dist/result-acts.js +36 -25
  315. package/dist/result-follow-ups.d.ts +2 -2
  316. package/dist/result-follow-ups.js +18 -4
  317. package/dist/result-review.d.ts +1 -1
  318. package/dist/route-change-check.d.ts +4 -0
  319. package/dist/route-change-check.js +13 -0
  320. package/dist/route-change.d.ts +22 -0
  321. package/dist/route-change.js +89 -0
  322. package/dist/route-hooks.js +3 -2
  323. package/dist/route-results.d.ts +6 -1
  324. package/dist/route-results.js +14 -5
  325. package/dist/run-closeout.d.ts +1 -1
  326. package/dist/run-closeout.js +7 -5
  327. package/dist/runner-process.js +3 -2
  328. package/dist/runner.js +2 -1
  329. package/dist/scope.d.ts +28 -4
  330. package/dist/scope.js +92 -28
  331. package/dist/scout.d.ts +1 -1
  332. package/dist/scout.js +2 -1
  333. package/dist/serve.d.ts +1 -1
  334. package/dist/serve.js +26 -18
  335. package/dist/server/chat.js +16 -14
  336. package/dist/server/chrome.d.ts +1 -1
  337. package/dist/server/chrome.js +26 -35
  338. package/dist/server/console.css +73 -0
  339. package/dist/server/guards.js +3 -0
  340. package/dist/server/home.d.ts +6 -0
  341. package/dist/server/home.js +21 -13
  342. package/dist/server/http.js +1 -1
  343. package/dist/server/kit.js +1 -1
  344. package/dist/server/merge-ready-view.d.ts +10 -0
  345. package/dist/server/merge-ready-view.js +30 -0
  346. package/dist/server/pages-assets.d.ts +1 -0
  347. package/dist/server/pages-assets.js +8 -5
  348. package/dist/server/pages.js +103 -82
  349. package/dist/server/render-chat.js +16 -3
  350. package/dist/server/render-code-map.d.ts +30 -0
  351. package/dist/server/render-code-map.js +137 -0
  352. package/dist/server/render-flaky.d.ts +20 -0
  353. package/dist/server/render-flaky.js +59 -0
  354. package/dist/server/render-follow-through.d.ts +11 -0
  355. package/dist/server/render-follow-through.js +68 -0
  356. package/dist/server/render-history.js +1 -1
  357. package/dist/server/render-new-task.d.ts +26 -1
  358. package/dist/server/render-new-task.js +30 -5
  359. package/dist/server/render-pages.d.ts +1 -175
  360. package/dist/server/render-pages.js +38 -313
  361. package/dist/server/render-projects.d.ts +2 -1
  362. package/dist/server/render-projects.js +9 -7
  363. package/dist/server/render-release.d.ts +2 -0
  364. package/dist/server/render-release.js +3 -3
  365. package/dist/server/render-results.d.ts +2 -0
  366. package/dist/server/render-results.js +68 -68
  367. package/dist/server/render-tasks.d.ts +16 -2
  368. package/dist/server/render-tasks.js +177 -141
  369. package/dist/server/retired-routes.d.ts +17 -0
  370. package/dist/server/retired-routes.js +53 -0
  371. package/dist/server/route-table.d.ts +3 -0
  372. package/dist/server/route-table.js +48 -12
  373. package/dist/server/settings.js +166 -34
  374. package/dist/server/task-views.js +66 -26
  375. package/dist/server/tasks.d.ts +2 -6
  376. package/dist/server/tasks.js +250 -321
  377. package/dist/server/welcome.js +1 -1
  378. package/dist/settings-groups-ui.d.ts +1 -0
  379. package/dist/settings-groups-ui.js +4 -2
  380. package/dist/settings-kit.js +3 -2
  381. package/dist/settings-proofs.js +3 -1
  382. package/dist/slack-chat.js +14 -1
  383. package/dist/steer-mailbox.d.ts +8 -1
  384. package/dist/steer-mailbox.js +164 -6
  385. package/dist/stop-proof.js +6 -4
  386. package/dist/storage-sweep-process.js +1 -1
  387. package/dist/storage-sweep.d.ts +5 -3
  388. package/dist/storage-sweep.js +30 -9
  389. package/dist/storage-ui.js +28 -17
  390. package/dist/storage.d.ts +27 -2
  391. package/dist/storage.js +39 -2
  392. package/dist/store.d.ts +89 -7
  393. package/dist/store.js +386 -114
  394. package/dist/surface.js +67 -6
  395. package/dist/sweep-quarantine.d.ts +1 -0
  396. package/dist/sweep-quarantine.js +6 -4
  397. package/dist/tamper-scan.d.ts +4 -0
  398. package/dist/tamper-scan.js +90 -0
  399. package/dist/task-aliases.d.ts +5 -0
  400. package/dist/task-aliases.js +9 -0
  401. package/dist/task-control.d.ts +2 -1
  402. package/dist/task-control.js +4 -1
  403. package/dist/task-outcome-cli.d.ts +2 -0
  404. package/dist/task-outcome-cli.js +17 -17
  405. package/dist/task-sizing.d.ts +5 -0
  406. package/dist/task-sizing.js +2 -0
  407. package/dist/task-source.d.ts +7 -0
  408. package/dist/task-source.js +14 -0
  409. package/dist/task-status.d.ts +9 -0
  410. package/dist/task-status.js +45 -49
  411. package/dist/teardown-git.d.ts +18 -0
  412. package/dist/teardown-git.js +105 -21
  413. package/dist/telegram-lead.js +23 -6
  414. package/dist/telegram-progress.js +5 -3
  415. package/dist/telegram-status.js +6 -4
  416. package/dist/telegram.js +12 -1
  417. package/dist/test-infra.d.ts +8 -0
  418. package/dist/test-infra.js +18 -0
  419. package/dist/tidy.js +1 -1
  420. package/dist/toolroll-update.js +19 -5
  421. package/dist/tui-contract.d.ts +24 -0
  422. package/dist/tui-source.js +67 -8
  423. package/dist/tui.js +51 -51
  424. package/dist/vanished-retry.d.ts +30 -0
  425. package/dist/vanished-retry.js +174 -0
  426. package/dist/work-index.d.ts +2 -0
  427. package/dist/work-index.js +95 -66
  428. package/dist/work-summary.d.ts +1 -1
  429. package/dist/work-summary.js +7 -2
  430. package/dist/workspace-ui.d.ts +7 -3
  431. package/dist/workspace-ui.js +38 -23
  432. package/dist/worktree.d.ts +12 -3
  433. package/dist/worktree.js +91 -14
  434. package/package.json +2 -1
  435. package/dist/server/render-next.d.ts +0 -63
  436. package/dist/server/render-next.js +0 -109
@@ -4,6 +4,7 @@
4
4
  * CLI show: Ready for review once the saved result can be inspected, Complete
5
5
  * once the lead or a person has marked that exact result. Slack, Discord and
6
6
  * Teams send this same card. */
7
+ import { machineChecked } from "./machine-check.js";
7
8
  import { assignmentOf } from "./assignment.js";
8
9
  import { chatResultHref, chatControlHref } from "./chat-controls.js";
9
10
  import { phoneText, projectLabel } from "./telegram-status.js";
@@ -55,8 +56,8 @@ export function telegramProgressCard(store, run, taskId, project, now = new Date
55
56
  }
56
57
  else if (accessBlocked) {
57
58
  facts = { stage: "needs-you", need: "other", reason: holds.some(hold => hold.ownerKind === "backoff")
58
- ? "The worker can't read the project folder. It retries after a short pause; check its folder access."
59
- : "The worker can't read the project folder. Restore its access, then resume." };
59
+ ? "The builder can't read the project folder. It retries after a short pause; check its folder access."
60
+ : "The builder can't read the project folder. Restore its access, then resume." };
60
61
  }
61
62
  else if (run.outcome === null && stop !== null && stop.resumedAt === null) {
62
63
  facts = { stage: "stopped", reason: stop.settledAt === null ? "Stopping. Waiting for the running process to end." : "Paused by a person. Inspect the saved work, then resume." };
@@ -65,7 +66,8 @@ export function telegramProgressCard(store, run, taskId, project, now = new Date
65
66
  facts = { stage: "stopped", reason: `On hold: ${phoneText(operatorHold.reason, 150)}` };
66
67
  }
67
68
  else if (run.outcome === null) {
68
- facts = { stage: run.phase !== null && run.phase !== "agent-running" ? "checking" : run.role === "planner" ? "planning" : "building" };
69
+ facts = { stage: run.phase !== null && run.phase !== "agent-running" ? "checking" : run.role === "planner" ? "planning" : "building",
70
+ ...(machineChecked(store, taskId) ? { machine: true } : {}) };
69
71
  }
70
72
  else if (run.outcome === "parked") {
71
73
  facts = { stage: "needs-you", need: "answer" };
@@ -1,4 +1,5 @@
1
1
  import { publicChatText } from './chat-display.js';
2
+ import { machineChecked } from "./machine-check.js";
2
3
  import { manualReviewOnly } from "./proof.js";
3
4
  /** Read-only phone views over the same dispatch and proof records as chat.
4
5
  * No provider calls, repository access, new workflow state, or inferred success. */
@@ -65,7 +66,8 @@ function headlineFor(store, id, d, read_ = {}) {
65
66
  return taskStatusOf(assignmentStatusFacts(assignment));
66
67
  }
67
68
  const finished = read.stage === "finished" || read.stage === "complete" || read.stage === "failed";
68
- return taskStatusOf({ stage: read.stage, ...(read.need === undefined ? {} : { need: read.need }), reason: finished ? null : plainReasonOf(read.stage, d.code, d.detail),
69
+ return taskStatusOf({ stage: read.stage, ...(read.need === undefined ? {} : { need: read.need }), ...(read.wait === undefined ? {} : { wait: read.wait }), reason: finished ? null : plainReasonOf(read.stage, d.code, d.detail),
70
+ ...(machineChecked(store, id) ? { machine: true } : {}),
69
71
  checks: read.stage === "failed" && d.code === "proof-refuted" ? { status: "failed", exitCode: null, head: null } : null });
70
72
  }
71
73
  function groupOf(d) {
@@ -238,7 +240,7 @@ export function phoneTaskView(store, repos, id, now, root) {
238
240
  const hiddenDependency = blocker !== null && (blocker.repo === null || !repos.includes(blocker.repo));
239
241
  lines.push(hiddenDependency ? "A required task outside this phone view has not finished. Open the dependency in the console." : plain(shared.sentence, 650));
240
242
  if (d.nextAt !== null)
241
- lines.push(`Earliest recorded wake: ${plain(d.nextAt, 40)} (a connected worker is still required).`);
243
+ lines.push(`Earliest recorded wake: ${plain(d.nextAt, 40)} (a connected builder is still required).`);
242
244
  const runs = store.runsFor(ref.id);
243
245
  const result = task.state === "done" ? runs.find(r => (r.role === "builder" || r.role === "scout") && (r.outcome === "built" || r.outcome === "no-change") && r.finishedAt !== null) : undefined;
244
246
  const latest = result ?? runs[0];
@@ -262,14 +264,14 @@ export function phoneTaskView(store, repos, id, now, root) {
262
264
  : approvedCheckStateOf(approvedCheckOf(proof.verdict, proof.reasons, checksFactOf(assignmentChecksForRun(store, root, result.id, now), result.headRevision)));
263
265
  const verifiedWords = root === undefined ? "Open the result to see its checks" : checkNow === "passed" ? "Checks passed at completion"
264
266
  : checkNow === "failed" ? "Checks failed" : checkNow === "running" ? "Checks running" : "The check result couldn't be read";
265
- const proofWords = { verified: verifiedWords, attested: "Checks reported by the agent, not run by Toolroll", short: "Required saved material is missing", refuted: "The saved result conflicts with the approved scope" };
267
+ const proofWords = { verified: verifiedWords, attested: "Checks reported by the agent, not run by Toolroll", short: "Required saved material is missing", refuted: "The saved result doesn't match the approved plan" };
266
268
  lines.push(`Checks: ${proof === null ? "No completion record saved" : manualReviewOnly(proof) ? accepted ? "Accepted by a person; the recorded checks are unchanged" : "A person must inspect this result; no recorded check failed" : proofWords[proof.verdict]}.`);
267
269
  if (manualReviewOnly(proof) && !accepted)
268
270
  lines.push('Reply “Send the result summary” for the checks, notes and screenshots.');
269
271
  if (proof !== null && proof.matrix.length > 0)
270
272
  lines.push(`Requirements: ${proof.matrix.filter(row => row.state === "pass").length}/${proof.matrix.length} satisfied in the saved record.`);
271
273
  if (accepted && !manualReviewOnly(proof))
272
- lines.push("An operator accepted this result; that does not change its recorded checks.");
274
+ lines.push("An approver accepted this result; that does not change its recorded checks.");
273
275
  const publication = store.publicationForRun(result.id);
274
276
  const delivery = publication?.remoteState === "MERGED" ? `#${publication.prNumber ?? "?"} merged` : publication?.remoteState === "CLOSED" ? `#${publication.prNumber ?? "?"} closed without merging` : publication?.state === "opened" ? `#${publication.prNumber ?? "?"} open` : publication?.state === "pushed" || publication?.state === "intended" ? "Opening…" : publication?.state === "failed" ? "Couldn't open; the commit is safe locally" : null;
275
277
  if (delivery !== null)
package/dist/telegram.js CHANGED
@@ -18,6 +18,8 @@
18
18
  * BotFather token plus `bridge telegram unpair` is the recovery, and both
19
19
  * are one command.
20
20
  */
21
+ import { telegramCardMessage } from "./card-render.js";
22
+ import { flowDoneCard } from "./flow-result-card.js";
21
23
  import { applyTelegramQuestionReply, applyTelegramQuestionTap, openQuestionOf, telegramQuestionButtons } from "./subagent-question.js";
22
24
  import { acceptanceEvidenceText } from "./chat-acceptance.js";
23
25
  import { verifyApproverStanding } from "./principal.js";
@@ -1288,6 +1290,15 @@ async function deliverOne(store, botId, binding, sender, notification, clock, ph
1288
1290
  parts = voiced.map(one => one.text);
1289
1291
  entities = voiced.map(one => one.entities);
1290
1292
  }
1293
+ // A flow's result as a card (flow-result-card.ts): one more message, its tables as monospaced text.
1294
+ const resultCard = offer === null ? sent?.card ?? flowDoneCard(store, notification, clock()) : null;
1295
+ if (resultCard != null) {
1296
+ const message = telegramCardMessage(resultCard);
1297
+ entities = [...parts.map((_, at) => entities[at] ?? []), message.entities];
1298
+ parts = [...parts, message.text];
1299
+ }
1300
+ // Its links stay on the words: the card follows them.
1301
+ const keyedPart = parts.length - (resultCard != null ? 2 : 1);
1291
1302
  // A subagent's question (v93): its options and "Answer in words", for the person it asks.
1292
1303
  const asked = flowKeys === null && choiceKeys === null ? openQuestionOf(store, notification.dedupeKey) : null;
1293
1304
  const questionKeys = asked === null ? null : telegramQuestionButtons(store, binding, asked, clock());
@@ -1301,7 +1312,7 @@ async function deliverOne(store, botId, binding, sender, notification, clock, ph
1301
1312
  }
1302
1313
  }
1303
1314
  for (const [index, part] of parts.entries()) {
1304
- const final = index === parts.length - 1;
1315
+ const final = index === keyedPart;
1305
1316
  const decideKeys = decided === null ? [] : decideKeyboard(phoneOrigin, decided.rows);
1306
1317
  const keyboard = !final ? undefined : keys !== null ? [...keys.keyboard, ...(button === null ? [] : [button])] : decideKeys.length > 0 ? decideKeys : button !== null ? [button] : undefined;
1307
1318
  const sent = await sender(part, keyboard, undefined, entities[index]?.length ? entities[index] : undefined);
@@ -24,3 +24,11 @@ export declare function testInfrastructure(files: ReadonlyMap<string, string>, a
24
24
  * the other rules don't already trust: any source file that is neither a test nor product code.
25
25
  */
26
26
  export declare function mightName(open: Unresolved, path: string, found: TestInfrastructure): boolean;
27
+ /** Whether a path is a test file by any extension a test runner could be pointed at, not only those run today. */
28
+ export declare const isTestPath: (path: string) => boolean;
29
+ /**
30
+ * Why a new test file can't carry on what it imports, or null (docs/plans/trusted-release-reports.md, H4). A test file is
31
+ * never infrastructure here, so nothing else looks at an edge between two of them, and importing one runs its top level
32
+ * (its `vi.mock`s and hooks included) in the importer. A computed import might name one, so it refuses too.
33
+ */
34
+ export declare function testImportProblem(path: string, text: string): string | null;
@@ -319,3 +319,21 @@ export function mightName(open, path, found) {
319
319
  const stem = path.replace(/\.[^/.]+$/, "");
320
320
  return path === prefix || stem === prefix.replace(/\.(?:[cm]?js|jsx)$/, "") || path.startsWith(`${prefix}/`) || (open.specifier !== null && open.specifier.endsWith("/") === false && path.startsWith(prefix));
321
321
  }
322
+ /** Whether a path is a test file by any extension a test runner could be pointed at, not only those run today. */
323
+ export const isTestPath = (path) => TEST.test(path);
324
+ /** A specifier that names a test file, whatever it is spelled as: `./a.test.js`, `../b.test`, `@/c.test.ts`. */
325
+ const NAMES_TEST = /\.test(?:\.[cm]?[jt]sx?)?(?:[?#].*)?$/;
326
+ /**
327
+ * Why a new test file can't carry on what it imports, or null (docs/plans/trusted-release-reports.md, H4). A test file is
328
+ * never infrastructure here, so nothing else looks at an edge between two of them, and importing one runs its top level
329
+ * (its `vi.mock`s and hooks included) in the importer. A computed import might name one, so it refuses too.
330
+ */
331
+ export function testImportProblem(path, text) {
332
+ const { literal, computed, soft } = specifiersOf(path, text);
333
+ const named = [...literal, ...soft].find(spec => NAMES_TEST.test(spec));
334
+ if (named !== undefined)
335
+ return `${path} imports another test file (${named}), which would run its code here`;
336
+ if (computed.length > 0)
337
+ return `${path} imports a path it computes, which might name another test file`;
338
+ return null;
339
+ }
package/dist/tidy.js CHANGED
@@ -478,7 +478,7 @@ export function familyRepoOf(store, refs) {
478
478
  }
479
479
  /** "Archived by tidy: <reason>" or "Archived by <person>: <reason>": the one sentence every surface shows. */
480
480
  export function archivedWords(archived) {
481
- return `Archived by ${archived.byKind === "tidy" ? "tidy" : archived.by}: ${archived.reason}`;
481
+ return `${archived.byKind === "tidy" ? "Archived automatically" : `Archived by ${archived.by}`}: ${archived.reason}`;
482
482
  }
483
483
  /** The release journals beside the store's own database file (none for an in-memory one). */
484
484
  export function releaseFactsOf(store) {
@@ -39,7 +39,10 @@ import { installLaunchdService, launchdPlist, stopLaunchdService, writeFileDurab
39
39
  import { LAPTOP_LABEL_DARWIN, LAPTOP_LABEL_LINUX, unitFlag } from "./laptop-service.js";
40
40
  import { processGone, readRunnerProcessRecord, realProcessProbe, recordStandsFor, RUNNER_PROCESS_DIR } from "./runner-process.js";
41
41
  import { NAME } from "./names.js";
42
- import { orphanKey, updateSafeSchema, V117_RENAMED_COLUMNS, V117_RENAMED_TABLES, V118_MERGED_TABLES, V119_ADDED_COLUMNS, V120_ADDED_COLUMNS, V121_ADDED_COLUMNS, V122_ADDED_COLUMNS, V123_ADDED_COLUMNS, V125_ADDED_COLUMNS, V126_ADDED_COLUMNS, V128_ADDED_COLUMNS, V129_ADDED_COLUMNS, V134_ADDED_COLUMNS, V135_ADDED_COLUMNS, V138_ADDED_COLUMNS, V143_ADDED_COLUMNS, V147_ADDED_COLUMNS, V148_ADDED_COLUMNS } from "./store.js";
42
+ import { V151_ADDED_COLUMNS } from "./storage.js";
43
+ import { orphanKey, updateSafeSchema, V117_RENAMED_COLUMNS, V117_RENAMED_TABLES, V118_MERGED_TABLES, V119_ADDED_COLUMNS, V120_ADDED_COLUMNS, V121_ADDED_COLUMNS, V122_ADDED_COLUMNS, V123_ADDED_COLUMNS, V125_ADDED_COLUMNS, V126_ADDED_COLUMNS, V128_ADDED_COLUMNS, V129_ADDED_COLUMNS, V134_ADDED_COLUMNS, V135_ADDED_COLUMNS, V138_ADDED_COLUMNS, V143_ADDED_COLUMNS, V147_ADDED_COLUMNS, V148_ADDED_COLUMNS, V150_ADDED_COLUMNS } from "./store.js";
44
+ import { V152_ADDED_COLUMNS } from "./code-map-store.js";
45
+ import { V153_ADDED_COLUMNS } from "./plain-schema.js";
43
46
  import { isNewer, REGISTRY } from "./releases.js";
44
47
  import { markNeverIndex } from "./never-index.js";
45
48
  import { readRuntimeUpdateJournal, RUNTIME_PHASES, RUNTIME_UPDATE_STEPS, stagedStartedAt, updaterStartingOf } from "./contracts/update-journal.js";
@@ -379,12 +382,16 @@ function addedColumns(...versions) {
379
382
  return rules;
380
383
  }
381
384
  /** Rules on tables that later gained declared columns (addedColumns merges into these instead of replacing them). */
382
- const EARLIER_RULES = { flow_trigger: { fromRoutines: "trigger" } };
385
+ const EARLIER_RULES = { flow_trigger: { fromRoutines: "trigger" },
386
+ // v114: a finished run whose process witnesses have all exited keeps one summary row in place of them (v150 adds
387
+ // their machine id).
388
+ run_process: { compacted: { into: "run_process_summary", sum: "witnesses" } } };
383
389
  const HISTORY_RULES = {
384
390
  ...Object.fromEntries(Object.entries(CHAT_MOVES).map(([table, moved]) => [table, { moved }])),
385
391
  action_ledger: { appendOnly: true }, ledger_seal: { appendOnly: true }, ledger_checkpoint: { appendOnly: true },
386
- // v114: a finished run whose process witnesses have all exited keeps one summary row in place of them.
387
- run_process: { compacted: { into: "run_process_summary", sum: "witnesses" } }, run_process_summary: { summarizes: "run_process" },
392
+ // v114: a finished run whose process witnesses have all exited keeps one summary row in place of them (the
393
+ // run_process rule is in EARLIER_RULES, under its v150 column).
394
+ run_process: EARLIER_RULES["run_process"], run_process_summary: { summarizes: "run_process" },
388
395
  // v114: single-destination delivery columns may be dropped only once their values are legacy receipts.
389
396
  notification: { dropped: ["attempts", "last_attempt_at", "last_error", "delivered_at", "receipt", "claim_owner", "claim_expires_at"], carried: { into: "notification_delivery", destination: LEGACY_DESTINATION } },
390
397
  notification_delivery: { receives: LEGACY_DESTINATION },
@@ -415,7 +422,14 @@ const HISTORY_RULES = {
415
422
  // console record reads no key epoch.
416
423
  // v148: a run's execution class and a revision's origin read none (NULL), and a project's suggestion switch reads on.
417
424
  // v149 adds tables only (the learning-loops records): no saved row changes, so no rule is needed for it.
418
- ...Object.fromEntries(Object.entries(addedColumns(V119_ADDED_COLUMNS, V120_ADDED_COLUMNS, V121_ADDED_COLUMNS, V122_ADDED_COLUMNS, V123_ADDED_COLUMNS, V125_ADDED_COLUMNS, V126_ADDED_COLUMNS, V128_ADDED_COLUMNS, V129_ADDED_COLUMNS, V134_ADDED_COLUMNS, V135_ADDED_COLUMNS, V138_ADDED_COLUMNS, V143_ADDED_COLUMNS, V147_ADDED_COLUMNS, V148_ADDED_COLUMNS))
425
+ // v150: a saved process witness reads no machine id (NULL), and is matched by host name as before.
426
+ // v151: a saved cleanup setting's idle limit reads none (NULL): the default.
427
+ // v152: a saved project's code map reads on, with no enrollment yet; the code map's tables are new.
428
+ // v153: a saved task reads no fast start and a saved project no fast-start setting (NULL); its tables are new.
429
+ // v154 adds a table only (check_stamp): no saved row changes, so no rule is needed for it.
430
+ // v155 adds tables only (fleet-schema.ts): no saved row changes, so no rule is needed for it.
431
+ // v156 adds tables only (fallback chains): likewise.
432
+ ...Object.fromEntries(Object.entries(addedColumns(V119_ADDED_COLUMNS, V120_ADDED_COLUMNS, V121_ADDED_COLUMNS, V122_ADDED_COLUMNS, V123_ADDED_COLUMNS, V125_ADDED_COLUMNS, V126_ADDED_COLUMNS, V128_ADDED_COLUMNS, V129_ADDED_COLUMNS, V134_ADDED_COLUMNS, V135_ADDED_COLUMNS, V138_ADDED_COLUMNS, V143_ADDED_COLUMNS, V147_ADDED_COLUMNS, V148_ADDED_COLUMNS, V150_ADDED_COLUMNS, V151_ADDED_COLUMNS, V152_ADDED_COLUMNS, V153_ADDED_COLUMNS))
419
433
  .map(([table, rule]) => [table, { ...EARLIER_RULES[table], ...rule }])),
420
434
  };
421
435
  /** The tables a migration may remove whole (v115's removed features). */
@@ -42,6 +42,8 @@ export type TuiTask = {
42
42
  /** A finished result that can be marked Complete or sent back with a revision. */
43
43
  readonly hasResult: boolean;
44
44
  readonly decisions: readonly TuiDecision[];
45
+ /** "Can I merge?" (merge-checklist.ts, `toolroll task ready`'s lines): the answer, then each check. Empty: no result. */
46
+ readonly ready?: readonly string[];
45
47
  };
46
48
  /** The welcome's steps, as lines (welcome-facts.ts). */
47
49
  export type TuiSetup = {
@@ -56,11 +58,19 @@ export type TuiSnapshot = {
56
58
  readonly projects: readonly string[];
57
59
  /** Whether the local owner has set a password (decides where a refusal leads). */
58
60
  readonly passwordSet: boolean;
61
+ /** One line about flaky tests and project memory waiting, and the commands that show them; null when there's nothing. */
62
+ readonly learning?: string | null;
59
63
  };
60
64
  export type TuiAct = {
61
65
  readonly kind: "new";
62
66
  readonly text: string;
63
67
  readonly repo: string | null;
68
+ }
69
+ /** Build: the terms the person just read (fast-start.ts). */
70
+ | {
71
+ readonly kind: "build";
72
+ readonly preview: string;
73
+ readonly digest: string;
64
74
  } | {
65
75
  readonly kind: "approve";
66
76
  readonly id: string;
@@ -76,11 +86,23 @@ export type TuiAct = {
76
86
  } | {
77
87
  readonly kind: "complete";
78
88
  readonly id: string;
89
+ } | {
90
+ readonly kind: "retry";
91
+ readonly id: string;
79
92
  } | {
80
93
  readonly kind: "answer";
81
94
  readonly decision: number;
82
95
  readonly option: string;
83
96
  };
97
+ /** What Build would approve: the same lines every approval surface reads. */
98
+ export type TuiFastTerms = {
99
+ readonly preview: string;
100
+ readonly digest: string;
101
+ readonly terms: readonly {
102
+ readonly label: string;
103
+ readonly words: string;
104
+ }[];
105
+ };
84
106
  /** A write's answer: its words. `needsPassword`: refused because the local owner may not do it. */
85
107
  export type TuiActResult = {
86
108
  readonly ok: true;
@@ -100,6 +122,8 @@ export interface TuiSource {
100
122
  /** A counter that moves when the plane's work changes (the store's wake sequence). */
101
123
  changed(): number;
102
124
  act(act: TuiAct): Promise<TuiActResult>;
125
+ /** A small task's exact terms, or null when it takes the ordinary road (New task then files it). */
126
+ fastTerms(text: string, repo: string | null): Promise<TuiFastTerms | null>;
103
127
  /** The welcome's steps, or null once setup is done. */
104
128
  setup(): Promise<TuiSetup | null>;
105
129
  }
@@ -9,11 +9,15 @@
9
9
  */
10
10
  import { dirname, join } from "node:path";
11
11
  import { assignmentOf } from "./assignment.js";
12
+ import { checklistLines, mergeChecklistOf } from "./merge-checklist.js";
12
13
  import { runAsLocalOwner } from "./local-owner.js";
13
14
  import { snapshotLiveRuns } from "./peek-cli.js";
14
15
  import { loadProjectRegistry } from "./repos.js";
15
16
  import { describeScope } from "./scope.js";
16
17
  import { localModeOf, openStoreReadOnly } from "./store.js";
18
+ import { routeChangeOf } from "./route-change.js";
19
+ import { flakyCount } from "./flaky.js";
20
+ import { memoryWaiting } from "./lesson-notes.js";
17
21
  import { terminalText } from "./terminal-text.js";
18
22
  import { welcomeHere, welcomeLines } from "./welcome-facts.js";
19
23
  const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -26,13 +30,17 @@ function refusalOf(envelope) {
26
30
  const message = shown(envelope.message, "That was refused.");
27
31
  return { ok: false, message, needsPassword: envelope.reason === "refused" || envelope.reason === "machine-proof" || envelope.reason === "person-required" || /password/i.test(message) };
28
32
  }
33
+ const routeLines = (store, id) => { const words = routeChangeOf(store, id); return words === null ? [] : [words]; };
29
34
  export function createTuiSource(options) {
30
35
  const file = options.databaseFile;
31
36
  const clock = options.clock ?? (() => new Date());
32
37
  const evidenceRoot = join(dirname(file), "evidence");
33
38
  const tails = new Map();
34
39
  let reader = null;
40
+ let closed = false;
35
41
  const read = () => {
42
+ if (closed)
43
+ return null;
36
44
  reader ??= openStoreReadOnly(file);
37
45
  return reader;
38
46
  };
@@ -74,7 +82,7 @@ export function createTuiSource(options) {
74
82
  const store = read();
75
83
  const mode = store === null ? null : localModeOf(store);
76
84
  const passwordSet = store !== null && mode !== null && store.accountOf(mode.owner)?.passwordSet === true;
77
- return { rows, needsYou, projects: "error" in registry ? [] : registry.repos, passwordSet };
85
+ return { rows, needsYou, projects: "error" in registry ? [] : registry.repos, passwordSet, learning: store === null ? null : learningLine(store, "error" in registry ? [] : registry.repos, clock()) };
78
86
  },
79
87
  async task(id) {
80
88
  const answer = await command(["task", "show", id]);
@@ -83,7 +91,7 @@ export function createTuiSource(options) {
83
91
  const task = record(answer["task"]), work = record(answer["work"]), status = record(work["status"]);
84
92
  const store = read();
85
93
  const scope = store === null ? null : store.getScope(id);
86
- const plan = scope === null || scope.approvedDigest === scope.digest ? null : { digest: scope.digest, lines: describeScope(scope).map(line => terminalText(line)) };
94
+ const plan = scope === null || scope.approvedDigest === scope.digest ? null : { digest: scope.digest, lines: [...(store === null ? [] : routeLines(store, id)), ...describeScope(scope)].map(line => terminalText(line)) };
87
95
  let hasResult = false;
88
96
  try {
89
97
  hasResult = store !== null && assignmentOf(store, id, clock(), { principal: "operator", repos: null })?.receipt != null;
@@ -93,9 +101,18 @@ export function createTuiSource(options) {
93
101
  }
94
102
  const decisions = store === null ? [] : store.listDecisions("unanswered").filter(one => one.taskId === id)
95
103
  .map(one => ({ id: one.id, question: terminalText(one.question), options: one.options.map(option => ({ id: option.id, label: terminalText(option.label) })) }));
104
+ // "Can I merge?": the same checklist and lines as `toolroll task ready`, read from the same records.
105
+ let ready = [];
106
+ try {
107
+ const list = !hasResult || store === null ? null : mergeChecklistOf(store, id, clock(), { principal: "operator", repos: null }, evidenceRoot);
108
+ ready = list === null ? [] : checklistLines(list).map(line => terminalText(line));
109
+ }
110
+ catch {
111
+ ready = [];
112
+ }
96
113
  return {
97
114
  id, title: shown(task["title"], id), status: shown(status["label"], words(work["state"])), detail: shown(status["detail"]),
98
- plan, liveRunId: typeof work["liveRunId"] === "number" ? work["liveRunId"] : null, hasResult, decisions,
115
+ plan, liveRunId: typeof work["liveRunId"] === "number" ? work["liveRunId"] : null, hasResult, decisions, ready,
99
116
  };
100
117
  },
101
118
  live(id) {
@@ -125,6 +142,10 @@ export function createTuiSource(options) {
125
142
  argv = ["task", "add", act.text, ...(act.repo === null ? [] : ["--repo", act.repo])];
126
143
  done = "Filed. Its plan will be ready for you to approve.";
127
144
  break;
145
+ case "build":
146
+ argv = ["task", "new", "--build", act.preview, "--digest", act.digest];
147
+ done = "Building. A builder starts it next.";
148
+ break;
128
149
  case "approve":
129
150
  argv = ["task", "approve", act.id, "--yes", "--digest", act.digest];
130
151
  done = "Approved. An agent starts on it.";
@@ -135,12 +156,17 @@ export function createTuiSource(options) {
135
156
  break;
136
157
  case "revise":
137
158
  argv = ["task", "revise", act.id, "--feedback", act.text];
138
- done = "Revision requested.";
159
+ done = "Sent back with your note.";
139
160
  break;
140
161
  case "answer":
141
162
  argv = ["decide", String(act.decision), "--choose", act.option];
142
163
  done = "Answered.";
143
164
  break;
165
+ // Retry is today's requeue (the console's Retry), the same command and the same refusals.
166
+ case "retry":
167
+ argv = ["task", "retry", act.id];
168
+ done = "Queued again. A builder starts it next.";
169
+ break;
144
170
  case "complete": {
145
171
  const store = read();
146
172
  let digest;
@@ -151,32 +177,65 @@ export function createTuiSource(options) {
151
177
  digest = undefined;
152
178
  }
153
179
  if (digest === undefined)
154
- return { ok: false, message: "This task has no finished result to mark Complete.", needsPassword: false };
180
+ return { ok: false, message: "This task has no finished result to accept.", needsPassword: false };
155
181
  argv = ["task", "complete", act.id, "--digest", digest];
156
- done = "Marked Complete.";
182
+ done = "Accepted.";
157
183
  break;
158
184
  }
159
185
  }
160
186
  const answer = await command(argv);
161
187
  if (answer.ok !== true)
162
188
  return refusalOf(answer);
163
- const filed = act.kind === "new" ? words(record(answer["task"])["id"], words(answer["id"])) : "";
189
+ const filed = act.kind === "new" ? words(record(answer["task"])["id"], words(answer["id"])) : act.kind === "build" ? words(answer["task"]) : "";
164
190
  return { ok: true, message: done, ...(filed === "" ? {} : { id: filed }) };
165
191
  },
192
+ async fastTerms(text, repo) {
193
+ if (repo === null)
194
+ return null;
195
+ const answer = await command(["task", "new", text, "--repo", repo, "--preview"]);
196
+ if (answer.ok !== true || answer["eligible"] !== true)
197
+ return null;
198
+ const terms = Array.isArray(answer["terms"]) ? answer["terms"].map(one => ({ label: words(record(one)["label"]), words: words(record(one)["words"]) })) : [];
199
+ return { preview: words(answer["preview"]), digest: words(answer["digest"]), terms };
200
+ },
166
201
  async setup() {
167
202
  if (setupCache !== null && Date.now() - setupCache.at < 30_000)
168
203
  return setupCache.value;
169
204
  const store = read();
170
205
  if (store === null)
171
206
  return null;
172
- const here = await welcomeHere(store, file, clock(), options.check === undefined ? {} : { check: options.check });
207
+ // The screen can close while this waits on the sign-in checks: the store it holds is gone then, and so is the question.
208
+ const here = await welcomeHere(store, file, clock(), options.check === undefined ? {} : { check: options.check }).catch((problem) => {
209
+ if (closed)
210
+ return null;
211
+ throw problem;
212
+ });
213
+ if (here === null)
214
+ return null;
173
215
  const value = here.model.left === 0 ? null : { left: here.model.left, lines: welcomeLines(here.model).map(line => terminalText(line)) };
174
216
  setupCache = { at: Date.now(), value };
175
217
  return value;
176
218
  },
177
219
  close() {
220
+ closed = true;
178
221
  reader?.close();
179
222
  reader = null;
180
223
  },
181
224
  };
182
225
  }
226
+ /** The screen's one line about the learning loops: flaky tests and what waits in project memory, each with its command. */
227
+ function learningLine(store, repos, now) {
228
+ let flaky = 0, memory = 0;
229
+ try {
230
+ for (const repo of repos) {
231
+ flaky += flakyCount(store, repo, now);
232
+ const waiting = memoryWaiting(store, repo);
233
+ memory += waiting.notes + waiting.cleanups;
234
+ }
235
+ }
236
+ catch {
237
+ return null;
238
+ }
239
+ const parts = [flaky === 0 ? "" : `${flaky} flaky test${flaky === 1 ? "" : "s"}: open the project's Flaky tests in the browser`, memory === 0 ? "" : `${memory} project memory suggestion${memory === 1 ? "" : "s"}: open Settings → Knowledge`].filter(Boolean);
240
+ return parts.length === 0 ? null : parts.join(" · ");
241
+ }