toolroll 0.9.63 → 0.9.67

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 (302) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/README.md +33 -5
  3. package/dist/acp-agents.d.ts +43 -0
  4. package/dist/acp-agents.js +62 -0
  5. package/dist/acp-attest.d.ts +44 -0
  6. package/dist/acp-attest.js +269 -0
  7. package/dist/acp-check.d.ts +28 -0
  8. package/dist/acp-check.js +410 -0
  9. package/dist/acp-client.d.ts +163 -0
  10. package/dist/acp-client.js +738 -0
  11. package/dist/acp-inspect.d.ts +23 -0
  12. package/dist/acp-inspect.js +109 -0
  13. package/dist/agent-board.d.ts +19 -6
  14. package/dist/agent-board.js +30 -9
  15. package/dist/agent-fence.d.ts +117 -2
  16. package/dist/agent-fence.js +439 -12
  17. package/dist/agent-pulse.js +9 -2
  18. package/dist/agent-state-words.d.ts +19 -0
  19. package/dist/agent-state-words.js +20 -0
  20. package/dist/agent-state.d.ts +65 -0
  21. package/dist/agent-state.js +229 -0
  22. package/dist/agentconfig.js +39 -13
  23. package/dist/agents-board.d.ts +34 -2
  24. package/dist/agents-board.js +110 -1
  25. package/dist/approval-rules-ui.js +2 -2
  26. package/dist/assignment-delivery.d.ts +14 -0
  27. package/dist/assignment-delivery.js +13 -0
  28. package/dist/assignment.js +13 -0
  29. package/dist/attest.js +7 -0
  30. package/dist/backup-ui.js +2 -2
  31. package/dist/batch-checks.js +3 -2
  32. package/dist/browser/THIRD_PARTY_NOTICES.txt +94 -0
  33. package/dist/browser/terminal.css +37 -0
  34. package/dist/browser/terminal.js +228 -0
  35. package/dist/browser/workspace.css +2 -2
  36. package/dist/browser/workspace.js +42 -38
  37. package/dist/browser-shell.js +6 -3
  38. package/dist/browser-workspace.d.ts +235 -1
  39. package/dist/browser-workspace.js +60 -0
  40. package/dist/builder.d.ts +10 -1
  41. package/dist/builder.js +87 -24
  42. package/dist/chat-actions.d.ts +13 -1
  43. package/dist/chat-actions.js +197 -15
  44. package/dist/chat-ask.d.ts +4 -0
  45. package/dist/chat-ask.js +14 -0
  46. package/dist/chat-channel.js +20 -0
  47. package/dist/chat-continuity.js +5 -4
  48. package/dist/chat-decide.d.ts +0 -14
  49. package/dist/chat-decide.js +4 -1
  50. package/dist/chat-delivery.d.ts +9 -0
  51. package/dist/chat-delivery.js +45 -6
  52. package/dist/chat-messages.d.ts +8 -0
  53. package/dist/chat-messages.js +36 -4
  54. package/dist/check-levels-ui.js +2 -2
  55. package/dist/checkout-proof.d.ts +28 -0
  56. package/dist/checkout-proof.js +62 -0
  57. package/dist/claim.d.ts +12 -0
  58. package/dist/claim.js +19 -0
  59. package/dist/cli-help.d.ts +1 -1
  60. package/dist/cli-help.js +4 -1
  61. package/dist/cli.d.ts +3 -0
  62. package/dist/cli.js +21 -2
  63. package/dist/coding-ui.js +6 -4
  64. package/dist/console-instance.d.ts +124 -0
  65. package/dist/console-instance.js +337 -0
  66. package/dist/contracts/chat-actions.d.ts +16 -0
  67. package/dist/contracts/chat-actions.js +4 -0
  68. package/dist/contracts/chat-content.d.ts +19 -0
  69. package/dist/contracts/chat-content.js +6 -0
  70. package/dist/contracts/console-api.d.ts +13 -4
  71. package/dist/contracts/console-api.js +13 -4
  72. package/dist/contracts/flow-card.d.ts +4 -0
  73. package/dist/contracts/flow-card.js +3 -0
  74. package/dist/contracts/flow.d.ts +46 -0
  75. package/dist/contracts/flow.js +11 -2
  76. package/dist/contracts/lead-tools.d.ts +92 -0
  77. package/dist/contracts/lead-tools.js +13 -0
  78. package/dist/contracts/provider.d.ts +11 -1
  79. package/dist/contracts/provider.js +1 -1
  80. package/dist/contracts/route.d.ts +76 -1
  81. package/dist/contracts/route.js +1 -1
  82. package/dist/contracts/store-json.d.ts +2 -0
  83. package/dist/control-setup.d.ts +1 -1
  84. package/dist/control-ui.js +2 -2
  85. package/dist/converse.d.ts +16 -0
  86. package/dist/converse.js +32 -4
  87. package/dist/demo-chat.js +4 -4
  88. package/dist/demo.js +2 -2
  89. package/dist/desktop-update-gate.js +6 -0
  90. package/dist/desktop-update.d.ts +1 -1
  91. package/dist/discord-chat.js +4 -1
  92. package/dist/doctor.js +1 -1
  93. package/dist/egress-bridge.d.ts +17 -0
  94. package/dist/egress-bridge.js +111 -0
  95. package/dist/egress.d.ts +119 -0
  96. package/dist/egress.js +423 -0
  97. package/dist/exec.d.ts +78 -0
  98. package/dist/exec.js +367 -9
  99. package/dist/export-ui.js +2 -2
  100. package/dist/flow-engine.js +24 -5
  101. package/dist/flow-gallery-ui.js +2 -2
  102. package/dist/flow-gallery.js +27 -8
  103. package/dist/flow-share.js +16 -5
  104. package/dist/flow-triggers.d.ts +77 -8
  105. package/dist/flow-triggers.js +517 -70
  106. package/dist/flows-cli.js +8 -2
  107. package/dist/flows-ui.d.ts +0 -2
  108. package/dist/flows-ui.js +52 -4
  109. package/dist/flows.d.ts +4 -0
  110. package/dist/flows.js +9 -1
  111. package/dist/html.d.ts +9 -0
  112. package/dist/html.js +11 -0
  113. package/dist/invoke.d.ts +35 -0
  114. package/dist/invoke.js +347 -28
  115. package/dist/keys.d.ts +18 -14
  116. package/dist/keys.js +5 -0
  117. package/dist/lead-capabilities.js +3 -2
  118. package/dist/lead-contract.js +2 -0
  119. package/dist/lead-doors.d.ts +2 -0
  120. package/dist/lead-doors.js +7 -0
  121. package/dist/lead-follow.d.ts +2 -0
  122. package/dist/lead-follow.js +58 -2
  123. package/dist/lead-progress.js +1 -0
  124. package/dist/lead-queue-runtime.d.ts +46 -0
  125. package/dist/lead-queue-runtime.js +191 -0
  126. package/dist/lead-queue.d.ts +104 -0
  127. package/dist/lead-queue.js +187 -0
  128. package/dist/lead-sweep.d.ts +67 -0
  129. package/dist/lead-sweep.js +99 -0
  130. package/dist/lead-tools.d.ts +22 -0
  131. package/dist/lead-tools.js +152 -1
  132. package/dist/lead.d.ts +13 -5
  133. package/dist/lead.js +89 -29
  134. package/dist/limits-ui.d.ts +8 -1
  135. package/dist/limits-ui.js +26 -0
  136. package/dist/live-bus.d.ts +8 -0
  137. package/dist/live-bus.js +40 -4
  138. package/dist/live-detail.d.ts +27 -0
  139. package/dist/live-detail.js +57 -0
  140. package/dist/live-notes.d.ts +20 -0
  141. package/dist/live-notes.js +47 -0
  142. package/dist/live-records.d.ts +140 -0
  143. package/dist/live-records.js +935 -0
  144. package/dist/live-terminal.d.ts +269 -0
  145. package/dist/live-terminal.js +686 -0
  146. package/dist/live.d.ts +38 -27
  147. package/dist/live.js +142 -124
  148. package/dist/mcp-oauth.d.ts +6 -3
  149. package/dist/mcp-oauth.js +8 -4
  150. package/dist/memory-pass.js +2 -2
  151. package/dist/mobile-viewport.d.ts +5 -1
  152. package/dist/mobile-viewport.js +18 -2
  153. package/dist/model-catalog.js +4 -0
  154. package/dist/monitoring-ui.js +2 -2
  155. package/dist/needs-you.d.ts +1 -1
  156. package/dist/needs-you.js +11 -4
  157. package/dist/operate.d.ts +4 -0
  158. package/dist/operate.js +335 -19
  159. package/dist/passwordless.d.ts +23 -0
  160. package/dist/passwordless.js +26 -0
  161. package/dist/peek-cli.d.ts +12 -4
  162. package/dist/peek-cli.js +19 -11
  163. package/dist/phase-routing.js +10 -3
  164. package/dist/planner-source.d.ts +3 -0
  165. package/dist/planner-source.js +14 -0
  166. package/dist/planner.d.ts +2 -1
  167. package/dist/planner.js +7 -1
  168. package/dist/policy-ui.js +2 -2
  169. package/dist/policy.d.ts +1 -20
  170. package/dist/policy.js +29 -2
  171. package/dist/project-delete-ui.d.ts +18 -0
  172. package/dist/project-delete-ui.js +60 -9
  173. package/dist/project-delete.js +2 -2
  174. package/dist/project-memory.d.ts +3 -1
  175. package/dist/project-memory.js +57 -25
  176. package/dist/project-tools.d.ts +5 -3
  177. package/dist/project-tools.js +12 -9
  178. package/dist/provider-auth.d.ts +4 -3
  179. package/dist/provider-auth.js +5 -4
  180. package/dist/provider-connection.d.ts +2 -1
  181. package/dist/provider-connection.js +5 -0
  182. package/dist/provider.d.ts +25 -2
  183. package/dist/provider.js +63 -9
  184. package/dist/pull-request-ui.js +2 -2
  185. package/dist/push.js +1 -1
  186. package/dist/quick-start.d.ts +24 -0
  187. package/dist/quick-start.js +127 -0
  188. package/dist/release-adapters.d.ts +6 -0
  189. package/dist/release-adapters.js +70 -3
  190. package/dist/release.d.ts +10 -1
  191. package/dist/release.js +34 -15
  192. package/dist/request-budget-ui.js +2 -2
  193. package/dist/result-follow-ups.js +3 -2
  194. package/dist/result-review.d.ts +1 -1
  195. package/dist/result-review.js +9 -3
  196. package/dist/retention-ui.js +2 -2
  197. package/dist/retention.js +10 -1
  198. package/dist/run-efficiency.d.ts +73 -0
  199. package/dist/run-efficiency.js +228 -0
  200. package/dist/runner.d.ts +5 -1
  201. package/dist/runner.js +22 -1
  202. package/dist/scope.d.ts +183 -5
  203. package/dist/scope.js +256 -31
  204. package/dist/scout-net.d.ts +4 -1
  205. package/dist/scout-net.js +37 -12
  206. package/dist/scout.d.ts +20 -6
  207. package/dist/scout.js +27 -3
  208. package/dist/serve.js +248 -40
  209. package/dist/server/chat.d.ts +1 -1
  210. package/dist/server/chat.js +122 -31
  211. package/dist/server/chrome.d.ts +16 -2
  212. package/dist/server/chrome.js +63 -11
  213. package/dist/server/console.css +107 -42
  214. package/dist/server/flows.js +38 -8
  215. package/dist/server/guards.d.ts +1 -0
  216. package/dist/server/guards.js +23 -9
  217. package/dist/server/http.d.ts +7 -0
  218. package/dist/server/http.js +3 -2
  219. package/dist/server/live.d.ts +34 -1
  220. package/dist/server/live.js +39 -17
  221. package/dist/server/pages-assets.js +5 -0
  222. package/dist/server/pages.js +90 -13
  223. package/dist/server/people-tokens.d.ts +3 -0
  224. package/dist/server/people-tokens.js +55 -17
  225. package/dist/server/remote-hooks.js +12 -6
  226. package/dist/server/remote.d.ts +2 -1
  227. package/dist/server/remote.js +14 -5
  228. package/dist/server/render-chat.d.ts +12 -3
  229. package/dist/server/render-chat.js +47 -16
  230. package/dist/server/render-pages.d.ts +32 -4
  231. package/dist/server/render-pages.js +83 -13
  232. package/dist/server/render-people.d.ts +3 -2
  233. package/dist/server/render-people.js +3 -2
  234. package/dist/server/render-results.d.ts +18 -2
  235. package/dist/server/render-results.js +37 -28
  236. package/dist/server/render-settings.js +6 -5
  237. package/dist/server/render-tasks.d.ts +35 -10
  238. package/dist/server/render-tasks.js +111 -27
  239. package/dist/server/request-context.d.ts +2 -0
  240. package/dist/server/request-context.js +2 -1
  241. package/dist/server/route-table.d.ts +3 -0
  242. package/dist/server/route-table.js +47 -5
  243. package/dist/server/runtime.d.ts +33 -2
  244. package/dist/server/session.d.ts +25 -1
  245. package/dist/server/session.js +18 -4
  246. package/dist/server/settings.js +142 -10
  247. package/dist/server/sweeps.d.ts +4 -0
  248. package/dist/server/sweeps.js +58 -0
  249. package/dist/server/task-views.d.ts +2 -1
  250. package/dist/server/task-views.js +96 -6
  251. package/dist/server/tasks.js +327 -78
  252. package/dist/server/terminals.d.ts +31 -0
  253. package/dist/server/terminals.js +365 -0
  254. package/dist/setup-guide.js +3 -2
  255. package/dist/slack-chat.js +4 -1
  256. package/dist/spend-ui.js +3 -3
  257. package/dist/spend.js +2 -1
  258. package/dist/steer-capabilities.d.ts +32 -0
  259. package/dist/steer-capabilities.js +60 -0
  260. package/dist/steer-controls.d.ts +14 -0
  261. package/dist/steer-controls.js +36 -0
  262. package/dist/steer-status.js +2 -2
  263. package/dist/storage-ui.js +4 -4
  264. package/dist/store-baseline.d.ts +1 -1
  265. package/dist/store-baseline.js +1 -1
  266. package/dist/store.d.ts +440 -15
  267. package/dist/store.js +1072 -52
  268. package/dist/subagent-desk.js +1 -1
  269. package/dist/summary.js +3 -0
  270. package/dist/task-source.d.ts +58 -0
  271. package/dist/task-source.js +93 -0
  272. package/dist/team-leads.js +1 -1
  273. package/dist/teams-chat.js +4 -1
  274. package/dist/teardown-git.d.ts +22 -0
  275. package/dist/teardown-git.js +136 -2
  276. package/dist/telegram-lead.d.ts +3 -0
  277. package/dist/telegram-lead.js +44 -7
  278. package/dist/telegram.d.ts +11 -2
  279. package/dist/telegram.js +51 -17
  280. package/dist/terminal-catalog.d.ts +11 -0
  281. package/dist/terminal-catalog.js +129 -0
  282. package/dist/text-limits.d.ts +2 -0
  283. package/dist/text-limits.js +2 -0
  284. package/dist/tool-broker.d.ts +14 -0
  285. package/dist/tool-broker.js +67 -2
  286. package/dist/toolroll-update-ui.js +2 -2
  287. package/dist/toolroll-update.js +13 -3
  288. package/dist/tools-ui.js +2 -2
  289. package/dist/unfenced-test-support.d.ts +2 -0
  290. package/dist/unfenced-test-support.js +11 -0
  291. package/dist/webhook-limits.d.ts +23 -0
  292. package/dist/webhook-limits.js +30 -0
  293. package/dist/webhook-readers.d.ts +56 -0
  294. package/dist/webhook-readers.js +138 -0
  295. package/dist/webhook-signing.d.ts +27 -0
  296. package/dist/webhook-signing.js +119 -0
  297. package/dist/work-index.d.ts +29 -0
  298. package/dist/work-index.js +16 -2
  299. package/dist/workspace-revision.js +3 -1
  300. package/dist/writes-mode.d.ts +9 -0
  301. package/dist/writes-mode.js +8 -0
  302. package/package.json +15 -2
@@ -1,4 +1,3 @@
1
- /** Results and runs: the review cockpit, evidence, receipts, diffs and the result panel. */
2
1
  import { assignmentPresentationOf, historicalAssessmentReason, shortenedMaterialReason } from "../assignment-presentation.js";
3
2
  import { assignmentActionHref, assignmentStatusOf, assignmentWithEvidence } from "../assignment-ui.js";
4
3
  import { owedAcceptance } from "../assignment.js";
@@ -26,7 +25,7 @@ import { ACCEPT_NEEDS_REASON, acceptWordsOf, cantAcceptYetOf, evidenceProblemOf,
26
25
  import { createHash, randomBytes } from "node:crypto";
27
26
  import { buildsViews, oneLineOf, projectChip, safePrUrl, screen, sentenceCase, strokeIcon, when, whenTime } from "./chrome.js";
28
27
  import { chatResultHref, reviewHref, taskChatHref, taskHref } from "./http.js";
29
- import { attributes, html, htmlString, joinHtml, postForm } from "../html.js";
28
+ import { attributes, html, htmlString, joinHtml, postForm, reauth } from "../html.js";
30
29
  import { publicationFactsOf, statusActionHref, statusLineHtml } from "./render-tasks.js";
31
30
  export const RUNS_PAGE = 50;
32
31
  /**
@@ -574,23 +573,23 @@ export function reviewCockpitPage(chrome, data) {
574
573
  export function reviewCockpitDetail(view, csrf, noted, canRetryReview = false, tab = "summary", user = "") {
575
574
  return reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab, user).html;
576
575
  }
577
- /** The selected result's HTML and, for the rebuilt page, the same result
578
- * as data: every form and panel body is the one the HTML carries. */
579
- export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab, user) {
576
+ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab, user, host = { kind: "review" }) {
580
577
  const parts = [];
581
578
  const run = view.run;
582
579
  const proof = view.detail?.proof ?? null;
583
580
  const accepted = proof?.accepted !== null && proof?.accepted !== undefined;
584
581
  const canAnnotate = canAnnotateDiff(view, csrf);
585
582
  const status = cockpitStatusOf(view);
586
- // Header: what this is, its verdict word, and why it sits where it does.
587
- parts.push(joinHtml([
588
- html `<header class="cockpit-head" data-review-task="${view.taskId}">`,
589
- html `<h1>${view.title}</h1>`,
590
- html `<p class="meta">${run === null ? "No build" : `Build #${run.id}`} · <a href="${taskHref(view.taskId)}">Open task</a>${projectChip(view.repo)}</p>`,
591
- html `<p class="cockpit-chips">${statusLineHtml(status)}</p>`,
592
- html `</header>`,
593
- ]));
583
+ // Header: what this is, its verdict word, and why it sits where it does. On a task page the task's own header says
584
+ // all of it, once.
585
+ if (host.kind === "review")
586
+ parts.push(joinHtml([
587
+ html `<header class="cockpit-head" data-review-task="${view.taskId}">`,
588
+ html `<h1>${view.title}</h1>`,
589
+ html `<p class="meta">${run === null ? "No build" : `Build #${run.id}`} · <a href="${taskHref(view.taskId)}">Open task</a>${projectChip(view.repo)}</p>`,
590
+ html `<p class="cockpit-chips">${statusLineHtml(status)}</p>`,
591
+ html `</header>`,
592
+ ]));
594
593
  if (view.detail === null && view.historyProblem !== null)
595
594
  parts.push(html `<p class="problem" data-history-problem>${view.historyProblem} <a href="${taskHref(view.taskId)}">Open task</a></p>`);
596
595
  // The primary next act — exactly one road, chosen from the state.
@@ -629,8 +628,10 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
629
628
  taskHref: taskHref(view.taskId), chatHref: taskChatHref(view.taskId),
630
629
  status: { label: status.label, tone: status.tone, token: status.token },
631
630
  problem: view.detail === null ? view.historyProblem : null,
632
- next: reviewNextActionOf(view, csrf), complete: null, decision: null, checks: null, intent: intentView, noRun: null, panel: null,
631
+ next: reviewNextActionOf(view, csrf, host.kind === "task" && run !== null ? `${host.base}&run=${run.id}` : undefined), complete: null, decision: null, checks: null, intent: intentView, noRun: null, panel: null,
633
632
  notes: view.notes.map(one => ({ author: one.author, at: one.createdAt, note: one.note })),
633
+ efficiency: view.efficiency ?? null,
634
+ network: view.network ?? null,
634
635
  acts: { primary: null, secondary: null, line: null }, runChecks: null, mismatch: null,
635
636
  // The raw run record lives under Details now (2026-10-02): /r/<id> for this result redirects here.
636
637
  record: run === null ? null : { build: run.id, href: `/r/${run.id}?record=1`, facts: [
@@ -651,6 +652,10 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
651
652
  // v50 review-retry panel and the accept-with-exception form.
652
653
  const extraChecks = reviewRetryPanel(view.taskId, run.id, view.reviewRetry, { csrf, canAct: false, returnTo: null });
653
654
  const here = reviewHref(view.taskId);
655
+ /** This result's own address on its host, at one of its views (summary when none). */
656
+ const at = (section = "summary") => host.kind === "task"
657
+ ? `${host.base}&run=${run.id}${section === "summary" ? "" : `&section=${section}`}`
658
+ : `${here}&run=${run.id}${section === "summary" ? "" : `&tab=${section}`}`;
654
659
  const assignment = view.assignment === null ? null : assignmentWithEvidence(view.assignment, receiptStatusOf(view.detail.receipt), run.id);
655
660
  const checks = assignment?.receipt?.checks;
656
661
  if (checks !== undefined)
@@ -664,13 +669,16 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
664
669
  user,
665
670
  noted,
666
671
  requestToken: randomBytes(16).toString("hex"),
667
- hrefFor: one => `${here}&run=${run.id}${one === "summary" ? "" : `&tab=${one}`}`,
668
- returnTo: `${here}&run=${run.id}`,
672
+ hrefFor: one => at(one),
673
+ returnTo: at(),
669
674
  back: null,
670
675
  extraChecks,
671
676
  headStatus: false,
672
677
  action: false,
673
678
  });
679
+ // On a task page the result script keeps the result's own view in `section=` (the page's `tab` is the task's).
680
+ if (host.kind === "task")
681
+ panel.panel.attributes = { ...panel.panel.attributes, "data-result-param": "section" };
674
682
  parts.push(html `<div id="verification" data-cockpit-section="result">${panel.html}</div>`);
675
683
  // What no acceptance resolves (a failed check, a HIGH finding): Complete is refused, so no Accept is offered and
676
684
  // the one line says the next step.
@@ -682,7 +690,7 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
682
690
  const owed = accepted ? null : youCheck?.accept != null ? { note: null } : panel.panel.need?.accept != null ? { note: panel.panel.need.accept.note }
683
691
  : blocked === ACCEPT_NEEDS_REASON ? { note: "Why is this safe to accept?" } : null;
684
692
  const complete = hardStop === null && assignment?.state === "ready-to-check" && assignment.receipt !== null && canRetryReview && csrf !== ""
685
- ? { action: `${taskHref(view.taskId)}/complete`, receipt: assignment.receipt.digest, run: run.id, accept: owed } : null;
693
+ ? { action: `${taskHref(view.taskId)}/complete`, receipt: assignment.receipt.digest, run: run.id, accept: owed, ...(host.kind === "task" ? { returnTo: at() } : {}) } : null;
686
694
  if (complete !== null)
687
695
  parts.push(completionForm(view.taskId, run.id, complete.receipt, view.detail?.pullRequestTo ?? null, owed));
688
696
  // The one decision, after the evidence: Accept and finish only when every requirement is met and the checks passed.
@@ -708,13 +716,14 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
708
716
  const runChecks = canRetryReview && csrf !== "" && followUps !== null && (followUps.full || followUps.quick) && !checksRunning &&
709
717
  (checks === undefined || ((checks.status === "not-run" || checks.status === "unavailable") && checks.release == null))
710
718
  // Back on this result's Checks tab, where #follow-ups shows the run it started.
711
- ? { action: `/r/${run.id}/checks`, level: followUps.full ? "full" : "quick", returnTo: `${here}&run=${run.id}&tab=checks` } : null;
719
+ ? { action: `/r/${run.id}/checks`, level: followUps.full ? "full" : "quick", returnTo: at("checks") } : null;
712
720
  const need = panel.panel.need;
713
721
  const nextKind = selected.next?.kind;
714
722
  // A failed build: what went wrong is the card, Retry the act; a link to this same page goes nowhere, so it isn't one.
715
723
  const failure = view.failure == null ? null : { line: view.failure.line, evidence: view.failure.evidence, suggestion: view.failure.suggestion, retry: view.failure.retry,
716
- link: view.failure.link === null || (view.failure.link.href.startsWith(`${here}&run=${run.id}`) && !view.failure.link.href.includes("#")) ? null : view.failure.link,
717
- ...(view.failure.acceptAnyway == null ? {} : { acceptAnyway: { ...view.failure.acceptAnyway, returnTo: `${here}&run=${run.id}` } }) };
724
+ link: view.failure.link === null || (view.failure.link.href.startsWith(`${here}&run=${run.id}`) && !view.failure.link.href.includes("#")) ? null
725
+ : host.kind === "task" && view.failure.link.href.startsWith(`${here}&run=${run.id}&tab=`) ? { ...view.failure.link, href: view.failure.link.href.replace(`${here}&run=${run.id}&tab=`, `${host.base}&run=${run.id}&section=`) } : view.failure.link,
726
+ ...(view.failure.acceptAnyway == null ? {} : { acceptAnyway: { ...view.failure.acceptAnyway, returnTo: at() } }) };
718
727
  const actFacts = failure !== null
719
728
  ? { accept: null, runChecks: runChecks !== null, checksRunning, blocked: null, canRequest: false, need: null, next: null, failed: { retry: failure.retry !== null, acceptAnyway: failure.acceptAnyway !== undefined } }
720
729
  : {
@@ -744,7 +753,7 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
744
753
  const lines = (added.length > 0 ? added : shown).map(line => line.newLine);
745
754
  return [file.path, lines.length === 0 ? null : { from: Math.min(...lines), to: Math.max(...lines) }];
746
755
  }));
747
- const changesHref = `${here}&run=${run.id}&tab=changes`;
756
+ const changesHref = at("changes");
748
757
  const found = reportMismatchesOf(proof.reasons, proof.proofProblem === null ? proof.matrix : [], changes);
749
758
  // The saved report itself can't be read: that is the evidence problem, said once.
750
759
  if (proof.proofProblem !== null)
@@ -757,7 +766,7 @@ export function reviewCockpitDetailParts(view, csrf, noted, canRetryReview, tab,
757
766
  text: one.text, path: one.path, absent: one.inChanges === false,
758
767
  lines: one.lines === null ? null : one.lines.from === one.lines.to ? `line ${one.lines.from}` : `lines ${one.lines.from}–${one.lines.to}`,
759
768
  href: one.path !== null && one.inChanges === true ? `${changesHref}#${diffFileAnchor(one.path)}${hunkStart.has(one.path) ? `-L${hunkStart.get(one.path)}` : ""}`
760
- : one.note !== null && (proof.proof?.caveats.length ?? 0) >= one.note ? `${here}&run=${run.id}#report-note-${one.note}` : null,
769
+ : one.note !== null && (proof.proof?.caveats.length ?? 0) >= one.note ? `${at()}#report-note-${one.note}` : null,
761
770
  noteLabel: one.path === null && one.note !== null ? `The report, note ${one.note}` : null,
762
771
  })),
763
772
  said: [...new Set([...proof.reasons, ...found.map(one => one.reason)].flatMap(reason => [reason, plainReasonWords(reason)]))],
@@ -825,7 +834,7 @@ export function pullRequestCardHtml(pr, csrf) {
825
834
  const merged = view.mergeCommit === null ? "" : html `<p class="meta">Merge commit <span class="mono">${view.mergeCommit.slice(0, 12)}</span></p>`;
826
835
  const target = pr.target === null ? "the base branch" : pr.target;
827
836
  const act = !view.canMerge || csrf === "" || view.prNumber === null ? "" :
828
- postForm(`${taskHref(pr.taskId)}/merge`, html `<p class="meta">${view.mergeMethod === "squash" ? "Squash-merges" : view.mergeMethod === "rebase" ? "Rebase-merges" : "Merges"} PR #${view.prNumber} into ${target} and deletes its branch.</p><label>Password<input type="password" name="token" autocomplete="current-password" required></label>${view.fullCheck === null ? html `<button type="submit">Merge</button>` : html `<input type="hidden" name="anyway" value="1"><button type="submit" class="secondary">Merge anyway</button>`}`, { attrs: { class: "pull-request-act", "data-merge-form": true }, hidden: { run: view.runId } });
837
+ postForm(`${taskHref(pr.taskId)}/merge`, html `<p class="meta">${view.mergeMethod === "squash" ? "Squash-merges" : view.mergeMethod === "rebase" ? "Rebase-merges" : "Merges"} PR #${view.prNumber} into ${target} and deletes its branch.</p>${reauth(html `<label>Password<input type="password" name="token" autocomplete="current-password" required></label>`)}${view.fullCheck === null ? html `<button type="submit">Merge</button>` : html `<input type="hidden" name="anyway" value="1"><button type="submit" class="secondary">Merge anyway</button>`}`, { attrs: { class: "pull-request-act", "data-merge-form": true }, hidden: { run: view.runId } });
829
838
  return html `<section class="card pull-request pull-request--${tone}" id="merge" data-pull-request="${view.state}"><div class="pull-request-head"><strong>${view.label}</strong>${link}</div><p class="meta">${view.detail}${revision}</p>${merged}${act}</section>`;
830
839
  }
831
840
  /** Exactly one primary road per result, chosen from its state; the
@@ -837,11 +846,11 @@ export function reviewNextAction(view, csrf, _accepted, _canAnnotate) {
837
846
  return next === null ? html `` : html `<div class="card cockpit-next" data-next-action="${next.kind}"><div><strong>${next.title}</strong><span class="meta">${next.detail}</span></div>${next.control}</div>`;
838
847
  }
839
848
  /** The next action for the browser workspace's JSON: its control as markup text. */
840
- export function reviewNextActionOf(view, csrf) {
841
- const next = reviewNextActionParts(view, csrf);
849
+ export function reviewNextActionOf(view, csrf, back) {
850
+ const next = reviewNextActionParts(view, csrf, back);
842
851
  return next === null ? null : { ...next, control: htmlString(next.control) };
843
852
  }
844
- function reviewNextActionParts(view, csrf) {
853
+ function reviewNextActionParts(view, csrf, back) {
845
854
  const run = view.run;
846
855
  const detail = view.detail;
847
856
  const card = (kind, title, detailWords, control) => ({ kind, title, detail: detailWords, control });
@@ -852,7 +861,7 @@ function reviewNextActionParts(view, csrf) {
852
861
  return card("draft-repair", "CI is failing on its pull request", "Toolroll confirmed the failure. Draft one repair task, then approve it before it runs.", postForm(`/r/${run.id}/draft-repair`, html `<button type="submit">Draft a repair task</button>`));
853
862
  }
854
863
  if (detail.comments.length > 0 && csrf !== "") {
855
- return card("revise", `${detail.comments.length} note${detail.comments.length === 1 ? "" : "s"} ready`, "Create one revision from these notes. You approve it before it runs.", postForm(`/r/${run.id}/revise`, html `${revisionSealFields(detail.comments, detail.sourceDigest)}<button type="submit">Revise</button>`, { returnTo: reviewHref(view.taskId) }));
864
+ return card("revise", `${detail.comments.length} note${detail.comments.length === 1 ? "" : "s"} ready`, "Create one revision from these notes. You approve it before it runs.", postForm(`/r/${run.id}/revise`, html `${revisionSealFields(detail.comments, detail.sourceDigest)}<button type="submit">Revise</button>`, { returnTo: back ?? reviewHref(view.taskId) }));
856
865
  }
857
866
  return null;
858
867
  }
@@ -1982,7 +1991,7 @@ export function resultNeedAction(need, o, canRequest) {
1982
1991
  : need.rebuild != null
1983
1992
  ? postForm(need.rebuild.action, html `<button type="submit" data-primary-action data-rebuild style="min-height:44px">${need.label}</button>`, { attrs: { class: "rebuild" } })
1984
1993
  : need.confirm !== null
1985
- ? postForm(need.confirm.action, html `${need.confirm.checked === true ? html `<label><input type="checkbox" name="checked" value="yes" required> Nothing from build #${need.confirm.run} is running</label>` : ""}<label>Your password<input type="password" name="token" autocomplete="current-password" required></label><button type="submit" style="min-height:44px">${need.label}</button>`, { attrs: { id: "confirm-stopped", class: "confirm-stopped" }, returnTo: need.confirm.returnTo, hidden: { run: need.confirm.run } })
1994
+ ? postForm(need.confirm.action, html `${need.confirm.checked === true ? html `<label><input type="checkbox" name="checked" value="yes" required> Nothing from build #${need.confirm.run} is running</label>` : ""}${reauth(html `<label>Your password<input type="password" name="token" autocomplete="current-password" required></label>`)}<button type="submit" style="min-height:44px">${need.label}</button>`, { attrs: { id: "confirm-stopped", class: "confirm-stopped" }, returnTo: need.confirm.returnTo, hidden: { run: need.confirm.run } })
1986
1995
  : html `<a class="button-link" href="${need.href ?? "#"}" data-primary-action>${need.label}</a>`;
1987
1996
  return html `<div class="result-action" data-result-action="need">${control}${canRequest && o.csrf !== "" ? html `<a class="result-feedback-link" href="#request-changes">Request changes</a>` : ""}</div>`;
1988
1997
  }
@@ -23,7 +23,7 @@ import { redactToken, TOKEN_ENV } from "../telegram.js";
23
23
  import { requestContext } from "./request-context.js";
24
24
  import { chatMoney, screen, strokeIcon, when, whenTime } from "./chrome.js";
25
25
  import { taskHref } from "./http.js";
26
- import { html, joinHtml, postForm } from "../html.js";
26
+ import { html, joinHtml, postForm, reauth } from "../html.js";
27
27
  import { permissionModeChoices, qualityModeChoices } from "./render-tasks.js";
28
28
  /** Settings → Lead: one line for what runs the lead and one action; the full form, turning it off and stored keys under Advanced. */
29
29
  export function leadSettingsHtml(data) {
@@ -36,7 +36,7 @@ export function leadSettingsHtml(data) {
36
36
  : data.words !== null
37
37
  ? html `<p>The lead uses ${data.words}.</p><p class="meta">${config.model === "default" ? "Its default model" : `Model ${config.model}`} · up to ${config.dailyTurns} turns a day · no dollar spend. Every action it proposes waits for you to confirm it.</p>`
38
38
  : html `<p>The lead uses the ${config.provider === "anthropic-api" ? "Anthropic" : "OpenRouter"} API with ${config.model}.</p><p class="meta">Up to ${chatMoney(config.weeklyCeilingMicrousd)} a week · up to ${config.dailyTurns} turns a day.</p>`;
39
- const forget = facts.keyFacts.filter(one => one.state === "stored").map(one => postForm("/chat/config", html `<input type="password" name="token" placeholder="your password" autocomplete="current-password" aria-label="Your password"><button type="submit" class="secondary">Forget the stored ${one.provider} key</button>`, { attrs: { class: "inline" }, returnTo, hidden: { "forget-key": one.provider } }));
39
+ const forget = facts.keyFacts.filter(one => one.state === "stored").map(one => postForm("/chat/config", html `${reauth(html `<input type="password" name="token" placeholder="your password" autocomplete="current-password" aria-label="Your password">`)}<button type="submit" class="secondary">Forget the stored ${one.provider} key</button>`, { attrs: { class: "inline" }, returnTo, hidden: { "forget-key": one.provider } }));
40
40
  return joinHtml([
41
41
  html `<p><a href="/settings">Settings</a></p><h1>Lead</h1>`,
42
42
  data.said === null ? "" : html `<p class="problem" role="status">${data.said}</p>`,
@@ -58,7 +58,7 @@ ${postForm("/settings/lead/promise/cancel", html `<button type="submit" class="s
58
58
  : html `<ul class="lead-subagent-list">${data.subagents.map(one => html `<li data-subagent="${one.id}"><a href="/settings/lead/subagents/${one.id}">${one.label}</a><span class="meta">${one.project}${one.paused ? " · Paused" : ""}</span></li>`)}</ul>`}<p><a class="button-link" href="/settings/lead/subagents?add=1#add" data-add-subagent>Add subagent</a></p></section>`,
59
59
  html `<details class="lead-advanced" data-lead-advanced><summary>Advanced</summary>`,
60
60
  leadConfigForm(config, facts),
61
- config === null ? "" : postForm("/chat/config", html `<input type="password" name="token" placeholder="your password" autocomplete="current-password" aria-label="Your password"><button type="submit" class="secondary">Turn the lead off</button>`, { attrs: { class: "inline" }, returnTo, hidden: { off: "1" } }),
61
+ config === null ? "" : postForm("/chat/config", html `${reauth(html `<input type="password" name="token" placeholder="your password" autocomplete="current-password" aria-label="Your password">`)}<button type="submit" class="secondary">Turn the lead off</button>`, { attrs: { class: "inline" }, returnTo, hidden: { off: "1" } }),
62
62
  forget,
63
63
  html `</details>`,
64
64
  ], "\n");
@@ -102,7 +102,7 @@ ${models.map(model => html `<option value="${model}">${labels.get(model) ?? ""}<
102
102
  .join(" · ")})</span>\
103
103
  <input type="password" name="key" placeholder="direct API only — leave empty to keep" autocomplete="off"></label>`,
104
104
  html `<label>Your password <span class="meta">(typed again to change the provider)</span>\
105
- <input type="password" name="token" autocomplete="current-password"></label>`,
105
+ ${reauth(html `<input type="password" name="token" autocomplete="current-password">`)}</label>`,
106
106
  html `<button type="submit">${current === null ? "turn chat on" : "save"}</button>`,
107
107
  "",
108
108
  ], "\n"), { attrs: { class: "card" }, returnTo: data.returnTo }),
@@ -290,7 +290,7 @@ ${[
290
290
  postForm("/push/subscribe", joinHtml([
291
291
  "",
292
292
  html `<input type="hidden" name="endpoint" value=""><input type="hidden" name="p256dh" value=""><input type="hidden" name="auth" value="">`,
293
- html `<label>Your password <input type="password" name="token" autocomplete="current-password"></label>`,
293
+ html `${reauth(html `<label>Your password <input type="password" name="token" autocomplete="current-password"></label>`)}`,
294
294
  html `<button type="submit" id="push-enable">Get alerts on this device</button>`,
295
295
  html `<p class="meta" id="push-state"></p>`,
296
296
  "",
@@ -528,6 +528,7 @@ export const SETTINGS_GROUPS = [
528
528
  ]],
529
529
  ["Access and rules", [
530
530
  ["/settings/sign-in", "Sign-in", html `<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>`],
531
+ ["/settings/passwordless", "Passwordless", html `<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>`],
531
532
  ["/settings/sessions", "Sessions & tokens", html `<circle cx="7.5" cy="15.5" r="5.5"/><path d="m21 2-9.6 9.6M15.5 7.5l3 3L22 7l-3-3"/>`],
532
533
  ["/settings/project", "Project", html `<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>`],
533
534
  ["/settings/policy", "Policy", html `<path d="M9 12l2 2 4-4"/><rect x="4" y="3" width="16" height="18" rx="2"/>`],
@@ -1,10 +1,9 @@
1
- /** Task pages: approval, agents, plans, controls, decisions and the task body. */
2
1
  import { type Html } from "../html.js";
3
2
  import { type RunActivity } from "../activity-line.js";
4
3
  import { type AgentChoice } from "../agentconfig.js";
5
4
  import { type AssignmentSnapshot } from "../assignment.js";
6
5
  import { type TaskBaseView } from "../task-base.js";
7
- import { type BrowserTaskView } from "../browser-workspace.js";
6
+ import { type BrowserAgentControls, type BrowserTaskView } from "../browser-workspace.js";
8
7
  import { type FormView } from "../contracts/console-api.js";
9
8
  import { type DispatchDiagnosis } from "../dispatch.js";
10
9
  import { type ReportView } from "../evidence.js";
@@ -23,6 +22,7 @@ import { type DisplayStatus, type PublicationFacts, type ReviewFacts, type WorkS
23
22
  import { type Chrome, type Screen } from "./chrome.js";
24
23
  import { type CompletionReceiptView, type EvidenceLinkMap, type TaskPullRequest } from "./render-results.js";
25
24
  import { type Who } from "./session.js";
25
+ import { type TaskOrigin } from "../task-source.js";
26
26
  /** What the task and approval views show about a drafted plan's contract
27
27
  * (contract handoff, task 1). A problem is a named problem, never a blank. */
28
28
  export type PlanContractView = {
@@ -74,14 +74,6 @@ export declare function revisionSentence(revision: Extract<RevisionView, {
74
74
  /** A planner's amendment, said plainly and kept in view: approving binds
75
75
  * the amended terms, so this is never folded away. */
76
76
  export declare function approvalAmendmentHtml(view: PlanContractView | null | undefined): Html;
77
- /**
78
- * The approval sheet (approval critique, Oct 2): the plan open, in plain
79
- * rows — Goal, Changes, Won't touch, Done when — one line of who builds,
80
- * one Approve & start beside the password, and every remaining signed
81
- * term (lineage, routing, runtime limits, the seal) in one Details fold.
82
- * Presentation only: the same hidden fields, nonce, digest and password
83
- * post to the same route, and the task page and chat card share it.
84
- */
85
77
  export declare function approvalSheetHtml(input: {
86
78
  surface: "task" | "chat";
87
79
  action: string;
@@ -103,7 +95,11 @@ export declare function approvalSheetHtml(input: {
103
95
  label: string;
104
96
  filedAgo: string | null;
105
97
  } | null;
98
+ /** v126: where the work came from: an outside event's one line of context (never a term the approval agrees to). */
99
+ origin?: TaskOrigin | null;
106
100
  deliverable: "branch" | "report";
101
+ /** The plan was rewritten after this build: the yes builds again to it (the approve POST requeues). */
102
+ rebuild?: number | null;
107
103
  editHref: string;
108
104
  notNowHref: string;
109
105
  sticky: boolean;
@@ -121,6 +117,8 @@ export declare function approvalSheetHtml(input: {
121
117
  open: boolean;
122
118
  stepsHref: string | null;
123
119
  } | null;
120
+ /** Cockpit B2: this person's password is remembered (when, ISO) and these terms may stand on it. */
121
+ freshSince?: string | null;
124
122
  }): Html;
125
123
  /** Earlier versions of a task still in flight, in plain words: queued
126
124
  * while they only wait, running once one has started; null when none. */
@@ -233,6 +231,11 @@ export declare function agentsStripHtml(view: RouteView | null, taskId: string):
233
231
  /** A ceremony nonce as stored: the sha256 hex of the value the form carried. */
234
232
  export declare function nonceHashOf(value: string): string;
235
233
  /** The approve POST's refusal, in words a person can act on. */
234
+ /** " (password remembered from 10:42)" when the approval stood on a remembered password or sign-in; nothing otherwise. */
235
+ export declare function approvalProofWords(proof: {
236
+ method: string;
237
+ at: string;
238
+ } | null | undefined): string;
236
239
  export declare function approveRefusalWords(reason: string): string;
237
240
  /** The browser's one-click approval binds not only the signed scope but the
238
241
  * exact advisory plan revision shown beside it. The scope digest remains the
@@ -473,6 +476,8 @@ export declare function taskBodyParts(data: {
473
476
  /** Immutable filing provenance (v12) — the approver sees which door
474
477
  * filed this (console, cli, intake, template:<name>) at the yes. */
475
478
  filedVia?: string | null;
479
+ /** v126: where the work came from — the flow and the outside event — in words; null for everything else. */
480
+ origin?: TaskOrigin | null;
476
481
  /** Coordinator provenance when an agent filed this; null otherwise. */
477
482
  coordinator?: {
478
483
  label: string;
@@ -500,6 +505,23 @@ export declare function taskBodyParts(data: {
500
505
  activity?: RunActivity | null;
501
506
  /** Live steering: the Claude build that takes Pause right now, and its latest pause (null: none, or it continued). */
502
507
  livePause?: LivePauseFact | null;
508
+ /** The running attempt's composer facts (steer-controls.ts), for this reader. */
509
+ steerComposer?: {
510
+ controls: BrowserAgentControls;
511
+ steer: {
512
+ action: string;
513
+ run: number;
514
+ } | null;
515
+ } | null;
516
+ /** This task's latest attempts, newest first (a tab's unsent draft for one that ended is offered on). */
517
+ steerRecent?: number[];
518
+ /** Cockpit B2: when this person's remembered password was given, when it may approve these terms. */
519
+ approvalFresh?: string | null;
520
+ /** Cockpit B2: how the current approval's person was proved (approval proved ledger), when it was a remembered one. */
521
+ approvalProof?: {
522
+ method: string;
523
+ at: string;
524
+ } | null;
503
525
  /** Workers that are both alive and authorized for this task's project. */
504
526
  worker?: {
505
527
  answering: number;
@@ -583,6 +605,9 @@ export declare function taskBodyParts(data: {
583
605
  steering?: SteerNote[];
584
606
  /** A build's agent is running now and reads new notes when it next checks for them (v120). */
585
607
  steeringLive?: boolean;
608
+ /** The running build a note from this page is bound to (cockpit §4): the exact attempt, so a stale page's note is
609
+ * refused rather than filed for whatever runs later. Null: no build reads notes now (the note waits for the next). */
610
+ steeringRun?: number | null;
586
611
  /** The publication grant the publisher would act under — from
587
612
  * publicationGrantFor(repo) only; null when none, or no project. */
588
613
  grant?: PublicationGrant | null;