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
package/dist/scout.js CHANGED
@@ -27,6 +27,7 @@ import { scoutHandbackSchema } from "./contracts/scout-report.js";
27
27
  import { parseReport, REPORT_IMAGE_FILE, REPORT_LIMITS, REPORT_VERSION, SCOUT_OUTPUT_JSON_SCHEMA } from "./scout-report.js";
28
28
  import { TOKEN_ENVS as TELEGRAM_TOKEN_ENVS } from "./telegram.js";
29
29
  import { evidenceRoot, mailboxName, quarantineMailboxes, readMailbox, reportFileName, SCREENSHOT_BYTE_CAP, storeEvidence, validateScreenshotBytes, writeEvidenceFile, } from "./evidence.js";
30
+ import { gitFailureWords } from "./builder.js";
30
31
  import { MARKER as LEASE_MARKER } from "./worktree.js";
31
32
  import { liveLogContext } from "./live-detail.js";
32
33
  import { openLiveLog } from "./live.js";
@@ -251,7 +252,7 @@ async function scoutWith(store, request, outputDir) {
251
252
  }
252
253
  const revision = await git(GIT, ["--no-optional-locks", "rev-parse", "HEAD"], { cwd: worktree });
253
254
  if (revision.code !== 0) {
254
- return { ok: false, kind: "failure", reason: "git", message: `could not read the base revision in ${worktree}` };
255
+ return { ok: false, kind: "failure", reason: "git", message: `could not read the base revision in ${worktree} (${gitFailureWords(revision)})` };
255
256
  }
256
257
  const baseRevision = revision.stdout.trim();
257
258
  store.stampRun(request.runId, { baseRevision });
package/dist/serve.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare function createDecisionServer(options: ServeOptions): DecisionSer
4
4
  export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
5
5
  export { redactedPath, SHUTDOWN_WAIT_MS, type ServeOptions } from "./server/http.js";
6
6
  export { TASK_COMPOSER_MODES, type TaskComposerMode } from "./server/render-chat.js";
7
- export { inboxFingerprints, parseInboxTab, queueScript, type InboxTab } from "./server/render-pages.js";
7
+ export { queueScript } from "./server/render-pages.js";
8
8
  export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
9
9
  export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches, type ReviewFileRow, type ReviewPriority, type ReviewQueueFacts } from "./server/render-results.js";
10
10
  export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords, type RouteView } from "./server/render-tasks.js";
package/dist/serve.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { secretFolder } from "./tool-secret-store.js";
2
+ import { fallbackSettingOf } from "./fallback.js";
2
3
  import { acceptedIdentities, recoverLearning } from "./project-learning.js";
3
4
  import { consoleFolderGate, syncProjectIdentities } from "./project-identity.js";
4
5
  import { inFolderScope } from "./folder-gate.js";
@@ -108,6 +109,7 @@ import { keepSlowRequest, Timeline } from "./latency-timeline.js";
108
109
  import { readFileSync } from "node:fs";
109
110
  import { createServer } from "node:http";
110
111
  import { homedir, hostname } from "node:os";
112
+ import { sameMachineHost } from "./machine-identity.js";
111
113
  import { dirname, join } from "node:path";
112
114
  import { pinnedAccent } from "./accent-colors.js";
113
115
  import { CHAT_KEY_ENV, credentialKeyOf, fetchOpenRouterCatalog, isSubscriptionChatProvider, priceForConfig, subscriptionCredentialKey } from "./converse.js";
@@ -506,6 +508,7 @@ export function createDecisionServer(options) {
506
508
  builds: projectBuildsOf(repo, who),
507
509
  access: projectAccessOf(repo),
508
510
  network: { setting: store.projectNetwork(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
511
+ fallback: { setting: fallbackSettingOf(store, repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
509
512
  writes: { setting: store.projectWrites(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
510
513
  sandbox: { setting: store.projectSandbox(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
511
514
  checkAccess: {
@@ -1109,7 +1112,7 @@ export function createDecisionServer(options) {
1109
1112
  // A project link is a read context, not a session-changing operation.
1110
1113
  // Prove it against both admission and the known project catalog before
1111
1114
  // collection queries; unknown/foreign paths reveal no work.
1112
- if ((route.id === 'work' || route.id === 'system') && url.searchParams.has('project')) {
1115
+ if ((route.id === 'tasks' || route.id === 'work' || route.id === 'system') && url.searchParams.has('project')) {
1113
1116
  const wanted = url.searchParams.get('project') ?? '';
1114
1117
  if (url.searchParams.getAll('project').length !== 1 || !visible(wanted) ||
1115
1118
  ![...managedRepos(), ...store.listProjects().map(one => one.path)].includes(wanted)) {
@@ -1128,7 +1131,9 @@ export function createDecisionServer(options) {
1128
1131
  project = wanted;
1129
1132
  }
1130
1133
  // All projects, asked for by name on Tasks (its project filter): the rolled-up list, admission-bound as ever.
1131
- if (route.id === 'work' && url.searchParams.get('all') === '1' && !url.searchParams.has('project') && url.searchParams.getAll('all').length === 1)
1134
+ // Tasks (P1.4) says every project as scope=all; an old link's all=1 still reads so.
1135
+ if (route.id === 'tasks' && !url.searchParams.has('project') && ((url.searchParams.get('scope') === 'all' && url.searchParams.getAll('scope').length === 1)
1136
+ || (url.searchParams.get('all') === '1' && url.searchParams.getAll('all').length === 1)))
1132
1137
  project = null;
1133
1138
  // Every page's Tasks count covers this one project view, whatever project the page itself shows.
1134
1139
  const facts = requestContext.getStore();
@@ -1145,7 +1150,7 @@ export function createDecisionServer(options) {
1145
1150
  const namedProject = url.searchParams.get("project");
1146
1151
  if (url.searchParams.getAll("result").length !== 1 || url.searchParams.getAll("run").length > 1 || url.searchParams.getAll("project").length > 1 ||
1147
1152
  (namedProject !== null && (ref === null || !visible(ref.repo) || namedProject !== ref.repo))) {
1148
- return refuse(response, who, 404, "No such result in your projects.", "/work");
1153
+ return refuse(response, who, 404, "No such result in your projects.", "/tasks");
1149
1154
  }
1150
1155
  if (who.via === "cookie" && ref !== null && visible(ref.repo))
1151
1156
  project = ref.repo;
@@ -1171,7 +1176,7 @@ export function createDecisionServer(options) {
1171
1176
  const needsProject = who.via === "cookie" && project === null && !unscopedMode &&
1172
1177
  route.needsProject &&
1173
1178
  !(route.id === "review" && url.searchParams.has("result")) &&
1174
- !(route.id === "board" && url.searchParams.get("scope") === "all");
1179
+ !(route.id === "board" && url.searchParams.get("scope") === "all") && !(route.id === "tasks" && url.searchParams.get("scope") === "all");
1175
1180
  if (needsProject)
1176
1181
  return redirect(response, `/projects?return=${encodeURIComponent(safeReturn(url.pathname + url.search))}`);
1177
1182
  return dispatchConsole(route, { url, who, request, response, route, now, project, chosenProject, posted: new URLSearchParams() });
@@ -1201,9 +1206,10 @@ export function createDecisionServer(options) {
1201
1206
  const here = hostname();
1202
1207
  const registered = store.listRunners().filter(one => one.retiredAt === null);
1203
1208
  const workers = registered.filter(one => runnerAlive(one, now));
1204
- if (workers.some(one => one.host !== here && store.providerReadiness(one.name).some(seen => seen.state === "ready")))
1209
+ // This machine under any of its own names (machine-identity.ts): a hostname that moved with the network is still here.
1210
+ if (workers.some(one => !sameMachineHost(one.host, here) && store.providerReadiness(one.name).some(seen => seen.state === "ready")))
1205
1211
  return true;
1206
- return options.localRunner !== undefined || registered.length === 0 || workers.some(one => one.host === here) ? localAgentSignedIn() : false;
1212
+ return options.localRunner !== undefined || registered.length === 0 || workers.some(one => sameMachineHost(one.host, here)) ? localAgentSignedIn() : false;
1207
1213
  }
1208
1214
  let localSignIn = null;
1209
1215
  let localSignInChecking = null;
@@ -1495,15 +1501,15 @@ export function createDecisionServer(options) {
1495
1501
  function paletteIndexTag(project) {
1496
1502
  const admitted = project === null ? admissionList() : null;
1497
1503
  const entries = [
1498
- { label: "tasks", href: "/work" },
1499
- { label: "needs you", href: "/work?view=needs-you" },
1500
- { label: "inbox", href: "/" },
1501
- { label: "board", href: "/board?scope=all" },
1504
+ { label: "tasks", href: "/tasks" },
1505
+ { label: "needs you", href: "/tasks?view=needs-you" },
1506
+ { label: "home", href: "/" },
1507
+ { label: "board", href: "/tasks?view=board&scope=all" },
1502
1508
  { label: "queue", href: QUEUE_VIEW },
1503
- { label: "workbench", href: "/workbench" },
1509
+ { label: "every project", href: "/tasks?scope=all" },
1504
1510
  { label: "flows", href: "/flows" },
1505
- { label: "done", href: "/done" },
1506
- { label: "review cockpit", href: "/review" },
1511
+ { label: "finished", href: "/tasks?view=done" },
1512
+ { label: "ready for review", href: "/tasks?view=ready" },
1507
1513
  { label: "fleet", href: "/fleet" },
1508
1514
  { label: "activity", href: "/activity" },
1509
1515
  { label: "action ledger", href: "/ledger" },
@@ -1518,8 +1524,8 @@ export function createDecisionServer(options) {
1518
1524
  entries.push({ label: `${one.id} — ${one.title}`, href: `/t/${encodeURIComponent(one.id)}` });
1519
1525
  }
1520
1526
  const saturated = open.length > 200;
1521
- const safeEntries = restricted() ? entries.filter(one => ["/work", "/work?view=needs-you", "/", "/board", "/flows", "/done", "/review", "/runs", "/projects", "/ledger"].includes(one.href) || one.href.startsWith("/t/")) : entries;
1522
- return jsonScript(saturated ? [...safeEntries, { label: "… more in Tasks", href: "/work" }] : safeEntries, { id: "palette-index" });
1527
+ const safeEntries = restricted() ? entries.filter(one => ["/tasks", "/tasks?view=needs-you", "/", "/tasks?view=board", "/flows", "/tasks?view=done", "/tasks?view=ready", "/runs", "/projects", "/ledger"].includes(one.href) || one.href.startsWith("/t/")) : entries;
1528
+ return jsonScript(saturated ? [...safeEntries, { label: "… more in Tasks", href: "/tasks" }] : safeEntries, { id: "palette-index" });
1523
1529
  }
1524
1530
  /**
1525
1531
  * The palette cache (arc 4, finding 6), and its honest contract: a
@@ -1710,7 +1716,7 @@ export function createDecisionServer(options) {
1710
1716
  needsYou: { count: needsYou, saturated: s.chrome.inboxSaturated === true, scope: tasksProject ?? null,
1711
1717
  label: s.chrome.inboxLabel ?? `${needsYou} ${needsYou === 1 ? 'needs' : 'need'} you`,
1712
1718
  // Every project, said by name (all=1), so a session's own open project never narrows the list the count opens.
1713
- href: tasksProject === null ? '/work?all=1&view=needs-you' : `/work?project=${encodeURIComponent(tasksProject)}&view=needs-you` },
1719
+ href: tasksProject === null ? '/tasks?scope=all&view=needs-you' : `/tasks?project=${encodeURIComponent(tasksProject)}&view=needs-you` },
1714
1720
  chats,
1715
1721
  // The same count per project (the rail's project rows), read from the same work index totals.
1716
1722
  ...(() => { if (sensitive)
@@ -1753,7 +1759,9 @@ export function createDecisionServer(options) {
1753
1759
  // A page with its own view keeps its script; the chat page runs the result script.
1754
1760
  const functional = conversation === null || extras.view ? (s.functional?.script ?? '') : RESULT_REVIEW_SCRIPT;
1755
1761
  const document = shell(s.title, s.body, { chrome: s.chrome, sensitive });
1756
- return page(response, status, browserWorkspaceDocument(document, workspace, nonce, functional + MOBILE_VIEWPORT_SCRIPT + keyFill), nonce, true);
1762
+ // The keys and their list (keymap.ts) work here as on every chromed page; the list sits beside the app React owns.
1763
+ // A sensitive page keeps to its own script.
1764
+ return page(response, status, browserWorkspaceDocument(document, workspace, nonce, functional + MOBILE_VIEWPORT_SCRIPT + keyFill + (sensitive ? '' : chromeScript()), sensitive ? html `` : KBD_HELP), nonce, true);
1757
1765
  }
1758
1766
  // A one-time secret on screen (a token, an invite link, a pairing code): the
1759
1767
  // page carries no script of any kind, so it leaves the workspace for a
@@ -2485,7 +2493,7 @@ export function createDecisionServer(options) {
2485
2493
  export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
2486
2494
  export { redactedPath, SHUTDOWN_WAIT_MS } from "./server/http.js";
2487
2495
  export { TASK_COMPOSER_MODES } from "./server/render-chat.js";
2488
- export { inboxFingerprints, parseInboxTab, queueScript } from "./server/render-pages.js";
2496
+ export { queueScript } from "./server/render-pages.js";
2489
2497
  export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
2490
2498
  export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches } from "./server/render-results.js";
2491
2499
  export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords } from "./server/render-tasks.js";
@@ -1,6 +1,6 @@
1
- import { freshFacts, freshlyApprovable, freshnessFor, spendingOnlyOnSuccess, withFreshness } from "../scope.js";
1
+ import { freshFacts, freshnessFor, spendingOnlyOnSuccess, withFreshness } from "../scope.js";
2
+ import { approvalPasswordField } from "../approval-password.js";
2
3
  import { CHAT_ACTION_LOCAL_ACTS, localOwnerRefusal } from "../local-owner.js";
3
- import { localApprovalEligible } from "../scope.js";
4
4
  import { handlersOf } from './handler-registry.js';
5
5
  import { DEPRECATED_PAGE } from "../deprecations.js";
6
6
  /** chat handlers, moved without changing their route bodies. */
@@ -170,7 +170,7 @@ export function createChatHandlers(runtime) {
170
170
  const requestedRevision = url.searchParams.get("revision");
171
171
  if (requestedRevision !== null) {
172
172
  if (focusTask === null || !focusTask.family.versions.some(one => one.id === requestedRevision) || url.searchParams.has("result")) {
173
- return refuse(response, who, 404, "That revision is not available for this task.", "/work");
173
+ return refuse(response, who, 404, "That revision is not available for this task.", "/tasks");
174
174
  }
175
175
  if (requestedRevision !== focusTask.executionId)
176
176
  return redirect(response, `${taskHref(focusTask.id)}?version=${encodeURIComponent(requestedRevision)}`);
@@ -402,20 +402,22 @@ export function createChatHandlers(runtime) {
402
402
  const evidenceLink = action.operation === 'result_accept' ? html `<a href="/r/${Number(action.request['run'])}">Inspect this result</a>` : '';
403
403
  // Cockpit B2: approving standard work may stand on a password remembered on this session, exactly as on the task
404
404
  // page (the same rule approve() applies when the form comes back); the field then may be left empty.
405
+ // The one password rule every approve form reads (approval-password.ts).
405
406
  const freshSince = (() => {
406
407
  const task = typeof action.request['task'] === 'string' ? action.request['task'] : null;
407
408
  if (action.operation !== 'scope_approve' || task === null)
408
409
  return null;
409
410
  const scope = store.getScope(task), fresh = withFreshness('approve-standard', () => freshnessFor(who.name, Date.now(), true));
410
- if (scope === null || fresh === null)
411
+ if (scope === null)
411
412
  return null;
412
- const gate = store.approvalGate(task, who.name, 'person');
413
- return freshlyApprovable(store, task, scope, gate.verdict === 'seal' && !gate.protectedWork) ? new Date(fresh.at) : null;
413
+ const field = approvalPasswordField(store, { name: who.name, taskId: task, scope, passwordless: false, localOwner: false, freshAt: fresh?.at ?? null, returnTo: '/chat' });
414
+ return field.field === 'remembered' ? new Date(field.since) : null;
414
415
  })();
415
416
  // Easy-start C5: a laptop's local owner confirms its own acts without a password (an approval only when it is
416
417
  // eligible: localApprovalEligible, the rule the seal applies again); anything else says how to get a password.
417
418
  const reviewTask = typeof action.request['task'] === 'string' ? action.request['task'] : null;
418
- const localOk = who.authority === 'local-owner' && CHAT_ACTION_LOCAL_ACTS[action.operation] !== null && (action.operation !== 'scope_approve' || (reviewTask !== null && localApprovalEligible(store, who.name, reviewTask).ok));
419
+ const localScope = reviewTask === null ? null : store.getScope(reviewTask);
420
+ const localOk = who.authority === 'local-owner' && CHAT_ACTION_LOCAL_ACTS[action.operation] !== null && (action.operation !== 'scope_approve' || (reviewTask !== null && localScope !== null && approvalPasswordField(store, { name: who.name, taskId: reviewTask, scope: localScope, passwordless: false, localOwner: true, freshAt: null, returnTo: '/chat' }).field === 'none'));
419
421
  const localWords = who.authority === 'local-owner' && !localOk ? localOwnerRefusal(store.accountOf(who.name)?.passwordSet === true, '/chat') : null;
420
422
  const passwordField = !CHAT_ACTIONS[action.operation].password || localOk ? '' : localWords !== null ? html `<p class="approval-password-note">${localWords.message} <a href="${localWords.href}">${localWords.action}</a></p>` : reauth(freshSince === null
421
423
  ? html `<label>Your password<input type="password" name="token" autocomplete="current-password" required></label>`
@@ -788,7 +790,7 @@ export function createChatHandlers(runtime) {
788
790
  }
789
791
  // A scope approval's re-check is spent only if the whole confirmation commits (one transaction: the proposal's
790
792
  // settlement included). Any other action spends it whatever comes of it (its effects aren't all in the database).
791
- const confirmIt = () => confirmLeadProposal(store, principal, id, now, { authority: who.authority, chatProvider: teamChatProvider, confirm: body.get("confirm") === "yes", via: "web", evidenceRoot, ...(body.has("nonce") ? { actionReview: { nonce: body.get("nonce") ?? "", password: body.get("token") ?? "" } } : {}) });
793
+ const confirmIt = () => confirmLeadProposal(store, principal, id, now, { authority: who.authority, chatProvider: teamChatProvider, confirm: body.get("confirm") === "yes", via: "web", person: who.via === "cookie", evidenceRoot, ...(body.has("nonce") ? { actionReview: { nonce: body.get("nonce") ?? "", password: body.get("token") ?? "" } } : {}) });
792
794
  const proposed = store.getLeadProposal(id);
793
795
  const approving = proposed?.kind === "action" && sharedActionPayload(proposed.payload)?.operation === "scope_approve";
794
796
  const outcome = approving ? spendingOnlyOnSuccess(confirmIt, result => !result.ok || ("already" in result && result.already === true)) : confirmIt();
@@ -830,7 +832,7 @@ export function createChatHandlers(runtime) {
830
832
  }
831
833
  if (outcome.ok && outcome.kind === "task_action" && outcome.taskId !== null) {
832
834
  const proposal = store.getLeadProposal(id);
833
- if (proposal.payload["operation"] === "resume") {
835
+ if (proposal.payload["operation"] === "resume" && who.via !== "cookie") {
834
836
  return armTaskResume(response, who, outcome.taskId, String(proposal.payload["run"]), "chat", now);
835
837
  }
836
838
  return redirect(response, `${proposalTaskHref(outcome.taskId)}#task-chat-live`);
@@ -1471,11 +1473,11 @@ export function createChatHandlers(runtime) {
1471
1473
  const all = view("all"), needs = view("needs-you"), done = view("completed");
1472
1474
  const weekAgo = new Date(now.getTime() - 7 * 86_400_000).toISOString();
1473
1475
  const counts = [
1474
- { key: "working", label: "Working now", value: agents.length, href: "/work?view=running" },
1476
+ { key: "working", label: "Working now", value: agents.length, href: "/tasks?view=running" },
1475
1477
  // Each by its shared headline, as the Tasks list words it: a result whose checks failed waits on you, it isn't ready.
1476
- { key: "waiting", label: "Waiting on you", value: needs.items.filter(one => one.status.label !== "Ready for review").length, href: "/work?view=needs-you" },
1477
- { key: "ready", label: "Ready to review", value: needs.items.filter(one => one.status.label === "Ready for review").length, href: "/work?view=needs-you" },
1478
- { key: "done", label: "Done this week", value: done.items.filter(one => (one.completion?.at ?? one.updatedAt) >= weekAgo).length, href: "/work?view=completed" },
1478
+ { key: "waiting", label: "Waiting on you", value: needs.items.filter(one => one.status.label !== "Ready for review").length, href: "/tasks?view=needs-you" },
1479
+ { key: "ready", label: "Ready to review", value: needs.items.filter(one => one.status.label === "Ready for review").length, href: "/tasks?view=needs-you" },
1480
+ { key: "done", label: "Done this week", value: done.items.filter(one => (one.completion?.at ?? one.updatedAt) >= weekAgo).length, href: "/tasks?view=completed" },
1479
1481
  ];
1480
1482
  const tabOf = (one) => one.assignmentState === "ready-to-check" ? one.status.label === "Ready for review" ? "ready" : "needs-you"
1481
1483
  : one.assignmentState === "needs-decision" ? "needs-you" : one.assignmentState === "working" || one.assignmentState === "checking" ? "running" : "finished";
@@ -1494,7 +1496,7 @@ export function createChatHandlers(runtime) {
1494
1496
  const lead = activity === null ? null : { name: activity.name, doing: activity.doing, at: activity.at,
1495
1497
  href: leadTask == null || !admitted(leadTask.repo) ? null : taskHref(familyOf(activity.taskId)?.root.id ?? activity.taskId) };
1496
1498
  return {
1497
- agents, counts, catchUp, allHref: "/work", ...(lead === null ? {} : { lead }),
1499
+ agents, counts, catchUp, allHref: "/tasks", ...(lead === null ? {} : { lead }),
1498
1500
  planUse: (windows?.tiles ?? []).map(one => ({ name: one.name, window: one.window, percent: one.percent, detail: one.detail, tone: one.tone })),
1499
1501
  };
1500
1502
  }
@@ -264,7 +264,7 @@ export declare const TO_FRONT_ICON: Html;
264
264
  * wear an icon each; the foot's list stays text, the way Linear's does. */
265
265
  export declare const strokeIcon: (paths: Html | string) => Html;
266
266
  /** Where the queue lives now: the board, flipped to dispatch order. */
267
- export declare const QUEUE_VIEW = "/board?view=order";
267
+ export declare const QUEUE_VIEW = "/tasks?view=order";
268
268
  export declare const FOLDER_PATHS: Html;
269
269
  export declare const CHAT_PATHS: Html;
270
270
  export declare const WORK_PATHS: Html;
@@ -14,6 +14,7 @@ import { DISCLOSURE_CSS } from "../disclosure.js";
14
14
  import { EVIDENCE_PACK_CSS } from "../evidence-pack.js";
15
15
  import { EXPORT_CSS } from "../export-ui.js";
16
16
  import { START_COMMAND } from "../first-run.js";
17
+ import { SHORTCUTS, webKeymapScript } from "../keymap.js";
17
18
  import { GALLERY_CSS } from "../flow-gallery-ui.js";
18
19
  import { STARTERS_CSS } from "../flow-starters-ui.js";
19
20
  import { FLOWS_CSS } from "../flows-ui.js";
@@ -347,8 +348,9 @@ export function chromeScript() {
347
348
  `navGroups.forEach(function(g){g.addEventListener("toggle",function(){` +
348
349
  `if(g.open){navGroups.forEach(function(o){if(o!==g)o.removeAttribute("open");});}});});` +
349
350
  // the palette
350
- `var raw=document.getElementById("palette-index");if(!raw)return;` +
351
- `var index;try{index=JSON.parse(raw.textContent||"[]");}catch(e){return;}` +
351
+ // No index on a workspace page: search is the workspace's own there (keymap.ts search), and the keys still work.
352
+ `var raw=document.getElementById("palette-index");var index=[];` +
353
+ `if(raw){try{index=JSON.parse(raw.textContent||"[]");}catch(e){return;}}` +
352
354
  `var open=false,box=null,list=null,input=null,items=[],paletteBack=null;` +
353
355
  `function close(){if(!open)return;open=false;box.remove();box=null;if(paletteBack&&paletteBack.isConnected)paletteBack.focus();paletteBack=null;}` +
354
356
  `function go(href){location.href=href;}` +
@@ -395,23 +397,22 @@ export function chromeScript() {
395
397
  `var next=at===-1?(delta>0?0:set.length-1):Math.max(0,Math.min(set.length-1,at+delta));` +
396
398
  `if(next===at)return;` +
397
399
  `set[next].focus();ev.preventDefault();}` +
398
- // key routing: never inside editable targets, no modifiers, no IME
399
- // composition (finding 4); repeats allowed only for j/k
400
+ // key routing (keymap.ts, one table with the terminal UI): never inside editable targets, no modifiers, no IME
401
+ // composition (finding 4); repeats allowed only for j/k. A press key presses only a control the page rendered.
402
+ webKeymapScript() +
400
403
  `var pending=null;` +
401
404
  `document.addEventListener("keydown",function(ev){` +
402
405
  `if(ev.isComposing||ev.metaKey||ev.ctrlKey||ev.altKey)return;` +
403
406
  `var t=ev.target;var tag=t&&t.tagName?t.tagName.toLowerCase():"";` +
404
- `if(tag==="input"||tag==="textarea"||tag==="select"||tag==="button"||(t&&t.isContentEditable))return;` +
407
+ `if(tag==="input"||tag==="textarea"||tag==="select"||(t&&t.isContentEditable)||(t&&t.closest&&t.closest("[role=textbox],[role=dialog]:not(.kbd-help)")))return;` +
405
408
  `if(ev.key==="Escape"){if(helpOpen()){toggleHelp();ev.preventDefault();return;}close();return;}` +
406
409
  `if(helpOpen())return;` +
407
410
  `if(ev.repeat&&ev.key!=="j"&&ev.key!=="k")return;` +
408
- `if(ev.key==="/"){show();ev.preventDefault();return;}` +
409
- `if(ev.key==="?"){toggleHelp();ev.preventDefault();return;}` +
410
411
  `if(ev.key==="j"||ev.key==="k"){rove(ev.key==="j"?1:-1,ev);return;}` +
411
- `if(pending==="g"){pending=null;` +
412
- `var map={b:"/board",i:"/",w:"/workbench",d:"/done",q:"/board?view=order",f:"/fleet",t:"/work",a:"/activity",p:"/projects"};` +
413
- `if(map[ev.key]){go(map[ev.key]);ev.preventDefault();}return;}` +
414
- `if(ev.key==="g"){pending="g";setTimeout(function(){pending=null;},800);}});` +
412
+ `if(pending==="g"){pending=null;var after=GKEYS[ev.key];if(after&&run(after))ev.preventDefault();return;}` +
413
+ `if(ev.key==="g"){pending="g";setTimeout(function(){pending=null;},800);return;}` +
414
+ `var act=Object.prototype.hasOwnProperty.call(KEYS,ev.key)?KEYS[ev.key]:null;` +
415
+ `if(act&&run(act))ev.preventDefault();});` +
415
416
  `})();`);
416
417
  }
417
418
  export const ROLE_TITLES = { plan: "Planner", build: "Builder", review: "Reviewer", repair: "Repair" };
@@ -440,17 +441,7 @@ FINISH: unreviewed and undocumented is unfinished; this build ends with the fini
440
441
  * absent from sensitive pages. Navigation help in plain words — no key
441
442
  * ever posts. */
442
443
  export const KBD_HELP = html `<div class="kbd-help" hidden role="dialog" aria-label="keyboard shortcuts" tabindex="-1">\
443
- <h2>Keyboard shortcuts</h2><table>\
444
- <tr><td><kbd>/</kbd></td><td>jump to a page or an open task</td></tr>\
445
- <tr><td><kbd>g</kbd> then <kbd>i</kbd></td><td>go to the inbox</td></tr>\
446
- <tr><td><kbd>g</kbd> then <kbd>b</kbd></td><td>go to the board</td></tr>\
447
- <tr><td><kbd>g</kbd> then <kbd>q</kbd></td><td>go to the queue</td></tr>\
448
- <tr><td><kbd>g</kbd> then <kbd>f</kbd></td><td>go to the fleet</td></tr>\
449
- <tr><td><kbd>g</kbd> then <kbd>w</kbd></td><td>go to the workbench</td></tr>\
450
- <tr><td><kbd>g</kbd> then <kbd>t</kbd></td><td>go to the task list</td></tr>\
451
- <tr><td><kbd>g</kbd> then <kbd>a</kbd></td><td>go to the activity view</td></tr>\
452
- <tr><td><kbd>g</kbd> then <kbd>p</kbd></td><td>go to the projects</td></tr>\
453
- <tr><td><kbd>g</kbd> then <kbd>d</kbd></td><td>go to what is done</td></tr>\
444
+ <h2>Keyboard shortcuts</h2><table>${SHORTCUTS.map(one => html `<tr><td>${joinHtml(one.keys.split(" ").map(key => html `<kbd>${key}</kbd>`), " then ")}</td><td>${one.says}</td></tr>`)}\
454
445
  <tr><td><kbd>j</kbd> / <kbd>k</kbd></td><td>move through the rows on this page</td></tr>\
455
446
  <tr><td><kbd>Escape</kbd></td><td>close this</td></tr>\
456
447
  </table></div>`;
@@ -513,8 +504,8 @@ ${count !== undefined && count > 0 ? html ` <span class="count badge badge-open"
513
504
  const scopeStatus = peekCounts === null
514
505
  ? null
515
506
  : html `<span class="scope-status">\
516
- ${peekCounts.waiting > 0 ? html `<a class="hot" href="/work?view=needs-you">${peekCounts.waiting} needs you</a>` : html `<a href="/work?view=needs-you">0 needs you</a>`}\
517
- <a href="/runs">${peekCounts.running} live</a><a href="/board?view=order">${peekCounts.queued} queued</a></span>`;
507
+ ${peekCounts.waiting > 0 ? html `<a class="hot" href="/tasks?view=needs-you">${peekCounts.waiting} needs you</a>` : html `<a href="/tasks?view=needs-you">0 needs you</a>`}\
508
+ <a href="/runs">${peekCounts.running} live</a><a href="/tasks?view=order">${peekCounts.queued} queued</a></span>`;
518
509
  const scopeName = effectiveScope === "project" && chrome.project !== null ? projectName(chrome.project) : "All projects";
519
510
  // The switcher (board pass): the scope's name opens a menu of every
520
511
  // enrolled project — one tap to open one, or to widen to all — as plain
@@ -556,7 +547,7 @@ ${scopeStatus}</div>`;
556
547
  ${count !== undefined && count > 0 ? html ` <span${chrome.inboxLabel === undefined ? "" : html ` aria-label="${chrome.inboxLabel}" title="${chrome.inboxLabel}"`} class="count badge badge-open">${count}${chrome.inboxSaturated ? "+" : ""}</span>` : ""}</a>`;
557
548
  const side = joinHtml([
558
549
  html `<aside class="side">`,
559
- html `<div class="side-head"><a class="brand" href="${chrome.chat === true ? "/chat" : "/work"}"><span class="brand-long">Toolroll</span><span class="brand-short">T</span></a>`,
550
+ html `<div class="side-head"><a class="brand" href="${chrome.chat === true ? "/chat" : "/tasks"}"><span class="brand-long">Toolroll</span><span class="brand-short">T</span></a>`,
560
551
  ...(options.sidebarToggle === true
561
552
  ? [html `<button type="button" class="side-toggle" aria-label="collapse sidebar" aria-expanded="true" title="collapse sidebar">${strokeIcon(html `<path d="m15 18-6-6 6-6"/>`)}</button>`]
562
553
  : []),
@@ -566,7 +557,7 @@ ${count !== undefined && count > 0 ? html ` <span${chrome.inboxLabel === undefin
566
557
  // gating); Work and Projects always. Every specialist tool is a dim
567
558
  // text row inside one of the two accordion groups below.
568
559
  ...(chrome.chat ? [primaryItem("chat", "/chat", "Chat")] : []),
569
- primaryItem("work", "/work", "Tasks", chrome.inboxCount),
560
+ primaryItem("work", "/tasks", "Tasks", chrome.inboxCount),
570
561
  primaryItem("flows", "/flows", "Flows"),
571
562
  primaryItem("projects", "/projects", "Projects"),
572
563
  html `</nav>`,
@@ -607,7 +598,7 @@ ${postForm(update.dismissHref, html `<button type="submit">Dismiss</button>`, {
607
598
  // these only below 760px; desktop keeps the sidebar untouched.
608
599
  const mobileTop = joinHtml([
609
600
  html `<header class="mobile-top">`,
610
- html `<a class="brand-mini" href="${chrome.chat === true ? "/chat" : "/work"}">T</a>`,
601
+ html `<a class="brand-mini" href="${chrome.chat === true ? "/chat" : "/tasks"}">T</a>`,
611
602
  // On a phone the pill IS the scope row (mobile pass): the project's
612
603
  // name, its three counts, and the one /projects link at that
613
604
  // breakpoint — the scope bar hides below 760px so the header is one
@@ -640,7 +631,7 @@ ${count !== undefined && count > 0 ? html `<span class="dot-badge" role="img" ar
640
631
  const tabbar = joinHtml([
641
632
  html `<nav class="tabbar">`,
642
633
  ...(chrome.chat ? [tab("chat", "/chat", "Chat")] : []),
643
- tab("work", "/work", "Tasks", chrome.inboxCount),
634
+ tab("work", "/tasks", "Tasks", chrome.inboxCount),
644
635
  tab("flows", "/flows", "Flows"),
645
636
  tab("projects", "/projects", "Projects"),
646
637
  html `</nav>`,
@@ -702,7 +693,7 @@ export const TO_FRONT_ICON = html `<svg viewBox="0 0 24 24" fill="none" stroke="
702
693
  * wear an icon each; the foot's list stays text, the way Linear's does. */
703
694
  export const strokeIcon = (paths) => html `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${paths}</svg>`;
704
695
  /** Where the queue lives now: the board, flipped to dispatch order. */
705
- export const QUEUE_VIEW = "/board?view=order";
696
+ export const QUEUE_VIEW = "/tasks?view=order";
706
697
  export const FOLDER_PATHS = html `<path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"/>`;
707
698
  export const CHAT_PATHS = html `<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>`;
708
699
  export const WORK_PATHS = html `<path d="M9 6h11"/><path d="M9 12h11"/><path d="M9 18h11"/><path d="m4 6 1 1 2-2"/><path d="m4 12 1 1 2-2"/><path d="m4 18 1 1 2-2"/>`;
@@ -730,11 +721,11 @@ export function workToolRows(scoped = false, _offersChat = false, offersCode = f
730
721
  // D5: coding sessions are deprecated; /code still opens this release, but nothing links to it.
731
722
  // Live terminals: an operator's own Claude Code, Codex or shell, in a real terminal (docs/plans/live-terminal.md).
732
723
  ...(offersCode ? [{ key: "code", href: "/term", label: "Live", hint: "your own terminals: Claude Code, Codex or a shell" }] : []),
733
- { key: "inbox", href: "/inbox", label: "Inbox", hint: "questions, approvals, and repairs to act on" },
734
- { key: "board", href: "/board", label: "Board", hint: "lanes by state, with the order view" },
735
- { key: "tasks", href: "/work", label: "Task list", hint: "everything, filterable by state" },
724
+ { key: "inbox", href: "/", label: "Home", hint: "what needs you, what runs, and what waits" },
725
+ { key: "board", href: "/tasks?view=board", label: "Board", hint: "lanes by state, with the order view" },
726
+ { key: "tasks", href: "/tasks", label: "Task list", hint: "everything, filterable by state" },
736
727
  { key: "recipes", href: "/recipes", label: "Recipes", hint: "choose, customize, and reuse a workflow" },
737
- { key: "workbench", href: "/workbench", label: "Portfolio", hint: "every project and live build in one place" },
728
+ { key: "workbench", href: "/tasks?scope=all", label: "Every project", hint: "every project's tasks in one list" },
738
729
  { key: "ledger", href: "/ledger", label: "Action ledger", hint: "who acted, what happened, and the result" },
739
730
  { key: "spend", href: "/spend", label: "Spend", hint: "what agent work cost, and monthly budgets" },
740
731
  ];
@@ -759,8 +750,8 @@ export const SETTINGS_KEYS = new Set(["settings", "fleet", "caps", "people", "mo
759
750
  export function buildsViews(current) {
760
751
  const views = [
761
752
  ["builds", "/runs", "builds"],
762
- ["done", "/done", "done"],
763
- ["review", "/review", "review"],
753
+ ["done", "/tasks?view=done", "done"],
754
+ ["review", "/tasks?view=ready", "review"],
764
755
  ["activity", "/activity", "activity"],
765
756
  ];
766
757
  return html `<p class="meta board-view">${joinHtml(views.map(([key, href, label]) => (key === current ? html `<strong>${label}</strong>` : html `<a href="${href}">${label}</a>`)), " \u00b7 ")}</p>`;
@@ -1229,6 +1229,9 @@
1229
1229
  .approval-field-hint { color: var(--muted-foreground); font-size: 12px; line-height: 1.5; }
1230
1230
  .approval-field textarea, .approval-field input[type=text] { width: 100%; max-width: 75ch; margin: 0; font-family: var(--font-sans); font-size: 14px; line-height: 1.55; }
1231
1231
  .approval-requirements { display: grid; gap: 6px; margin: 2px 0 0; padding: 0; list-style: none; }
1232
+ .approval-requirements li { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
1233
+ .approval-requirements li input[type=text] { flex: 1 1 22rem; }
1234
+ .approval-how { flex: 0 1 auto; max-width: 100%; min-height: 2.125rem; margin: 0; font-size: 13px; }
1232
1235
  .approval-edit-act { display: flex; flex-wrap: wrap; align-items: center; gap: var(--so-space-sm); }
1233
1236
  .approval-edit-act button { margin: 0; min-height: 2.125rem; white-space: nowrap; }
1234
1237
  .approval-link { display: inline-flex; align-items: center; min-height: 32px; padding: 0 var(--so-space-md); border: 1px solid var(--border); border-radius: var(--so-radius-md); background: var(--card); color: var(--foreground); font-size: 13px; font-weight: 500; text-decoration: none; }
@@ -2793,3 +2796,73 @@ html.so-swap::view-transition-old(*):only-child { animation: so-card-out 160ms e
2793
2796
  @media (max-width: 40rem) { .welcome form > .k-btn[type=submit] { width: auto; } }
2794
2797
  /* On a phone the step's primary lives in the dock: its copy in the step is hidden. */
2795
2798
  @media (max-width: 760px) { .welcome .k-btn.k-docked { display: none; } }
2799
+
2800
+ /* Code map: every name is repository data, however long; nothing may push the page wider. */
2801
+ .cm-list { list-style: none; margin: 0; padding: 0; }
2802
+ .cm-item { display: grid; gap: 2px; min-width: 0; padding: 10px 0; border-bottom: 1px solid var(--so-line); overflow-wrap: anywhere; }
2803
+ .cm-title { font-size: 13px; font-weight: 500; color: var(--so-ink); }
2804
+ .cm-meta { font-size: 12.5px; color: var(--so-muted); }
2805
+ .cm-path { overflow-wrap: anywhere; user-select: all; }
2806
+ .cm-search { display: flex; gap: var(--so-space-sm); align-items: center; margin: 0 0 var(--so-space-md); }
2807
+ .cm-search .k-input, .cm-search input[type="search"] { flex: 1 1 auto; min-width: 0; }
2808
+ .cm-search .k-btn { flex: 0 0 auto; white-space: nowrap; }
2809
+ /* A test's name is the row: it wraps whole, its facts sit under it, and the one action stays on one line. */
2810
+ .flaky-rows .k-row-a .k-btn { white-space: nowrap; }
2811
+ @media (min-width: 761px) {
2812
+ .flaky-rows .k-row { grid-template-columns: 96px minmax(0, 1fr) auto auto; padding-block: 10px; }
2813
+ .flaky-rows .k-row-t { grid-column: 2; grid-row: 1; white-space: normal; overflow-wrap: anywhere; }
2814
+ .flaky-rows .k-row-d { grid-column: 2; grid-row: 2; white-space: normal; }
2815
+ .flaky-rows .k-row-m { grid-column: 3; grid-row: 1 / span 2; }
2816
+ .flaky-rows .k-row-a { grid-column: 4; grid-row: 1 / span 2; }
2817
+ .flaky-rows .k-row-c { grid-row: 1 / span 2; }
2818
+ }
2819
+
2820
+ /* A Toolroll card (card-render.ts): tables, charts and key facts in chat, on the console's own tokens. */
2821
+ .tc-card { display: grid; gap: var(--so-space-sm); min-width: 0; font-size: 13px; line-height: 1.45; color: var(--so-ink); }
2822
+ .tc-part { display: grid; gap: 6px; min-width: 0; }
2823
+ .tc-part h4 { margin: 0; font-size: 12.5px; font-weight: 600; }
2824
+ .tc-text { margin: 0; }
2825
+ /* The lead's own words in a card: set apart from the records, never styled as one. */
2826
+ .tc-lead { display: grid; gap: 2px; padding-left: var(--so-space-sm); border-left: 2px solid var(--so-line); font-style: italic; }
2827
+ .tc-lead .tc-note { font-style: normal; }
2828
+ .tc-note { margin: 0; font-size: 11.5px; color: var(--so-muted); }
2829
+ .tc-rule { width: 100%; margin: 0; border: 0; border-top: 1px solid var(--so-line); }
2830
+ .tc-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--so-space-sm); margin: 0; }
2831
+ .tc-facts > div { display: grid; gap: 1px; min-width: 0; }
2832
+ .tc-facts dt { font-size: 11.5px; color: var(--so-muted); }
2833
+ .tc-facts dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
2834
+ .tc-scroll { max-width: 100%; overflow-x: auto; }
2835
+ .tc-table { width: 100%; border-collapse: collapse; }
2836
+ .tc-table th { font-size: 11.5px; font-weight: 500; color: var(--so-muted); text-align: left; white-space: nowrap; }
2837
+ .tc-table th, .tc-table td { padding: 5px var(--so-space-md) 5px 0; border-bottom: 1px solid var(--so-line); vertical-align: top; }
2838
+ /* Cells break between words, never inside one: a narrow screen scrolls the table (.tc-scroll) instead. */
2839
+ .tc-table td { overflow-wrap: break-word; }
2840
+ .tc-table tr:last-child td { border-bottom: 0; }
2841
+ .tc-table .tc-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
2842
+ .tc-bars { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
2843
+ .tc-bars li { display: grid; grid-template-columns: minmax(0, 8rem) minmax(0, 1fr) auto; gap: var(--so-space-sm); align-items: center; }
2844
+ .tc-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2845
+ .tc-bar-track { height: 8px; border-radius: 4px; background: var(--so-raised); }
2846
+ .tc-bar-fill { display: block; height: 100%; border-radius: 4px; background: var(--so-ink); }
2847
+ .tc-bar-value { font-variant-numeric: tabular-nums; }
2848
+ .tc-pie { display: flex; flex-wrap: wrap; align-items: center; gap: var(--so-space-md); }
2849
+ .tc-pie svg { flex: none; width: 88px; height: 88px; }
2850
+ .tc-legend { display: grid; flex: 1 1 140px; gap: 3px; margin: 0; padding: 0; list-style: none; }
2851
+ .tc-legend li { display: flex; align-items: center; gap: 6px; min-width: 0; }
2852
+ .tc-legend strong { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
2853
+ .tc-key { flex: none; width: 9px; height: 9px; border-radius: 2px; background: currentColor; }
2854
+ .tc-c0 { color: var(--so-ink); stroke: var(--so-ink); }
2855
+ .tc-c1 { color: var(--so-info); stroke: var(--so-info); }
2856
+ .tc-c2 { color: var(--so-success); stroke: var(--so-success); }
2857
+ .tc-c3 { color: var(--so-warning); stroke: var(--so-warning); }
2858
+ .tc-c4 { color: var(--so-danger); stroke: var(--so-danger); }
2859
+ .tc-c5 { color: var(--so-muted); stroke: var(--so-muted); }
2860
+ .tc-line { margin: 0; display: grid; gap: var(--so-space-xs); }
2861
+ .tc-line svg { width: 100%; height: 90px; }
2862
+ .tc-line figcaption { font-size: 11.5px; color: var(--so-muted); }
2863
+ .tc-stroke { stroke: var(--so-ink); stroke-width: 1.5; }
2864
+ .tc-area { fill: var(--so-raised); }
2865
+ .tc-notes { display: grid; gap: var(--so-space-xs); margin: 0; padding-left: var(--so-space-md); overflow-wrap: anywhere; }
2866
+
2867
+ /* The handover note wraps on a narrow screen rather than scrolling sideways. */
2868
+ .handover-note { white-space: pre-wrap; }
@@ -272,6 +272,9 @@ export function createSharedGuards(runtime) {
272
272
  if (url.searchParams.get("view") === "order")
273
273
  url.searchParams.delete("view");
274
274
  }
275
+ // Tasks (P1.4) keeps the board's rule: the queue's order view stays an instance view, never a limited person's.
276
+ if (route.id === "tasks" && url.searchParams.get("view") === "order")
277
+ url.searchParams.set("view", "board");
275
278
  return true;
276
279
  }
277
280
  function workAccess() {
@@ -25,6 +25,12 @@ export type HomeFacts = {
25
25
  chat: boolean;
26
26
  /** This person can answer an agent's question (an approver in a browser session). */
27
27
  canAnswer: boolean;
28
+ /** Why this task's plan can't take a yes right now (render-tasks.ts consentDoorOf), or null when it can. */
29
+ closedDoor: (taskId: string) => {
30
+ title: string;
31
+ why: string;
32
+ road: "scope" | "agents";
33
+ } | null;
28
34
  };
29
35
  /** "7 need you across 2 projects." — the sentence and the figures read the same totals. */
30
36
  export declare function homeSentence(needs: number, perProject: readonly {