toolroll 0.9.34 → 0.9.37

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 (195) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +7 -0
  3. package/dist/assignment-adapters.d.ts +12 -48
  4. package/dist/assignment-adapters.js +33 -43
  5. package/dist/assignment.d.ts +1 -0
  6. package/dist/assignment.js +2 -2
  7. package/dist/browser-workspace.d.ts +3 -3
  8. package/dist/build-review.d.ts +1 -1
  9. package/dist/build-review.js +2 -1
  10. package/dist/builder.js +4 -7
  11. package/dist/chat-acceptance.d.ts +2 -2
  12. package/dist/chat-actions.d.ts +18 -12
  13. package/dist/chat-actions.js +15 -65
  14. package/dist/chat-ask.js +5 -5
  15. package/dist/chat-decide.d.ts +14 -1
  16. package/dist/chat-decide.js +12 -6
  17. package/dist/chat-delivery-state.d.ts +12 -70
  18. package/dist/chat-delivery-state.js +17 -135
  19. package/dist/chat-delivery.js +58 -30
  20. package/dist/chat-flow.js +8 -6
  21. package/dist/chat-inbox.js +1 -1
  22. package/dist/coding-context.d.ts +2 -39
  23. package/dist/coding-context.js +2 -1
  24. package/dist/coding-handoff.d.ts +6 -25
  25. package/dist/coding-handoff.js +11 -5
  26. package/dist/coding-types.d.ts +2 -26
  27. package/dist/coding-workspace.d.ts +2 -0
  28. package/dist/coding-workspace.js +50 -14
  29. package/dist/contracts/acceptance-terms.d.ts +14 -0
  30. package/dist/contracts/acceptance-terms.js +16 -0
  31. package/dist/contracts/chat-actions.d.ts +328 -0
  32. package/dist/contracts/chat-actions.js +133 -0
  33. package/dist/contracts/chat-callback-rows.d.ts +59 -0
  34. package/dist/contracts/chat-callback-rows.js +46 -0
  35. package/dist/contracts/chat-content.d.ts +276 -0
  36. package/dist/contracts/chat-content.js +127 -0
  37. package/dist/contracts/chat-tables.d.ts +6 -0
  38. package/dist/contracts/chat-tables.js +136 -0
  39. package/dist/contracts/coding-context.d.ts +97 -0
  40. package/dist/contracts/coding-context.js +60 -0
  41. package/dist/contracts/coding-handoff.d.ts +44 -0
  42. package/dist/contracts/coding-handoff.js +47 -0
  43. package/dist/contracts/coding-workspace.d.ts +165 -0
  44. package/dist/contracts/coding-workspace.js +71 -0
  45. package/dist/contracts/contract.d.ts +40 -7
  46. package/dist/contracts/contract.js +155 -19
  47. package/dist/contracts/decision.d.ts +45 -0
  48. package/dist/contracts/decision.js +45 -0
  49. package/dist/contracts/discord-callback.d.ts +45 -0
  50. package/dist/contracts/discord-callback.js +34 -0
  51. package/dist/contracts/flow-card.d.ts +50 -0
  52. package/dist/contracts/flow-card.js +46 -0
  53. package/dist/contracts/flow-propose.d.ts +325 -0
  54. package/dist/contracts/flow-propose.js +41 -0
  55. package/dist/contracts/flow-send.d.ts +119 -0
  56. package/dist/contracts/flow-send.js +112 -0
  57. package/dist/contracts/flow.d.ts +19405 -0
  58. package/dist/contracts/flow.js +364 -0
  59. package/dist/contracts/gateway-tools.d.ts +374 -0
  60. package/dist/contracts/gateway-tools.js +94 -0
  61. package/dist/contracts/handoff.d.ts +91 -0
  62. package/dist/contracts/handoff.js +82 -0
  63. package/dist/contracts/lead-context.d.ts +165 -0
  64. package/dist/contracts/lead-context.js +73 -0
  65. package/dist/contracts/lead-tools.d.ts +1905 -0
  66. package/dist/contracts/lead-tools.js +265 -0
  67. package/dist/contracts/memory-pass.d.ts +158 -0
  68. package/dist/contracts/memory-pass.js +102 -0
  69. package/dist/contracts/project-knowledge.d.ts +126 -0
  70. package/dist/contracts/project-knowledge.js +93 -0
  71. package/dist/contracts/project-memory.d.ts +117 -0
  72. package/dist/contracts/project-memory.js +51 -0
  73. package/dist/contracts/project-skills.d.ts +121 -0
  74. package/dist/contracts/project-skills.js +76 -0
  75. package/dist/contracts/proof.d.ts +136 -0
  76. package/dist/contracts/proof.js +110 -0
  77. package/dist/contracts/review-findings.d.ts +46 -0
  78. package/dist/contracts/review-findings.js +48 -0
  79. package/dist/contracts/route.d.ts +484 -0
  80. package/dist/contracts/route.js +128 -0
  81. package/dist/contracts/scope.d.ts +105 -0
  82. package/dist/contracts/scope.js +114 -0
  83. package/dist/contracts/scout-report.d.ts +234 -0
  84. package/dist/contracts/scout-report.js +141 -0
  85. package/dist/contracts/slack-callback.d.ts +43 -0
  86. package/dist/contracts/slack-callback.js +35 -0
  87. package/dist/contracts/sort-answer.d.ts +83 -0
  88. package/dist/contracts/sort-answer.js +77 -0
  89. package/dist/contracts/stage-output.d.ts +127 -0
  90. package/dist/contracts/stage-output.js +166 -0
  91. package/dist/contracts/task-sizing.d.ts +24 -0
  92. package/dist/contracts/task-sizing.js +28 -0
  93. package/dist/contracts/teammate-turn.d.ts +43 -0
  94. package/dist/contracts/teammate-turn.js +51 -0
  95. package/dist/contracts/teams-callback.d.ts +14 -0
  96. package/dist/contracts/teams-callback.js +14 -0
  97. package/dist/contracts/telegram-callback.d.ts +120 -0
  98. package/dist/contracts/telegram-callback.js +97 -0
  99. package/dist/contracts/verification-receipt.d.ts +148 -0
  100. package/dist/contracts/verification-receipt.js +87 -0
  101. package/dist/decision.d.ts +11 -20
  102. package/dist/decision.js +86 -167
  103. package/dist/demo.js +28 -11
  104. package/dist/discord-chat.js +31 -20
  105. package/dist/evidence.d.ts +3 -40
  106. package/dist/evidence.js +5 -1
  107. package/dist/flow-engine.js +14 -17
  108. package/dist/flow-gallery.d.ts +3 -2
  109. package/dist/flow-items.d.ts +4 -13
  110. package/dist/flow-items.js +1 -15
  111. package/dist/flow-send.d.ts +6 -37
  112. package/dist/flow-send.js +18 -14
  113. package/dist/flow-share.d.ts +10 -32
  114. package/dist/flow-share.js +72 -84
  115. package/dist/flow-sort.d.ts +7 -26
  116. package/dist/flow-sort.js +25 -20
  117. package/dist/flow-starters.d.ts +2 -1
  118. package/dist/flow-steps.js +3 -2
  119. package/dist/flow-triggers.d.ts +15 -72
  120. package/dist/flow-triggers.js +94 -83
  121. package/dist/flows.d.ts +37 -220
  122. package/dist/flows.js +356 -387
  123. package/dist/invoke.js +4 -4
  124. package/dist/lead-context.d.ts +4 -2
  125. package/dist/lead-context.js +24 -17
  126. package/dist/mate-tools.d.ts +4 -0
  127. package/dist/mate-tools.js +111 -308
  128. package/dist/mcp-connect.d.ts +27 -4
  129. package/dist/mcp-connect.js +92 -17
  130. package/dist/mcp.js +84 -216
  131. package/dist/memory-pass.d.ts +17 -42
  132. package/dist/memory-pass.js +54 -26
  133. package/dist/operate.js +31 -2
  134. package/dist/phase-routing.d.ts +19 -72
  135. package/dist/phase-routing.js +34 -164
  136. package/dist/plan.d.ts +5 -5
  137. package/dist/plan.js +5 -25
  138. package/dist/process-recovery-eligibility.d.ts +2 -2
  139. package/dist/process-recovery-eligibility.js +13 -8
  140. package/dist/project-knowledge.d.ts +16 -35
  141. package/dist/project-knowledge.js +42 -21
  142. package/dist/project-memory.d.ts +2 -28
  143. package/dist/project-memory.js +28 -13
  144. package/dist/project-skills.d.ts +16 -38
  145. package/dist/project-skills.js +41 -32
  146. package/dist/project-tools.d.ts +1 -0
  147. package/dist/project-tools.js +4 -4
  148. package/dist/proof.d.ts +15 -91
  149. package/dist/proof.js +90 -249
  150. package/dist/provider.d.ts +2 -0
  151. package/dist/provider.js +4 -16
  152. package/dist/result-evidence-readers.d.ts +42 -0
  153. package/dist/result-evidence-readers.js +91 -0
  154. package/dist/result-shots.d.ts +1 -1
  155. package/dist/result-shots.js +2 -1
  156. package/dist/review-switch.d.ts +3 -8
  157. package/dist/reviewer.d.ts +8 -12
  158. package/dist/reviewer.js +11 -35
  159. package/dist/scope.d.ts +21 -43
  160. package/dist/scope.js +42 -128
  161. package/dist/scout-report.d.ts +9 -194
  162. package/dist/scout-report.js +113 -264
  163. package/dist/scout.js +15 -11
  164. package/dist/serve.js +17 -101
  165. package/dist/slack-chat.js +26 -20
  166. package/dist/slack-state.js +2 -1
  167. package/dist/store.d.ts +9 -32
  168. package/dist/store.js +18 -15
  169. package/dist/structured-output.js +2 -1
  170. package/dist/subscription-chat.d.ts +4 -0
  171. package/dist/subscription-chat.js +4 -1
  172. package/dist/surface.js +8 -1
  173. package/dist/task-review-brief.d.ts +69 -0
  174. package/dist/task-review-brief.js +179 -0
  175. package/dist/task-sizing.d.ts +3 -27
  176. package/dist/task-sizing.js +11 -26
  177. package/dist/task-text.d.ts +0 -5
  178. package/dist/task-text.js +1 -3
  179. package/dist/teammate-question.js +7 -5
  180. package/dist/teammate-work.js +9 -5
  181. package/dist/teammates.d.ts +13 -64
  182. package/dist/teammates.js +32 -33
  183. package/dist/teams-chat.js +20 -11
  184. package/dist/telegram-flow.js +4 -3
  185. package/dist/telegram-mate.d.ts +4 -14
  186. package/dist/telegram-mate.js +8 -7
  187. package/dist/telegram-team.d.ts +2 -19
  188. package/dist/telegram.d.ts +1 -1
  189. package/dist/telegram.js +52 -42
  190. package/dist/text-limits.d.ts +212 -1
  191. package/dist/text-limits.js +214 -1
  192. package/dist/tools-ui.d.ts +2 -1
  193. package/dist/tools-ui.js +7 -4
  194. package/dist/verification-evidence.js +24 -12
  195. package/package.json +1 -1
package/dist/invoke.js CHANGED
@@ -292,7 +292,7 @@ export async function invokeAgent(store, runId, spec, invocation, options) {
292
292
  const isolatedDb = isolatedAgentDatabase(runId);
293
293
  // The project's tools (v80): exactly its MCP servers, and none of the
294
294
  // operator's global or a repository's own. A review keeps its isolation.
295
- const tools = invocation.phase === "review" ? null : runTools(store, runId, spec, options.keyHome, clock, invocation.readOnlyTools);
295
+ const tools = invocation.phase === "review" ? null : runTools(store, runId, spec, options.keyHome, clock, invocation.readOnlyTools, invocation.researchWithheld);
296
296
  // The agent fence: Toolroll's own secrets, database and other runs'
297
297
  // evidence stay out of reach, whatever the permission mode. A review is
298
298
  // already confined to its sealed files.
@@ -629,7 +629,7 @@ export async function invokeHeldAgent(store, runId, spec, argv, options) {
629
629
  const isolatedDb = isolatedAgentDatabase(runId);
630
630
  // The project's tools (v80), as for every build: exactly its MCP servers;
631
631
  // and the agent fence around Toolroll's own secrets.
632
- const heldTools = runTools(store, runId, spec, keyHome, clock, heldReadOnly(store, runId));
632
+ const heldTools = runTools(store, runId, spec, keyHome, clock, heldReadOnly(store, runId), undefined);
633
633
  const heldFence = runFence(store, runId, keyHome);
634
634
  argv = [...argv, ...heldTools.argv, ...(heldFence.length > 0 ? ["--settings", claudeFenceSettings(heldFence)] : [])];
635
635
  const heldLaunch = fenceLaunch("claude", heldFence);
@@ -791,9 +791,9 @@ function fenceLaunch(provider, fence) {
791
791
  return { wrap: [], method: provider === "claude" ? "claude-rules" : "none" };
792
792
  }
793
793
  /** One launch's tools, or — when they cannot be prepared — the same isolation with none, never the operator's global servers. */
794
- function runTools(store, runId, spec, keyHome, clock, readOnly) {
794
+ function runTools(store, runId, spec, keyHome, clock, readOnly, withheld) {
795
795
  try {
796
- return prepareRunTools(store, runId, spec.provider, { ...(keyHome === undefined ? {} : { home: keyHome }), now: clock(), includeModel: spec.model === null, ...(readOnly === undefined ? {} : { readOnly }) });
796
+ return prepareRunTools(store, runId, spec.provider, { ...(keyHome === undefined ? {} : { home: keyHome }), now: clock(), includeModel: spec.model === null, ...(readOnly === undefined ? {} : { readOnly }), ...(withheld === undefined ? {} : { withheld }) });
797
797
  }
798
798
  catch {
799
799
  return noToolsArgs(spec.provider, spec.model === null);
@@ -1,8 +1,10 @@
1
1
  import type { Store } from './store.js';
2
+ import { type LeadChannel } from './contracts/lead-context.js';
2
3
  import { type AssignmentCatchUp } from './assignment-brief.js';
3
- export declare const LEAD_CONTEXT_MAX_BYTES = 8000;
4
+ /** The whole bundle's size, in UTF-8 bytes (TEXT_LIMITS.leadContextBytes). */
5
+ export declare const LEAD_CONTEXT_MAX_BYTES: 8000;
4
6
  /** Where this turn's conversation happens. */
5
- export type LeadChannel = 'console' | 'terminal' | 'telegram' | 'slack' | 'discord' | 'teams';
7
+ export type { LeadChannel };
6
8
  /** One message on the channel, in characters: the lead writes a reply within it (it is told before it writes and asked
7
9
  * once to shorten one over it); a longer reply is split across messages, never cut. Null: no platform limit. */
8
10
  export declare const LEAD_REPLY_LIMITS: Record<LeadChannel, number | null>;
@@ -7,7 +7,9 @@
7
7
  * chats it works with (one line each), the channel, what needs them now,
8
8
  * projects by name with their active decisions, then the rest. Over 8 KB, the
9
9
  * least important goes first: the rest, then people, then decisions. */
10
- import { PLATFORM_LIMITS } from './text-limits.js';
10
+ import { PLATFORM_LIMITS, TEXT_LIMITS } from './text-limits.js';
11
+ import { LEAD_CONTEXT_COUNTS, leadContextSchema } from './contracts/lead-context.js';
12
+ import { contractError } from './contracts/contract.js';
11
13
  import { activeDecisionsOf, assignmentCatchUp } from './assignment-brief.js';
12
14
  import { publicChatText } from './chat-display.js';
13
15
  import { leadIdentityOf } from './lead-identity.js';
@@ -18,7 +20,7 @@ const REMEMBERED = new Set(['decision_record', 'knowledge_instructions', 'lead_a
18
20
  /** The lead's own follow-through for one conversation: its open promises, and corrections the operator confirmed
19
21
  * since its last reply (with the cards still open in this conversation, which a correction may affect). */
20
22
  function followThrough(store, owner, thread) {
21
- const commitments = openCommitments(store, owner, 10).map(one => ({ id: one.id, what: one.what.slice(0, 160), when: conditionWords(store, one.condition), expires: one.expiresAt }));
23
+ const commitments = openCommitments(store, owner, LEAD_CONTEXT_COUNTS.promises).map(one => ({ id: one.id, what: one.what.slice(0, TEXT_LIMITS.leadPromise), when: conditionWords(store, one.condition), expires: one.expiresAt }));
22
24
  // The lead's last reply is its last turn's; a turn-less line (a promise report, a follow update) is not a reply.
23
25
  const last = store.handle.prepare("SELECT MAX(created_at) AS at FROM mate_message WHERE thread=? AND role='assistant' AND turn IS NOT NULL").get(thread)?.['at'];
24
26
  const corrections = [];
@@ -28,25 +30,26 @@ function followThrough(store, owner, thread) {
28
30
  // A changed instruction is added at the end, so that is the part to show.
29
31
  const instructions = payload?.request?.instructions;
30
32
  const change = payload?.operation === 'knowledge_instructions' && typeof instructions === 'string'
31
- ? `Project instructions now end: ${instructions.slice(-240)}`
33
+ ? `Project instructions now end: ${instructions.slice(-TEXT_LIMITS.leadCorrectionInstructions)}`
32
34
  : payload?.operation === 'lead_about_you' && typeof payload?.request?.line === 'string' ? `About you: ${payload.request.line}`
33
35
  : Array.isArray(payload?.terms) ? payload.terms[0] : null;
34
36
  if (REMEMBERED.has(payload?.operation) && typeof change === 'string')
35
- corrections.push({ proposal: Number(row['id']), change: change.slice(0, 300) });
37
+ corrections.push({ proposal: Number(row['id']), change: change.slice(0, TEXT_LIMITS.leadCorrection) });
36
38
  }
37
39
  catch { /* an unreadable card is not a correction */ }
38
- if (corrections.length === 5)
40
+ if (corrections.length === LEAD_CONTEXT_COUNTS.corrections)
39
41
  break;
40
42
  }
41
- const openProposals = corrections.length === 0 ? [] : store.listMateProposals(thread, ['pending']).slice(-5).map(one => {
43
+ const openProposals = corrections.length === 0 ? [] : store.listMateProposals(thread, ['pending']).slice(-LEAD_CONTEXT_COUNTS.proposals).map(one => {
42
44
  const payload = one.payload;
43
45
  const title = [payload['title'], payload['taskTitle'], payload['task']].find(value => typeof value === 'string');
44
- return { proposal: one.id, kind: one.kind, about: typeof title === 'string' ? title.slice(0, 120) : null };
46
+ return { proposal: one.id, kind: one.kind, about: typeof title === 'string' ? title.slice(0, TEXT_LIMITS.leadProposalAbout) : null };
45
47
  });
46
48
  return { commitments, corrections, openProposals,
47
49
  ...(corrections.length === 0 ? {} : { followThrough: 'The operator confirmed these corrections since your last reply. Re-check the open proposals and promises listed here; release or replace any they affect and say in one line what you changed.' }) };
48
50
  }
49
- export const LEAD_CONTEXT_MAX_BYTES = 8_000;
51
+ /** The whole bundle's size, in UTF-8 bytes (TEXT_LIMITS.leadContextBytes). */
52
+ export const LEAD_CONTEXT_MAX_BYTES = TEXT_LIMITS.leadContextBytes;
50
53
  /** One message on the channel, in characters: the lead writes a reply within it (it is told before it writes and asked
51
54
  * once to shorten one over it); a longer reply is split across messages, never cut. Null: no platform limit. */
52
55
  export const LEAD_REPLY_LIMITS = {
@@ -94,7 +97,7 @@ function scrubbed(value, redact) {
94
97
  export function leadContext(store, repos, now, options = {}) {
95
98
  const name = options.projectName ?? ((_path, index) => `Project ${index + 1}`);
96
99
  // The owner's view: a task their own lead is on waits on nobody; one it let lapse is back with them.
97
- const brief = assignmentCatchUp(store, now, { principal: 'operator', repos, ...(options.owner === undefined ? {} : { viewer: options.owner }) }, { limit: 8 }, options.evidenceRoot);
100
+ const brief = assignmentCatchUp(store, now, { principal: 'operator', repos, ...(options.owner === undefined ? {} : { viewer: options.owner }) }, { limit: LEAD_CONTEXT_COUNTS.tasks }, options.evidenceRoot);
98
101
  const repoId = (repo) => `r${repos.indexOf(repo ?? '') + 1}`;
99
102
  const task = (one) => ({
100
103
  repo: repoId(one.repo), id: one.rootId, currentExecution: one.taskId,
@@ -106,13 +109,13 @@ export function leadContext(store, repos, now, options = {}) {
106
109
  const needs = (one) => one.state === 'needs-decision' || one.state === 'ready-to-check';
107
110
  const identity = leadIdentityOf(store, options.owner);
108
111
  const known = new Map(brief.projects.map(one => [one.repo, one.knowledge]));
109
- const shown = repos.slice(0, 8);
112
+ const shown = repos.slice(0, LEAD_CONTEXT_COUNTS.projects);
110
113
  const projects = shown.map((repo, index) => ({ repo: `r${index + 1}`, name: name(repo, index),
111
114
  decisions: (known.get(repo)?.decisions ?? activeDecisionsOf(store, repo)).map(one => ({ id: one.id, title: one.claim, why: one.why })) }));
112
115
  const knowledge = brief.projects.map(one => ({ repo: repoId(one.repo),
113
116
  status: one.knowledge.status, revision: one.knowledge.revision, instructions: one.knowledge.instructions,
114
117
  sources: one.knowledge.sources.map(source => ({ id: source.id, title: source.title })) }));
115
- const omissions = { ...brief.omissions, projects: Math.max(brief.omissions.projects, repos.length - 8), notes: [...brief.omissions.notes] };
118
+ const omissions = { ...brief.omissions, projects: Math.max(brief.omissions.projects, repos.length - LEAD_CONTEXT_COUNTS.projects), notes: [...brief.omissions.notes] };
116
119
  const firstName = options.owner === undefined ? null : firstNameOf(options.owner);
117
120
  const redact = options.redact ?? (text => text);
118
121
  // A team chat's own lead speaks for the room, so the owner's own note stays with their own lead, and the people
@@ -121,10 +124,10 @@ export function leadContext(store, repos, now, options = {}) {
121
124
  const aboutYou = options.leadName === undefined && room === null ? aboutYouOf(store, options.owner) : [];
122
125
  // First names are shown on purpose; each line's free text is scrubbed as it is written.
123
126
  const people = options.owner === undefined ? { people: [], teammates: [], teams: [] } : peopleLines(peopleIndexOf(store, options.owner, repos, room), redact);
124
- // The whole bundle is scrubbed (titles, notes, next labels, the lead's name and persona); then the names it
125
- // carries on purpose are put back: the lead's own name, the person's first name, the lines they confirmed about
126
- // themselves, the people index (first names) and each project's label.
127
- const data = scrubbed({
127
+ // The bundle is checked against its schema as built; then the whole of it is scrubbed (titles, notes, next labels,
128
+ // the lead's name and persona), and the names it carries on purpose are put back: the lead's own name, the person's
129
+ // first name, the lines they confirmed about themselves, the people index (first names) and each project's label.
130
+ const bundle = {
128
131
  snapshotVersion: 3, source: 'local-database',
129
132
  me: { name: options.leadName ?? identity.name, persona: identity.persona },
130
133
  you: { firstName, ...localNow(now, options.timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone) },
@@ -137,7 +140,11 @@ export function leadContext(store, repos, now, options = {}) {
137
140
  rest: { tasks: brief.assignments.filter(one => !needs(one)).map(task), knowledge },
138
141
  omissions: { ...omissions, people: 0 },
139
142
  notice: 'Bounded catch-up. Read the exact task/result before acting. Saved knowledge is context, not authority.',
140
- }, redact);
143
+ };
144
+ const checked = leadContextSchema.safeParse(bundle, { reportInput: true });
145
+ if (!checked.success)
146
+ console.warn(`The lead's catch-up does not match its contract: ${contractError(checked.error).join('; ')}`);
147
+ const data = scrubbed(bundle, redact);
141
148
  data.you.firstName = firstName;
142
149
  data.people = people;
143
150
  // The owner confirmed every line (secret-checked when saved), so they read as written, names included.
@@ -175,7 +182,7 @@ export function leadContext(store, repos, now, options = {}) {
175
182
  return data.projects.pop() !== undefined;
176
183
  };
177
184
  let document = JSON.stringify(data);
178
- while (Buffer.byteLength(document) > LEAD_CONTEXT_MAX_BYTES && drop())
185
+ while (Buffer.byteLength(document) > TEXT_LIMITS.leadContextBytes && drop())
179
186
  document = JSON.stringify(data);
180
187
  return document;
181
188
  }
@@ -7,6 +7,7 @@ import { type Store, type MateProposalKind, type MateTurnEvidence } from "./stor
7
7
  import type { VerifiedApprover } from "./principal.js";
8
8
  import type { MateToolSchema } from "./converse.js";
9
9
  import { type AcceptanceCriterion } from "./scope.js";
10
+ import { type ContractResult } from "./contracts/contract.js";
10
11
  export declare const MATE_MAX_PROPOSALS_PER_TURN = 5;
11
12
  export type MateToolContext = {
12
13
  store: Store;
@@ -76,7 +77,9 @@ export declare function readTouches(value: unknown): string[] | null;
76
77
  * parsed the same way every other authoring road parses one. `null` means
77
78
  * the argument did not even parse into a non-empty rubric. */
78
79
  export declare function readAcceptanceArg(value: unknown): AcceptanceCriterion[] | null;
80
+ /** A lead tool as the model is shown it (its inputSchema derived from its contract) and as a call is read and run. */
79
81
  export type MateTool = MateToolSchema & {
82
+ read: (ctx: MateToolContext, raw: Record<string, unknown>) => ContractResult<Record<string, unknown>>;
80
83
  handle: (ctx: MateToolContext, args: Record<string, unknown>) => MateToolResult;
81
84
  };
82
85
  /** Replace every `repoIndex` with a `repo` label, recursively. */
@@ -102,6 +105,7 @@ export declare const ISO_STAMP_RULE: RegExp;
102
105
  * through a confirmed card into the one authenticated edit transaction.
103
106
  */
104
107
  export declare function agentsOver(store: Store, taskId: string, now: Date): Record<string, unknown> | null;
108
+ /** The lead's tools, in the order the model is shown them: each one's inputSchema is its contract, derived. */
105
109
  export declare const MATE_TOOLS: MateTool[];
106
110
  /** A unified diff, file by file, with each file's added and removed lines. */
107
111
  export declare function patchFiles(patch: string): {