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
@@ -1,14 +1,15 @@
1
1
  import { type KnowledgeDraft, type KnowledgeSelection, type KnowledgeView } from './project-knowledge.js';
2
+ import { type Html } from './html.js';
2
3
  export declare const KNOWLEDGE_CSS = ".knowledge{max-width:780px;min-width:0;overflow-wrap:anywhere}.knowledge .card{padding:20px;min-width:0;margin:16px 0}.knowledge h2{margin:0 0 12px}.knowledge form{display:grid;gap:12px;margin:0}.knowledge label{display:grid;gap:6px}.knowledge textarea,.knowledge input,.knowledge select{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.knowledge textarea{resize:vertical;min-height:110px}.knowledge button,.knowledge summary,.knowledge .button-link{min-height:44px}.knowledge button{justify-self:start;white-space:nowrap}.knowledge summary{padding:12px 0;cursor:pointer}.knowledge pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.knowledge .knowledge-actions{display:flex;gap:12px;flex-wrap:wrap}.knowledge .meta{font-size:.86rem}.knowledge .knowledge-source{display:block}.knowledge details+details{border-top:1px solid var(--so-line)}.memory-stats{display:flex;flex-wrap:wrap;gap:.4rem}.memory-stats span{padding:.15rem .55rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}@media(max-width:600px){.knowledge .card{padding:16px}.knowledge h2{font-size:1.1rem}}";
3
- export declare function knowledgeHtml(view: KnowledgeView, csrf: string, canManage: boolean, draft?: KnowledgeDraft, error?: string): string;
4
- export declare function knowledgeContextHtml(snapshot: KnowledgeSelection | null): string;
4
+ export declare function knowledgeHtml(view: KnowledgeView, csrf: string, canManage: boolean, draft?: KnowledgeDraft, error?: string): Html;
5
+ export declare function knowledgeContextHtml(snapshot: KnowledgeSelection | null): Html | '';
5
6
  import type { Decision, MemoryHit } from './project-memory.js';
6
7
  export declare const MEMORY_INTRO = "What the lead and crew read before they work. Every change keeps its history.";
7
8
  export declare function decisionsHtml(repo: string, decisions: Decision[], csrf: string, canManage: boolean, draft?: {
8
9
  claim?: string;
9
10
  why?: string;
10
- }, error?: string): string;
11
- export declare function memorySearchHtml(repo: string, query: string, hits: MemoryHit[] | null): string;
11
+ }, error?: string): Html;
12
+ export declare function memorySearchHtml(repo: string, query: string, hits: MemoryHit[] | null): Html;
12
13
  import type { MemoryProposal } from './memory-pass.js';
13
14
  export declare function proposalsHtml(repo: string, proposals: MemoryProposal[], status: {
14
15
  surface: string;
@@ -21,4 +22,4 @@ export declare function proposalsHtml(repo: string, proposals: MemoryProposal[],
21
22
  };
22
23
  openGaps: number;
23
24
  pending: number;
24
- } | null, csrf: string, canManage: boolean): string;
25
+ } | null, csrf: string, canManage: boolean): Html;
@@ -1,47 +1,48 @@
1
1
  import { STALE_KNOWLEDGE } from './project-knowledge.js';
2
- const e = (s) => String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
3
- const fields = (data) => Object.entries(data).map(([k, v]) => `<input type="hidden" name="${e(k)}" value="${e(v)}">`).join('');
2
+ import { html, postForm } from './html.js';
3
+ // Hidden fields as they always were: a missing value is an empty field.
4
+ const fields = (data) => Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v ?? '')]));
4
5
  export const KNOWLEDGE_CSS = `.knowledge{max-width:780px;min-width:0;overflow-wrap:anywhere}.knowledge .card{padding:20px;min-width:0;margin:16px 0}.knowledge h2{margin:0 0 12px}.knowledge form{display:grid;gap:12px;margin:0}.knowledge label{display:grid;gap:6px}.knowledge textarea,.knowledge input,.knowledge select{box-sizing:border-box;width:100%;min-width:0;max-width:100%}.knowledge textarea{resize:vertical;min-height:110px}.knowledge button,.knowledge summary,.knowledge .button-link{min-height:44px}.knowledge button{justify-self:start;white-space:nowrap}.knowledge summary{padding:12px 0;cursor:pointer}.knowledge pre{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.knowledge .knowledge-actions{display:flex;gap:12px;flex-wrap:wrap}.knowledge .meta{font-size:.86rem}.knowledge .knowledge-source{display:block}.knowledge details+details{border-top:1px solid var(--so-line)}.memory-stats{display:flex;flex-wrap:wrap;gap:.4rem}.memory-stats span{padding:.15rem .55rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}@media(max-width:600px){.knowledge .card{padding:16px}.knowledge h2{font-size:1.1rem}}`;
5
6
  export function knowledgeHtml(view, csrf, canManage, draft, error) {
6
7
  const manage = canManage && !!csrf;
7
- const base = { csrf, repo: view.repo, identity: view.identity, revision: view.revision };
8
- const form = (action, body, extra = {}) => `<form method="post" action="/settings/knowledge/change">${fields({ ...base, action, ...extra })}${body}</form>`;
9
- const referenceFields = (d) => `<label>Name<input name="title" maxlength="120" value="${e(d.title)}" required></label><label>Reference text<textarea name="content" rows="5" maxlength="12000">${e(d.content)}</textarea></label><details${d.path ? ' open' : ''}><summary>Use a project document</summary><label>Committed .md or .txt path<input name="path" value="${e(d.path)}" placeholder="docs/design-guide.md"></label><p class="meta">Uses the committed file instead of the text above. Save again to refresh it.</p></details><button type="submit">Save reference</button>`;
10
- const refs = view.knowledge.references.map(ref => `<details class="card"${draft?.id === ref.id ? ' open' : ''}><summary><strong>${e(ref.title)}</strong></summary>${ref.path ? `<span class="meta knowledge-source">${e(ref.path)} · ${e(ref.sourceRevision?.slice(0, 7))}</span>` : ''}<pre>${e(ref.content)}</pre>${manage ? `<details${draft?.id === ref.id ? ' open' : ''}><summary>Edit reference</summary>${form('save', referenceFields(draft?.id === ref.id ? draft : { title: ref.title, content: ref.path ? '' : ref.content, path: ref.path ?? '' }), { id: ref.id })}<details><summary>Remove reference</summary>${form('remove', '<p>Remove from future tasks. Previous run context stays available.</p><button>Remove reference</button>', { id: ref.id })}</details></details>` : ''}</details>`).join('');
11
- const history = view.history.map(h => `<li><a class="button-link" href="/settings/knowledge?repo=${encodeURIComponent(view.repo)}&version=${h.revision}">Version ${h.revision}</a> · ${e(h.actor)} · ${e(h.at.slice(0, 16).replace('T', ' '))} UTC</li>`).join('');
8
+ const base = { repo: view.repo, identity: view.identity, revision: view.revision };
9
+ const form = (action, body, extra = {}) => postForm('/settings/knowledge/change', body, { hidden: fields({ ...base, action, ...extra }) });
10
+ const referenceFields = (d) => html `<label>Name<input name="title" maxlength="120" value="${d.title}" required></label><label>Reference text<textarea name="content" rows="5" maxlength="12000">${d.content}</textarea></label><details${d.path ? html ` open` : ''}><summary>Use a project document</summary><label>Committed .md or .txt path<input name="path" value="${d.path}" placeholder="docs/design-guide.md"></label><p class="meta">Uses the committed file instead of the text above. Save again to refresh it.</p></details><button type="submit">Save reference</button>`;
11
+ const refs = view.knowledge.references.map(ref => html `<details class="card"${draft?.id === ref.id ? html ` open` : ''}><summary><strong>${ref.title}</strong></summary>${ref.path ? html `<span class="meta knowledge-source">${ref.path} · ${ref.sourceRevision?.slice(0, 7)}</span>` : ''}<pre>${ref.content}</pre>${manage ? html `<details${draft?.id === ref.id ? html ` open` : ''}><summary>Edit reference</summary>${form('save', referenceFields(draft?.id === ref.id ? draft : { title: ref.title, content: ref.path ? '' : ref.content, path: ref.path ?? '' }), { id: ref.id })}<details><summary>Remove reference</summary>${form('remove', html `<p>Remove from future tasks. Previous run context stays available.</p><button>Remove reference</button>`, { id: ref.id })}</details></details>` : ''}</details>`);
12
+ const history = view.history.map(h => html `<li><a class="button-link" href="/settings/knowledge?repo=${encodeURIComponent(view.repo)}&version=${h.revision}">Version ${h.revision}</a> · ${h.actor} · ${h.at.slice(0, 16).replace('T', ' ')} UTC</li>`);
12
13
  if (view.stale) {
13
14
  // One notice, the saved knowledge on demand, one approver action. Editing waits until it is applied.
14
15
  const saved = view.stale.knowledge;
15
- const review = `<details><summary>Review saved knowledge</summary><pre class="knowledge-instructions">${e(saved.instructions || 'No project instructions.')}</pre>${saved.references.map(ref => `<details><summary>${e(ref.title)}</summary><pre>${e(ref.content)}</pre></details>`).join('')}</details>`;
16
- return `<section class="knowledge knowledge-library">${error ? `<p class="problem" role="alert">${e(error)}</p>` : ''}<section class="card knowledge-stale"><p role="status">${e(STALE_KNOWLEDGE)}.</p>${review}${manage ? form('apply', '<button>Apply saved knowledge</button>') : ''}</section></section>`;
16
+ const review = html `<details><summary>Review saved knowledge</summary><pre class="knowledge-instructions">${saved.instructions || 'No project instructions.'}</pre>${saved.references.map(ref => html `<details><summary>${ref.title}</summary><pre>${ref.content}</pre></details>`)}</details>`;
17
+ return html `<section class="knowledge knowledge-library">${error ? html `<p class="problem" role="alert">${error}</p>` : ''}<section class="card knowledge-stale"><p role="status">${STALE_KNOWLEDGE}.</p>${review}${manage ? form('apply', html `<button>Apply saved knowledge</button>`) : ''}</section></section>`;
17
18
  }
18
- const instructions = `<pre class="knowledge-instructions">${e(view.knowledge.instructions || 'No project instructions yet.')}</pre>`;
19
- const editor = manage ? `<details class="knowledge-editor"${draft?.instructions !== undefined ? ' open' : ''}><summary>${view.knowledge.instructions ? 'Edit instructions' : 'Add instructions'}</summary>${form('instructions', `<textarea aria-label="Project instructions" name="instructions" rows="5" maxlength="4000" placeholder="Goals, preferences, and what good work looks like…">${e(draft?.instructions ?? view.knowledge.instructions)}</textarea><button>Save instructions</button>`)}</details>` : '';
20
- return `<section class="knowledge knowledge-library">${error ? `<p class="problem" role="alert">${e(error)}</p>` : ''}<section class="knowledge-intro"><h2>Instructions</h2>${instructions}${editor}</section><section><h2>References</h2>${refs || '<p class="meta">Add a spec, design guide, or useful project document.</p>'}${manage ? `<details class="card"${draft?.title && !draft.id ? ' open' : ''}><summary>Add reference</summary>${form('save', referenceFields(draft?.id ? {} : draft ?? {}))}</details>` : ''}</section>${history ? `<details><summary>Change history</summary><ol>${history}</ol></details>` : ''}</section>`;
19
+ const instructions = html `<pre class="knowledge-instructions">${view.knowledge.instructions || 'No project instructions yet.'}</pre>`;
20
+ const editor = manage ? html `<details class="knowledge-editor"${draft?.instructions !== undefined ? html ` open` : ''}><summary>${view.knowledge.instructions ? 'Edit instructions' : 'Add instructions'}</summary>${form('instructions', html `<textarea aria-label="Project instructions" name="instructions" rows="5" maxlength="4000" placeholder="Goals, preferences, and what good work looks like…">${draft?.instructions ?? view.knowledge.instructions}</textarea><button>Save instructions</button>`)}</details>` : '';
21
+ return html `<section class="knowledge knowledge-library">${error ? html `<p class="problem" role="alert">${error}</p>` : ''}<section class="knowledge-intro"><h2>Instructions</h2>${instructions}${editor}</section><section><h2>References</h2>${refs.length ? refs : html `<p class="meta">Add a spec, design guide, or useful project document.</p>`}${manage ? html `<details class="card"${draft?.title && !draft.id ? html ` open` : ''}><summary>Add reference</summary>${form('save', referenceFields(draft?.id ? {} : draft ?? {}))}</details>` : ''}</section>${history.length ? html `<details><summary>Change history</summary><ol>${history}</ol></details>` : ''}</section>`;
21
22
  }
22
23
  export function knowledgeContextHtml(snapshot) {
23
24
  if (!snapshot)
24
25
  return '';
25
- return `<details class="knowledge result-knowledge"><summary>Context used</summary><p class="meta">Project knowledge · version ${snapshot.revision}${snapshot.inheritedFrom === null ? '' : ` · from run #${snapshot.inheritedFrom}`}</p>${snapshot.instructions ? `<details><summary>Instructions</summary><pre>${e(snapshot.instructions)}</pre></details>` : '<p>No project instructions were supplied.</p>'}${snapshot.references.map(r => `<details><summary>${e(r.title)}</summary>${r.path ? `<p class="meta">${e(r.path)} · ${e(r.sourceRevision)}</p>` : ''}<pre>${e(r.content)}</pre></details>`).join('')}${snapshot.omitted.length ? `<details><summary>Not included (${snapshot.omitted.length})</summary><ul>${snapshot.omitted.map(r => `<li>${e(r.title)} — ${e(r.reason)}</li>`).join('')}</ul></details>` : ''}</details>`;
26
+ return html `<details class="knowledge result-knowledge"><summary>Context used</summary><p class="meta">Project knowledge · version ${snapshot.revision}${snapshot.inheritedFrom === null ? '' : ` · from run #${snapshot.inheritedFrom}`}</p>${snapshot.instructions ? html `<details><summary>Instructions</summary><pre>${snapshot.instructions}</pre></details>` : html `<p>No project instructions were supplied.</p>`}${snapshot.references.map(r => html `<details><summary>${r.title}</summary>${r.path ? html `<p class="meta">${r.path} · ${r.sourceRevision}</p>` : ''}<pre>${r.content}</pre></details>`)}${snapshot.omitted.length ? html `<details><summary>Not included (${snapshot.omitted.length})</summary><ul>${snapshot.omitted.map(r => html `<li>${r.title} — ${r.reason}</li>`)}</ul></details>` : ''}</details>`;
26
27
  }
27
28
  export const MEMORY_INTRO = 'What the lead and crew read before they work. Every change keeps its history.';
28
29
  export function decisionsHtml(repo, decisions, csrf, canManage, draft, error) {
29
30
  const manage = canManage && !!csrf;
30
- const base = { csrf, repo };
31
- const form = (action, body, extra = {}) => `<form method="post" action="/settings/knowledge/decision">${fields({ ...base, action, ...extra })}${body}</form>`;
32
- const rows = decisions.map(d => `<details class="card decision" id="decision-${d.id}"><summary><strong>${e(d.claim)}</strong> <span class="meta">#${d.id} · ${e(d.decidedBy)} · ${e(d.decidedAt.slice(0, 10))}</span></summary><p>${e(d.why)}</p><p class="meta">${e(d.sourceKind)}${d.sourceRef ? ` · ${e(d.sourceRef)}` : ''}${d.supersedes === null ? '' : ` · replaces #${d.supersedes}`}</p>${manage ? form('retire', `<label>Why it no longer holds<input name="reason" maxlength="500" required></label><button type="submit">Retire</button>`, { decision: d.id }) : ''}</details>`).join('');
33
- const add = manage ? `<details class="knowledge-editor"${draft?.claim !== undefined ? ' open' : ''}><summary>Record a decision</summary>${form('record', `<label>The choice, in one sentence<input name="claim" maxlength="240" value="${e(draft?.claim)}" required></label><label>Why<textarea name="why" rows="3" maxlength="2000" required>${e(draft?.why)}</textarea></label><button type="submit">Record</button>`)}</details>` : '';
34
- return `<section class="knowledge"><h2>Decisions</h2>${error ? `<p class="problem" role="alert">${e(error)}</p>` : ''}${rows || '<p class="meta">No decisions yet. The lead suggests one when a conversation settles a choice.</p>'}${add}</section>`;
31
+ const base = { repo };
32
+ const form = (action, body, extra = {}) => postForm('/settings/knowledge/decision', body, { hidden: fields({ ...base, action, ...extra }) });
33
+ const rows = decisions.map(d => html `<details class="card decision" id="decision-${d.id}"><summary><strong>${d.claim}</strong> <span class="meta">#${d.id} · ${d.decidedBy} · ${d.decidedAt.slice(0, 10)}</span></summary><p>${d.why}</p><p class="meta">${d.sourceKind}${d.sourceRef ? ` · ${d.sourceRef}` : ''}${d.supersedes === null ? '' : ` · replaces #${d.supersedes}`}</p>${manage ? form('retire', html `<label>Why it no longer holds<input name="reason" maxlength="500" required></label><button type="submit">Retire</button>`, { decision: d.id }) : ''}</details>`);
34
+ const add = manage ? html `<details class="knowledge-editor"${draft?.claim !== undefined ? html ` open` : ''}><summary>Record a decision</summary>${form('record', html `<label>The choice, in one sentence<input name="claim" maxlength="240" value="${draft?.claim}" required></label><label>Why<textarea name="why" rows="3" maxlength="2000" required>${draft?.why}</textarea></label><button type="submit">Record</button>`)}</details>` : '';
35
+ return html `<section class="knowledge"><h2>Decisions</h2>${error ? html `<p class="problem" role="alert">${error}</p>` : ''}${rows.length ? rows : html `<p class="meta">No decisions yet. The lead suggests one when a conversation settles a choice.</p>`}${add}</section>`;
35
36
  }
36
37
  export function memorySearchHtml(repo, query, hits) {
37
- const kind = (h) => h.kind === 'decision' ? `<a href="#decision-${e(h.ref)}">decision #${e(h.ref)}</a>` : h.kind === 'conversation' ? 'conversation' : h.kind;
38
- const results = hits === null ? '' : hits.length === 0 ? '<p class="meta">Nothing in project memory matches.</p>' : `<ul class="memory-hits">${hits.map(h => `<li><strong>${kind(h)}</strong> · ${e(h.title)}<br><span class="meta">${e(h.snippet)}</span></li>`).join('')}</ul>`;
39
- return `<section class="knowledge memory-search"><form method="get" action="/settings/knowledge"><input type="hidden" name="repo" value="${e(repo)}"><label>Search project memory<input name="memory" value="${e(query)}" maxlength="300" placeholder="Search decisions, references, lessons…" type="search" autocomplete="off"></label><button type="submit">Search</button></form>${results}</section>`;
38
+ const kind = (h) => h.kind === 'decision' ? html `<a href="#decision-${h.ref}">decision #${h.ref}</a>` : h.kind === 'conversation' ? 'conversation' : h.kind;
39
+ const results = hits === null ? '' : hits.length === 0 ? html `<p class="meta">Nothing in project memory matches.</p>` : html `<ul class="memory-hits">${hits.map(h => html `<li><strong>${kind(h)}</strong> · ${h.title}<br><span class="meta">${h.snippet}</span></li>`)}</ul>`;
40
+ return html `<section class="knowledge memory-search"><form method="get" action="/settings/knowledge"><input type="hidden" name="repo" value="${repo}"><label>Search project memory<input name="memory" value="${query}" maxlength="300" placeholder="Search decisions, references, lessons…" type="search" autocomplete="off"></label><button type="submit">Search</button></form>${results}</section>`;
40
41
  }
41
42
  export function proposalsHtml(repo, proposals, status, csrf, canManage) {
42
43
  const manage = canManage && !!csrf;
43
- const line = status === null ? '' : `<p class="meta memory-stats"><span>${status.sessions.analyzed}/${status.sessions.total} sessions read${status.sessions.failed ? ` · ${status.sessions.failed} failed` : ''}</span><span>${status.openGaps} open gap${status.openGaps === 1 ? '' : 's'}</span><span>Instructions ${status.instructionBytes}/${status.budgetBytes} bytes</span></p>` +
44
- `<details class="settings-more"><summary>Read new sessions</summary><p class="meta">Run <code>toolroll memory propose --repo ${e(repo)}</code> on this computer.</p></details>`;
45
- const cards = proposals.map(p => `<details class="card proposal" open><summary><strong>${e(p.title)}</strong> <span class="meta">#${p.id} · ${e(p.kind)} · ${p.sessions} sessions</span></summary><p>${e(p.rationale)}</p>${p.beforeText ? `<pre class="knowledge-instructions">- ${e(p.beforeText)}</pre>` : ''}${p.afterText ? `<pre class="knowledge-instructions">+ ${e(p.afterText)}</pre>` : ''}<ul class="memory-evidence">${p.evidence.map(ev => `<li>“${e(ev.quote.slice(0, 200))}” <span class="meta">${e(ev.session.split(':')[0] ?? '')}</span></li>`).join('')}</ul>${manage ? `<form method="post" action="/settings/knowledge/proposal" class="inline">${fields({ csrf, repo, proposal: p.id, decision: 'accept' })}<button type="submit">Accept</button></form> <form method="post" action="/settings/knowledge/proposal" class="inline">${fields({ csrf, repo, proposal: p.id, decision: 'reject' })}<button type="submit">Reject</button></form>` : ''}</details>`).join('');
46
- return `<section class="knowledge"><h2>Proposed from sessions</h2>${line}${cards || '<p class="meta">Nothing to review. Suggestions appear when the same mistake shows up in two sessions.</p>'}</section>`;
44
+ const line = status === null ? '' : html `<p class="meta memory-stats"><span>${status.sessions.analyzed}/${status.sessions.total} sessions read${status.sessions.failed ? ` · ${status.sessions.failed} failed` : ''}</span><span>${status.openGaps} open gap${status.openGaps === 1 ? '' : 's'}</span><span>Instructions ${status.instructionBytes}/${status.budgetBytes} bytes</span></p><details class="settings-more"><summary>Read new sessions</summary><p class="meta">Run <code>toolroll memory propose --repo ${repo}</code> on this computer.</p></details>`;
45
+ const decide = (p, decision, label) => postForm('/settings/knowledge/proposal', html `<button type="submit">${label}</button>`, { attrs: { class: 'inline' }, hidden: fields({ repo, proposal: p.id, decision }) });
46
+ const cards = proposals.map(p => html `<details class="card proposal" open><summary><strong>${p.title}</strong> <span class="meta">#${p.id} · ${p.kind} · ${p.sessions} sessions</span></summary><p>${p.rationale}</p>${p.beforeText ? html `<pre class="knowledge-instructions">- ${p.beforeText}</pre>` : ''}${p.afterText ? html `<pre class="knowledge-instructions">+ ${p.afterText}</pre>` : ''}<ul class="memory-evidence">${p.evidence.map(ev => html `<li>“${ev.quote.slice(0, 200)}” <span class="meta">${ev.session.split(':')[0] ?? ''}</span></li>`)}</ul>${manage ? html `${decide(p, 'accept', 'Accept')} ${decide(p, 'reject', 'Reject')}` : ''}</details>`);
47
+ return html `<section class="knowledge"><h2>Proposed from sessions</h2>${line}${cards.length ? cards : html `<p class="meta">Nothing to review. Suggestions appear when the same mistake shows up in two sessions.</p>`}</section>`;
47
48
  }
@@ -1,16 +1,16 @@
1
- import { type MateProposal, type Store } from "./store.js";
1
+ import { type LeadProposal, type Store } from "./store.js";
2
2
  import { type ShapeOptions } from "./reply-shape.js";
3
- import type { SubscriptionMateRunner } from "./subscription-chat.js";
4
- export type MateCliSeams = {
3
+ import type { SubscriptionLeadRunner } from "./subscription-chat.js";
4
+ export type LeadCliSeams = {
5
5
  fetcher?: typeof fetch;
6
6
  env?: Record<string, string | undefined>;
7
7
  /** Lines the REPL reads instead of stdin (tests). */
8
8
  lines?: AsyncIterable<string> | Iterable<string>;
9
9
  clock?: () => Date;
10
10
  /** Subscription harness seam; tests never consume a real membership turn. */
11
- subscriptionRunner?: SubscriptionMateRunner;
11
+ subscriptionRunner?: SubscriptionLeadRunner;
12
12
  };
13
- export type MateCliInput = {
13
+ export type LeadCliInput = {
14
14
  store: Store;
15
15
  databaseFile: string;
16
16
  write: (line: string) => void;
@@ -25,18 +25,18 @@ export type MateCliInput = {
25
25
  end: boolean;
26
26
  follow?: boolean;
27
27
  ceilingUsd: number | undefined;
28
- seams?: MateCliSeams;
28
+ seams?: LeadCliSeams;
29
29
  /** Where evidence lives — a scout's report reads from here. */
30
30
  evidenceRoot?: string;
31
31
  /** The console's address(es): a reply's links there are named as its pages ("the task"), not by host. */
32
32
  appOrigin?: ShapeOptions["appOrigin"];
33
33
  };
34
- export type MateCliResult = {
34
+ export type LeadCliResult = {
35
35
  code: number;
36
36
  reason?: string;
37
37
  message?: string;
38
38
  };
39
- export declare const MATE_CLI_EXIT: {
39
+ export declare const LEAD_CLI_EXIT: {
40
40
  readonly ok: 0;
41
41
  readonly failed: 1;
42
42
  readonly usage: 2;
@@ -49,7 +49,7 @@ export declare const MATE_CLI_EXIT: {
49
49
  */
50
50
  export declare function answerContextLines(store: Store, payload: Record<string, unknown>): string[];
51
51
  /** One line per proposal, numbered in thread order, for the operator to name. */
52
- export declare function proposalLines(proposals: readonly MateProposal[], repos: readonly string[], ordinal?: (proposal: MateProposal) => number): string[];
52
+ export declare function proposalLines(proposals: readonly LeadProposal[], repos: readonly string[], ordinal?: (proposal: LeadProposal) => number): string[];
53
53
  /** The lines for one proposal, its answer context included when it is an answer. */
54
- export declare function proposalBlock(store: Store, proposal: MateProposal, repos: readonly string[], number: number): string[];
55
- export declare function runMateCli(input: MateCliInput): Promise<MateCliResult>;
54
+ export declare function proposalBlock(store: Store, proposal: LeadProposal, repos: readonly string[], number: number): string[];
55
+ export declare function runLeadCli(input: LeadCliInput): Promise<LeadCliResult>;
@@ -1,7 +1,7 @@
1
1
  import { configureLeadFollow, leadFollowStatus } from './lead-follow.js';
2
2
  /**
3
3
  * `toolroll chat` (mate arc §6): the same thread the console shows,
4
- * driven from a terminal. The password is typed once — it mints the mate
4
+ * driven from a terminal. The password is typed once — it mints the lead
5
5
  * session, the one ceremony a conversation gets — and every later turn
6
6
  * debits that session without asking again. Confirming a card runs the
7
7
  * same doors the console runs; password-class acts (approving a scope,
@@ -10,16 +10,16 @@ import { configureLeadFollow, leadFollowStatus } from './lead-follow.js';
10
10
  import { createHash } from "node:crypto";
11
11
  import { readFileSync } from "node:fs";
12
12
  import { dirname, join } from "node:path";
13
- import { MATE_ASK_OTHER } from "./store.js";
13
+ import { LEAD_ASK_OTHER } from "./store.js";
14
14
  import { CHAT_KEY_ENV, credentialKeyOf, isDirectChatProvider, priceForConfig, subscriptionCredentialKey } from "./converse.js";
15
15
  import { verifyApproverByPassword } from "./principal.js";
16
- import { runMateTurn } from "./mate.js";
16
+ import { runLeadTurn } from "./lead.js";
17
17
  import { voiceReply } from "./reply-shape.js";
18
- import { confirmMateProposal, dismissMateProposal } from "./mate-doors.js";
18
+ import { confirmLeadProposal, dismissLeadProposal } from "./lead-doors.js";
19
19
  import { projectName } from "./project.js";
20
20
  import { CHAT_CONTROLS, chatControlHref, isChatControl } from "./chat-controls.js";
21
21
  import { CHAT_TASK_ACTIONS, isChatTaskAction } from "./chat-task-actions.js";
22
- export const MATE_CLI_EXIT = { ok: 0, failed: 1, usage: 2, refused: 3 };
22
+ export const LEAD_CLI_EXIT = { ok: 0, failed: 1, usage: 2, refused: 3 };
23
23
  function money(microusd) {
24
24
  return `$${(microusd / 1_000_000).toFixed(2)}`;
25
25
  }
@@ -119,7 +119,7 @@ async function* linesOf(seams) {
119
119
  reader.close();
120
120
  }
121
121
  }
122
- export async function runMateCli(input) {
122
+ export async function runLeadCli(input) {
123
123
  const { store, write, json } = input;
124
124
  const seams = input.seams ?? {};
125
125
  const clock = seams.clock ?? (() => new Date());
@@ -132,7 +132,7 @@ export async function runMateCli(input) {
132
132
  if (json)
133
133
  write(JSON.stringify({ command: "chat", ...envelope }));
134
134
  };
135
- const refuse = (reason, message, code = MATE_CLI_EXIT.refused) => {
135
+ const refuse = (reason, message, code = LEAD_CLI_EXIT.refused) => {
136
136
  if (json)
137
137
  write(JSON.stringify({ ok: false, command: "chat", reason, message }));
138
138
  else
@@ -154,22 +154,22 @@ export async function runMateCli(input) {
154
154
  return refuse("no-key", `no ${directProvider} key — export ${CHAT_KEY_ENV[directProvider]}, or paste one on the console's chat page`);
155
155
  const repos = [...input.repos];
156
156
  if (repos.length === 0)
157
- return refuse("empty-ceiling", "The lead has no projects to look at. Name some with --repo, or add projects in the console.", MATE_CLI_EXIT.usage);
157
+ return refuse("empty-ceiling", "The lead has no projects to look at. Name some with --repo, or add projects in the console.", LEAD_CLI_EXIT.usage);
158
158
  const verified = verifyApproverByPassword(store, input.credentials.name, input.credentials.token, repos);
159
159
  if (!verified.ok)
160
160
  return refuse("unauthenticated", "that is not an approver, or the password does not match");
161
161
  const who = verified.who;
162
162
  let now = clock();
163
163
  if (input.end) {
164
- const turns = store.failLiveMateTurnsFor(who.name, "ended", now);
165
- const sessions = store.endMateSessionsFor(who.name, who.name, now);
166
- const threads = store.closeMateThreadsFor(who.name, now);
164
+ const turns = store.failLiveLeadTurnsFor(who.name, "ended", now);
165
+ const sessions = store.endLeadSessionsFor(who.name, who.name, now);
166
+ const threads = store.closeLeadThreadsFor(who.name, now);
167
167
  emit({ ok: true, ended: { sessions, threads, turns } });
168
168
  say(sessions === 0 ? "No conversation was open, so there was nothing to end." : "The conversation has ended and its history is forgotten.");
169
- return { code: MATE_CLI_EXIT.ok };
169
+ return { code: LEAD_CLI_EXIT.ok };
170
170
  }
171
- store.sweepStaleMateTurns(now);
172
- let session = store.activeMateSession(who.name);
171
+ store.sweepStaleLeadTurns(now);
172
+ let session = store.activeLeadSession(who.name);
173
173
  const credentialKey = direct ? credentialKeyOf(directProvider, key) : subscriptionCredentialKey(subscriptionProvider);
174
174
  if (session !== null && session.credentialKey !== credentialKey) {
175
175
  // A session minted under another provider key cannot be spent by this
@@ -177,38 +177,38 @@ export async function runMateCli(input) {
177
177
  return refuse("key-mismatch", "The open conversation was started with a different provider key. Use that key, or end it with --end and start a new one.");
178
178
  }
179
179
  if (session !== null && session.ceilingDigest !== who.ceilingDigest) {
180
- store.endMateSession(session.id, who.name, now);
181
- store.closeMateThreadsFor(who.name, now);
180
+ store.endLeadSession(session.id, who.name, now);
181
+ store.closeLeadThreadsFor(who.name, now);
182
182
  say("The projects you named differ from the open conversation's, so it ended. Starting a new one.");
183
183
  session = null;
184
184
  }
185
185
  if (session === null) {
186
186
  const ceilingUsd = direct ? (input.ceilingUsd ?? 5) : 0;
187
187
  if (direct && (!Number.isFinite(ceilingUsd) || ceilingUsd <= 0 || ceilingUsd > 1_000))
188
- return refuse("usage", "--ceiling-usd is a dollar amount between 0 and 1000", MATE_CLI_EXIT.usage);
188
+ return refuse("usage", "--ceiling-usd is a dollar amount between 0 and 1000", LEAD_CLI_EXIT.usage);
189
189
  const ceilingMicrousd = Math.round(ceilingUsd * 1_000_000);
190
190
  const termsDigest = createHash("sha256").update(`${ceilingMicrousd}\n${who.ceilingDigest}`).digest("hex");
191
- const id = store.mintMateSession({ approver: who.name, approverGeneration: who.generation, credentialKey, ceilingMicrousd, ceilingDigest: who.ceilingDigest, termsDigest }, now);
192
- session = store.getMateSession(id);
191
+ const id = store.mintLeadSession({ approver: who.name, approverGeneration: who.generation, credentialKey, ceilingMicrousd, ceilingDigest: who.ceilingDigest, termsDigest }, now);
192
+ session = store.getLeadSession(id);
193
193
  if (session === null)
194
- return refuse("failed", "A new conversation couldn't be started. Try again.", MATE_CLI_EXIT.failed);
194
+ return refuse("failed", "A new conversation couldn't be started. Try again.", LEAD_CLI_EXIT.failed);
195
195
  if (!direct && input.ceilingUsd !== undefined)
196
196
  say("the supplied --ceiling-usd value is ignored for membership usage");
197
- say(`mate conversation started: ${direct ? `up to ${money(ceilingMicrousd)}` : "subscription usage (no dollar limit)"} over ${repos.map(one => projectName(one)).join(", ")} — live until you end it`);
197
+ say(`lead conversation started: ${direct ? `up to ${money(ceilingMicrousd)}` : "subscription usage (no dollar limit)"} over ${repos.map(one => projectName(one)).join(", ")} — live until you end it`);
198
198
  if (direct)
199
199
  say(`(the weekly chat limit, ${money(config.weeklyCeilingMicrousd)}, still applies)`);
200
200
  }
201
201
  else {
202
- say(`mate conversation live: ${direct ? `${money(session.spentMicrousd)} of ${money(session.ceilingMicrousd)} spent` : "subscription usage (no dollar limit)"} — live until you end it`);
202
+ say(`lead conversation live: ${direct ? `${money(session.spentMicrousd)} of ${money(session.ceilingMicrousd)} spent` : "subscription usage (no dollar limit)"} — live until you end it`);
203
203
  }
204
- const thread = store.openMateThread(who.name, who.ceilingDigest, now).thread;
204
+ const thread = store.openLeadThread(who.name, who.ceilingDigest, now).thread;
205
205
  if (input.follow !== undefined) {
206
206
  if (!configureLeadFollow(store, who, session, thread, input.follow, now))
207
207
  return refuse("standing", "Conversation access changed.");
208
208
  say(leadFollowStatus(store, who.name).detail);
209
209
  emit({ ok: true, follow: leadFollowStatus(store, who.name) });
210
210
  }
211
- const pendingProposals = () => store.listMateProposals(thread.id, ["pending"]);
211
+ const pendingProposals = () => store.listLeadProposals(thread.id, ["pending"]);
212
212
  // Ordinals are assigned once per proposal and never reused within this
213
213
  // run (slice-2 review, finding 4): `confirm 2` means the card printed as
214
214
  // 2, whatever the console did to its neighbours meanwhile.
@@ -224,7 +224,7 @@ export async function runMateCli(input) {
224
224
  const byOrdinal = (ordinal) => {
225
225
  for (const [id, n] of ordinals)
226
226
  if (n === ordinal)
227
- return store.getMateProposal(id);
227
+ return store.getLeadProposal(id);
228
228
  return null;
229
229
  };
230
230
  const printProposals = () => {
@@ -239,12 +239,12 @@ export async function runMateCli(input) {
239
239
  say(line);
240
240
  };
241
241
  const turn = async (message) => {
242
- const live = store.activeMateSession(who.name);
242
+ const live = store.activeLeadSession(who.name);
243
243
  if (live === null) {
244
244
  const outcome = { ok: false, refused: "session-ended", message: "This conversation has ended. Run chat again to start a new one." };
245
245
  return outcome;
246
246
  }
247
- return runMateTurn({ store, who, session: live, thread, config, key, message, channel: "terminal", ...(seams.fetcher === undefined ? {} : { fetcher: seams.fetcher }), ...(seams.subscriptionRunner === undefined ? {} : { subscriptionRunner: seams.subscriptionRunner }), ...(input.evidenceRoot === undefined ? {} : { evidenceRoot: input.evidenceRoot }), clock });
247
+ return runLeadTurn({ store, who, session: live, thread, config, key, message, channel: "terminal", ...(seams.fetcher === undefined ? {} : { fetcher: seams.fetcher }), ...(seams.subscriptionRunner === undefined ? {} : { subscriptionRunner: seams.subscriptionRunner }), ...(input.evidenceRoot === undefined ? {} : { evidenceRoot: input.evidenceRoot }), clock });
248
248
  };
249
249
  const report = (outcome, message) => {
250
250
  if (outcome.ok && outcome.replayed) {
@@ -253,14 +253,14 @@ export async function runMateCli(input) {
253
253
  return;
254
254
  }
255
255
  if (outcome.ok) {
256
- const ask = store.mateAsk(outcome.turn);
256
+ const ask = store.leadAsk(outcome.turn);
257
257
  emit({ ok: true, turn: outcome.turn, reply: outcome.reply, activity: outcome.activity, steps: outcome.steps, settledMicrousd: outcome.settledMicrousd, proposals: pendingProposals().map(one => ({ id: one.id, ordinal: ordinalOf(one), kind: one.kind, payload: one.payload })),
258
- ...(ask === null ? {} : { ask: { question: ask.question, options: [...ask.options, MATE_ASK_OTHER] } }) });
258
+ ...(ask === null ? {} : { ask: { question: ask.question, options: [...ask.options, LEAD_ASK_OTHER] } }) });
259
259
  say(` ${outcome.activity}`);
260
260
  say(voiceReply(outcome.reply, "terminal", { appOrigin: input.appOrigin ?? null, ...(message === undefined ? {} : { asked: message }) }));
261
261
  // The lead's question: the terminal has no buttons, so the options are listed to type back.
262
262
  if (ask !== null)
263
- say(`${ask.question}\n${ask.options.map(one => ` · ${one}`).join("\n")}\n · ${MATE_ASK_OTHER} (type your answer)`);
263
+ say(`${ask.question}\n${ask.options.map(one => ` · ${one}`).join("\n")}\n · ${LEAD_ASK_OTHER} (type your answer)`);
264
264
  printProposals();
265
265
  return;
266
266
  }
@@ -270,7 +270,7 @@ export async function runMateCli(input) {
270
270
  if (input.say !== undefined) {
271
271
  const outcome = await turn(input.say);
272
272
  report(outcome, input.say);
273
- return { code: outcome.ok ? MATE_CLI_EXIT.ok : MATE_CLI_EXIT.refused };
273
+ return { code: outcome.ok ? LEAD_CLI_EXIT.ok : LEAD_CLI_EXIT.refused };
274
274
  }
275
275
  // The REPL. Text is a turn; a few words are acts on the cards.
276
276
  say("say something, or: proposals · confirm N · dismiss N · open N · end · quit");
@@ -311,12 +311,12 @@ export async function runMateCli(input) {
311
311
  openTask(proposal);
312
312
  }
313
313
  else if (verb === "dismiss") {
314
- const done = dismissMateProposal(store, who, proposal.id, now);
314
+ const done = dismissLeadProposal(store, who, proposal.id, now);
315
315
  emit({ ok: done, act: "dismiss", proposal: proposal.id });
316
316
  say(done ? `dismissed ${act[2]}` : "that proposal was already acted on");
317
317
  }
318
318
  else {
319
- const outcome = confirmMateProposal(store, who, proposal.id, now, { confirm: act[3] !== undefined, via: "cli", chatProvider: () => {
319
+ const outcome = confirmLeadProposal(store, who, proposal.id, now, { confirm: act[3] !== undefined, via: "cli", chatProvider: () => {
320
320
  const current = store.getChatConfig();
321
321
  return current === null ? null : { config: current, key: isDirectChatProvider(current.provider) ? keyFor(current, input.databaseFile, env) : null };
322
322
  }, ...(input.evidenceRoot === undefined ? {} : { evidenceRoot: input.evidenceRoot }) });
@@ -338,12 +338,12 @@ export async function runMateCli(input) {
338
338
  if (word === "quit" || word === "exit")
339
339
  break;
340
340
  if (word === "end") {
341
- store.failLiveMateTurnsFor(who.name, "ended", now);
342
- store.endMateSessionsFor(who.name, who.name, now);
343
- store.closeMateThreadsFor(who.name, now);
341
+ store.failLiveLeadTurnsFor(who.name, "ended", now);
342
+ store.endLeadSessionsFor(who.name, who.name, now);
343
+ store.closeLeadThreadsFor(who.name, now);
344
344
  say("The conversation has ended and its history is forgotten.");
345
345
  emit({ ok: true, ended: true });
346
- return { code: MATE_CLI_EXIT.ok };
346
+ return { code: LEAD_CLI_EXIT.ok };
347
347
  }
348
348
  if (word === "help" || word === "?") {
349
349
  say("say something, or: proposals · confirm N · dismiss N · open N · end · quit");
@@ -351,5 +351,5 @@ export async function runMateCli(input) {
351
351
  }
352
352
  report(await turn(line), line);
353
353
  }
354
- return { code: MATE_CLI_EXIT.ok };
354
+ return { code: LEAD_CLI_EXIT.ok };
355
355
  }
@@ -90,7 +90,7 @@ export function getCommitment(store, id) {
90
90
  /** The reply that made a promise was shown: its turn is over, and it was answered or its text reached the conversation
91
91
  * before it failed. A turn still running has shown nothing yet, whatever it has written so far. */
92
92
  const SHOWN = (turn) => `EXISTS (SELECT 1 FROM mate_turn t WHERE t.id = ${turn} AND (t.state = 'answered'
93
- OR t.state = 'failed' AND EXISTS (SELECT 1 FROM mate_message m WHERE m.turn = t.id AND m.role = 'assistant')))`;
93
+ OR t.state = 'failed' AND EXISTS (SELECT 1 FROM lead_message m WHERE m.turn = t.id AND m.role = 'assistant')))`;
94
94
  /** A promise only counts once the reply that made it was shown: one from a reply still being written, or one that
95
95
  * failed without reaching the owner, was never heard. */
96
96
  const HEARD = `(c.turn IS NULL OR ${SHOWN('c.turn')})`;
@@ -173,7 +173,7 @@ export function checkLeadCommitments(store, now, root) {
173
173
  continue;
174
174
  }
175
175
  // A reply still being written may yet be delivered; one that was not is dropped above.
176
- const turn = one.turn === null ? null : store.getMateTurn(one.turn);
176
+ const turn = one.turn === null ? null : store.getLeadTurn(one.turn);
177
177
  if (turn !== null && (turn.state === 'queued' || turn.state === 'running'))
178
178
  continue;
179
179
  const account = store.accountOf(one.owner);
@@ -181,7 +181,7 @@ export function checkLeadCommitments(store, now, root) {
181
181
  close('cancelled', 'Access to this project ended.');
182
182
  continue;
183
183
  }
184
- const thread = store.getMateThread(one.thread);
184
+ const thread = store.getLeadThread(one.thread);
185
185
  if (thread === null || thread.approver !== one.owner || thread.closedAt !== null) {
186
186
  close('cancelled', 'The conversation it was promised in was closed.');
187
187
  continue;
@@ -203,7 +203,7 @@ export function checkLeadCommitments(store, now, root) {
203
203
  return;
204
204
  // The shared conversation always keeps the line; a promise made on a phone or team chat is also said there, as
205
205
  // the lead's own message to its owner, on that chat alone (the usual delivery receipts apply).
206
- store.appendMateMessage({ thread: one.thread, turn: null, role: 'assistant', text: line }, now);
206
+ store.appendLeadMessage({ thread: one.thread, turn: null, role: 'assistant', text: line }, now);
207
207
  if (one.channel !== 'chat')
208
208
  store.enqueueNotification({ dedupeKey: `${PROMISE_KEY}${one.channel}:${one.id}`, kind: LEAD_SAY_KIND, subject: leadNameOf(store, one.owner),
209
209
  body: line.slice(0, 300), recipient: one.owner, source: { installation: true } }, now);
@@ -1,3 +1,13 @@
1
+ /** Bounded DB memory shared by browser and terminal lead turns. No provider,
2
+ * repository scan, mutation, or hidden approval happens while catching up.
3
+ *
4
+ * The bundle is ordered by importance and built fresh each turn: who the lead
5
+ * is (name, persona), who it is talking to (first name, time zone, today), what
6
+ * it knows about them (their confirmed lines), the people, subagents and team
7
+ * chats it works with (one line each), the channel, what needs them now,
8
+ * projects by name with their active decisions, then the rest. Over 8 KB, the
9
+ * least important goes first: the rest, then people, then decisions. */
10
+ import { type Html } from './html.js';
1
11
  import type { Store } from './store.js';
2
12
  import { type LeadChannel } from './contracts/lead-context.js';
3
13
  import { type AssignmentCatchUp } from './assignment-brief.js';
@@ -31,5 +41,5 @@ export declare function firstNameOf(account: string): string;
31
41
  export declare function leadChannelOf(label: string): LeadChannel | undefined;
32
42
  export declare function leadContext(store: Store, repos: readonly string[], now: Date, options?: LeadContextOptions): string;
33
43
  /** The same saved brief is useful before chat spending is authorized. */
34
- export declare function leadBriefHtml(brief: AssignmentCatchUp): string;
35
- export declare const LEAD_CONTEXT_CSS = ".lead-promise-list{list-style:none;margin:0;padding:0}.lead-promise-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.5rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-promise-list li:last-child{border-bottom:0}.lead-promise-list p{margin:0;overflow-wrap:anywhere}.lead-promise-list form{grid-column:2;grid-row:1/span 2;margin:0}.lead-promise-list button{min-height:44px;width:auto;white-space:nowrap}.lead-promise-list .nowrap{white-space:nowrap}.lead-brief{margin:1rem 0;min-width:0}.lead-brief h2{font-size:1.1rem;margin:0 0 .8rem}.repository-context input[name=q]{display:block;box-sizing:border-box;min-height:44px;width:100%;margin:.4rem 0 .75rem;padding:.6rem .75rem;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:inherit;font:inherit}.repository-context form{margin:.5rem 0 1rem}.repository-context summary{min-height:44px;padding:.75rem 0;overflow-wrap:anywhere}.lead-brief h3{font-size:.85rem;margin:1rem 0 .4rem;color:var(--muted-foreground)}.lead-brief ul{list-style:none;margin:0;padding:0}.lead-brief li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-brief li a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;text-decoration:none}.lead-brief li a:hover{text-decoration:underline}.lead-brief-state{font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap}.lead-brief-state--needs-decision,.lead-brief-state--ready-to-check{background:var(--so-attention-soft);color:var(--so-attention)}.lead-brief-state--working,.lead-brief-state--checking{background:var(--so-info-soft);color:var(--so-info)}.lead-brief-state--complete{background:var(--so-success-soft);color:var(--so-success)}.lead-brief li a.lead-brief-act{grid-column:1/-1;justify-self:start;display:inline-flex;min-height:40px;margin:.15rem 0 .4rem;font-weight:600}@media(max-width:760px){.lead-brief li a.lead-brief-act{justify-self:stretch;justify-content:center;min-height:44px}}.lead-brief-detail{grid-column:1/-1;font-size:.85rem;color:var(--muted-foreground);overflow-wrap:anywhere;padding-bottom:.35rem}@media(max-width:760px){.lead-brief{margin:.5rem 0}.lead-brief h2{margin:0 0 .25rem}.lead-brief h3{margin:.5rem 0 0}.lead-brief li{padding:0 0 .375rem}.lead-brief-detail{margin-top:-.375rem;padding-bottom:0;line-height:1.35;pointer-events:none}}";
44
+ export declare function leadBriefHtml(brief: AssignmentCatchUp): Html;
45
+ export declare const LEAD_CONTEXT_CSS = ".lead-subagent-list{list-style:none;margin:0 0 .5rem;padding:0}.lead-subagent-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;border-bottom:1px solid var(--border);min-width:0}.lead-subagent-list li:last-child{border-bottom:0}.lead-subagent-list a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;min-width:0}.lead-subagent-list .meta{text-align:right;overflow-wrap:anywhere}@media(max-width:600px){.lead-subagent-list li{grid-template-columns:minmax(0,1fr)}.lead-subagent-list .meta{text-align:left;padding-bottom:.4rem}}.lead-subagents .button-link{min-height:44px;display:inline-flex;align-items:center}.lead-promise-list{list-style:none;margin:0;padding:0}.lead-promise-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.5rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-promise-list li:last-child{border-bottom:0}.lead-promise-list p{margin:0;overflow-wrap:anywhere}.lead-promise-list form{grid-column:2;grid-row:1/span 2;margin:0}.lead-promise-list button{min-height:44px;width:auto;white-space:nowrap}.lead-promise-list .nowrap{white-space:nowrap}.lead-brief{margin:1rem 0;min-width:0}.lead-brief h2{font-size:1.1rem;margin:0 0 .8rem}.repository-context input[name=q]{display:block;box-sizing:border-box;min-height:44px;width:100%;margin:.4rem 0 .75rem;padding:.6rem .75rem;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:inherit;font:inherit}.repository-context form{margin:.5rem 0 1rem}.repository-context summary{min-height:44px;padding:.75rem 0;overflow-wrap:anywhere}.lead-brief h3{font-size:.85rem;margin:1rem 0 .4rem;color:var(--muted-foreground)}.lead-brief ul{list-style:none;margin:0;padding:0}.lead-brief li{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:.75rem;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border);min-width:0}.lead-brief li a{display:flex;min-height:44px;align-items:center;font-weight:500;overflow-wrap:anywhere;text-decoration:none}.lead-brief li a:hover{text-decoration:underline}.lead-brief-state{font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:.375rem;background:var(--so-neutral-soft);color:var(--so-neutral-ink);white-space:nowrap}.lead-brief-state--needs-decision,.lead-brief-state--ready-to-check{background:var(--so-attention-soft);color:var(--so-attention)}.lead-brief-state--working,.lead-brief-state--checking{background:var(--so-info-soft);color:var(--so-info)}.lead-brief-state--complete{background:var(--so-success-soft);color:var(--so-success)}.lead-brief li a.lead-brief-act{grid-column:1/-1;justify-self:start;display:inline-flex;min-height:40px;margin:.15rem 0 .4rem;font-weight:600}@media(max-width:760px){.lead-brief li a.lead-brief-act{justify-self:stretch;justify-content:center;min-height:44px}}.lead-brief-detail{grid-column:1/-1;font-size:.85rem;color:var(--muted-foreground);overflow-wrap:anywhere;padding-bottom:.35rem}@media(max-width:760px){.lead-brief{margin:.5rem 0}.lead-brief h2{margin:0 0 .25rem}.lead-brief h3{margin:.5rem 0 0}.lead-brief li{padding:0 0 .375rem}.lead-brief-detail{margin-top:-.375rem;padding-bottom:0;line-height:1.35;pointer-events:none}}";