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,21 +1,21 @@
1
1
  /**
2
- * A teammate's turn (teammates.ts): one schema for the JSON Schema Claude answers in (`--json-schema`) and the reader
2
+ * A subagent's turn (subagents.ts): one schema for the JSON Schema Claude answers in (`--json-schema`) and the reader
3
3
  * that takes the answer back. One flat object with every field (a root union is refused by the API); fields a turn
4
4
  * does not use are "" (or [] for options).
5
5
  *
6
6
  * The text limits (TURN_LIMITS, from TEXT_LIMITS) are deliberately not in the schema: the CLI refuses an answer a few
7
7
  * characters over one whole, so they are checked after parsing and an answer over one is asked once to shorten
8
- * (teammate-work.ts), then kept whole. What the zone allows — which actions, which answers, a note for a send-back, a
8
+ * (subagent-work.ts), then kept whole. What the zone allows — which actions, which answers, a note for a send-back, a
9
9
  * question for an ask, a tool for a tool call — is checked after parsing too (`readTurn`), by path.
10
10
  *
11
11
  * A turn is kept as the step's decision (`flow_step_run.decision_json`) as it was read, so a saved one is this shape.
12
12
  */
13
13
  import { z } from "zod";
14
14
  import { parseContract, toModelSchema } from "./contract.js";
15
- /** What a teammate may do on one turn. A decision zone: approve, send back, or hand it to a person. A work zone: pick
15
+ /** What a subagent may do on one turn. A decision zone: approve, send back, or hand it to a person. A work zone: pick
16
16
  * where it goes, ask its person, or say it can't. v94: "use_tool" asks for one tool call. */
17
17
  export const TURN_ACTIONS = ["approve", "send_back", "hand_off", "route", "ask", "cant", "use_tool"];
18
- export const teammateTurnSchema = z.object({
18
+ export const subagentTurnSchema = z.object({
19
19
  action: z.enum(TURN_ACTIONS),
20
20
  /** route: one of the zone's answers, exactly as written. */
21
21
  answer: z.string(),
@@ -35,17 +35,17 @@ export const teammateTurnSchema = z.object({
35
35
  remember: z.string(),
36
36
  });
37
37
  /** What Claude's `--json-schema` is for a turn: the turn schema, exactly. */
38
- export const TURN_MODEL_SCHEMA = toModelSchema(teammateTurnSchema);
38
+ export const TURN_MODEL_SCHEMA = toModelSchema(subagentTurnSchema);
39
39
  /** Older and plain-text turns default absent or non-text fields to "", and keep only string options. */
40
40
  export function readTurnAnswer(value) {
41
41
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
42
42
  const body = { ...value };
43
- for (const key of Object.keys(teammateTurnSchema.shape)) {
43
+ for (const key of Object.keys(subagentTurnSchema.shape)) {
44
44
  if (key !== "action" && key !== "options" && typeof body[key] !== "string")
45
45
  body[key] = "";
46
46
  }
47
47
  body["options"] = Array.isArray(body["options"]) ? body["options"].filter(one => typeof one === "string") : [];
48
48
  value = body;
49
49
  }
50
- return parseContract(teammateTurnSchema, value);
50
+ return parseContract(subagentTurnSchema, value);
51
51
  }
@@ -1,12 +1,12 @@
1
1
  /** Shared setup views over the existing project configuration and approval doors. */
2
+ import { type Html } from "./html.js";
2
3
  import type { ProviderId } from "./provider.js";
3
4
  import type { ProviderConnection } from "./provider-connection.js";
4
5
  import { type ModelChoice } from "./setup-guide.js";
5
6
  import type { SetupInputs } from "./control-setup.js";
6
7
  import { type OpenRouterModels } from "./openrouter-models.js";
7
- export declare function hiddenFields(values: Record<string, string>): string;
8
8
  export declare function connectionWords(connection: ProviderConnection): string;
9
- export declare function connectionHtml(provider: ProviderId, connection: ProviderConnection, task?: string): string;
9
+ export declare function connectionHtml(provider: ProviderId, connection: ProviderConnection, task?: string): Html;
10
10
  export declare function controlSetupHtml(data: {
11
11
  repo: string;
12
12
  csrf: string;
@@ -25,5 +25,6 @@ export declare function controlSetupHtml(data: {
25
25
  installed: boolean;
26
26
  message?: string;
27
27
  };
28
- }): string;
29
- export declare function setupPreviewHtml(inputs: SetupInputs, fields: Record<string, string>): string;
28
+ }): Html;
29
+ /** `fields` may still carry the session's csrf (a caller's habit): postForm writes the one CSRF field. */
30
+ export declare function setupPreviewHtml(inputs: SetupInputs, fields: Record<string, string>): Html;
@@ -1,9 +1,7 @@
1
+ /** Shared setup views over the existing project configuration and approval doors. */
2
+ import { html, joinHtml, postForm } from "./html.js";
1
3
  import { ASSISTANTS } from "./setup-guide.js";
2
4
  import { openRouterPicker } from "./openrouter-models.js";
3
- const escape = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4
- export function hiddenFields(values) {
5
- return Object.entries(values).map(([name, value]) => `<input type="hidden" name="${escape(name)}" value="${escape(value)}">`).join("");
6
- }
7
5
  export function connectionWords(connection) {
8
6
  return {
9
7
  connected: "Connected", "signed-out": "Not signed in", "not-installed": "CLI not installed",
@@ -12,42 +10,19 @@ export function connectionWords(connection) {
12
10
  }
13
11
  export function connectionHtml(provider, connection, task = "") {
14
12
  const query = new URLSearchParams({ provider, ...(task ? { task } : {}) });
15
- return `<div class="card assistant-account"><p><strong>${escape(ASSISTANTS[provider].name)} · ${connectionWords(connection)}</strong></p>` +
16
- `<p class="meta">${[connection.email, connection.plan, connection.method].filter(Boolean).map(one => escape(one)).join(" · ")}</p>` +
17
- `<p class="meta">Checked ${escape(new Date(connection.checkedAt).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", timeZoneName: "short" }))} on the computer running this console. Sign-in does not prove model access or remaining quota.</p>` +
18
- `<a class="button-link" href="/control/connection?${escape(query.toString())}">${connection.state === "connected" ? "Manage connection" : "Connect account"}</a> · ` +
19
- `<a href="/control?${escape(query.toString())}&amp;check-connection=1">Check again</a></div>`;
13
+ return html `<div class="card assistant-account"><p><strong>${ASSISTANTS[provider].name} · ${connectionWords(connection)}</strong></p><p class="meta">${[connection.email, connection.plan, connection.method].filter(Boolean).join(" · ")}</p><p class="meta">Checked ${new Date(connection.checkedAt).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", timeZoneName: "short" })} on the computer running this console. Sign-in does not prove model access or remaining quota.</p><a class="button-link" href="/control/connection?${query.toString()}">${connection.state === "connected" ? "Manage connection" : "Connect account"}</a> · <a href="/control?${query.toString()}&amp;check-connection=1">Check again</a></div>`;
20
14
  }
21
15
  export function controlSetupHtml(data) {
22
16
  const { provider, inputs, task = "" } = data;
23
17
  const query = new URLSearchParams({ provider, ...(task ? { task } : {}) });
24
18
  const model = data.catalog !== null
25
19
  ? openRouterPicker(data.catalog, inputs.model || null, `/control?${query}&refresh-models=1`)
26
- : `<label>Model<input type="text" name="model" value="${escape(inputs.model)}" list="setup-models" required autocomplete="off" placeholder="Exact model id or supported alias"></label>` +
27
- `<datalist id="setup-models">${data.models.map(one => `<option value="${escape(one.value)}">${escape(one.label)}</option>`).join("")}</datalist>`;
28
- return `<h1>Project setup</h1><p>${escape(data.repo)}</p>` +
29
- `<p class="meta">Choose the default builder for new tasks and the preparation command for this project.</p>` +
30
- `<nav class="assistant-picker row" aria-label="Choose provider">${Object.keys(ASSISTANTS).map(id => `<a class="button-link" href="/control?${escape(new URLSearchParams({ provider: id, ...(task ? { task } : {}) }).toString())}"${id === provider ? ' aria-current="page"' : ""}>${ASSISTANTS[id].name}</a>`).join(" ")}</nav>` +
31
- connectionHtml(provider, data.connection, task) +
32
- `<form method="post" action="/control/setup-preview" class="card">${hiddenFields({ csrf: data.csrf, repo: data.repo, provider, task })}` + model +
33
- `<details class="setup-advanced"><summary>Project preparation</summary>` +
34
- (data.preparation === null ? "" : `<p class="meta">Suggested from ${escape(data.preparation.evidence)}: ${escape(data.preparation.label)} — <code>${escape(data.preparation.command)}</code>. Review before approving.</p>`) +
35
- `<label>Preparation command<textarea name="command" rows="2" maxlength="2000">${escape(inputs.command)}</textarea></label>` +
36
- `<label>Preparation timeout in seconds<input name="seconds" type="number" min="1" max="3600" value="${escape(inputs.seconds)}" required></label>` +
37
- `<p class="meta">Preparation applies to subsequent runs, including already approved tasks. Saving setup does not execute it.</p></details>` +
38
- `<button type="submit">Review project setup</button></form>` +
39
- `<section class="card"><h2>Agent instructions</h2>` +
40
- (data.instructions.message ? `<p>${escape(data.instructions.message)}</p>` : data.instructions.installed ? `<p>Toolroll instructions are installed.</p>` :
41
- `<p>Give the agent the project's Toolroll handoff instructions.</p><form method="post" action="/control/instructions-preview">${hiddenFields({ csrf: data.csrf, repo: data.repo })}<button>Review instructions</button></form>`) +
42
- `</section><p><a href="/fleet">Configure planning, repair, and review agents</a> · <a href="/tasks/new">Describe a task</a></p>`;
20
+ : html `<label>Model<input type="text" name="model" value="${inputs.model}" list="setup-models" required autocomplete="off" placeholder="Exact model id or supported alias"></label><datalist id="setup-models">${data.models.map(one => html `<option value="${one.value}">${one.label}</option>`)}</datalist>`;
21
+ return html `<h1>Project setup</h1><p>${data.repo}</p><p class="meta">Choose the default builder for new tasks and the preparation command for this project.</p><nav class="assistant-picker row" aria-label="Choose provider">${joinHtml(Object.keys(ASSISTANTS).map(id => html `<a class="button-link" href="/control?${new URLSearchParams({ provider: id, ...(task ? { task } : {}) }).toString()}"${id === provider ? html ` aria-current="page"` : ""}>${ASSISTANTS[id].name}</a>`), " ")}</nav>${connectionHtml(provider, data.connection, task)}${postForm("/control/setup-preview", html `${model}<details class="setup-advanced"><summary>Project preparation</summary>${data.preparation === null ? "" : html `<p class="meta">Suggested from ${data.preparation.evidence}: ${data.preparation.label} — <code>${data.preparation.command}</code>. Review before approving.</p>`}<label>Preparation command<textarea name="command" rows="2" maxlength="2000">${inputs.command}</textarea></label><label>Preparation timeout in seconds<input name="seconds" type="number" min="1" max="3600" value="${inputs.seconds}" required></label><p class="meta">Preparation applies to subsequent runs, including already approved tasks. Saving setup does not execute it.</p></details><button type="submit">Review project setup</button>`, { attrs: { class: "card" }, hidden: { repo: data.repo, provider, task } })}<section class="card"><h2>Agent instructions</h2>${data.instructions.message ? html `<p>${data.instructions.message}</p>` : data.instructions.installed ? html `<p>Toolroll instructions are installed.</p>` :
22
+ html `<p>Give the agent the project's Toolroll handoff instructions.</p>${postForm("/control/instructions-preview", html `<button>Review instructions</button>`, { hidden: { repo: data.repo } })}`}</section><p><a href="/fleet">Configure planning, repair, and review agents</a> · <a href="/tasks/new">Describe a task</a></p>`;
43
23
  }
24
+ /** `fields` may still carry the session's csrf (a caller's habit): postForm writes the one CSRF field. */
44
25
  export function setupPreviewHtml(inputs, fields) {
45
- return `<h1>Approve project setup</h1><div class="card"><p>${escape(fields.repo ?? "")}</p>` +
46
- `<p><strong>Builder:</strong> ${escape(inputs.provider)} · ${escape(inputs.model)}</p>` +
47
- `<p><strong>Preparation:</strong></p><pre class="recap">${escape(inputs.command || "No preparation command")}</pre>` +
48
- `<p>Preparation timeout: ${escape(inputs.seconds)} seconds.</p>` +
49
- `<p>The builder default applies to new tasks. Preparation applies to subsequent runs, including already approved tasks. Existing signed task settings and verification rules remain in force.</p>` +
50
- `<form method="post" action="/control/setup-approve">${hiddenFields({ ...fields, ...inputs })}` +
51
- `<label>Your password<input type="password" name="token" autocomplete="current-password" required></label>` +
52
- `<button>Approve project setup</button></form></div>`;
26
+ const { csrf: _csrf, ...rest } = fields;
27
+ return html `<h1>Approve project setup</h1><div class="card"><p>${fields.repo ?? ""}</p><p><strong>Builder:</strong> ${inputs.provider} · ${inputs.model}</p><p><strong>Preparation:</strong></p><pre class="recap">${inputs.command || "No preparation command"}</pre><p>Preparation timeout: ${inputs.seconds} seconds.</p><p>The builder default applies to new tasks. Preparation applies to subsequent runs, including already approved tasks. Existing signed task settings and verification rules remain in force.</p>${postForm("/control/setup-approve", html `<label>Your password<input type="password" name="token" autocomplete="current-password" required></label><button>Approve project setup</button>`, { hidden: { ...rest, ...inputs } })}</div>`;
53
28
  }
@@ -142,15 +142,15 @@ export type ProviderAnswer = {
142
142
  * ruling 14): a negative, fractional, or absurd usage is a malformed reply,
143
143
  * never a discount on the pinned settlement. */
144
144
  export declare function tokenCount(value: number): boolean;
145
- export declare const MATE_MAX_STEPS = 8;
146
- export declare const MATE_MAX_CALLS_PER_STEP = 4;
145
+ export declare const LEAD_MAX_STEPS = 8;
146
+ export declare const LEAD_MAX_CALLS_PER_STEP = 4;
147
147
  /** A tool result, measured AS EMBEDDED — the JSON-encoded string, escapes included. */
148
- export declare const MATE_TOOL_RESULT_CAP_BYTES = 16384;
148
+ export declare const LEAD_TOOL_RESULT_CAP_BYTES = 16384;
149
149
  /** A tool call, measured as the serialized `{id, name, args}` — the id counts. */
150
- export declare const MATE_TOOL_CALL_CAP_BYTES = 2048;
151
- export declare const MATE_TOOL_CALL_ID_CAP_BYTES = 64;
150
+ export declare const LEAD_TOOL_CALL_CAP_BYTES = 2048;
151
+ export declare const LEAD_TOOL_CALL_ID_CAP_BYTES = 64;
152
152
  /** One step's assistant text; over it the reply is malformed (review finding 7). */
153
- export declare const MATE_STEP_TEXT_CAP_BYTES = 8192;
153
+ export declare const LEAD_STEP_TEXT_CAP_BYTES = 8192;
154
154
  /**
155
155
  * The triangular worst case (mate arc, ruling 6; slice-1 review finding 7):
156
156
  * request s carries the base prompt plus every earlier step's calls,
@@ -160,7 +160,7 @@ export declare const MATE_STEP_TEXT_CAP_BYTES = 8192;
160
160
  * body), so each is budgeted at twice its cap — escaping at most doubles
161
161
  * a string. Each step may answer with the full output allowance.
162
162
  */
163
- export declare function mateWorstCaseForPrice(price: ModelPrice, baseBytes: number, caps?: {
163
+ export declare function leadWorstCaseForPrice(price: ModelPrice, baseBytes: number, caps?: {
164
164
  steps?: number;
165
165
  callsPerStep?: number;
166
166
  resultCap?: number;
@@ -169,32 +169,32 @@ export declare function mateWorstCaseForPrice(price: ModelPrice, baseBytes: numb
169
169
  }): number;
170
170
  /** The bytes a tool result costs on the wire: its JSON string form. */
171
171
  export declare function embeddedBytes(text: string): number;
172
- export type MateToolSchema = {
172
+ export type LeadToolSchema = {
173
173
  name: string;
174
174
  description: string;
175
175
  inputSchema: Record<string, unknown>;
176
176
  };
177
- export type MateToolCall = {
177
+ export type LeadToolCall = {
178
178
  id: string;
179
179
  name: string;
180
180
  args: Record<string, unknown>;
181
181
  };
182
182
  /** A provider answer with tool calls allowed: text, calls, usage. */
183
- export type MateProviderAnswer = {
183
+ export type LeadProviderAnswer = {
184
184
  text: string;
185
- calls: MateToolCall[];
185
+ calls: LeadToolCall[];
186
186
  tokensIn: number;
187
187
  tokensOut: number;
188
188
  reportedCostMicrousd: number | null;
189
189
  };
190
- /** One message of the mate's own history, provider-neutral. */
191
- export type MateHistoryMessage = {
190
+ /** One message of the lead's own history, provider-neutral. */
191
+ export type LeadHistoryMessage = {
192
192
  role: "operator";
193
193
  text: string;
194
194
  } | {
195
195
  role: "assistant";
196
196
  text: string;
197
- calls: MateToolCall[];
197
+ calls: LeadToolCall[];
198
198
  } | {
199
199
  role: "tool";
200
200
  callId: string;
@@ -207,36 +207,36 @@ export type MateHistoryMessage = {
207
207
  * most M per answer, each argument object under the call cap), and
208
208
  * anything else about the shape is malformed.
209
209
  */
210
- export declare function parseMateProviderWrapper(provider: DirectChatProviderId, bytes: Buffer): {
210
+ export declare function parseLeadProviderWrapper(provider: DirectChatProviderId, bytes: Buffer): {
211
211
  ok: true;
212
- answer: MateProviderAnswer;
212
+ answer: LeadProviderAnswer;
213
213
  } | {
214
214
  ok: false;
215
215
  problem: string;
216
216
  };
217
- /** The mate's request: system contract, the data document as the first
217
+ /** The lead's request: system contract, the data document as the first
218
218
  * operator message, the history in provider-native shape, the tools. */
219
- export declare function composeMateRequest(args: {
219
+ export declare function composeLeadRequest(args: {
220
220
  provider: DirectChatProviderId;
221
221
  model: string;
222
222
  key: string;
223
223
  system: string;
224
224
  dataDocument: string;
225
- history: readonly MateHistoryMessage[];
226
- tools: readonly MateToolSchema[];
225
+ history: readonly LeadHistoryMessage[];
226
+ tools: readonly LeadToolSchema[];
227
227
  }): {
228
228
  url: string;
229
229
  headers: Record<string, string>;
230
230
  body: string;
231
231
  };
232
- /** The mate's network call: the same transport posture as fleet chat's, the tool-capable parser at the end. */
233
- export declare function performMateRequest(request: {
232
+ /** The lead's network call: the same transport posture as fleet chat's, the tool-capable parser at the end. */
233
+ export declare function performLeadRequest(request: {
234
234
  url: string;
235
235
  headers: Record<string, string>;
236
236
  body: string;
237
237
  }, provider: DirectChatProviderId, signal: AbortSignal, fetcher?: typeof fetch): Promise<{
238
238
  ok: true;
239
- answer: MateProviderAnswer;
239
+ answer: LeadProviderAnswer;
240
240
  } | {
241
241
  ok: false;
242
242
  problem: string;
package/dist/converse.js CHANGED
@@ -357,16 +357,16 @@ export function parseAssistantEnvelope(text) {
357
357
  export function tokenCount(value) {
358
358
  return Number.isSafeInteger(value) && value >= 0 && value <= 1_000_000_000;
359
359
  }
360
- // ---------------------------------------------------------------- the mate
361
- export const MATE_MAX_STEPS = 8;
362
- export const MATE_MAX_CALLS_PER_STEP = 4;
360
+ // ---------------------------------------------------------------- the lead
361
+ export const LEAD_MAX_STEPS = 8;
362
+ export const LEAD_MAX_CALLS_PER_STEP = 4;
363
363
  /** A tool result, measured AS EMBEDDED — the JSON-encoded string, escapes included. */
364
- export const MATE_TOOL_RESULT_CAP_BYTES = 16_384;
364
+ export const LEAD_TOOL_RESULT_CAP_BYTES = 16_384;
365
365
  /** A tool call, measured as the serialized `{id, name, args}` — the id counts. */
366
- export const MATE_TOOL_CALL_CAP_BYTES = 2_048;
367
- export const MATE_TOOL_CALL_ID_CAP_BYTES = 64;
366
+ export const LEAD_TOOL_CALL_CAP_BYTES = 2_048;
367
+ export const LEAD_TOOL_CALL_ID_CAP_BYTES = 64;
368
368
  /** One step's assistant text; over it the reply is malformed (review finding 7). */
369
- export const MATE_STEP_TEXT_CAP_BYTES = 8_192;
369
+ export const LEAD_STEP_TEXT_CAP_BYTES = 8_192;
370
370
  /**
371
371
  * The triangular worst case (mate arc, ruling 6; slice-1 review finding 7):
372
372
  * request s carries the base prompt plus every earlier step's calls,
@@ -376,12 +376,12 @@ export const MATE_STEP_TEXT_CAP_BYTES = 8_192;
376
376
  * body), so each is budgeted at twice its cap — escaping at most doubles
377
377
  * a string. Each step may answer with the full output allowance.
378
378
  */
379
- export function mateWorstCaseForPrice(price, baseBytes, caps = {}) {
380
- const S = caps.steps ?? MATE_MAX_STEPS;
381
- const M = caps.callsPerStep ?? MATE_MAX_CALLS_PER_STEP;
382
- const R = caps.resultCap ?? MATE_TOOL_RESULT_CAP_BYTES;
383
- const C = caps.callCap ?? MATE_TOOL_CALL_CAP_BYTES;
384
- const T = caps.textCap ?? MATE_STEP_TEXT_CAP_BYTES;
379
+ export function leadWorstCaseForPrice(price, baseBytes, caps = {}) {
380
+ const S = caps.steps ?? LEAD_MAX_STEPS;
381
+ const M = caps.callsPerStep ?? LEAD_MAX_CALLS_PER_STEP;
382
+ const R = caps.resultCap ?? LEAD_TOOL_RESULT_CAP_BYTES;
383
+ const C = caps.callCap ?? LEAD_TOOL_CALL_CAP_BYTES;
384
+ const T = caps.textCap ?? LEAD_STEP_TEXT_CAP_BYTES;
385
385
  const tokens = (bytes) => Math.ceil(bytes / 3);
386
386
  let input = 0;
387
387
  for (let s = 1; s <= S; s++) {
@@ -399,7 +399,7 @@ export function embeddedBytes(text) {
399
399
  * most M per answer, each argument object under the call cap), and
400
400
  * anything else about the shape is malformed.
401
401
  */
402
- export function parseMateProviderWrapper(provider, bytes) {
402
+ export function parseLeadProviderWrapper(provider, bytes) {
403
403
  const parsed = strictJsonParse(bytes, WRAPPER_CAP_BYTES, 14);
404
404
  if (!parsed.ok)
405
405
  return { ok: false, problem: parsed.problem };
@@ -408,9 +408,9 @@ export function parseMateProviderWrapper(provider, bytes) {
408
408
  return { ok: false, problem: "not-an-object" };
409
409
  const readArgs = (raw) => {
410
410
  const text = typeof raw === "string" ? raw : JSON.stringify(raw ?? null);
411
- if (Buffer.byteLength(text, "utf8") > MATE_TOOL_CALL_CAP_BYTES)
411
+ if (Buffer.byteLength(text, "utf8") > LEAD_TOOL_CALL_CAP_BYTES)
412
412
  return null;
413
- const inner = strictJsonParse(Buffer.from(text, "utf8"), MATE_TOOL_CALL_CAP_BYTES, 6);
413
+ const inner = strictJsonParse(Buffer.from(text, "utf8"), LEAD_TOOL_CALL_CAP_BYTES, 6);
414
414
  if (!inner.ok || typeof inner.value !== "object" || inner.value === null || Array.isArray(inner.value))
415
415
  return null;
416
416
  return inner.value;
@@ -418,7 +418,7 @@ export function parseMateProviderWrapper(provider, bytes) {
418
418
  // A call is bounded WHOLE (finding 7): the id is repeated in the assistant
419
419
  // block and the result, so it is capped and counted inside the call cap.
420
420
  const readCall = (id, name, rawArgs) => {
421
- if (typeof id !== "string" || id === "" || Buffer.byteLength(id, "utf8") > MATE_TOOL_CALL_ID_CAP_BYTES)
421
+ if (typeof id !== "string" || id === "" || Buffer.byteLength(id, "utf8") > LEAD_TOOL_CALL_ID_CAP_BYTES)
422
422
  return null;
423
423
  if (typeof name !== "string" || name === "" || name.length > 64)
424
424
  return null;
@@ -426,7 +426,7 @@ export function parseMateProviderWrapper(provider, bytes) {
426
426
  if (args === null)
427
427
  return null;
428
428
  const call = { id, name, args };
429
- if (Buffer.byteLength(JSON.stringify(call), "utf8") > MATE_TOOL_CALL_CAP_BYTES)
429
+ if (Buffer.byteLength(JSON.stringify(call), "utf8") > LEAD_TOOL_CALL_CAP_BYTES)
430
430
  return null;
431
431
  return call;
432
432
  };
@@ -447,7 +447,7 @@ export function parseMateProviderWrapper(provider, bytes) {
447
447
  if (body["type"] !== "message")
448
448
  return { ok: false, problem: "wrong-type" };
449
449
  const content = body["content"];
450
- if (!Array.isArray(content) || content.length === 0 || content.length > MATE_MAX_CALLS_PER_STEP + 1)
450
+ if (!Array.isArray(content) || content.length === 0 || content.length > LEAD_MAX_CALLS_PER_STEP + 1)
451
451
  return { ok: false, problem: "bad-content" };
452
452
  let text = "";
453
453
  const calls = [];
@@ -468,9 +468,9 @@ export function parseMateProviderWrapper(provider, bytes) {
468
468
  return { ok: false, problem: "bad-block" };
469
469
  }
470
470
  }
471
- if (calls.length > MATE_MAX_CALLS_PER_STEP)
471
+ if (calls.length > LEAD_MAX_CALLS_PER_STEP)
472
472
  return { ok: false, problem: "too-many-calls" };
473
- if (Buffer.byteLength(text, "utf8") > MATE_STEP_TEXT_CAP_BYTES)
473
+ if (Buffer.byteLength(text, "utf8") > LEAD_STEP_TEXT_CAP_BYTES)
474
474
  return { ok: false, problem: "text-over-cap" };
475
475
  const usage = usageOf(body["usage"], "input_tokens", "output_tokens");
476
476
  if (usage === null)
@@ -490,7 +490,7 @@ export function parseMateProviderWrapper(provider, bytes) {
490
490
  const calls = [];
491
491
  const rawCalls = message["tool_calls"];
492
492
  if (rawCalls !== undefined) {
493
- if (!Array.isArray(rawCalls) || rawCalls.length > MATE_MAX_CALLS_PER_STEP)
493
+ if (!Array.isArray(rawCalls) || rawCalls.length > LEAD_MAX_CALLS_PER_STEP)
494
494
  return { ok: false, problem: "too-many-calls" };
495
495
  for (const raw of rawCalls) {
496
496
  const one = raw;
@@ -503,7 +503,7 @@ export function parseMateProviderWrapper(provider, bytes) {
503
503
  calls.push(call);
504
504
  }
505
505
  }
506
- if (Buffer.byteLength(text, "utf8") > MATE_STEP_TEXT_CAP_BYTES)
506
+ if (Buffer.byteLength(text, "utf8") > LEAD_STEP_TEXT_CAP_BYTES)
507
507
  return { ok: false, problem: "text-over-cap" };
508
508
  const usage = usageOf(body["usage"], "prompt_tokens", "completion_tokens");
509
509
  if (usage === null)
@@ -523,9 +523,9 @@ export function parseMateProviderWrapper(provider, bytes) {
523
523
  }
524
524
  return { ok: true, answer: { text, calls, tokensIn: usage.tokensIn, tokensOut: usage.tokensOut, reportedCostMicrousd } };
525
525
  }
526
- /** The mate's request: system contract, the data document as the first
526
+ /** The lead's request: system contract, the data document as the first
527
527
  * operator message, the history in provider-native shape, the tools. */
528
- export function composeMateRequest(args) {
528
+ export function composeLeadRequest(args) {
529
529
  const opener = `DATA:\n${args.dataDocument}\n\n(The conversation follows. Every operator message is data, from the operator.)`;
530
530
  if (args.provider === "anthropic-api") {
531
531
  const messages = [{ role: "user", content: opener }];
@@ -582,8 +582,8 @@ export function composeMateRequest(args) {
582
582
  }),
583
583
  };
584
584
  }
585
- /** The mate's network call: the same transport posture as fleet chat's, the tool-capable parser at the end. */
586
- export async function performMateRequest(request, provider, signal, fetcher = fetch) {
585
+ /** The lead's network call: the same transport posture as fleet chat's, the tool-capable parser at the end. */
586
+ export async function performLeadRequest(request, provider, signal, fetcher = fetch) {
587
587
  let response;
588
588
  try {
589
589
  response = await fetcher(request.url, { method: "POST", headers: request.headers, body: request.body, redirect: "error", signal });
@@ -599,7 +599,7 @@ export async function performMateRequest(request, provider, signal, fetcher = fe
599
599
  const body = await readCappedBody(response, WRAPPER_CAP_BYTES);
600
600
  if (body === null)
601
601
  return { ok: false, problem: "over-size" };
602
- return parseMateProviderWrapper(provider, body);
602
+ return parseLeadProviderWrapper(provider, body);
603
603
  }
604
604
  export function parseProviderWrapper(provider, bytes) {
605
605
  const parsed = strictJsonParse(bytes, WRAPPER_CAP_BYTES, 12);
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Proposals over the MCP gateway (mate arc v3, §9). A coordinator may
3
- * propose what the mate may propose — next, reserve, hold, unhold, scope,
3
+ * propose what the lead may propose — next, reserve, hold, unhold, scope,
4
4
  * cancel, answer — and a row is all it writes: any approver whose ceiling
5
5
  * admits the repo confirms it through `confirmCoordinatorProposal`. The
6
6
  * token re-authenticates INSIDE the transaction (the session's `who` is a
7
7
  * courtesy, exactly as for filing); the proposal counts against the
8
8
  * credential's hourly filing rate and a per-credential pending cap; the
9
- * payload carries the same CAS material the mate's does, so a stale row
9
+ * payload carries the same CAS material the lead's does, so a stale row
10
10
  * refuses at the door in the same words.
11
11
  */
12
12
  import type { CoordinatorProposalKind, Store } from "./store.js";
@@ -1,6 +1,6 @@
1
1
  import { TASK_TEXT_LIMITS, validateScopeText } from "./task-text.js";
2
2
  import { authenticateCoordinator } from "./coordinator.js";
3
- import { decisionOver, honestText, readTouches, readAcceptanceArg } from "./mate-tools.js";
3
+ import { decisionOver, honestText, readTouches, readAcceptanceArg } from "./lead-tools.js";
4
4
  export const PER_CID_PENDING_PROPOSALS = 20;
5
5
  const TASK_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
6
6
  /** The coordinator's proposal as a row; the shape of `args` is the MCP tool's. */
@@ -18,7 +18,7 @@ import { createHash, randomBytes } from "node:crypto";
18
18
  import { canonicalRepos } from "./runner.js";
19
19
  import { fileTaskProposal } from "./proposal.js";
20
20
  import { describeScope } from "./scope.js";
21
- import { reportSummaryFor } from "./mate-tools.js";
21
+ import { reportSummaryFor } from "./lead-tools.js";
22
22
  import { taskWorkSummaryOf } from "./work-summary.js";
23
23
  import { assignmentOf, assignmentBrief } from "./assignment.js";
24
24
  /** Module-private: the ONLY maker, reachable only through the token
@@ -4,6 +4,7 @@
4
4
  * can see and end everyone's.
5
5
  */
6
6
  import type { ApiTokenRow, WebSessionRow } from "./store.js";
7
+ import { type Html } from "./html.js";
7
8
  export declare const CREDENTIALS_CSS: string;
8
9
  /** "Chrome on macOS", from a user agent, for a person to recognise a session. */
9
10
  export declare function deviceWords(agent: string | null): string;
@@ -19,12 +20,12 @@ export type CredentialsView = {
19
20
  /** Request limits (request-budget-ui.ts): words for each token's line, and the operator's disclosure. */
20
21
  limits?: {
21
22
  note: (token: ApiTokenRow) => string;
22
- section: string;
23
+ section: Html;
23
24
  };
24
25
  };
25
- export declare function credentialsHtml(view: CredentialsView, csrf: string, notice: {
26
+ export declare function credentialsHtml(view: CredentialsView, notice: {
26
27
  said?: string | null;
27
28
  problem?: string | null;
28
- }): string;
29
+ }): Html;
29
30
  /** The token, once: a focused page with no script. */
30
- export declare function tokenShownHtml(name: string, token: string, access: "read" | "act", expiresAt: string): string;
31
+ export declare function tokenShownHtml(name: string, token: string, access: "read" | "act", expiresAt: string): Html;
@@ -1,6 +1,6 @@
1
1
  import { daysLeft, expiryNoticeDue, TOKEN_DAYS, tokenLive } from "./api-tokens.js";
2
2
  import { projectName } from "./project.js";
3
- const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
3
+ import { html, postForm } from "./html.js";
4
4
  export const CREDENTIALS_CSS = `.credentials{max-width:820px;min-width:0}.credentials .card{padding:14px 16px;margin:12px 0}.credentials h2{font-size:1.05rem;margin:0 0 8px}` +
5
5
  `.credentials .rows{display:grid;gap:0;border:1px solid var(--so-line);border-radius:10px;overflow:hidden}.credentials .row-item{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border-bottom:1px solid var(--so-line)}` +
6
6
  `.credentials .row-item:last-child{border-bottom:0}.credentials .row-item p{margin:0}.credentials .row-item .meta{font-size:.85rem}.credentials form{margin:0}.credentials button{min-height:40px;white-space:nowrap}` +
@@ -22,39 +22,38 @@ const when = (value, now) => {
22
22
  const minutes = Math.round((now - at) / 60_000);
23
23
  return minutes < 1 ? "just now" : minutes < 60 ? `${minutes} min ago` : minutes < 60 * 24 ? `${Math.round(minutes / 60)} h ago` : new Date(at).toISOString().slice(0, 10);
24
24
  };
25
- export function credentialsHtml(view, csrf, notice) {
26
- const hidden = (fields) => Object.entries(fields).map(([k, v]) => `<input type="hidden" name="${e(k)}" value="${e(v)}">`).join("");
27
- const post = (fields, label, style = "secondary") => `<form method="post" action="/settings/sessions">${hidden({ csrf, ...fields, ...(view.everyone ? { everyone: "1" } : {}) })}<button class="${style}">${label}</button></form>`;
28
- const note = notice.problem ? `<p class="problem" role="alert">${e(notice.problem)}</p>` : notice.said ? `<p role="status">${e(notice.said)}</p>` : "";
29
- const toggle = view.canSeeEveryone ? `<p class="meta"><a href="/settings/sessions${view.everyone ? "" : "?everyone=1"}">${view.everyone ? "Show only mine" : "Show everyone's"}</a></p>` : "";
30
- const sessions = view.sessions.length === 0 ? `<p class="meta">No one else is signed in.</p>` : `<div class="rows">${view.sessions.map(one => `<div class="row-item" data-session="${e(one.idHash.slice(0, 12))}"><div><p>${view.everyone ? `<strong>${e(one.account)}</strong> · ` : ""}${e(deviceWords(one.agent))}${one.here ? `<span class="badge-here">This browser</span>` : ""}</p>` +
31
- `<p class="meta">${one.ssoAt === null ? "Password" : "Identity provider"} · ${e(one.address ?? "unknown address")} · active ${e(when(one.lastSeen, view.now))} · signed in ${e(when(one.createdAt, view.now))}</p></div>` +
32
- `${one.here ? "" : post({ action: "end-session", session: one.idHash }, "Sign out")}</div>`).join("")}</div>`;
25
+ export function credentialsHtml(view, notice) {
26
+ const post = (fields, label, style = "secondary") => postForm("/settings/sessions", html `<button class="${style}">${label}</button>`, { hidden: { ...fields, ...(view.everyone ? { everyone: "1" } : {}) } });
27
+ const note = notice.problem ? html `<p class="problem" role="alert">${notice.problem}</p>` : notice.said ? html `<p role="status">${notice.said}</p>` : "";
28
+ const toggle = view.canSeeEveryone ? html `<p class="meta"><a href="/settings/sessions${view.everyone ? "" : "?everyone=1"}">${view.everyone ? "Show only mine" : "Show everyone's"}</a></p>` : "";
29
+ const sessions = view.sessions.length === 0 ? html `<p class="meta">No one else is signed in.</p>` : html `<div class="rows">${view.sessions.map(one => html `<div class="row-item" data-session="${one.idHash.slice(0, 12)}"><div><p>${view.everyone ? html `<strong>${one.account}</strong> · ` : ""}${deviceWords(one.agent)}${one.here ? html `<span class="badge-here">This browser</span>` : ""}</p>\
30
+ <p class="meta">${one.ssoAt === null ? "Password" : "Identity provider"} · ${one.address ?? "unknown address"} · active ${when(one.lastSeen, view.now)} · signed in ${when(one.createdAt, view.now)}</p></div>\
31
+ ${one.here ? "" : post({ action: "end-session", session: one.idHash }, "Sign out")}</div>`)}</div>`;
33
32
  const others = view.sessions.filter(one => !one.here && one.account === view.who).length;
34
33
  const endOthers = others > 0 && !view.everyone ? post({ action: "end-others" }, `Sign out everywhere else (${others})`) : "";
35
34
  const live = view.tokens.filter(one => tokenLive(one, view.now));
36
35
  // v111: its projects, and one state: when it stops (soon, said once and marked) or, once replaced, when it ends.
37
36
  const ends = (one) => {
38
37
  if (one.replacedBy !== null && one.overlapUntil !== null)
39
- return `<span class="soon">Replaced · stops ${e(one.overlapUntil.slice(11, 16))} UTC</span>`;
38
+ return html `<span class="soon">Replaced · stops ${one.overlapUntil.slice(11, 16)} UTC</span>`;
40
39
  if (expiryNoticeDue(one, view.now) === null)
41
- return `Expires ${e(one.expiresAt.slice(0, 10))}`;
40
+ return html `Expires ${one.expiresAt.slice(0, 10)}`;
42
41
  const days = daysLeft(one.expiresAt, view.now);
43
- return `<span class="soon">Expires ${days <= 1 ? "within a day" : `in ${days} days`}</span>`;
42
+ return html `<span class="soon">Expires ${days <= 1 ? "within a day" : `in ${days} days`}</span>`;
44
43
  };
45
- const scope = (one) => one.projects === null ? "All projects" : one.projects.length === 0 ? "No projects" : one.projects.map(repo => e(projectName(repo))).join(", ");
46
- const tokens = live.length === 0 ? `<p class="meta">No API tokens.</p>` : `<div class="rows">${live.map(one => `<div class="row-item" data-token="${e(one.id)}"><div><p>${view.everyone ? `<strong>${e(one.account)}</strong> · ` : ""}${e(one.name)} · ${one.access === "act" ? "Can act" : "Read only"}</p>` +
47
- `<p class="meta">${scope(one)} · ${ends(one)} · last used ${e(when(one.lastUsedAt, view.now))}${view.limits === undefined ? "" : ` · ${e(view.limits.note(one))}`}</p></div>${post({ action: "revoke-token", token: one.id }, "Revoke")}</div>`).join("")}</div>`;
48
- const create = `<details class="card"><summary>New API token</summary><form method="post" action="/settings/sessions" class="create">${hidden({ csrf, action: "create-token" })}` +
49
- `<label>Name<input type="text" name="name" maxlength="60" required placeholder="for example: CI"></label>` +
50
- `<label>It can<select name="access"><option value="read">Read (tasks, results, the ledger)</option><option value="act">Act as you (file and manage work; never approve)</option></select></label>` +
51
- `<label>Expires in<select name="days">${TOKEN_DAYS.map(days => `<option value="${days}"${days === 90 ? " selected" : ""}>${days} days</option>`).join("")}</select></label>` +
52
- `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label><button>Make the token</button></form></details>`;
53
- return `<section class="credentials">${note}${toggle}<h2>Signed in</h2>${sessions}${endOthers}<h2 style="margin-top:1.5rem">API tokens</h2>` +
54
- `<p class="meta">For scripts and CI: send <code>Authorization: Bearer &lt;token&gt;</code>. A token can't approve anything.</p>${tokens}${view.everyone ? "" : create}${view.limits?.section ?? ""}</section>`;
44
+ const scope = (one) => one.projects === null ? "All projects" : one.projects.length === 0 ? "No projects" : one.projects.map(repo => projectName(repo)).join(", ");
45
+ const tokens = live.length === 0 ? html `<p class="meta">No API tokens.</p>` : html `<div class="rows">${live.map(one => html `<div class="row-item" data-token="${one.id}"><div><p>${view.everyone ? html `<strong>${one.account}</strong> · ` : ""}${one.name} · ${one.access === "act" ? "Can act" : "Read only"}</p>\
46
+ <p class="meta">${scope(one)} · ${ends(one)} · last used ${when(one.lastUsedAt, view.now)}${view.limits === undefined ? "" : ` · ${view.limits.note(one)}`}</p></div>${post({ action: "revoke-token", token: one.id }, "Revoke")}</div>`)}</div>`;
47
+ const create = html `<details class="card"><summary>New API token</summary>${postForm("/settings/sessions", html `\
48
+ <label>Name<input type="text" name="name" maxlength="60" required placeholder="for example: CI"></label>\
49
+ <label>It can<select name="access"><option value="read">Read (tasks, results, the ledger)</option><option value="act">Act as you (file and manage work; never approve)</option></select></label>\
50
+ <label>Expires in<select name="days">${TOKEN_DAYS.map(days => html `<option value="${days}"${days === 90 ? " selected" : ""}>${days} days</option>`)}</select></label>\
51
+ <label>Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label><button>Make the token</button>`, { attrs: { class: "create" }, hidden: { action: "create-token" } })}</details>`;
52
+ return html `<section class="credentials">${note}${toggle}<h2>Signed in</h2>${sessions}${endOthers}<h2 style="margin-top:1.5rem">API tokens</h2>\
53
+ <p class="meta">For scripts and CI: send <code>Authorization: Bearer &lt;token&gt;</code>. A token can't approve anything.</p>${tokens}${view.everyone ? "" : create}${view.limits?.section ?? ""}</section>`;
55
54
  }
56
55
  /** The token, once: a focused page with no script. */
57
56
  export function tokenShownHtml(name, token, access, expiresAt) {
58
- return `<h1>${e(name)}</h1><div class="card"><p>Your API token, shown once. Only a hash is kept, so copy it now.</p><p class="mono secret-value">${e(token)}</p>` +
59
- `<p class="meta">${access === "act" ? "It acts as you (never approves)" : "It reads"} until ${e(expiresAt.slice(0, 10))}. Revoke it any time on Sessions &amp; tokens.</p></div><p class="meta"><a href="/settings/sessions">Back to Sessions &amp; tokens</a></p>`;
57
+ return html `<h1>${name}</h1><div class="card"><p>Your API token, shown once. Only a hash is kept, so copy it now.</p><p class="mono secret-value">${token}</p>\
58
+ <p class="meta">${access === "act" ? "It acts as you (never approves)" : "It reads"} until ${expiresAt.slice(0, 10)}. Revoke it any time on Sessions &amp; tokens.</p></div><p class="meta"><a href="/settings/sessions">Back to Sessions &amp; tokens</a></p>`;
60
59
  }
@@ -1,3 +1,4 @@
1
+ import { type Html } from "./html.js";
1
2
  import type { DemoExchange } from "./demo.js";
2
3
  /** What a finished exchange's stored result holds, read back from its evidence. */
3
4
  export type DemoResultView = {
@@ -17,14 +18,13 @@ export type DemoResultView = {
17
18
  taskHref: string;
18
19
  };
19
20
  /** The conversation itself; the live script swaps this region in place. */
20
- export declare function demoThreadHtml(exchanges: readonly DemoExchange[], csrf: string, resultOf: (exchange: DemoExchange) => DemoResultView | null): string;
21
+ export declare function demoThreadHtml(exchanges: readonly DemoExchange[], resultOf: (exchange: DemoExchange) => DemoResultView | null): Html;
21
22
  export declare function demoChatHtml(input: {
22
23
  exchanges: readonly DemoExchange[];
23
- csrf: string;
24
24
  version: number;
25
25
  problem: string | null;
26
26
  resultOf: (exchange: DemoExchange) => DemoResultView | null;
27
- }): string;
27
+ }): Html;
28
28
  /**
29
29
  * Keeps a running build live: polls while one is working and swaps the
30
30
  * thread in place, unless the visitor is typing inside it. Enter sends.