toolroll 0.9.55 → 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 (200) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +24 -8
  3. package/dist/action-ledger.d.ts +2 -4
  4. package/dist/action-ledger.js +2 -10
  5. package/dist/approval-policy.d.ts +5 -5
  6. package/dist/approval-policy.js +4 -4
  7. package/dist/approval-rules-ui.js +2 -2
  8. package/dist/browser/workspace.js +5 -5
  9. package/dist/browser-workspace.d.ts +12 -12
  10. package/dist/budget-alerts.js +3 -3
  11. package/dist/chat-actions.d.ts +23 -18
  12. package/dist/chat-actions.js +110 -88
  13. package/dist/chat-ask.d.ts +2 -2
  14. package/dist/chat-ask.js +5 -5
  15. package/dist/chat-channel.d.ts +15 -15
  16. package/dist/chat-channel.js +20 -20
  17. package/dist/chat-controls.d.ts +0 -4
  18. package/dist/chat-controls.js +0 -1
  19. package/dist/chat-core.js +1 -1
  20. package/dist/chat-delivery-state.js +2 -2
  21. package/dist/chat-delivery.d.ts +2 -2
  22. package/dist/chat-delivery.js +27 -34
  23. package/dist/chat-flow.js +3 -3
  24. package/dist/chat-messages.d.ts +1 -1
  25. package/dist/chat-messages.js +4 -4
  26. package/dist/chat-migration.d.ts +1 -1
  27. package/dist/chat-migration.js +11 -11
  28. package/dist/chat-rooms.js +3 -3
  29. package/dist/chat-warmth.d.ts +2 -2
  30. package/dist/cli.d.ts +1 -1
  31. package/dist/cli.js +6 -7
  32. package/dist/contracts/chat-actions.d.ts +32 -27
  33. package/dist/contracts/chat-actions.js +29 -11
  34. package/dist/contracts/chat-content.d.ts +1 -1
  35. package/dist/contracts/chat-content.js +1 -1
  36. package/dist/contracts/chat-tables.js +4 -4
  37. package/dist/contracts/console-api.d.ts +6 -6
  38. package/dist/contracts/console-api.js +7 -7
  39. package/dist/contracts/flow-propose.d.ts +3 -3
  40. package/dist/contracts/flow.d.ts +132 -125
  41. package/dist/contracts/flow.js +27 -12
  42. package/dist/contracts/lead-context.d.ts +1 -1
  43. package/dist/contracts/lead-context.js +2 -2
  44. package/dist/contracts/lead-tools.d.ts +20 -18
  45. package/dist/contracts/lead-tools.js +15 -15
  46. package/dist/contracts/stage-output.d.ts +1 -1
  47. package/dist/contracts/stage-output.js +1 -1
  48. package/dist/contracts/store-json.d.ts +23 -22
  49. package/dist/contracts/store-json.js +17 -17
  50. package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
  51. package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
  52. package/dist/converse.d.ts +23 -23
  53. package/dist/converse.js +28 -28
  54. package/dist/coordinator-proposals.d.ts +2 -2
  55. package/dist/coordinator-proposals.js +1 -1
  56. package/dist/coordinator.js +1 -1
  57. package/dist/deprecations.d.ts +12 -0
  58. package/dist/deprecations.js +20 -0
  59. package/dist/desktop-update-gate.js +8 -4
  60. package/dist/desktop-update.js +6 -1
  61. package/dist/discord-chat.js +6 -6
  62. package/dist/dispatch.d.ts +1 -1
  63. package/dist/dispatch.js +1 -1
  64. package/dist/envelope.js +0 -1
  65. package/dist/export-ui.js +1 -1
  66. package/dist/export.js +7 -7
  67. package/dist/flow-engine.d.ts +2 -2
  68. package/dist/flow-engine.js +21 -21
  69. package/dist/flow-insights.d.ts +1 -1
  70. package/dist/flow-share.js +13 -8
  71. package/dist/flow-steps.d.ts +5 -5
  72. package/dist/flow-steps.js +19 -19
  73. package/dist/flow-triggers.d.ts +1 -1
  74. package/dist/flow-triggers.js +1 -1
  75. package/dist/flows-cli.js +1 -1
  76. package/dist/flows-ui.js +20 -20
  77. package/dist/flows.js +19 -19
  78. package/dist/guides.js +4 -3
  79. package/dist/invoke.js +1 -1
  80. package/dist/kits-ui.js +5 -5
  81. package/dist/kits.d.ts +12 -12
  82. package/dist/kits.js +31 -31
  83. package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
  84. package/dist/{mate-cli.js → lead-cli.js} +38 -38
  85. package/dist/lead-commitments.js +4 -4
  86. package/dist/lead-context.d.ts +2 -2
  87. package/dist/lead-context.js +9 -9
  88. package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
  89. package/dist/{mate-contract.js → lead-contract.js} +7 -6
  90. package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
  91. package/dist/{mate-doors.js → lead-doors.js} +24 -24
  92. package/dist/lead-follow.d.ts +5 -5
  93. package/dist/lead-follow.js +9 -9
  94. package/dist/lead-people.d.ts +5 -5
  95. package/dist/lead-people.js +14 -14
  96. package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
  97. package/dist/{mate-progress.js → lead-progress.js} +3 -3
  98. package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
  99. package/dist/{mate-tools.js → lead-tools.js} +109 -101
  100. package/dist/{mate.d.ts → lead.d.ts} +27 -27
  101. package/dist/{mate.js → lead.js} +102 -102
  102. package/dist/limits-ui.d.ts +1 -1
  103. package/dist/limits-ui.js +1 -1
  104. package/dist/mcp-connect.d.ts +1 -1
  105. package/dist/mcp-connect.js +3 -3
  106. package/dist/mcp-core.js +1 -1
  107. package/dist/memory-pass.d.ts +2 -2
  108. package/dist/memory-pass.js +7 -7
  109. package/dist/notification-rows.d.ts +2 -2
  110. package/dist/operate.d.ts +3 -3
  111. package/dist/operate.js +35 -34
  112. package/dist/policy.d.ts +1 -1
  113. package/dist/principal.d.ts +1 -1
  114. package/dist/principal.js +2 -2
  115. package/dist/project-delete-ui.js +1 -1
  116. package/dist/project-delete.d.ts +1 -1
  117. package/dist/project-delete.js +26 -26
  118. package/dist/project-memory.js +1 -1
  119. package/dist/project-tools.d.ts +1 -1
  120. package/dist/project-tools.js +1 -1
  121. package/dist/recipe-ui.js +1 -1
  122. package/dist/retention.js +4 -4
  123. package/dist/scope.d.ts +2 -2
  124. package/dist/scout-report.d.ts +1 -1
  125. package/dist/scout-report.js +1 -1
  126. package/dist/serve.js +40 -45
  127. package/dist/server/chat.d.ts +4 -4
  128. package/dist/server/chat.js +97 -97
  129. package/dist/server/chrome.js +3 -3
  130. package/dist/server/flows.js +69 -62
  131. package/dist/server/guards.js +3 -3
  132. package/dist/server/http.d.ts +3 -3
  133. package/dist/server/http.js +1 -1
  134. package/dist/server/live.js +6 -6
  135. package/dist/server/people-tokens.js +1 -1
  136. package/dist/server/remote.js +12 -10
  137. package/dist/server/render-chat.d.ts +30 -30
  138. package/dist/server/render-chat.js +33 -33
  139. package/dist/server/render-pages.js +2 -2
  140. package/dist/server/render-settings.d.ts +7 -0
  141. package/dist/server/render-settings.js +3 -0
  142. package/dist/server/route-table.js +9 -7
  143. package/dist/server/runtime.d.ts +13 -13
  144. package/dist/server/settings.js +14 -13
  145. package/dist/server/tasks.js +6 -5
  146. package/dist/setup-guide.d.ts +2 -2
  147. package/dist/slack-chat.d.ts +2 -2
  148. package/dist/slack-chat.js +6 -6
  149. package/dist/spend-ui.d.ts +3 -3
  150. package/dist/spend-ui.js +9 -9
  151. package/dist/spend.d.ts +14 -14
  152. package/dist/spend.js +31 -31
  153. package/dist/store-baseline.d.ts +19 -0
  154. package/dist/store-baseline.js +2873 -0
  155. package/dist/store.d.ts +197 -249
  156. package/dist/store.js +747 -3084
  157. package/dist/subagent-admin.d.ts +53 -0
  158. package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
  159. package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
  160. package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
  161. package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
  162. package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
  163. package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
  164. package/dist/{teammate-question.js → subagent-question.js} +17 -17
  165. package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
  166. package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
  167. package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
  168. package/dist/{teammate-week.js → subagent-week.js} +23 -23
  169. package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
  170. package/dist/{teammate-work.js → subagent-work.js} +50 -50
  171. package/dist/subagents-ui.d.ts +22 -0
  172. package/dist/{teammates-ui.js → subagents-ui.js} +45 -45
  173. package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
  174. package/dist/{teammates.js → subagents.js} +21 -21
  175. package/dist/subscription-chat.d.ts +13 -13
  176. package/dist/subscription-chat.js +19 -19
  177. package/dist/surface.d.ts +19 -2
  178. package/dist/surface.js +7 -31
  179. package/dist/team-cli.d.ts +1 -0
  180. package/dist/team-cli.js +14 -2
  181. package/dist/team-leads.js +13 -13
  182. package/dist/team-runtime.d.ts +2 -2
  183. package/dist/team-runtime.js +8 -8
  184. package/dist/teams-chat.js +6 -6
  185. package/dist/telegram-flow.d.ts +3 -3
  186. package/dist/telegram-flow.js +3 -3
  187. package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
  188. package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
  189. package/dist/telegram-status.js +1 -1
  190. package/dist/telegram-team.d.ts +1 -1
  191. package/dist/telegram-team.js +5 -5
  192. package/dist/telegram.d.ts +1 -1
  193. package/dist/telegram.js +9 -30
  194. package/dist/text-limits.d.ts +18 -18
  195. package/dist/text-limits.js +18 -18
  196. package/dist/toolroll-update.d.ts +8 -0
  197. package/dist/toolroll-update.js +45 -8
  198. package/package.json +1 -2
  199. package/dist/teammate-admin.d.ts +0 -53
  200. package/dist/teammates-ui.d.ts +0 -21
@@ -20,7 +20,7 @@ export declare function limitsView(windows: readonly {
20
20
  observedAt: string;
21
21
  }[], budgets: readonly BudgetState[], names: {
22
22
  project: (repo: string) => string;
23
- teammate: (id: number) => string;
23
+ subagent: (id: number) => string;
24
24
  }, now: Date): BrowserLimits | null;
25
25
  /** The same tiles for the page without scripts. */
26
26
  export declare function limitsHtml(limits: BrowserLimits | null): Html;
package/dist/limits-ui.js CHANGED
@@ -38,7 +38,7 @@ export function limitsView(windows, budgets, names, now) {
38
38
  for (const budget of budgets) {
39
39
  const over = budget.spentMicrousd >= budget.limitMicrousd;
40
40
  const name = budget.scope === "installation" ? "Everything" : budget.scope === "project" ? names.project(budget.key)
41
- : budget.scope === "teammate" ? names.teammate(Number(budget.key)) : budget.key;
41
+ : budget.scope === "subagent" ? names.subagent(Number(budget.key)) : budget.key;
42
42
  tiles.push({
43
43
  key: `budget:${budget.id}`, name, window: "Budget", value: usd(budget.spentMicrousd), unit: `of ${usd(budget.limitMicrousd)}`,
44
44
  percent: budget.percent, tone: over ? (budget.hardStop ? "danger" : "warning") : budget.percent >= 80 ? "warning" : "neutral", marks: [50, 80], href: "/spend",
@@ -159,7 +159,7 @@ export declare function finishConnect(store: Store, visit: ConnectVisit, code: s
159
159
  ok: false;
160
160
  said: string;
161
161
  }>;
162
- /** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a teammate's call). */
162
+ /** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a subagent's call). */
163
163
  export declare function refreshConnections(store: Store, repos: readonly string[], now: Date, options?: {
164
164
  fetcher?: Fetch;
165
165
  home?: string;
@@ -8,7 +8,7 @@
8
8
  * with this console's callback, and sends the person to the service to sign
9
9
  * in. The callback trades the code for tokens, which live in the tool's own
10
10
  * secrets file (never the database, never a log), and the tool joins the
11
- * project like any other: tested, listed, and given to teammates under rules.
11
+ * project like any other: tested, listed, and given to subagents under rules.
12
12
  * The worker refreshes tokens before they expire.
13
13
  */
14
14
  import { createHash, randomBytes } from "node:crypto";
@@ -382,10 +382,10 @@ export async function finishConnect(store, visit, code, now, options = {}) {
382
382
  if (options.test === false)
383
383
  return { ok: true, said: `${service.label} is connected to ${to}.` };
384
384
  const tested = await testToolOf(store, visit.repo, spec.name, now, { home, ...(options.omitEnv === undefined ? {} : { omitEnv: options.omitEnv }) });
385
- return tested?.ok ? { ok: true, said: `${service.label} is connected to ${to}: ${tested.tools.length} action${tested.tools.length === 1 ? "" : "s"}. Let a teammate use it from its page.` }
385
+ return tested?.ok ? { ok: true, said: `${service.label} is connected to ${to}: ${tested.tools.length} action${tested.tools.length === 1 ? "" : "s"}. Let a subagent use it from its page.` }
386
386
  : { ok: true, said: `${service.label} is signed in for ${to}, but its test didn't pass yet: ${tested?.problem ?? "no answer"}.` };
387
387
  }
388
- /** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a teammate's call). */
388
+ /** Keep connected services signed in: any token expiring within ten minutes is refreshed (the worker's pass, and before a subagent's call). */
389
389
  export async function refreshConnections(store, repos, now, options = {}) {
390
390
  const fetcher = options.fetcher ?? fetch, home = options.home ?? homedir();
391
391
  const report = { refreshed: 0, problems: [] };
package/dist/mcp-core.js CHANGED
@@ -17,7 +17,7 @@ import { GATEWAY_TOOL_INPUTS, GATEWAY_TOOL_OUTPUTS } from "./contracts/gateway-t
17
17
  import { reportToolOutput } from "./contracts/lead-tools.js";
18
18
  import { PACKAGE_VERSION } from "./version.js";
19
19
  import { authenticateCoordinator, fileCoordinatorProposal, statusFor, listTasksFor, taskDetailFor, } from "./coordinator.js";
20
- import { ISO_STAMP_RULE, decisionOver, decisionsOver, labelRepos, queueOver, recapOver } from "./mate-tools.js";
20
+ import { ISO_STAMP_RULE, decisionOver, decisionsOver, labelRepos, queueOver, recapOver } from "./lead-tools.js";
21
21
  import { proposeAsCoordinator } from "./coordinator-proposals.js";
22
22
  export const MODERN = "2026-07-28";
23
23
  export const LEGACY = "2025-11-25";
@@ -1,5 +1,5 @@
1
1
  import type { Store } from './store.js';
2
- import { performSubscriptionMateRequest } from './subscription-chat.js';
2
+ import { performSubscriptionLeadRequest } from './subscription-chat.js';
3
3
  import { type MemoryProposal, type Verdict } from './contracts/memory-pass.js';
4
4
  export type { MemoryProposal, Verdict };
5
5
  /** One session's trace, in characters (TEXT_LIMITS.memoryTrace). */
@@ -66,7 +66,7 @@ export declare function defaultAnalyzer(store: Store, options: {
66
66
  env?: NodeJS.ProcessEnv;
67
67
  fetcher?: typeof fetch;
68
68
  timeoutMs?: number;
69
- runner?: Parameters<typeof performSubscriptionMateRequest>[1];
69
+ runner?: Parameters<typeof performSubscriptionLeadRequest>[1];
70
70
  }): MemoryAnalyzer;
71
71
  /**
72
72
  * Read the analyser's answer with the tolerant parse-side schema, then keep only claims whose quote
@@ -17,8 +17,8 @@ import { basename, join } from 'node:path';
17
17
  import { scanForSecrets, readVerifiedArtifact } from './evidence.js';
18
18
  import { changeKnowledge, knowledgeView } from './project-knowledge.js';
19
19
  import { listDecisions, recordDecision } from './project-memory.js';
20
- import { composeMateRequest, performMateRequest, isDirectChatProvider, CHAT_KEY_ENV } from './converse.js';
21
- import { performSubscriptionMateRequest } from './subscription-chat.js';
20
+ import { composeLeadRequest, performLeadRequest, isDirectChatProvider, CHAT_KEY_ENV } from './converse.js';
21
+ import { performSubscriptionLeadRequest } from './subscription-chat.js';
22
22
  import { TEXT_LIMITS } from './text-limits.js';
23
23
  import { contractError, parseContract } from './contracts/contract.js';
24
24
  import { MEMORY_VERDICT_MODEL_SCHEMA, MEMORY_VERDICT_VERSION, memoryEvidenceSchema, memoryProposalSchema, memoryVerdictReadSchema, readSavedVerdict, savedVerdictSchema } from './contracts/memory-pass.js';
@@ -138,11 +138,11 @@ function fileSources(repo, kind, home) {
138
138
  /** The plane's own sessions: lead threads that touched the project, and finished crew runs with their handoff and check output. */
139
139
  function planeSources(store, repo, evidenceRoot) {
140
140
  const out = [];
141
- const threads = store.handle.prepare(`SELECT c.thread AS thread, c.id AS conversation, MAX(m.id) AS last, MAX(m.created_at) AS at FROM team_conversation c JOIN mate_message m ON m.thread=c.thread
141
+ const threads = store.handle.prepare(`SELECT c.thread AS thread, c.id AS conversation, MAX(m.id) AS last, MAX(m.created_at) AS at FROM team_conversation c JOIN lead_message m ON m.thread=c.thread
142
142
  WHERE EXISTS (SELECT 1 FROM json_each(c.projects_json) WHERE value=?) GROUP BY c.thread`).all(repo);
143
143
  for (const row of threads) {
144
144
  const thread = Number(row['thread']);
145
- out.push({ id: `lead:${thread}:${Number(row['last'])}`, repo, kind: 'lead', source: `conversation:${String(row['conversation'])}`, at: String(row['at']), trace: () => redact(store.handle.prepare('SELECT role,text FROM mate_message WHERE thread=? ORDER BY id LIMIT 400').all(thread).map(m => `${m['role']}: ${clip(String(m['text']), 4000)}`).join('\n')) });
145
+ out.push({ id: `lead:${thread}:${Number(row['last'])}`, repo, kind: 'lead', source: `conversation:${String(row['conversation'])}`, at: String(row['at']), trace: () => redact(store.handle.prepare('SELECT role,text FROM lead_message WHERE thread=? ORDER BY id LIMIT 400').all(thread).map(m => `${m['role']}: ${clip(String(m['text']), 4000)}`).join('\n')) });
146
146
  }
147
147
  const runs = store.handle.prepare(`SELECT r.id, r.role, r.finished_at, r.handoff, t.external_id FROM run r JOIN task_ref t ON t.id=r.task_ref WHERE t.repo=? AND r.role IN ('builder','repair') AND r.outcome IS NOT NULL ORDER BY r.id DESC LIMIT 100`).all(repo);
148
148
  for (const row of runs) {
@@ -207,12 +207,12 @@ export function defaultAnalyzer(store, options) {
207
207
  }
208
208
  if (!key)
209
209
  return { ok: false, problem: `No ${config.provider} key is available for the backward pass.` };
210
- const request = composeMateRequest({ provider: config.provider, model: config.model, key, system, dataDocument, history, tools: [] });
211
- const answer = await performMateRequest(request, config.provider, AbortSignal.timeout(options.timeoutMs ?? 120_000), options.fetcher);
210
+ const request = composeLeadRequest({ provider: config.provider, model: config.model, key, system, dataDocument, history, tools: [] });
211
+ const answer = await performLeadRequest(request, config.provider, AbortSignal.timeout(options.timeoutMs ?? 120_000), options.fetcher);
212
212
  return answer.ok ? { ok: true, text: answer.answer.text } : { ok: false, problem: answer.problem };
213
213
  }
214
214
  // The verdict's own schema is the harness's structured output, so the answer is the verdict itself.
215
- const answer = await performSubscriptionMateRequest({ provider: config.provider, model: config.model, system, dataDocument, history, tools: [], outputSchema: MEMORY_VERDICT_MODEL_SCHEMA, timeoutMs: options.timeoutMs ?? 180_000 }, options.runner);
215
+ const answer = await performSubscriptionLeadRequest({ provider: config.provider, model: config.model, system, dataDocument, history, tools: [], outputSchema: MEMORY_VERDICT_MODEL_SCHEMA, timeoutMs: options.timeoutMs ?? 180_000 }, options.runner);
216
216
  return answer.ok ? { ok: true, text: answer.answer.text } : { ok: false, problem: answer.problem };
217
217
  };
218
218
  }
@@ -1,11 +1,11 @@
1
1
  /** Saved notifications, read and told apart without a store: the row readers, the lifecycle key and the predicates
2
2
  * the store and the chat core (chat-messages.ts) share. A leaf: it imports types only. */
3
- import type { MateProposal, Notification, NotificationReceipt } from "./store.js";
3
+ import type { LeadProposal, Notification, NotificationReceipt } from "./store.js";
4
4
  /** The one task a card is about: a task its confirmation created (a new
5
5
  * task, a revision), else the task it names (and, for feedback on a result,
6
6
  * that result). Null for a card about no single task. A pointer for
7
7
  * replies, never an authority. */
8
- export declare function proposalTaskOf(proposal: MateProposal | null): {
8
+ export declare function proposalTaskOf(proposal: LeadProposal | null): {
9
9
  task: string;
10
10
  run: number | null;
11
11
  } | null;
package/dist/operate.d.ts CHANGED
@@ -7,7 +7,7 @@ import type { FetchLike } from "./flow-share.js";
7
7
  import { type Store } from "./store.js";
8
8
  import { type DispatchAdapter } from "./sync.js";
9
9
  import { type TelegramTransport } from "./telegram.js";
10
- import { type MateCliSeams } from "./mate-cli.js";
10
+ import { type LeadCliSeams } from "./lead-cli.js";
11
11
  import { type Principal, type RemoteSource } from "./operate-remote.js";
12
12
  import { type PublishExec } from "./publish.js";
13
13
  import { type Runner as CommandRunner } from "./builder.js";
@@ -71,8 +71,8 @@ export type OperateOptions = {
71
71
  flowFetch?: FetchLike;
72
72
  /** Injected by tests: how `integrations` checks reach services (fetch, gh, sign-in checks, mail servers). */
73
73
  integrationIo?: Partial<IntegrationIo>;
74
- /** Injected by tests: the mate's provider fetch, key environment, and stdin lines. */
75
- mateSeams?: MateCliSeams;
74
+ /** Injected by tests: the lead's provider fetch, key environment, and stdin lines. */
75
+ leadSeams?: LeadCliSeams;
76
76
  /** Test seam for the short indexed wait loop. */
77
77
  waitSleep?: (milliseconds: number) => Promise<void>;
78
78
  /** Injected by tests: `onboard`'s home folder, terminal and probes. */
package/dist/operate.js CHANGED
@@ -22,7 +22,7 @@ import { checkoutPlan, cleanCheckouts, discardCheckout, finishedCheckouts, slimK
22
22
  import { closeOutCheckouts, closeOutRuns, stoppedWords } from "./run-closeout.js";
23
23
  import { MIN_DAYS, RETENTION_KINDS, countWords, dailyRetention, isRetentionKind, lastSweepAt, parsePeriod, periodLabel, periodWords, retentionPlan, sweepWords } from "./retention.js";
24
24
  import { checkPolicy, parseList, policyParts } from "./policy.js";
25
- import { billingOf, budgetHoldWords, budgetLabel, budgetStates, monthNamed, monthOf, spendItems, teammateNames, usd as spendUsd } from "./spend.js";
25
+ import { billingOf, budgetHoldWords, budgetLabel, budgetStates, monthNamed, monthOf, spendItems, subagentNames, usd as spendUsd } from "./spend.js";
26
26
  import { spendCsv } from "./spend-ui.js";
27
27
  import { buildExport, exportSummary, exportZip, writeExportFolder } from "./export.js";
28
28
  import { startBudgetAlerts } from "./budget-alerts.js";
@@ -43,8 +43,8 @@ import { origin, readMonitoring } from "./monitoring-settings.js";
43
43
  import { logEvent } from "./log.js";
44
44
  import { FLOW_EVERY_MS, flowHousekeeping, moveCards, moveCardsAfter } from "./flow-cadence.js";
45
45
  import { readHooksBase, scheduleFromWords } from "./flow-triggers.js";
46
- import { sendTeammateSummaries } from "./teammate-admin.js";
47
- import { runRequestedUndos, sendTeammateWeeklies } from "./teammate-week.js";
46
+ import { sendSubagentSummaries } from "./subagent-admin.js";
47
+ import { runRequestedUndos, sendSubagentWeeklies } from "./subagent-week.js";
48
48
  import { refreshConnections } from "./mcp-connect.js";
49
49
  import { followDiscord } from "./discord.js";
50
50
  import { followTeams } from "./teams.js";
@@ -156,8 +156,8 @@ import { bridgePass, clearBotToken, createTransport, followBridge, hashPairingCo
156
156
  import { scanRepo } from "./capscan.js";
157
157
  import { computeGaps, describeCapability } from "./gaps.js";
158
158
  import { ask as promptAsk, askHidden as promptHidden, confirm as promptConfirm, interactive as promptInteractive, underAgent } from "./prompt.js";
159
- import { runMateCli, answerContextLines } from "./mate-cli.js";
160
- import { confirmCoordinatorProposal, dismissCoordinatorProposal } from "./mate-doors.js";
159
+ import { runLeadCli, answerContextLines } from "./lead-cli.js";
160
+ import { confirmCoordinatorProposal, dismissCoordinatorProposal } from "./lead-doors.js";
161
161
  import { verifyApproverByPassword as approverByPassword } from "./principal.js";
162
162
  import { activeRemote, REMOTE_MESSAGES, REMOTE_REFUSED_FLAGS, REMOTE_SCOPES, RemoteRefusal, remoteAllows, remoteLensOf, remoteProjectOf, remoteRowOf, remoteSecret, reproveRemote, withRemote } from "./operate-remote.js";
163
163
  import { projectAuthority } from "./project-access.js";
@@ -256,9 +256,9 @@ export const OPERATE_HELP = `toolroll — operating the queue
256
256
  toolroll integrations [--json] which integrations work: Connected, Not set up or Broken, and what to do (--saved: no new checks)
257
257
  toolroll monitoring where the audit stream and traces go, and how each destination is doing
258
258
  toolroll check-progress <run> current or final approved check progress
259
- toolroll spend [--month YYYY-MM] [--csv] what agent work cost, by project, person, teammate and model
259
+ toolroll spend [--month YYYY-MM] [--csv] what agent work cost, by project, person, subagent and model
260
260
  toolroll export --out <path> [--zip] everything Toolroll knows, in a folder or .zip (no secrets)
261
- toolroll budget list|set|remove monthly budgets (--all | --project <p> | --person <name> | --teammate <id>) --usd <n> [--alerts-only]
261
+ toolroll budget list|set|remove monthly budgets (--all | --project <p> | --person <name> | --subagent <id>) --usd <n> [--alerts-only]
262
262
  toolroll notifications [quiet|all] how chats reach you: only when you're needed (the default), or every step
263
263
  toolroll notifications digest <HH:MM>|off one evening message: what finished, what waits, what failed
264
264
  toolroll notifications mute|unmute --repo <p> no pings for a project; the console and digest keep it
@@ -477,7 +477,7 @@ Agents — which provider and model each phase runs on
477
477
  toolroll chat --as <you> [--repo <path>…] [--say "…"] [--end]
478
478
  [--ceiling-usd <n>] [--json] (password at the prompt;
479
479
  --token <t> only for scripts — it lands in shell history)
480
- the mate: one conversation across your projects, the same thread the
480
+ your lead: one conversation across your projects, the same thread the
481
481
  console shows; the password mints a spending session once; it reads
482
482
  and proposes, you confirm cards (confirm N / dismiss N / open N;
483
483
  confirm N yes for an irreversible answer)
@@ -625,7 +625,7 @@ export const OPERATE_VALUE_FLAGS = new Set([
625
625
  // v103: the ledger chain and evidence packs.
626
626
  "checkpoint", "out", "from", "to",
627
627
  // v105: spend and budgets.
628
- "month", "usd", "person", "teammate",
628
+ "month", "usd", "person", "subagent", "teammate",
629
629
  // Sprint 8: the organisation policy.
630
630
  "providers", "models", "tools",
631
631
  "project-root", "schedule", "ceiling", "require",
@@ -869,7 +869,7 @@ async function dispatchOn(command, positional, flags, repoList, base, options, e
869
869
  ...(options.flowFetch === undefined ? {} : { flowFetch: options.flowFetch }),
870
870
  ...(options.integrationIo === undefined ? {} : { integrationIo: options.integrationIo }),
871
871
  ...(options.shouldStop === undefined ? {} : { shouldStop: options.shouldStop }),
872
- ...(options.mateSeams === undefined ? {} : { mateSeams: options.mateSeams }),
872
+ ...(options.leadSeams === undefined ? {} : { leadSeams: options.leadSeams }),
873
873
  ...(options.waitSleep === undefined ? {} : { waitSleep: options.waitSleep }),
874
874
  ...(options.releaseIo === undefined ? {} : { releaseIo: options.releaseIo }),
875
875
  ...(options.installBin === undefined ? {} : { installBin: options.installBin }),
@@ -1023,7 +1023,7 @@ function telegramCanDeliver(context, token) {
1023
1023
  function telegramConversation(context, options = {}) {
1024
1024
  return {
1025
1025
  evidenceRoot: context.evidenceRoot,
1026
- ...(context.mateSeams?.subscriptionRunner === undefined ? {} : { subscriptionRunner: context.mateSeams.subscriptionRunner }),
1026
+ ...(context.leadSeams?.subscriptionRunner === undefined ? {} : { subscriptionRunner: context.leadSeams.subscriptionRunner }),
1027
1027
  // Re-read on every card and every `/task`: the same console-url chat
1028
1028
  // links use, held to an https origin, and — inside `up`, where this
1029
1029
  // process also serves the console — equal to that console's own
@@ -2273,25 +2273,25 @@ async function tickCommand(flags, context) {
2273
2273
  const replyPass = housekeeping?.replies ?? { read: 0, taken: 0, problem: null };
2274
2274
  const stepPass = housekeeping?.steps ?? { ran: 0, problems: [] };
2275
2275
  const flowPass = housekeeping?.flows ?? { moved: 0, filed: [], problems: [] };
2276
- // Each AI teammate's daily summary to its manager (v92), once, after 5 pm; its weekly report (v97), Monday mornings.
2276
+ // Each subagent's daily summary to its manager (v92), once, after 5 pm; its weekly report (v97), Monday mornings.
2277
2277
  if (!buildsOnly)
2278
2278
  try {
2279
- sendTeammateSummaries(store, repo, clock());
2280
- sendTeammateWeeklies(store, repo, clock());
2279
+ sendSubagentSummaries(store, repo, clock());
2280
+ sendSubagentWeeklies(store, repo, clock());
2281
2281
  }
2282
2282
  catch (error) {
2283
- flowPass.problems.push(`teammate summaries: ${error instanceof Error ? error.message : "could not send"}`);
2283
+ flowPass.problems.push(`subagent summaries: ${error instanceof Error ? error.message : "could not send"}`);
2284
2284
  }
2285
- // Undoing a teammate's tool call asked for in chat (v97): made here, as the person who asked.
2285
+ // Undoing a subagent's tool call asked for in chat (v97): made here, as the person who asked.
2286
2286
  if (!buildsOnly && context.shouldStop?.() !== true) {
2287
2287
  try {
2288
2288
  await runRequestedUndos(store, {}, clock());
2289
2289
  }
2290
2290
  catch (error) {
2291
- flowPass.problems.push(`teammate undo: ${error instanceof Error ? error.message : "could not run"}`);
2291
+ flowPass.problems.push(`subagent undo: ${error instanceof Error ? error.message : "could not run"}`);
2292
2292
  }
2293
2293
  }
2294
- // Tools connected by signing in: a sign-in that runs out within ten minutes is renewed here, so a build or a teammate's call starts with a fresh one.
2294
+ // Tools connected by signing in: a sign-in that runs out within ten minutes is renewed here, so a build or a subagent's call starts with a fresh one.
2295
2295
  if (!buildsOnly && context.shouldStop?.() !== true) {
2296
2296
  try {
2297
2297
  flowPass.problems.push(...(await refreshConnections(store, [repo], clock(), context.flowStepIo?.fetch === undefined ? {} : { fetcher: context.flowStepIo.fetch })).problems);
@@ -6050,19 +6050,19 @@ async function runWatchLoop(args) {
6050
6050
  : startTelegramFollower({ context, publicUrl: text(flags, "public-url"), signal: followController.signal, progress, label: "watch: bridge", died: { prefix: "watch: ", then: "taps wait for the next watch" } });
6051
6051
  const slackFollower = followSlack({ store, dir: dirname(context.databaseFile), signal: followController.signal,
6052
6052
  readProjects: telegramReadProjects(context), evidenceRoot: context.evidenceRoot,
6053
- ...(context.mateSeams?.subscriptionRunner ? { subscriptionRunner: context.mateSeams.subscriptionRunner } : {}),
6053
+ ...(context.leadSeams?.subscriptionRunner ? { subscriptionRunner: context.leadSeams.subscriptionRunner } : {}),
6054
6054
  origin: () => phoneOrigin(process.env, dirname(context.databaseFile), { serverOrigin: text(flags, "public-url") ?? null }),
6055
6055
  notifications: () => effectivePrimary(process.env, dirname(context.databaseFile), loadBotToken(process.env, context.telegramTokenFile) !== null).channel === "slack",
6056
6056
  }).catch(() => progress("watch: Slack stopped. Check Slack settings before reconnecting."));
6057
6057
  const teamsFollower = followTeams({ store, dir: dirname(context.databaseFile), signal: followController.signal,
6058
6058
  readProjects: telegramReadProjects(context), evidenceRoot: context.evidenceRoot,
6059
- ...(context.mateSeams?.subscriptionRunner ? { subscriptionRunner: context.mateSeams.subscriptionRunner } : {}),
6059
+ ...(context.leadSeams?.subscriptionRunner ? { subscriptionRunner: context.leadSeams.subscriptionRunner } : {}),
6060
6060
  origin: () => phoneOrigin(process.env, dirname(context.databaseFile), { serverOrigin: text(flags, "public-url") ?? null }),
6061
6061
  notifications: () => effectivePrimary(process.env, dirname(context.databaseFile), loadBotToken(process.env, context.telegramTokenFile) !== null).channel === "teams",
6062
6062
  }).catch(() => progress("watch: Teams stopped. Check Teams settings before reconnecting."));
6063
6063
  const discordFollower = followDiscord({ store, dir: dirname(context.databaseFile), signal: followController.signal,
6064
6064
  readProjects: telegramReadProjects(context), evidenceRoot: context.evidenceRoot,
6065
- ...(context.mateSeams?.subscriptionRunner ? { subscriptionRunner: context.mateSeams.subscriptionRunner } : {}),
6065
+ ...(context.leadSeams?.subscriptionRunner ? { subscriptionRunner: context.leadSeams.subscriptionRunner } : {}),
6066
6066
  origin: () => phoneOrigin(process.env, dirname(context.databaseFile), { serverOrigin: text(flags, "public-url") ?? null }),
6067
6067
  notifications: () => effectivePrimary(process.env, dirname(context.databaseFile), loadBotToken(process.env, context.telegramTokenFile) !== null).channel === "discord",
6068
6068
  }).catch(() => progress("watch: Discord stopped. Check Discord settings before reconnecting."));
@@ -9987,7 +9987,7 @@ function describeApproveFailure(reason, id) {
9987
9987
  if (reason === "requester")
9988
9988
  return `you filed ${id}, and this project needs someone else to approve it`;
9989
9989
  if (reason === "person-required")
9990
- return `${id} is protected work: a person has to approve it, not an operating mode, a schedule or an AI teammate`;
9990
+ return `${id} is protected work: a person has to approve it, not an operating mode, a schedule or a subagent`;
9991
9991
  if (reason === "second-approver")
9992
9992
  return `your approval of ${id} is recorded; it is protected work, so a second person needs to approve it (toolroll task approve ${id} as them)`;
9993
9993
  if (reason === "no-approvers") {
@@ -10104,7 +10104,7 @@ async function chatCommand(flags, context) {
10104
10104
  return fail(write, json, "chat", "usage", "Choose --follow or --no-follow.", EXIT.usage);
10105
10105
  const credentials = await askCredentials(flags, context);
10106
10106
  if (credentials === null) {
10107
- return fail(write, json, "chat", "usage", "the mate takes your name and password — `--as <you>` and the hidden prompt; `--token <t>` only where a script must (it lands in shell history)", EXIT.usage);
10107
+ return fail(write, json, "chat", "usage", "the lead takes your name and password — `--as <you>` and the hidden prompt; `--token <t>` only where a script must (it lands in shell history)", EXIT.usage);
10108
10108
  }
10109
10109
  const ceilingGiven = text(flags, "ceiling-usd");
10110
10110
  // The ceiling: the `--repo` list, or the ENROLLED registry beside the
@@ -10120,7 +10120,7 @@ async function chatCommand(flags, context) {
10120
10120
  return fail(write, json, "chat", "registry", "the enrolled-project registry could not be read — name projects with --repo", EXIT.refused);
10121
10121
  repos = loaded.repos;
10122
10122
  }
10123
- const result = await runMateCli({
10123
+ const result = await runLeadCli({
10124
10124
  store,
10125
10125
  databaseFile: context.databaseFile,
10126
10126
  write,
@@ -10131,7 +10131,7 @@ async function chatCommand(flags, context) {
10131
10131
  end: flags.has("end"),
10132
10132
  ...(flags.has("follow") || flags.has("no-follow") ? { follow: flags.has("follow") && !flags.has("no-follow") } : {}),
10133
10133
  ceilingUsd: ceilingGiven === undefined ? undefined : Number(ceilingGiven),
10134
- ...(context.mateSeams === undefined ? {} : { seams: { ...context.mateSeams, clock: context.mateSeams.clock ?? context.clock } }),
10134
+ ...(context.leadSeams === undefined ? {} : { seams: { ...context.leadSeams, clock: context.leadSeams.clock ?? context.clock } }),
10135
10135
  ...(context.evidenceRoot === undefined ? {} : { evidenceRoot: context.evidenceRoot }),
10136
10136
  // The console's own address (and its public one): links there read as "the task", "the result", "Settings → Lead".
10137
10137
  appOrigin: [loadConsoleUrl(process.env, dirname(context.databaseFile)), phoneOrigin(process.env, dirname(context.databaseFile))],
@@ -10698,7 +10698,7 @@ async function projectDeleteCommand(positional, flags, context) {
10698
10698
  `Deleted ${repo}: ${holdingsWords(done.removed)}.`, ...done.left.map(one => `Git kept ${one}.`), `The ledger records it as entry #${done.ledgerId}.`,
10699
10699
  ]);
10700
10700
  }
10701
- /** `spend [--month YYYY-MM] [--csv]` (v105): what agent work cost in a month, by project, person, teammate and model. */
10701
+ /** `spend [--month YYYY-MM] [--csv]` (v105): what agent work cost in a month, by project, person, subagent and model. */
10702
10702
  function spendCommand(flags, context) {
10703
10703
  const command = "spend";
10704
10704
  for (const name of flags.keys())
@@ -10708,7 +10708,7 @@ function spendCommand(flags, context) {
10708
10708
  if (month === null)
10709
10709
  return fail(context.write, context.json, command, "usage", "Use spend --month YYYY-MM.", EXIT.usage);
10710
10710
  const items = spendItems(context.store.handle, month.from, month.to);
10711
- const names = teammateNames(context.store.handle);
10711
+ const names = subagentNames(context.store.handle);
10712
10712
  if (flags.has("csv")) {
10713
10713
  context.write(spendCsv(items, names).replace(/^\ufeff/, "").trimEnd());
10714
10714
  return EXIT.ok;
@@ -10722,7 +10722,7 @@ function spendCommand(flags, context) {
10722
10722
  byProject.set(item.project, (byProject.get(item.project) ?? 0) + (item.microusd ?? 0));
10723
10723
  // v105: subscription work is $0; what binds it is its plan's windows, as the provider last said.
10724
10724
  const limits = context.store.providerLimits();
10725
- const windows = limitsView(limits, [], { project: repo => basename(repo), teammate: id => String(id) }, context.clock())?.tiles ?? [];
10725
+ const windows = limitsView(limits, [], { project: repo => basename(repo), subagent: id => String(id) }, context.clock())?.tiles ?? [];
10726
10726
  // Sized routing: each tier's tasks, time to a result and plan use, and what the tiers saved.
10727
10727
  const tiers = tierReport(context.store.handle, month.from, month.to, items);
10728
10728
  return succeed(context.write, context.json, command, { month: month.name, totalMicrousd: total, unpriced, items: items.length, budgets, limits, tiers: { rows: tiers.rows, saved: tiers.saved } }, () => [
@@ -10825,21 +10825,22 @@ async function budgetCommand(positional, flags, context) {
10825
10825
  const store = context.store;
10826
10826
  if (action === undefined || action === "list") {
10827
10827
  const budgets = store.monthSpend(context.clock()).budgets;
10828
- return succeed(context.write, context.json, command, { budgets }, () => budgets.length === 0 ? ["No budgets. `budget set --all|--project <path>|--person <name>|--teammate <id> --usd <n>` makes one."]
10828
+ return succeed(context.write, context.json, command, { budgets }, () => budgets.length === 0 ? ["No budgets. `budget set --all|--project <path>|--person <name>|--subagent <id> --usd <n>` makes one."]
10829
10829
  : budgets.map(one => `#${one.id} ${budgetLabel(one).replace(/'s$/, "")}: ${spendUsd(one.spentMicrousd)} of ${spendUsd(one.limitMicrousd)} this month (${one.percent}%)${one.hardStop ? ", stops API work at 100%" : ", alerts only"}`));
10830
10830
  }
10831
10831
  if (action !== "set" && action !== "remove")
10832
10832
  return fail(context.write, context.json, command, "usage", "Use budget list, budget set or budget remove.", EXIT.usage);
10833
- const allowed = new Set(["all", "project", "person", "teammate", "usd", "alerts-only", "as", "token", "token-file", "token-env", "db", "json"]);
10833
+ // --teammate: the flag's name before D5, still read this release.
10834
+ const allowed = new Set(["all", "project", "person", "subagent", "teammate", "usd", "alerts-only", "as", "token", "token-file", "token-env", "db", "json"]);
10834
10835
  for (const name of flags.keys())
10835
10836
  if (!allowed.has(name))
10836
10837
  return fail(context.write, context.json, command, "usage", `--${name} is not a budget option.`, EXIT.usage);
10837
10838
  const chosen = [flags.has("all") ? { scope: "installation", key: "*" } : null,
10838
10839
  text(flags, "project") === undefined ? null : { scope: "project", key: resolve(text(flags, "project")) },
10839
10840
  text(flags, "person") === undefined ? null : { scope: "person", key: text(flags, "person") },
10840
- text(flags, "teammate") === undefined ? null : { scope: "teammate", key: text(flags, "teammate") }].filter(one => one !== null);
10841
+ (text(flags, "subagent") ?? text(flags, "teammate")) === undefined ? null : { scope: "subagent", key: (text(flags, "subagent") ?? text(flags, "teammate")) }].filter(one => one !== null);
10841
10842
  if (chosen.length !== 1)
10842
- return fail(context.write, context.json, command, "usage", "Name one of --all, --project <path>, --person <name> or --teammate <id>.", EXIT.usage);
10843
+ return fail(context.write, context.json, command, "usage", "Name one of --all, --project <path>, --person <name> or --subagent <id>.", EXIT.usage);
10843
10844
  const target = chosen[0];
10844
10845
  const acting = await askCredentials(flags, context);
10845
10846
  const verified = acting === null ? null : authenticateApprover(store, acting.name, acting.token);
@@ -10848,9 +10849,9 @@ async function budgetCommand(positional, flags, context) {
10848
10849
  }
10849
10850
  const known = target.scope === "installation" || (target.scope === "project" ? store.knownRepos().includes(target.key)
10850
10851
  : target.scope === "person" ? store.accountFacts().some(one => one.name === target.key && one.revokedAt === null)
10851
- : store.handle.prepare("SELECT 1 FROM teammate WHERE id = ?").get(Number(target.key)) !== undefined);
10852
+ : store.handle.prepare("SELECT 1 FROM subagent WHERE id = ?").get(Number(target.key)) !== undefined);
10852
10853
  if (!known)
10853
- return fail(context.write, context.json, command, "not-found", "That isn't a project, person or teammate here.", EXIT.refused);
10854
+ return fail(context.write, context.json, command, "not-found", "That isn't a project, person or subagent here.", EXIT.refused);
10854
10855
  if (action === "remove") {
10855
10856
  const existing = store.budgets().find(one => one.scope === target.scope && one.key === target.key);
10856
10857
  if (existing === undefined || !store.removeBudget(existing.id, acting.name, context.clock()))
package/dist/policy.d.ts CHANGED
@@ -15,7 +15,7 @@
15
15
  * (lowered), or, when there is none, doesn't run (refused); the words say which.
16
16
  *
17
17
  * Every road that admits work asks here: scope approval, the tick before a
18
- * run starts (and build() as the last look), the lead and project chats, teammates and flow steps.
18
+ * run starts (and build() as the last look), the lead and project chats, subagents and flow steps.
19
19
  */
20
20
  import type { Database } from "./store.js";
21
21
  import type { ExecutionProfile } from "./scope.js";
@@ -9,7 +9,7 @@ export type VerifiedApprover = {
9
9
  readonly repos: readonly string[];
10
10
  readonly ceilingDigest: string;
11
11
  };
12
- /** The mate's ceiling digest: the admitted repos IN ORDER, hashed — `rN`
12
+ /** The lead's ceiling digest: the admitted repos IN ORDER, hashed — `rN`
13
13
  * is an index, so two surfaces naming the same repos in a different order
14
14
  * hold different ceilings (slice-2 review, finding 3). */
15
15
  export declare function ceilingDigestOf(repos: readonly string[]): string;
package/dist/principal.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The branded approver principal (mate arc, ruling 3).
3
3
  *
4
- * Every act the mate proposes and every confirmation an operator taps
4
+ * Every act the lead proposes and every confirmation an operator taps
5
5
  * runs under a principal that PROVES it was authenticated — a password
6
6
  * ceremony, or a cookie session the edge already proved (csrf, role,
7
7
  * generation) and this module re-proves against the approver row. The
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { createHash } from "node:crypto";
17
17
  import { authenticateAccount } from "./scope.js";
18
- /** The mate's ceiling digest: the admitted repos IN ORDER, hashed — `rN`
18
+ /** The lead's ceiling digest: the admitted repos IN ORDER, hashed — `rN`
19
19
  * is an index, so two surfaces naming the same repos in a different order
20
20
  * hold different ceilings (slice-2 review, finding 3). */
21
21
  export function ceilingDigestOf(repos) {
@@ -49,7 +49,7 @@ export function projectDeleteConfirmHtml(view, problem) {
49
49
  "The checkouts and branches Toolroll made",
50
50
  ...(h.chats > 0 ? [count(h.chats, "chat")] : []),
51
51
  ...(h.flows > 0 ? [`${count(h.flows, "flow")} and ${count(h.cards, "card")}`] : []),
52
- ...(h.teammates > 0 ? [count(h.teammates, "teammate")] : []),
52
+ ...(h.subagents > 0 ? [count(h.subagents, "subagent")] : []),
53
53
  "Its budgets, settings and knowledge",
54
54
  ];
55
55
  return html `<section class="project-delete">${problem === null ? "" : html `<p class="problem" role="alert">${problem}</p>`}<p>This removes:</p><ul class="removes">${items.map(one => html `<li>${one}</li>`)}</ul><p>The repository at <span class="path">${view.repo}</span> and its own branches stay. The ledger keeps its history. There's no undo.</p>${postForm("/settings/project/delete", html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label><div class="actions"><button type="submit" class="danger">Delete project</button><a href="/settings/project?repo=${encodeURIComponent(view.repo)}">Cancel</a></div>`, { hidden: { repo: view.repo, name: view.name, step: "delete" } })}</section>`;
@@ -12,7 +12,7 @@ export type ProjectHoldings = {
12
12
  chats: number;
13
13
  flows: number;
14
14
  cards: number;
15
- teammates: number;
15
+ subagents: number;
16
16
  budgets: number;
17
17
  settings: number;
18
18
  };
@@ -2,7 +2,7 @@
2
2
  * Deleting a project: everything Toolroll holds for it goes, and
3
3
  * nothing else. Its tasks and their versions, runs and their evidence, the
4
4
  * checkouts and branches Toolroll made, its chats and threads, flows
5
- * and cards, teammates, budgets and settings. Never while any of its work is
5
+ * and cards, subagents, budgets and settings. Never while any of its work is
6
6
  * running. The project's own repository, its working copy and every branch
7
7
  * Toolroll didn't make stay exactly as they are. The action ledger
8
8
  * keeps every entry (its hash chain still verifies) and gains one: who
@@ -36,13 +36,13 @@ function doomed(db, repo) {
36
36
  const runs = ids(db, "SELECT id FROM run WHERE task_ref IN (SELECT value FROM json_each(?))", json(refs));
37
37
  const artifacts = ids(db, "SELECT id FROM artifact WHERE run IN (SELECT value FROM json_each(?))", json(runs));
38
38
  // A team conversation's thread is the team's, whatever it talked about.
39
- const threads = ids(db, `SELECT id FROM mate_thread WHERE ((scope_kind = 'project' AND scope_key = ?) OR (scope_kind = 'task' AND scope_key IN (SELECT value FROM json_each(?))))
39
+ const threads = ids(db, `SELECT id FROM lead_thread WHERE ((scope_kind = 'project' AND scope_key = ?) OR (scope_kind = 'task' AND scope_key IN (SELECT value FROM json_each(?))))
40
40
  AND id NOT IN (SELECT thread FROM team_conversation WHERE thread IS NOT NULL)`, repo, json(tasks));
41
41
  const turns = ids(db, "SELECT id FROM mate_turn WHERE thread IN (SELECT value FROM json_each(?))", json(threads));
42
42
  const flows = ids(db, "SELECT id FROM flow WHERE repo = ?", repo);
43
43
  const cards = ids(db, "SELECT id FROM flow_card WHERE flow IN (SELECT value FROM json_each(?))", json(flows));
44
- const teammates = ids(db, "SELECT id FROM teammate WHERE repo = ?", repo);
45
- return { refs, tasks, runs, artifacts, threads, turns, flows, cards, teammates };
44
+ const subagents = ids(db, "SELECT id FROM subagent WHERE repo = ?", repo);
45
+ return { refs, tasks, runs, artifacts, threads, turns, flows, cards, subagents };
46
46
  }
47
47
  /** A project's settings: one row per thing someone set for it. */
48
48
  const SETTINGS = [
@@ -61,8 +61,8 @@ export function projectHoldings(store, repo) {
61
61
  tasks: count("SELECT COUNT(DISTINCT external_id) AS n FROM task_ref WHERE repo = ?", repo) - versions, versions,
62
62
  runs: d.runs.length, evidence: d.artifacts.length,
63
63
  checkouts: count("SELECT COUNT(*) AS n FROM worktree WHERE repo = ?", repo),
64
- chats: d.threads.length, flows: d.flows.length, cards: d.cards.length, teammates: d.teammates.length,
65
- budgets: count(`SELECT COUNT(*) AS n FROM budget WHERE removed_at IS NULL AND ((scope_kind = 'project' AND scope_key = ?) OR (scope_kind = 'teammate' AND scope_key IN (SELECT CAST(value AS TEXT) FROM json_each(?))))`, repo, json(d.teammates)),
64
+ chats: d.threads.length, flows: d.flows.length, cards: d.cards.length, subagents: d.subagents.length,
65
+ budgets: count(`SELECT COUNT(*) AS n FROM budget WHERE removed_at IS NULL AND ((scope_kind = 'project' AND scope_key = ?) OR (scope_kind = 'subagent' AND scope_key IN (SELECT CAST(value AS TEXT) FROM json_each(?))))`, repo, json(d.subagents)),
66
66
  settings: SETTINGS.filter(([table]) => tableExists(db, table)).reduce((sum, [table, column]) => sum + count(`SELECT COUNT(*) AS n FROM ${table} WHERE ${column} = ?`, repo), 0),
67
67
  };
68
68
  }
@@ -72,7 +72,7 @@ export function holdingsWords(held) {
72
72
  plural(held.tasks, "task"), ...(held.versions > 0 ? [plural(held.versions, "version")] : []), plural(held.runs, "run"),
73
73
  ...(held.evidence > 0 ? [plural(held.evidence, "evidence file")] : []), ...(held.checkouts > 0 ? [plural(held.checkouts, "checkout")] : []),
74
74
  ...(held.branches ? [plural(held.branches, "branch", "branches")] : []), ...(held.chats > 0 ? [plural(held.chats, "chat")] : []),
75
- ...(held.flows > 0 ? [`${plural(held.flows, "flow")} with ${plural(held.cards, "card")}`] : []), ...(held.teammates > 0 ? [plural(held.teammates, "teammate")] : []),
75
+ ...(held.flows > 0 ? [`${plural(held.flows, "flow")} with ${plural(held.cards, "card")}`] : []), ...(held.subagents > 0 ? [plural(held.subagents, "subagent")] : []),
76
76
  ...(held.budgets > 0 ? [plural(held.budgets, "budget")] : []), ...(held.settings > 0 ? [plural(held.settings, "setting")] : []),
77
77
  ];
78
78
  return parts.join(", ");
@@ -87,7 +87,7 @@ export function projectRunning(store, repo, now) {
87
87
  const slots = count("SELECT COUNT(*) AS n FROM execution_slot WHERE state IN ('reserved','running') AND run IN (SELECT value FROM json_each(?))", json(d.runs));
88
88
  const chats = count("SELECT COUNT(*) AS n FROM mate_turn WHERE state IN ('queued','running') AND id IN (SELECT value FROM json_each(?))", json(d.turns));
89
89
  const steps = count("SELECT COUNT(*) AS n FROM flow_step_run WHERE state = 'running' AND card IN (SELECT value FROM json_each(?))", json(d.cards));
90
- const calls = count("SELECT COUNT(*) AS n FROM teammate_call WHERE state = 'running' AND teammate IN (SELECT value FROM json_each(?))", json(d.teammates));
90
+ const calls = count("SELECT COUNT(*) AS n FROM subagent_call WHERE state = 'running' AND subagent IN (SELECT value FROM json_each(?))", json(d.subagents));
91
91
  const merges = count(`SELECT COUNT(*) AS n FROM merge_intent WHERE state IN ('claimed','firing') AND publication IN (SELECT id FROM publication WHERE task_ref IN (SELECT value FROM json_each(?)))`, json(d.refs));
92
92
  const checkouts = count("SELECT COUNT(*) AS n FROM worktree WHERE repo = ? AND runner IS NOT NULL AND released_at IS NULL", repo);
93
93
  return [
@@ -95,7 +95,7 @@ export function projectRunning(store, repo, now) {
95
95
  ...(slots > 0 ? ["an agent is working"] : []),
96
96
  ...(chats > 0 ? ["a chat is answering"] : []),
97
97
  ...(steps > 0 ? ["a flow step is running"] : []),
98
- ...(calls > 0 ? ["a teammate is working"] : []),
98
+ ...(calls > 0 ? ["a subagent is working"] : []),
99
99
  ...(merges > 0 ? ["a merge is in progress"] : []),
100
100
  ...(checkouts > 0 && building === 0 ? [`${plural(checkouts, "checkout")} ${checkouts === 1 ? "is" : "are"} in use`] : []),
101
101
  ];
@@ -201,12 +201,12 @@ function deleteRows(store, repo, d, now) {
201
201
  rows += Number(db.prepare(`DELETE FROM ${table} WHERE ${where}`).run(...params).changes);
202
202
  };
203
203
  const IN = (column) => `${column} IN (SELECT value FROM json_each(?))`;
204
- const R = json(d.runs), T = json(d.refs), K = json(d.tasks), A = json(d.artifacts), H = json(d.threads), U = json(d.turns), F = json(d.flows), C = json(d.cards), M = json(d.teammates);
204
+ const R = json(d.runs), T = json(d.refs), K = json(d.tasks), A = json(d.artifacts), H = json(d.threads), U = json(d.turns), F = json(d.flows), C = json(d.cards), M = json(d.subagents);
205
205
  const decisions = json(ids(db, `SELECT id FROM decision WHERE ${IN("run")}`, R));
206
206
  const publications = json(ids(db, `SELECT id FROM publication WHERE ${IN("task_ref")} OR ${IN("run")}`, T, R));
207
207
  const notifications = json(ids(db, `SELECT id FROM notification WHERE project = ? OR ${IN("task_ref")} OR ${IN("source_run")}`, repo, T, R));
208
- const questions = json(ids(db, `SELECT id FROM teammate_question WHERE ${IN("teammate")} OR ${IN("card")}`, M, C));
209
- const proposals = json(ids(db, `SELECT id FROM mate_proposal WHERE ${IN("thread")}`, H));
208
+ const questions = json(ids(db, `SELECT id FROM subagent_question WHERE ${IN("subagent")} OR ${IN("card")}`, M, C));
209
+ const proposals = json(ids(db, `SELECT id FROM lead_proposal WHERE ${IN("thread")}`, H));
210
210
  // A chat message about one of the project's tasks (its turn named it), with its reply. Event ids are text ('m123'),
211
211
  // and the same id can be another app's: each is kept whole, as provider:id.
212
212
  const conversations = json(list(db, `SELECT provider || ':' || id FROM chat_event WHERE kind = 'message' AND json_extract(payload, '$.about.task') IN (SELECT value FROM json_each(?))`, K));
@@ -241,13 +241,13 @@ function deleteRows(store, repo, d, now) {
241
241
  del("chat_focus", IN("task"), K);
242
242
  del("team_task_owner", IN("task_ref"), T);
243
243
  del("team_mate_session", IN("thread"), H);
244
- del("mate_turn_evidence", `${IN("turn")} OR ${IN("run")} OR ${IN("task_ref")} OR ${IN("artifact")}`, U, R, T, A);
244
+ del("lead_turn_evidence", `${IN("turn")} OR ${IN("run")} OR ${IN("task_ref")} OR ${IN("artifact")}`, U, R, T, A);
245
245
  del("chat_turn", IN("mate_turn"), U);
246
- del("mate_ask", IN("turn"), U);
246
+ del("lead_ask", IN("turn"), U);
247
247
  del("mate_turn", IN("id"), U);
248
- del("mate_proposal", IN("id"), proposals);
249
- del("mate_message", IN("thread"), H);
250
- del("mate_thread", IN("id"), H);
248
+ del("lead_proposal", IN("id"), proposals);
249
+ del("lead_message", IN("thread"), H);
250
+ del("lead_thread", IN("id"), H);
251
251
  // Runs and their evidence.
252
252
  del("run_decision", `${IN("run")} OR ${IN("decision")}`, R, decisions);
253
253
  del("decision_artifact", `${IN("decision")} OR ${IN("artifact")}`, decisions, A);
@@ -288,19 +288,19 @@ function deleteRows(store, repo, d, now) {
288
288
  del("task_scope", IN("task_id"), K);
289
289
  del("task_edge", `${IN("blocked")} OR ${IN("blocker")}`, K, K);
290
290
  del("task", IN("id"), K);
291
- // Flows, cards and teammates.
291
+ // Flows, cards and subagents.
292
292
  del("flow_trigger_event", `${IN("card")} OR trigger IN (SELECT id FROM flow_trigger WHERE ${IN("flow")})`, C, F);
293
293
  del("flow_trigger", IN("flow"), F);
294
294
  for (const table of ["flow_card_watcher", "flow_comment", "flow_event", "flow_mail", "flow_step_run"])
295
295
  del(table, IN("card"), C);
296
- del("teammate_question", IN("id"), questions);
297
- del("teammate_call", `${IN("teammate")} OR ${IN("card")}`, M, C);
298
- for (const table of ["teammate_event", "teammate_memory", "teammate_turn"])
299
- del(table, `${IN("teammate")} OR ${IN("card")}`, M, C);
300
- for (const table of ["teammate_suggestion", "teammate_tool", "teammate_version"])
301
- del(table, IN("teammate"), M);
302
- del("budget", `(scope_kind = 'project' AND scope_key = ?) OR (scope_kind = 'teammate' AND scope_key IN (SELECT CAST(value AS TEXT) FROM json_each(?)))`, repo, M);
303
- del("teammate", IN("id"), M);
296
+ del("subagent_question", IN("id"), questions);
297
+ del("subagent_call", `${IN("subagent")} OR ${IN("card")}`, M, C);
298
+ for (const table of ["subagent_event", "subagent_memory", "subagent_turn"])
299
+ del(table, `${IN("subagent")} OR ${IN("card")}`, M, C);
300
+ for (const table of ["subagent_suggestion", "subagent_tool", "subagent_version"])
301
+ del(table, IN("subagent"), M);
302
+ del("budget", `(scope_kind = 'project' AND scope_key = ?) OR (scope_kind = 'subagent' AND scope_key IN (SELECT CAST(value AS TEXT) FROM json_each(?)))`, repo, M);
303
+ del("subagent", IN("id"), M);
304
304
  del("flow_card", IN("id"), C);
305
305
  del("flow", IN("id"), F);
306
306
  // Settings, knowledge and the project itself.
@@ -222,7 +222,7 @@ export function reindexProjectMemory(store, repo) {
222
222
  export function reindexConversations(store) {
223
223
  const key = 'memory-search:messages';
224
224
  const cursor = store.serviceCursor(key);
225
- const rows = store.handle.prepare('SELECT m.id,m.thread,m.role,m.text,t.approver FROM mate_message m JOIN mate_thread t ON t.id=m.thread WHERE m.id>? ORDER BY m.id LIMIT 500').all(cursor);
225
+ const rows = store.handle.prepare('SELECT m.id,m.thread,m.role,m.text,t.approver FROM lead_message m JOIN lead_thread t ON t.id=m.thread WHERE m.id>? ORDER BY m.id LIMIT 500').all(cursor);
226
226
  if (rows.length === 0)
227
227
  return;
228
228
  const insert = store.handle.prepare('INSERT INTO memory_search(kind,ref,repo,scope,title,body) VALUES (?,?,?,?,?,?)');