toolroll 0.9.54 → 0.9.56

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 (350) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +29 -12
  3. package/dist/action-ledger.d.ts +2 -4
  4. package/dist/action-ledger.js +2 -10
  5. package/dist/agent-onboard.js +4 -1
  6. package/dist/approval-policy.d.ts +5 -5
  7. package/dist/approval-policy.js +4 -4
  8. package/dist/approval-rules-ui.d.ts +3 -2
  9. package/dist/approval-rules-ui.js +17 -22
  10. package/dist/assignment-ui.d.ts +3 -2
  11. package/dist/assignment-ui.js +4 -11
  12. package/dist/backup-ui.d.ts +2 -1
  13. package/dist/backup-ui.js +16 -27
  14. package/dist/brand-mark.d.ts +3 -2
  15. package/dist/brand-mark.js +4 -4
  16. package/dist/browser/workspace.css +1 -1
  17. package/dist/browser/workspace.js +25 -25
  18. package/dist/browser-shell.d.ts +2 -1
  19. package/dist/browser-shell.js +9 -9
  20. package/dist/browser-workspace.d.ts +14 -15
  21. package/dist/browser-workspace.js +0 -3
  22. package/dist/budget-alerts.js +3 -3
  23. package/dist/chat-actions.d.ts +23 -18
  24. package/dist/chat-actions.js +110 -88
  25. package/dist/chat-ask.d.ts +2 -2
  26. package/dist/chat-ask.js +5 -5
  27. package/dist/chat-channel.d.ts +15 -15
  28. package/dist/chat-channel.js +20 -20
  29. package/dist/chat-controls.d.ts +0 -4
  30. package/dist/chat-controls.js +0 -1
  31. package/dist/chat-core.js +1 -1
  32. package/dist/chat-delivery-state.js +2 -2
  33. package/dist/chat-delivery.d.ts +2 -2
  34. package/dist/chat-delivery.js +27 -34
  35. package/dist/chat-flow.js +3 -3
  36. package/dist/chat-messages.d.ts +1 -1
  37. package/dist/chat-messages.js +4 -4
  38. package/dist/chat-migration.d.ts +1 -1
  39. package/dist/chat-migration.js +11 -11
  40. package/dist/chat-polish.d.ts +5 -4
  41. package/dist/chat-polish.js +9 -10
  42. package/dist/chat-rooms.js +3 -3
  43. package/dist/chat-warmth.d.ts +2 -2
  44. package/dist/check-levels-ui.d.ts +2 -1
  45. package/dist/check-levels-ui.js +26 -53
  46. package/dist/cli.d.ts +3 -1
  47. package/dist/cli.js +15 -10
  48. package/dist/coding-shipping-ui.d.ts +2 -1
  49. package/dist/coding-shipping-ui.js +6 -6
  50. package/dist/coding-ui.d.ts +3 -1
  51. package/dist/coding-ui.js +30 -29
  52. package/dist/contracts/chat-actions.d.ts +32 -27
  53. package/dist/contracts/chat-actions.js +29 -11
  54. package/dist/contracts/chat-content.d.ts +1 -1
  55. package/dist/contracts/chat-content.js +1 -1
  56. package/dist/contracts/chat-tables.js +4 -4
  57. package/dist/contracts/cli.d.ts +1 -3
  58. package/dist/contracts/console-api.d.ts +7 -7
  59. package/dist/contracts/console-api.js +13 -12
  60. package/dist/contracts/flow-propose.d.ts +3 -3
  61. package/dist/contracts/flow.d.ts +132 -125
  62. package/dist/contracts/flow.js +27 -12
  63. package/dist/contracts/health.d.ts +1 -3
  64. package/dist/contracts/lead-context.d.ts +1 -1
  65. package/dist/contracts/lead-context.js +2 -2
  66. package/dist/contracts/lead-tools.d.ts +20 -18
  67. package/dist/contracts/lead-tools.js +15 -15
  68. package/dist/contracts/stage-output.d.ts +1 -1
  69. package/dist/contracts/stage-output.js +1 -1
  70. package/dist/contracts/store-json.d.ts +23 -22
  71. package/dist/contracts/store-json.js +17 -17
  72. package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
  73. package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
  74. package/dist/control-ui.d.ts +5 -4
  75. package/dist/control-ui.js +9 -34
  76. package/dist/converse.d.ts +23 -23
  77. package/dist/converse.js +28 -28
  78. package/dist/coordinator-proposals.d.ts +2 -2
  79. package/dist/coordinator-proposals.js +1 -1
  80. package/dist/coordinator.js +1 -1
  81. package/dist/credentials-ui.d.ts +5 -4
  82. package/dist/credentials-ui.js +23 -24
  83. package/dist/demo-chat.d.ts +3 -3
  84. package/dist/demo-chat.js +29 -76
  85. package/dist/deprecations.d.ts +12 -0
  86. package/dist/deprecations.js +20 -0
  87. package/dist/desktop-update-gate.js +8 -4
  88. package/dist/desktop-update.js +6 -1
  89. package/dist/discord-chat.js +6 -6
  90. package/dist/discord-settings.d.ts +3 -2
  91. package/dist/discord-settings.js +17 -42
  92. package/dist/dispatch.d.ts +1 -1
  93. package/dist/dispatch.js +1 -1
  94. package/dist/envelope.js +10 -1
  95. package/dist/evidence-pack.d.ts +2 -1
  96. package/dist/evidence-pack.js +45 -49
  97. package/dist/export-ui.d.ts +7 -2
  98. package/dist/export-ui.js +4 -10
  99. package/dist/export.js +7 -7
  100. package/dist/flow-engine.d.ts +2 -2
  101. package/dist/flow-engine.js +21 -21
  102. package/dist/flow-gallery-ui.d.ts +4 -3
  103. package/dist/flow-gallery-ui.js +28 -43
  104. package/dist/flow-insights.d.ts +1 -1
  105. package/dist/flow-share.js +13 -8
  106. package/dist/flow-starters-ui.d.ts +2 -1
  107. package/dist/flow-starters-ui.js +12 -15
  108. package/dist/flow-steps.d.ts +5 -5
  109. package/dist/flow-steps.js +19 -19
  110. package/dist/flow-triggers.d.ts +2 -1
  111. package/dist/flow-triggers.js +17 -15
  112. package/dist/flows-cli.js +1 -1
  113. package/dist/flows-ui.d.ts +4 -3
  114. package/dist/flows-ui.js +38 -49
  115. package/dist/flows.js +21 -20
  116. package/dist/guides.js +112 -6
  117. package/dist/html.d.ts +76 -0
  118. package/dist/html.js +173 -0
  119. package/dist/integrations-ui.d.ts +2 -1
  120. package/dist/integrations-ui.js +19 -23
  121. package/dist/invoke.js +1 -1
  122. package/dist/kits-ui.d.ts +5 -4
  123. package/dist/kits-ui.js +22 -24
  124. package/dist/kits.d.ts +12 -12
  125. package/dist/kits.js +31 -31
  126. package/dist/knowledge-ui.d.ts +6 -5
  127. package/dist/knowledge-ui.js +26 -25
  128. package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
  129. package/dist/{mate-cli.js → lead-cli.js} +38 -38
  130. package/dist/lead-commitments.js +4 -4
  131. package/dist/lead-context.d.ts +12 -2
  132. package/dist/lead-context.js +15 -17
  133. package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
  134. package/dist/{mate-contract.js → lead-contract.js} +7 -6
  135. package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
  136. package/dist/{mate-doors.js → lead-doors.js} +24 -24
  137. package/dist/lead-follow.d.ts +5 -5
  138. package/dist/lead-follow.js +9 -9
  139. package/dist/lead-people.d.ts +5 -5
  140. package/dist/lead-people.js +14 -14
  141. package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
  142. package/dist/{mate-progress.js → lead-progress.js} +3 -3
  143. package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
  144. package/dist/{mate-tools.js → lead-tools.js} +109 -101
  145. package/dist/{mate.d.ts → lead.d.ts} +27 -27
  146. package/dist/{mate.js → lead.js} +102 -102
  147. package/dist/ledger-view.d.ts +2 -1
  148. package/dist/ledger-view.js +27 -29
  149. package/dist/limits-ui.d.ts +3 -2
  150. package/dist/limits-ui.js +8 -8
  151. package/dist/live-bus.d.ts +50 -8
  152. package/dist/live-bus.js +133 -50
  153. package/dist/mcp-connect.d.ts +1 -1
  154. package/dist/mcp-connect.js +3 -3
  155. package/dist/mcp-core.js +1 -1
  156. package/dist/mcp-oauth.js +35 -36
  157. package/dist/memory-pass.d.ts +2 -2
  158. package/dist/memory-pass.js +7 -7
  159. package/dist/models-ui.d.ts +2 -1
  160. package/dist/models-ui.js +25 -35
  161. package/dist/monitoring-ui.d.ts +4 -3
  162. package/dist/monitoring-ui.js +13 -26
  163. package/dist/notification-rows.d.ts +2 -2
  164. package/dist/openrouter-models.d.ts +2 -1
  165. package/dist/openrouter-models.js +5 -9
  166. package/dist/operate.d.ts +3 -3
  167. package/dist/operate.js +46 -41
  168. package/dist/people-audit-ui.d.ts +2 -1
  169. package/dist/people-audit-ui.js +13 -13
  170. package/dist/policy-ui.d.ts +3 -2
  171. package/dist/policy-ui.js +17 -23
  172. package/dist/policy.d.ts +1 -1
  173. package/dist/principal.d.ts +1 -1
  174. package/dist/principal.js +2 -2
  175. package/dist/project-delete-ui.d.ts +4 -3
  176. package/dist/project-delete-ui.js +16 -28
  177. package/dist/project-delete.d.ts +1 -1
  178. package/dist/project-delete.js +26 -26
  179. package/dist/project-memory.js +1 -1
  180. package/dist/project-tools.d.ts +1 -1
  181. package/dist/project-tools.js +1 -1
  182. package/dist/pull-request-ui.d.ts +2 -1
  183. package/dist/pull-request-ui.js +17 -32
  184. package/dist/recipe-ui.d.ts +8 -7
  185. package/dist/recipe-ui.js +39 -32
  186. package/dist/release-adapters.d.ts +60 -0
  187. package/dist/release-adapters.js +435 -0
  188. package/dist/release-cli.d.ts +24 -0
  189. package/dist/release-cli.js +181 -0
  190. package/dist/release-gate.d.ts +80 -0
  191. package/dist/release-gate.js +150 -0
  192. package/dist/release-links.d.ts +29 -0
  193. package/dist/release-links.js +102 -0
  194. package/dist/release.d.ts +331 -0
  195. package/dist/release.js +550 -0
  196. package/dist/reply-shape.d.ts +2 -1
  197. package/dist/reply-shape.js +5 -5
  198. package/dist/repository-context-ui.d.ts +2 -1
  199. package/dist/repository-context-ui.js +2 -7
  200. package/dist/request-budget-ui.d.ts +2 -1
  201. package/dist/request-budget-ui.js +16 -16
  202. package/dist/result-review.d.ts +2 -3
  203. package/dist/result-review.js +3 -9
  204. package/dist/retention-ui.d.ts +7 -1
  205. package/dist/retention-ui.js +7 -11
  206. package/dist/retention.js +4 -4
  207. package/dist/scope.d.ts +2 -2
  208. package/dist/scout-report.d.ts +1 -1
  209. package/dist/scout-report.js +1 -1
  210. package/dist/serve.d.ts +11 -2
  211. package/dist/serve.js +105 -99
  212. package/dist/server/chat.d.ts +7 -10
  213. package/dist/server/chat.js +984 -1021
  214. package/dist/server/chrome.d.ts +291 -0
  215. package/dist/server/chrome.js +747 -0
  216. package/dist/server/console.css +2819 -0
  217. package/dist/server/flows.d.ts +2 -6
  218. package/dist/server/flows.js +854 -773
  219. package/dist/server/guards.d.ts +1 -1
  220. package/dist/server/guards.js +8 -5
  221. package/dist/server/handler-context.d.ts +1 -1
  222. package/dist/server/handler-context.js +1 -1
  223. package/dist/server/handler-registry.d.ts +8 -6
  224. package/dist/server/handler-registry.js +14 -2
  225. package/dist/server/http.d.ts +274 -0
  226. package/dist/server/http.js +239 -0
  227. package/dist/server/live.d.ts +34 -0
  228. package/dist/server/live.js +309 -0
  229. package/dist/server/pages.d.ts +2 -6
  230. package/dist/server/pages.js +808 -789
  231. package/dist/server/people-tokens.d.ts +1 -6
  232. package/dist/server/people-tokens.js +581 -573
  233. package/dist/server/remote.d.ts +4 -7
  234. package/dist/server/remote.js +39 -70
  235. package/dist/server/render-chat.d.ts +402 -0
  236. package/dist/server/render-chat.js +927 -0
  237. package/dist/server/render-pages.d.ts +535 -0
  238. package/dist/server/render-pages.js +1277 -0
  239. package/dist/server/render-people.d.ts +32 -0
  240. package/dist/server/render-people.js +121 -0
  241. package/dist/server/render-results.d.ts +744 -0
  242. package/dist/server/render-results.js +2237 -0
  243. package/dist/server/render-settings.d.ts +154 -0
  244. package/dist/server/render-settings.js +580 -0
  245. package/dist/server/render-tasks.d.ts +632 -0
  246. package/dist/server/render-tasks.js +2345 -0
  247. package/dist/server/request-context.d.ts +46 -0
  248. package/dist/server/request-context.js +17 -0
  249. package/dist/server/route-table.d.ts +25 -3
  250. package/dist/server/route-table.js +167 -77
  251. package/dist/server/runtime.d.ts +28 -20
  252. package/dist/server/runtime.js +7 -1
  253. package/dist/server/session.d.ts +138 -0
  254. package/dist/server/session.js +94 -0
  255. package/dist/server/settings.d.ts +1 -5
  256. package/dist/server/settings.js +2186 -2121
  257. package/dist/server/task-views.d.ts +11 -4
  258. package/dist/server/task-views.js +26 -22
  259. package/dist/server/tasks.d.ts +9 -9
  260. package/dist/server/tasks.js +1489 -1420
  261. package/dist/server-telemetry.d.ts +4 -3
  262. package/dist/server-telemetry.js +4 -8
  263. package/dist/setup-guide.d.ts +2 -2
  264. package/dist/skills-ui.d.ts +4 -3
  265. package/dist/skills-ui.js +14 -17
  266. package/dist/skills.d.ts +1 -1
  267. package/dist/skills.js +2 -1
  268. package/dist/slack-chat.d.ts +2 -2
  269. package/dist/slack-chat.js +6 -6
  270. package/dist/slack-settings.d.ts +3 -2
  271. package/dist/slack-settings.js +17 -42
  272. package/dist/spend-ui.d.ts +5 -4
  273. package/dist/spend-ui.js +17 -40
  274. package/dist/spend.d.ts +14 -14
  275. package/dist/spend.js +31 -31
  276. package/dist/sso-ui.d.ts +3 -2
  277. package/dist/sso-ui.js +26 -27
  278. package/dist/storage-ui.d.ts +2 -1
  279. package/dist/storage-ui.js +14 -33
  280. package/dist/store-baseline.d.ts +19 -0
  281. package/dist/store-baseline.js +2873 -0
  282. package/dist/store.d.ts +197 -249
  283. package/dist/store.js +747 -3084
  284. package/dist/subagent-admin.d.ts +53 -0
  285. package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
  286. package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
  287. package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
  288. package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
  289. package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
  290. package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
  291. package/dist/{teammate-question.js → subagent-question.js} +17 -17
  292. package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
  293. package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
  294. package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
  295. package/dist/{teammate-week.js → subagent-week.js} +23 -23
  296. package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
  297. package/dist/{teammate-work.js → subagent-work.js} +50 -50
  298. package/dist/subagents-ui.d.ts +22 -0
  299. package/dist/subagents-ui.js +137 -0
  300. package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
  301. package/dist/{teammates.js → subagents.js} +21 -21
  302. package/dist/subscription-chat.d.ts +13 -13
  303. package/dist/subscription-chat.js +19 -19
  304. package/dist/surface.d.ts +19 -2
  305. package/dist/surface.js +20 -33
  306. package/dist/task-composer.d.ts +2 -1
  307. package/dist/task-composer.js +7 -7
  308. package/dist/task-status.d.ts +4 -3
  309. package/dist/task-status.js +15 -16
  310. package/dist/team-cli.d.ts +1 -0
  311. package/dist/team-cli.js +14 -2
  312. package/dist/team-http.d.ts +5 -9
  313. package/dist/team-http.js +5 -63
  314. package/dist/team-leads.js +13 -13
  315. package/dist/team-runtime.d.ts +2 -2
  316. package/dist/team-runtime.js +8 -8
  317. package/dist/team-ui.d.ts +2 -1
  318. package/dist/team-ui.js +2 -5
  319. package/dist/teams-chat.js +6 -6
  320. package/dist/teams-settings.d.ts +3 -2
  321. package/dist/teams-settings.js +20 -31
  322. package/dist/telegram-flow.d.ts +3 -3
  323. package/dist/telegram-flow.js +3 -3
  324. package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
  325. package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
  326. package/dist/telegram-settings.d.ts +3 -2
  327. package/dist/telegram-settings.js +14 -25
  328. package/dist/telegram-status.js +1 -1
  329. package/dist/telegram-team.d.ts +1 -1
  330. package/dist/telegram-team.js +5 -5
  331. package/dist/telegram.d.ts +1 -1
  332. package/dist/telegram.js +9 -30
  333. package/dist/text-limits.d.ts +18 -18
  334. package/dist/text-limits.js +18 -18
  335. package/dist/toolroll-update-ui.d.ts +3 -2
  336. package/dist/toolroll-update-ui.js +35 -39
  337. package/dist/toolroll-update.d.ts +8 -0
  338. package/dist/toolroll-update.js +45 -8
  339. package/dist/tools-ui.d.ts +5 -2
  340. package/dist/tools-ui.js +31 -31
  341. package/dist/when-html.d.ts +11 -3
  342. package/dist/when-html.js +5 -6
  343. package/dist/workspace-ui.d.ts +4 -2
  344. package/dist/workspace-ui.js +10 -10
  345. package/package.json +1 -2
  346. package/dist/server/shared.d.ts +0 -3151
  347. package/dist/server/shared.js +0 -12001
  348. package/dist/teammate-admin.d.ts +0 -53
  349. package/dist/teammates-ui.d.ts +0 -20
  350. package/dist/teammates-ui.js +0 -166
package/dist/demo-chat.js CHANGED
@@ -4,48 +4,26 @@
4
4
  * running build's progress live; without it the page still works by reload.
5
5
  */
6
6
  import { START_COMMAND } from "./first-run.js";
7
+ import { html, postForm } from "./html.js";
7
8
  import { headlineOf } from "./task-status.js";
8
9
  const SUGGESTIONS = ["Fix the flaky refund test", "Rewrite the empty Payouts page", "Put the new invoice view behind a flag"];
9
- const esc = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
10
- const hidden = (csrf) => `<input type="hidden" name="csrf" value="${esc(csrf)}">`;
11
- function hint(csrf) {
12
- return `<section class="demo-hint" aria-label="Get started">` +
13
- `<p class="demo-hint-title">Ask for something, like “fix the flaky refund test”</p>` +
14
- `<form method="post" action="/chat/demo/ask" class="demo-suggestions">${hidden(csrf)}` +
15
- SUGGESTIONS.map(one => `<button type="submit" name="message" value="${esc(one)}">${esc(one)}</button>`).join("") +
16
- `</form></section>`;
10
+ function hint() {
11
+ return html `<section class="demo-hint" aria-label="Get started"><p class="demo-hint-title">Ask for something, like “fix the flaky refund test”</p>${postForm("/chat/demo/ask", SUGGESTIONS.map(one => html `<button type="submit" name="message" value="${one}">${one}</button>`), { attrs: { class: "demo-suggestions" } })}</section>`;
17
12
  }
18
- function planCard(exchange, csrf) {
13
+ function planCard(exchange) {
19
14
  const plan = exchange.plan;
20
15
  const goal = exchange.note === null ? plan.goal : `${plan.goal} Also: ${exchange.note}`;
21
16
  const actions = exchange.state === "proposed"
22
- ? `<div class="demo-actions">` +
23
- `<form method="post" action="/chat/demo/${exchange.id}/approve" class="approve-form">${hidden(csrf)}<button type="submit">Approve</button></form>` +
24
- `<details class="demo-more"><summary>Change it</summary>` +
25
- `<form method="post" action="/chat/demo/${exchange.id}/change">${hidden(csrf)}` +
26
- `<label for="demo-change-${exchange.id}">What should change?</label>` +
27
- `<textarea id="demo-change-${exchange.id}" name="note" rows="2" maxlength="500" required></textarea>` +
28
- `<button type="submit">Update plan</button></form></details></div>`
17
+ ? html `<div class="demo-actions">${postForm(`/chat/demo/${exchange.id}/approve`, html `<button type="submit">Approve</button>`, { attrs: { class: "approve-form" } })}<details class="demo-more"><summary>Change it</summary>${postForm(`/chat/demo/${exchange.id}/change`, html `<label for="demo-change-${exchange.id}">What should change?</label><textarea id="demo-change-${exchange.id}" name="note" rows="2" maxlength="500" required></textarea><button type="submit">Update plan</button>`)}</details></div>`
29
18
  : exchange.state === "replaced"
30
- ? `<p class="meta">Replaced by the updated plan below.</p>`
31
- : `<p class="meta">Approved.</p>`;
32
- return `<section class="card demo-plan" aria-label="Plan">` +
33
- `<p class="demo-kicker">Plan · ${esc(plan.project)}</p>` +
34
- `<h2>${esc(plan.title)}</h2>` +
35
- `<p>${esc(goal)}</p>` +
36
- `<h3>Boundaries</h3><ul>${plan.boundaries.map(one => `<li>${esc(one)}</li>`).join("")}</ul>` +
37
- `<h3>Checks</h3><ul>${plan.checks.map(one => `<li>${esc(one)}</li>`).join("")}</ul>` +
38
- actions + `</section>`;
19
+ ? html `<p class="meta">Replaced by the updated plan below.</p>`
20
+ : html `<p class="meta">Approved.</p>`;
21
+ return html `<section class="card demo-plan" aria-label="Plan"><p class="demo-kicker">Plan · ${plan.project}</p><h2>${plan.title}</h2><p>${goal}</p><h3>Boundaries</h3><ul>${plan.boundaries.map(one => html `<li>${one}</li>`)}</ul><h3>Checks</h3><ul>${plan.checks.map(one => html `<li>${one}</li>`)}</ul>${actions}</section>`;
39
22
  }
40
23
  function buildCard(exchange) {
41
24
  const stages = [["planning", "Planning"], ["building", "Building"], ["checking", "Running checks"]];
42
25
  const at = stages.findIndex(([key]) => key === exchange.stage);
43
- return `<section class="card demo-build" id="demo-${exchange.id}-work" aria-label="Build" aria-busy="true">` +
44
- `<p class="demo-kicker">${esc(exchange.plan.project)}</p>` +
45
- `<h2>${esc(stages[Math.max(0, at)][1])}…</h2>` +
46
- `<ol class="demo-steps">${stages.map(([, label], index) => `<li class="${index < at ? "done" : index === at ? "now" : ""}"${index === at ? ` aria-current="step"` : ""}>${esc(label)}</li>`).join("")}</ol>` +
47
- (exchange.progress === null ? "" : `<p class="meta demo-progress">${esc(exchange.progress)}</p>`) +
48
- `</section>`;
26
+ return html `<section class="card demo-build" id="demo-${exchange.id}-work" aria-label="Build" aria-busy="true"><p class="demo-kicker">${exchange.plan.project}</p><h2>${stages[Math.max(0, at)][1]}…</h2><ol class="demo-steps">${stages.map(([, label], index) => html `<li class="${index < at ? "done" : index === at ? "now" : ""}"${index === at ? html ` aria-current="step"` : ""}>${label}</li>`)}</ol>${exchange.progress === null ? "" : html `<p class="meta demo-progress">${exchange.progress}</p>`}</section>`;
49
27
  }
50
28
  function diffHtml(diff) {
51
29
  return diff.replace(/\n$/, "").split("\n").map(line => {
@@ -53,71 +31,46 @@ function diffHtml(diff) {
53
31
  : line.startsWith("+++") || line.startsWith("---") ? "meta"
54
32
  : line.startsWith("@@") ? "hunk"
55
33
  : line.startsWith("+") ? "add" : line.startsWith("-") ? "del" : "ctx";
56
- return `<span class="demo-diff-${kind}">${esc(line) || " "}</span>`;
57
- }).join("");
34
+ return html `<span class="demo-diff-${kind}">${line || " "}</span>`;
35
+ });
58
36
  }
59
- function resultCard(exchange, csrf, result) {
37
+ function resultCard(exchange, result) {
60
38
  if (result === null)
61
- return `<section class="card demo-result"><p class="meta">This result's saved evidence is unavailable.</p></section>`;
39
+ return html `<section class="card demo-result"><p class="meta">This result's saved evidence is unavailable.</p></section>`;
62
40
  const passed = result.checks.status === "passed";
63
41
  // The shared headline (task-status.ts): the same words as every real task.
64
42
  const headline = headlineOf({ stage: exchange.state === "complete" ? "complete" : exchange.state === "sent-back" ? "building" : "finished",
65
43
  checks: { status: passed ? "passed" : "failed", exitCode: null, head: null } });
66
- const status = `<span class="badge${headline === "Complete" ? " demo-complete" : headline === "Ready for review" ? " demo-ready" : ""}" data-headline="${headline}">${headline}</span>`;
67
- const summary = `${result.files} file${result.files === 1 ? "" : "s"} changed · +${result.additions} −${result.deletions} · ` +
68
- `<span class="${passed ? "demo-pass" : "demo-fail"}">${esc(result.checks.detail)}</span>`;
44
+ const status = html `<span class="badge${headline === "Complete" ? " demo-complete" : headline === "Ready for review" ? " demo-ready" : ""}" data-headline="${headline}">${headline}</span>`;
45
+ const summary = html `${result.files} file${result.files === 1 ? "" : "s"} changed · +${result.additions} −${result.deletions} · <span class="${passed ? "demo-pass" : "demo-fail"}">${result.checks.detail}</span>`;
69
46
  const actions = exchange.state === "ready"
70
- ? `<div class="demo-actions">` +
71
- `<form method="post" action="/chat/demo/${exchange.id}/complete">${hidden(csrf)}<button type="submit" class="demo-primary">Complete</button></form>` +
72
- `<details class="demo-more"><summary>Request changes</summary>` +
73
- `<form method="post" action="/chat/demo/${exchange.id}/revise">${hidden(csrf)}` +
74
- `<label for="demo-revise-${exchange.id}">What should change?</label>` +
75
- `<textarea id="demo-revise-${exchange.id}" name="note" rows="2" maxlength="500" required></textarea>` +
76
- `<button type="submit">Send back</button></form></details></div>`
77
- : `<p class="meta"><a href="${esc(result.taskHref)}">Open in Tasks</a></p>`;
78
- return `<section class="card demo-result" id="demo-${exchange.id}-work" aria-label="Result">` +
79
- `<p class="demo-state">${status}<span class="meta">${esc(exchange.plan.project)}</span></p>` +
80
- `<h2>${esc(exchange.plan.title)}</h2>` +
81
- `<p>${esc(exchange.plan.conclusion)}</p>` +
82
- `<p class="meta">${summary}</p>` +
83
- actions +
84
- (result.diff === null ? "" : `<details class="demo-evidence"${exchange.state === "ready" ? " open" : ""}><summary>Changes</summary><pre class="demo-diff">${diffHtml(result.diff)}</pre></details>`) +
85
- (result.checkLog === null ? "" : `<details class="demo-evidence"><summary>Check log</summary><pre class="demo-log">${esc(result.checkLog)}</pre></details>`) +
86
- (result.screenshot === null ? "" : `<details class="demo-evidence"><summary>Screenshot</summary><figure><img src="${esc(result.screenshot.href)}" alt="${esc(result.screenshot.caption)}" width="960" height="600"><figcaption class="meta">${esc(result.screenshot.caption)}</figcaption></figure></details>`) +
87
- `</section>`;
47
+ ? html `<div class="demo-actions">${postForm(`/chat/demo/${exchange.id}/complete`, html `<button type="submit" class="demo-primary">Complete</button>`)}<details class="demo-more"><summary>Request changes</summary>${postForm(`/chat/demo/${exchange.id}/revise`, html `<label for="demo-revise-${exchange.id}">What should change?</label><textarea id="demo-revise-${exchange.id}" name="note" rows="2" maxlength="500" required></textarea><button type="submit">Send back</button>`)}</details></div>`
48
+ : html `<p class="meta"><a href="${result.taskHref}">Open in Tasks</a></p>`;
49
+ return html `<section class="card demo-result" id="demo-${exchange.id}-work" aria-label="Result"><p class="demo-state">${status}<span class="meta">${exchange.plan.project}</span></p><h2>${exchange.plan.title}</h2><p>${exchange.plan.conclusion}</p><p class="meta">${summary}</p>${actions}${result.diff === null ? "" : html `<details class="demo-evidence"${exchange.state === "ready" ? html ` open` : ""}><summary>Changes</summary><pre class="demo-diff">${diffHtml(result.diff)}</pre></details>`}${result.checkLog === null ? "" : html `<details class="demo-evidence"><summary>Check log</summary><pre class="demo-log">${result.checkLog}</pre></details>`}${result.screenshot === null ? "" : html `<details class="demo-evidence"><summary>Screenshot</summary><figure><img src="${result.screenshot.href}" alt="${result.screenshot.caption}" width="960" height="600"><figcaption class="meta">${result.screenshot.caption}</figcaption></figure></details>`}</section>`;
88
50
  }
89
51
  /** The conversation itself; the live script swaps this region in place. */
90
- export function demoThreadHtml(exchanges, csrf, resultOf) {
52
+ export function demoThreadHtml(exchanges, resultOf) {
91
53
  if (exchanges.length === 0)
92
- return hint(csrf);
93
- return exchanges.map(exchange => {
54
+ return hint();
55
+ return html `${exchanges.map(exchange => {
94
56
  const parts = [
95
- `<div class="demo-said demo-you"><p>${esc(exchange.asked)}</p></div>`,
96
- `<div class="demo-said demo-lead"><p class="demo-who">Lead</p><p>${esc(exchange.reply)}</p></div>`,
97
- planCard(exchange, csrf),
57
+ html `<div class="demo-said demo-you"><p>${exchange.asked}</p></div>`,
58
+ html `<div class="demo-said demo-lead"><p class="demo-who">Lead</p><p>${exchange.reply}</p></div>`,
59
+ planCard(exchange),
98
60
  ];
99
61
  if (exchange.state === "working")
100
62
  parts.push(buildCard(exchange));
101
63
  if (exchange.state === "ready" || exchange.state === "complete" || exchange.state === "sent-back")
102
- parts.push(resultCard(exchange, csrf, resultOf(exchange)));
64
+ parts.push(resultCard(exchange, resultOf(exchange)));
103
65
  if (exchange.state === "complete") {
104
- parts.push(`<div class="demo-said demo-lead"><p class="demo-who">Lead</p><p>Done. That's the whole loop: ask, approve, Ready, Complete. Ask for something else whenever you like.</p></div>`, `<section class="card demo-handoff" data-demo-handoff aria-label="Your own project"><h2>Now try it on your own project</h2>` +
105
- `<p>In your repository's folder, run:</p><pre class="demo-command"><code>${esc(START_COMMAND)}</code></pre>` +
106
- `<p class="meta">It opens in your browser, already signed in.</p></section>`);
66
+ parts.push(html `<div class="demo-said demo-lead"><p class="demo-who">Lead</p><p>Done. That's the whole loop: ask, approve, Ready, Complete. Ask for something else whenever you like.</p></div>`, html `<section class="card demo-handoff" data-demo-handoff aria-label="Your own project"><h2>Now try it on your own project</h2><p>In your repository's folder, run:</p><pre class="demo-command"><code>${START_COMMAND}</code></pre><p class="meta">It opens in your browser, already signed in.</p></section>`);
107
67
  }
108
- return `<article class="demo-turn" id="demo-${exchange.id}">${parts.join("")}</article>`;
109
- }).join("");
68
+ return html `<article class="demo-turn" id="demo-${exchange.id}">${parts}</article>`;
69
+ })}`;
110
70
  }
111
71
  export function demoChatHtml(input) {
112
72
  const working = input.exchanges.some(one => one.state === "working");
113
- return `<div class="demo-chat">` +
114
- (input.problem === null ? "" : `<p class="problem" role="alert">${esc(input.problem)}</p>`) +
115
- `<div id="demo-thread" class="demo-thread" aria-live="polite" data-version="${input.version}" data-working="${working ? "1" : "0"}">` +
116
- demoThreadHtml(input.exchanges, input.csrf, input.resultOf) + `</div>` +
117
- `<form method="post" action="/chat/demo/ask" class="demo-composer">${hidden(input.csrf)}` +
118
- `<label for="demo-message" class="so-sr-only">Message the lead</label>` +
119
- `<textarea id="demo-message" name="message" rows="2" maxlength="500" placeholder="Ask the lead for a change" required></textarea>` +
120
- `<button type="submit" class="demo-primary">Send</button></form></div>`;
73
+ return html `<div class="demo-chat">${input.problem === null ? "" : html `<p class="problem" role="alert">${input.problem}</p>`}<div id="demo-thread" class="demo-thread" aria-live="polite" data-version="${input.version}" data-working="${working ? "1" : "0"}">${demoThreadHtml(input.exchanges, input.resultOf)}</div>${postForm("/chat/demo/ask", html `<label for="demo-message" class="so-sr-only">Message the lead</label><textarea id="demo-message" name="message" rows="2" maxlength="500" placeholder="Ask the lead for a change" required></textarea><button type="submit" class="demo-primary">Send</button>`, { attrs: { class: "demo-composer" } })}</div>`;
121
74
  }
122
75
  /**
123
76
  * Keeps a running build live: polls while one is working and swaps the
@@ -0,0 +1,12 @@
1
+ /**
2
+ * D5 (schema v117): one AI concept, the lead. The central team service (`connect`, the central `lead list|create|update|
3
+ * member|transfer`, `conversation …`, and `chat`/`brief` with --lead, --conversation or a saved profile) and native
4
+ * coding sessions (`session …`) are deprecated. For this release they still work exactly as before, but they are
5
+ * hidden from help, the command contract and the console, and each run says so once on stderr — never on stdout, so a
6
+ * `--json` answer stays one envelope. Their code goes in the next minor release.
7
+ */
8
+ export type Deprecated = "team" | "session";
9
+ /** The one line a deprecated command prints on stderr: what it is, when it goes, and what to use instead. */
10
+ export declare function deprecationWarning(command: string, kind: Deprecated): string;
11
+ /** What a deprecated console page or API says about itself. */
12
+ export declare const DEPRECATED_PAGE: Record<Deprecated, string>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * D5 (schema v117): one AI concept, the lead. The central team service (`connect`, the central `lead list|create|update|
3
+ * member|transfer`, `conversation …`, and `chat`/`brief` with --lead, --conversation or a saved profile) and native
4
+ * coding sessions (`session …`) are deprecated. For this release they still work exactly as before, but they are
5
+ * hidden from help, the command contract and the console, and each run says so once on stderr — never on stdout, so a
6
+ * `--json` answer stays one envelope. Their code goes in the next minor release.
7
+ */
8
+ const NEXT_STEP = {
9
+ team: "Talk to your lead with `toolroll chat`.",
10
+ session: "Queue work with `toolroll task add`.",
11
+ };
12
+ /** The one line a deprecated command prints on stderr: what it is, when it goes, and what to use instead. */
13
+ export function deprecationWarning(command, kind) {
14
+ return `Warning: \`toolroll ${command}\` is deprecated and will be removed in the next minor release. ${NEXT_STEP[kind]}`;
15
+ }
16
+ /** What a deprecated console page or API says about itself. */
17
+ export const DEPRECATED_PAGE = {
18
+ team: "Team chat is deprecated and will be removed in the next minor release. Your lead in Chat does the same work.",
19
+ session: "Coding sessions are deprecated and will be removed in the next minor release. Queue work as a task instead.",
20
+ };
@@ -9,10 +9,14 @@ const statements = (id, frozen = false) => {
9
9
  `CREATE TRIGGER ${prefix}claim BEFORE INSERT ON claim BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
10
10
  `CREATE TRIGGER ${prefix}mate BEFORE INSERT ON mate_turn BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
11
11
  `CREATE TRIGGER ${prefix}run BEFORE INSERT ON run ${frozen ? "" : "WHEN NEW.parent_run IS NULL AND NOT EXISTS (SELECT 1 FROM claim WHERE lease_id=NEW.lease_id AND released_at IS NULL) "}BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
12
- // An already-owned mate turn may finish its remaining provider steps.
12
+ // An already-owned lead turn may finish its remaining provider steps.
13
13
  `CREATE TRIGGER ${prefix}chat BEFORE INSERT ON chat_turn ${frozen ? "" : "WHEN NEW.mate_turn IS NULL "}BEGIN SELECT RAISE(ABORT, '${UPDATE_PAUSED} [${id}]'); END`,
14
14
  ];
15
15
  };
16
+ /** A gate statement as SQLite may keep it: a table RENAME re-quotes names, and a later build may name the lead's turns
17
+ * lead_turn (D5). This build's updater lifts a gate it made under either name. */
18
+ const same = (sql) => sql.replace(/"([A-Za-z_][A-Za-z0-9_]*)"/g, "$1").replace(/\b(?:mate|lead)_turn\b/g, "mate_turn");
19
+ const owns = (wanted, sql) => wanted.map(same).includes(same(String(sql)));
16
20
  /** SQLite enforces the gate even for a CLI racing an old in-memory snapshot.
17
21
  * Existing leases, replies, heartbeats and task data remain writable. */
18
22
  export function installUpdateGate(db, id) {
@@ -20,7 +24,7 @@ export function installUpdateGate(db, id) {
20
24
  db.exec("BEGIN IMMEDIATE");
21
25
  try {
22
26
  const existing = rows(db);
23
- if (existing.length > 0 && (existing.length !== wanted.length || existing.some(row => ![...wanted, ...statements(id, true)].includes(String(row.sql)))))
27
+ if (existing.length > 0 && (existing.length !== wanted.length || existing.some(row => !owns([...wanted, ...statements(id, true)], row.sql))))
24
28
  throw Error("Another or unrecognized update owns admission. Recover that update first.");
25
29
  if (existing.length === 0)
26
30
  for (const statement of wanted)
@@ -38,7 +42,7 @@ export function removeUpdateGate(db, id) {
38
42
  db.exec("BEGIN IMMEDIATE");
39
43
  try {
40
44
  const existing = rows(db);
41
- if (existing.some(row => !wanted.includes(String(row.sql))))
45
+ if (existing.some(row => !owns(wanted, row.sql)))
42
46
  throw Error("This update does not own the admission pause. Nothing was cleared.");
43
47
  removeCodingUpdateGate(db, id);
44
48
  for (const row of existing)
@@ -53,7 +57,7 @@ export function removeUpdateGate(db, id) {
53
57
  export function updateAdmissionPaused(db) { return rows(db).length > 0; }
54
58
  export function updateGateOwned(db, id) {
55
59
  const wanted = [...statements(id), ...statements(id, true)], existing = rows(db);
56
- return existing.length === statements(id).length && existing.every(row => wanted.includes(String(row.sql)));
60
+ return existing.length === statements(id).length && existing.every(row => owns(wanted, row.sql));
57
61
  }
58
62
  export function activeUpdateWork(db) {
59
63
  const count = (sql) => Number(db.prepare(sql).get()?.n ?? 0);
@@ -8,6 +8,7 @@ import { readDesktopConfig, desktopServiceCommand, desktopServiceDefinition, ver
8
8
  import { daemonStatus } from "./daemon.js";
9
9
  import { run } from "./exec.js";
10
10
  import { readSchemaVersion, SCHEMA_VERSION, Store } from "./store.js";
11
+ import { BASELINE_SCHEMA_VERSION } from "./store-baseline.js";
11
12
  import { activeUpdateWork, freezeUpdateGate, installUpdateGate, removeUpdateGate, updateAdmissionPaused } from "./desktop-update-gate.js";
12
13
  import { currentDesktopAccess } from "./desktop-access.js";
13
14
  import { assertCodingUpdateStopped, backupCodingCatalog, codingCatalogExists, releaseStaleCodingOwner } from "./coding-update.js";
@@ -125,6 +126,8 @@ function connect(file, readOnly = false, accepts = currentSchemaOnly) {
125
126
  const schema = readSchemaVersion(db);
126
127
  if (!schema.ok || !accepts(schema.version)) {
127
128
  db.close();
129
+ if (schema.ok && schema.version !== null && Math.abs(schema.version) < BASELINE_SCHEMA_VERSION)
130
+ throw Error(`This database is schema v${Math.abs(schema.version)}, older than v${BASELINE_SCHEMA_VERSION}: update through 0.9.x first (Toolroll 0.9.54 brings it up to date). The installed app is unchanged.`);
128
131
  throw Error("This update needs the current database schema. Use the separate verified migration procedure; the installed app is unchanged.");
129
132
  }
130
133
  return db;
@@ -474,7 +477,9 @@ function assertConfig(j) {
474
477
  }
475
478
  function snapshot(db) {
476
479
  const result = {};
477
- for (const table of ["task", "task_scope", "approver", "run", "artifact", "mate_message", "project"]) {
480
+ // The lead's messages were mate_message before v117 (D5); a desktop update never migrates, so read whichever is here.
481
+ const messages = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'lead_message'").get() === undefined ? "mate_message" : "lead_message";
482
+ for (const table of ["task", "task_scope", "approver", "run", "artifact", messages, "project"]) {
478
483
  const rows = db.prepare(`SELECT * FROM "${table}" ORDER BY rowid`).all();
479
484
  result[table] = rows;
480
485
  }
@@ -1,5 +1,5 @@
1
1
  /** Discord messages and buttons transport the shared assistant's saved actions. */
2
- import { chatQuestionButtons } from "./teammate-question.js";
2
+ import { chatQuestionButtons } from "./subagent-question.js";
3
3
  import { chatAskButtons } from "./chat-ask.js";
4
4
  import { chatFlowButtons } from "./chat-flow.js";
5
5
  import { refuseResultShots, resultShotsPruned, shotWaitsUntil } from "./result-shots.js";
@@ -10,7 +10,7 @@ import { readChatPart } from "./contracts/chat-content.js";
10
10
  import { readDiscordButtonToken, readDiscordComponentInteraction } from "./contracts/discord-callback.js";
11
11
  import { processChatEvent, planChatNotifications, channelAccess, chatObject as object, planRoomMessages, } from "./chat-delivery.js";
12
12
  import { chatResultHref } from "./chat-controls.js";
13
- import { MATE_MESSAGE_MAX_CHARS } from "./mate.js";
13
+ import { LEAD_MESSAGE_MAX_CHARS } from "./lead.js";
14
14
  import { discordPlain, renderReply } from "./reply-shape.js";
15
15
  import { WARM_EMOJI } from "./chat-warmth.js";
16
16
  import { proposalPreview, proposalLink, proposalOutcomeText, armedCardText, armedYesLabel, } from "./chat-channel.js";
@@ -61,7 +61,7 @@ export function receiveDiscord(state, identity, type, raw, now) {
61
61
  payload = pair
62
62
  ? { hash: chatHash(pair[1]) }
63
63
  : {
64
- text: body.content.slice(0, MATE_MESSAGE_MAX_CHARS + 1),
64
+ text: body.content.slice(0, LEAD_MESSAGE_MAX_CHARS + 1),
65
65
  originalLength: body.content.length,
66
66
  ...(Array.isArray(body.attachments) && body.attachments.length
67
67
  ? {
@@ -200,7 +200,7 @@ export async function deliverDiscordPart(options) {
200
200
  return true;
201
201
  }
202
202
  try {
203
- const session = event.session === null ? null : store.getMateSession(event.session), repos = await channelAccess(shared, binding, session?.ceilingDigest);
203
+ const session = event.session === null ? null : store.getLeadSession(event.session), repos = await channelAccess(shared, binding, session?.ceilingDigest);
204
204
  if (event.kind === "notice" && options.canNotify?.() === false)
205
205
  return false;
206
206
  const content = partContent(row.payload);
@@ -241,7 +241,7 @@ export async function deliverDiscordPart(options) {
241
241
  });
242
242
  }
243
243
  if (content.proposal) {
244
- const proposal = store.getMateProposal(content.proposal);
244
+ const proposal = store.getLeadProposal(content.proposal);
245
245
  if (!proposal)
246
246
  text = "This proposal is unavailable.";
247
247
  else if (proposal.state !== "pending")
@@ -294,7 +294,7 @@ export async function deliverDiscordPart(options) {
294
294
  custom_id: `so_${one.token}`,
295
295
  }))
296
296
  : []),
297
- // A teammate's question (v93): its options, then "Answer in words".
297
+ // A subagent's question (v93): its options, then "Answer in words".
298
298
  ...(content.question
299
299
  ? chatQuestionButtons(state, row.id, now).map((one) => ({
300
300
  type: 2,
@@ -1,7 +1,8 @@
1
1
  import type { Store } from "./store.js";
2
- export declare function discordSettingsHtml(store: Store, dir: string, csrf: string, options?: {
2
+ import { type Html } from "./html.js";
3
+ export declare function discordSettingsHtml(store: Store, dir: string, options?: {
3
4
  code?: string;
4
5
  problem?: string;
5
6
  now?: Date;
6
7
  who?: string;
7
- }): string;
8
+ }): Html;
@@ -1,66 +1,41 @@
1
1
  import { loadPrimary } from "./webhooks.js";
2
+ import { html, postForm } from "./html.js";
2
3
  import { loadDiscordCredentials } from "./discord-api.js";
3
4
  import { ChatState } from "./chat-delivery-state.js";
4
- const escape = (text) => text
5
- .replaceAll("&", "&amp;")
6
- .replaceAll("<", "&lt;")
7
- .replaceAll(">", "&gt;")
8
- .replaceAll('"', "&quot;")
9
- .replaceAll("'", "&#39;");
10
- export function discordSettingsHtml(store, dir, csrf, options = {}) {
5
+ export function discordSettingsHtml(store, dir, options = {}) {
11
6
  const credentials = loadDiscordCredentials(dir), state = new ChatState(store, "discord"), bindings = credentials ? state.bindings(credentials.installation).filter(one => state.live(one)) : [], binding = options.who === undefined ? null : bindings.find(one => one.approver === options.who) ?? null, others = bindings.length - (binding === null ? 0 : 1);
12
7
  const runtime = credentials ? state.runtime(credentials.installation) : null;
13
8
  const now = options.now ?? new Date(), live = runtime &&
14
9
  runtime.leaseUntil !== null &&
15
10
  runtime.leaseUntil > now.toISOString() &&
16
11
  runtime.connected;
17
- const hidden = `<input type="hidden" name="csrf" value="${escape(csrf)}">`;
18
- const password = '<label>Your Toolroll password<input style="min-height:44px" type="password" name="password" autocomplete="current-password" required></label>';
19
- const post = (action, content) => `<form method="post" action="/settings/discord/${action}" class="card">${hidden}${content}</form>`;
20
- let content = "";
12
+ const password = html `<label>Your Toolroll password<input style="min-height:44px" type="password" name="password" autocomplete="current-password" required></label>`;
13
+ const post = (action, content) => postForm(`/settings/discord/${action}`, content, { attrs: { class: "card" } });
14
+ const parts = [];
21
15
  if (!credentials) {
22
- content =
23
- "<p>Manage projects and review results in a private Discord conversation.</p>" +
24
- '<details open><summary>Create your Discord app</summary><ol><li><a href="https://discord.com/developers/applications" target="_blank" rel="noopener noreferrer">Create an application</a>, then copy its token from the Bot page.</li><li>Keep the Interactions Endpoint URL empty and privileged intents off.</li><li>Under Installation, enable Guild Install with the bot scope and no server permissions. Use its install link to add it to your server, then open a direct message to the bot.</li></ol></details>' +
25
- post("connect", '<label>Bot token<input style="min-height:44px" type="password" name="bot-token" autocomplete="off" required></label>' +
26
- password +
27
- '<p class="meta">The token stays on this installation. Next, pair your own Discord account.</p><button type="submit">Connect Discord</button>');
16
+ parts.push(html `<p>Manage projects and review results in a private Discord conversation.</p>`, html `<details open><summary>Create your Discord app</summary><ol><li><a href="https://discord.com/developers/applications" target="_blank" rel="noopener noreferrer">Create an application</a>, then copy its token from the Bot page.</li><li>Keep the Interactions Endpoint URL empty and privileged intents off.</li><li>Under Installation, enable Guild Install with the bot scope and no server permissions. Use its install link to add it to your server, then open a direct message to the bot.</li></ol></details>`, post("connect", html `<label>Bot token<input style="min-height:44px" type="password" name="bot-token" autocomplete="off" required></label>${password}<p class="meta">The token stays on this installation. Next, pair your own Discord account.</p><button type="submit">Connect Discord</button>`));
28
17
  }
29
18
  else {
30
- content = `<p><strong>${escape(credentials.workspace)}</strong> · ${live ? "Connected" : "Waiting for connection"}</p>`;
19
+ parts.push(html `<p><strong>${credentials.workspace}</strong> · ${live ? "Connected" : "Waiting for connection"}</p>`);
31
20
  if (runtime?.problem)
32
- content += `<p role="status">${escape(String(runtime.problem))}</p>`;
21
+ parts.push(html `<p role="status">${String(runtime.problem)}</p>`);
33
22
  if (!live && !runtime?.problem)
34
- content +=
35
- "<p>Keep the Toolroll worker running to receive Discord messages.</p>";
23
+ parts.push(html `<p>Keep the Toolroll worker running to receive Discord messages.</p>`);
36
24
  if (options.code) {
37
- content +=
38
- "<h2>Pair your account</h2><p>Send this in a direct message to your Toolroll Discord app. It expires in 10 minutes.</p>" +
39
- `<label>Pairing message<input type="text" readonly value="pair ${escape(options.code)}" autocomplete="off" style="width:100%;max-width:100%;font-size:14px;min-height:44px"></label>` +
40
- '<a class="button-link" style="min-height:44px;white-space:nowrap" href="/settings/discord">Check connection</a>';
25
+ parts.push(html `<h2>Pair your account</h2><p>Send this in a direct message to your Toolroll Discord app. It expires in 10 minutes.</p>`, html `<label>Pairing message<input type="text" readonly value="pair ${options.code}" autocomplete="off" style="width:100%;max-width:100%;font-size:14px;min-height:44px"></label>`, html `<a class="button-link" style="min-height:44px;white-space:nowrap" href="/settings/discord">Check connection</a>`);
41
26
  }
42
27
  else if (binding && state.live(binding)) {
43
28
  const { pending, dropped: failed } = state.partCounts(binding.id);
44
- content +=
45
- `<p>Your Discord account is paired.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} paired too.` : ""}${pending ? ` ${pending} replies waiting to send.` : ""}${failed ? ` ${failed} replies could not be delivered. Open the saved chat to recover them.` : ""}</p>` +
46
- "<p>Try “What needs my attention?” or “Show the evidence for the latest result.”</p>" +
47
- '<p><a href="/chat">Open saved chat</a></p>' +
48
- (loadPrimary(process.env, dir) === "discord"
49
- ? "<p>Task updates are sent here.</p>"
50
- : post("alerts", '<button type="submit">Send task updates here</button>'));
29
+ parts.push(html `<p>Your Discord account is paired.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} paired too.` : ""}${pending ? ` ${pending} replies waiting to send.` : ""}${failed ? ` ${failed} replies could not be delivered. Open the saved chat to recover them.` : ""}</p>`, html `<p>Try “What needs my attention?” or “Show the evidence for the latest result.”</p>`, html `<p><a href="/chat">Open saved chat</a></p>`, loadPrimary(process.env, dir) === "discord"
30
+ ? html `<p>Task updates are sent here.</p>`
31
+ : post("alerts", html `<button type="submit">Send task updates here</button>`));
51
32
  }
52
33
  else {
53
- content += post("pair", "<h2>Pair your account</h2><p>Your paired Discord account can read your connected projects and confirm proposed changes. Password approvals still open in Toolroll." +
54
- (others ? ` ${others} teammate${others === 1 ? " is" : "s are"} already paired.` : "") + "</p>" +
55
- password +
56
- '<button type="submit">Create pairing code</button>');
34
+ parts.push(post("pair", html `<h2>Pair your account</h2><p>Your paired Discord account can read your connected projects and confirm proposed changes. Password approvals still open in Toolroll.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} already paired.` : ""}</p>${password}<button type="submit">Create pairing code</button>`));
57
35
  }
58
36
  if (binding && state.live(binding) && !options.code)
59
- content += post("unpair", password + '<p class="meta">Unpairing ends every open button in your chat. Teammates are unaffected.</p><button type="submit">Unpair my account</button>');
60
- content +=
61
- "<details><summary>Connection settings</summary>" +
62
- post("disconnect", password + '<button type="submit">Disconnect Discord</button>') +
63
- "</details>";
37
+ parts.push(post("unpair", html `${password}<p class="meta">Unpairing ends every open button in your chat. Teammates are unaffected.</p><button type="submit">Unpair my account</button>`));
38
+ parts.push(html `<details><summary>Connection settings</summary>${post("disconnect", html `${password}<button type="submit">Disconnect Discord</button>`)}</details>`);
64
39
  }
65
- return `<section style="max-width:42rem;overflow-wrap:anywhere"><p><a href="/settings">Settings</a></p><h1>Discord</h1>${options.problem ? `<p class="problem" role="alert">${escape(options.problem)}</p>` : ""}${content}<details><summary>Access and setup</summary><p>Private messages and replies use your Toolroll permissions. Shared channels are not supported. Secure review links use this installation’s configured HTTPS console address.</p><p>The worker connects out to Discord. It does not need a public webhook or a Tailscale account.</p></details></section>`;
40
+ return html `<section style="max-width:42rem;overflow-wrap:anywhere"><p><a href="/settings">Settings</a></p><h1>Discord</h1>${options.problem ? html `<p class="problem" role="alert">${options.problem}</p>` : ""}${parts}<details><summary>Access and setup</summary><p>Private messages and replies use your Toolroll permissions. Shared channels are not supported. Secure review links use this installation’s configured HTTPS console address.</p><p>The worker connects out to Discord. It does not need a public webhook or a Tailscale account.</p></details></section>`;
66
41
  }
@@ -98,5 +98,5 @@ export declare function missingCapability(store: Store, taskRef: number, dispatc
98
98
  export declare function diagnoseTaskDispatch(store: Store, taskId: string, now: Date, readableRepos?: readonly string[] | null): DispatchDiagnosis | null;
99
99
  export declare function diagnosisIsDispatchable(diagnosis: DispatchDiagnosis | null): boolean;
100
100
  /** Attach the same lifecycle answer to the bounded fleet snapshot used by
101
- * both direct chat and the long-running mate. */
101
+ * both direct chat and the long-running lead. */
102
102
  export declare function withDispatchDiagnoses(store: Store, snapshot: ChatSnapshot, now: Date): ChatSnapshot;
package/dist/dispatch.js CHANGED
@@ -330,7 +330,7 @@ export function diagnosisIsDispatchable(diagnosis) {
330
330
  return diagnosis?.code === "ready" || diagnosis?.code === "planning-ready" || diagnosis?.code === "scouting-ready";
331
331
  }
332
332
  /** Attach the same lifecycle answer to the bounded fleet snapshot used by
333
- * both direct chat and the long-running mate. */
333
+ * both direct chat and the long-running lead. */
334
334
  export function withDispatchDiagnoses(store, snapshot, now) {
335
335
  return {
336
336
  ...snapshot,
package/dist/envelope.js CHANGED
@@ -28,7 +28,6 @@ export const CAPABILITIES = [
28
28
  "output-file", // -o <file> writes the same envelope to a file
29
29
  "command-schema/1", // contract --commands dumps the declared command guide
30
30
  "skill-guides/1", // skills list / skills get serve version-matched guides
31
- "session-client/1", // typed operator transport; query the service for actual availability
32
31
  ];
33
32
  /**
34
33
  * DOCUMENTED reasons — the curated vocabulary the command guide's
@@ -71,6 +70,16 @@ export const DOCUMENTED_REASONS = [
71
70
  "repair-attempts-spent", // the chain's signed attempt cap is spent
72
71
  "repair-no-progress", // two consecutive repair attempts failed to shrink the unresolved set
73
72
  "repair-refused-integrity", // a refutation named an altered term, not a gap — no automatic repair
73
+ "ambiguous", // a value could mean two things (a lease id or a branch) — refused, never guessed
74
+ "drift", // the branch, pull request or result moved from the gated commit
75
+ "check-failed", // the release check failed; it stays visible and nothing reruns it
76
+ "ci-failed", // a required pull-request check failed or is missing — nothing merged
77
+ "base-moved", // main gained a commit the release branch lacks — nothing merged
78
+ "tree-mismatch", // main's merge commit has a different tree than the gated commit — nothing tagged
79
+ "conflict", // a task or tag exists for a different commit
80
+ "mixed-runtime", // the console, worker and CLI names don't run one build
81
+ "gate-held", // a deployment stopped before its swap and left new work paused — `release --release-gate <id>`
82
+ "after-swap", // the deployment got past stopping the service, so its pause is its own recovery's to lift
74
83
  ];
75
84
  let captured = null;
76
85
  let captureHook = null;
@@ -2,6 +2,7 @@ import { type Filer } from "./approval-policy.js";
2
2
  import { type AssignmentAccess, type AssignmentSnapshot } from "./assignment.js";
3
3
  import type { SealedLedgerEntry, Store } from "./store.js";
4
4
  import type { LedgerChainReport } from "./ledger-chain.js";
5
+ import { type Html } from "./html.js";
5
6
  export declare const EVIDENCE_PACK_FORMAT = "standing-orders/evidence-pack/v1";
6
7
  /** How to recheck one entry's seal, for whoever reads the JSON. */
7
8
  export declare const SEAL_RECIPE = "hash = sha256(prev + \"\\n\" + JSON.stringify([id, at, actor, repo, taskId, runId, action, outcome, source, detail]))";
@@ -179,7 +180,7 @@ export declare function ledgerExportChunks(store: Store, range: {
179
180
  }, access: AssignmentAccess, who: string, now: Date, evidenceRoot: string): Generator<string, void, undefined>;
180
181
  export declare const EVIDENCE_PACK_CSS: string;
181
182
  /** The pack as a page: the same facts, in the order an auditor reads them. No script. */
182
- export declare function evidencePackHtml(pack: EvidencePack): string;
183
+ export declare function evidencePackHtml(pack: EvidencePack): Html;
183
184
  /** The page as a file on its own (the CLI's --html): the same facts with just enough style to print. */
184
185
  export declare function standaloneEvidenceHtml(pack: EvidencePack): string;
185
186
  export {};