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
@@ -6,6 +6,10 @@ import { parseDocument } from "yaml";
6
6
  import { acceptedIdentities, learningIdentity, learningSha } from "./project-learning.js";
7
7
  import { scanForSecrets } from "./evidence.js";
8
8
  import { fileTaskProposal } from "./proposal.js";
9
+ import { TEXT_LIMITS } from "./text-limits.js";
10
+ import { contractError } from "./contracts/contract.js";
11
+ import { SKILL_COUNTS, SKILL_LIMITS, readSkillsSnapshotPayload, savedSkillPackageSchema, savedSkillsSnapshotSchema, skillPackageSchema, skillSelectionSchema, } from "./contracts/project-skills.js";
12
+ export { SKILL_LIMITS };
9
13
  export const SKILLS_SCHEMA = `
10
14
  CREATE TABLE IF NOT EXISTS skill_package (sha TEXT PRIMARY KEY, payload TEXT NOT NULL);
11
15
  CREATE TABLE IF NOT EXISTS skill_owner (sha TEXT NOT NULL REFERENCES skill_package(sha), actor TEXT NOT NULL, at TEXT NOT NULL, PRIMARY KEY(sha,actor));
@@ -14,14 +18,6 @@ CREATE TABLE IF NOT EXISTS skill_snapshot (run INTEGER PRIMARY KEY REFERENCES ru
14
18
  CREATE TABLE IF NOT EXISTS skill_test (task_ref INTEGER PRIMARY KEY REFERENCES task_ref(id), package TEXT NOT NULL REFERENCES skill_package(sha), actor TEXT NOT NULL, request_sha TEXT NOT NULL, sample TEXT NOT NULL, source_run INTEGER REFERENCES run(id), feedback TEXT, identity TEXT NOT NULL);
15
19
  ${["skill_package", "skill_owner", "project_skill_change", "skill_snapshot", "skill_test"].map((t) => `CREATE TRIGGER IF NOT EXISTS ${t}_no_update BEFORE UPDATE ON ${t} BEGIN SELECT RAISE(ABORT,'Skill history is immutable'); END; CREATE TRIGGER IF NOT EXISTS ${t}_no_delete BEFORE DELETE ON ${t} BEGIN SELECT RAISE(ABORT,'Skill history is immutable'); END;`).join("\n")}
16
20
  `;
17
- export const SKILL_LIMITS = {
18
- files: 64,
19
- packageBytes: 1024 * 1024,
20
- fileBytes: 256 * 1024,
21
- bodyBytes: 24 * 1024,
22
- enabled: 8,
23
- selectionBytes: 2 * 1024 * 1024,
24
- };
25
21
  const controls = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\u200b-\u200f\u202a-\u202e\u2066-\u2069\ufffd]/u;
26
22
  const text = (value, max, label) => {
27
23
  if (typeof value !== "string" ||
@@ -44,7 +40,7 @@ export function validateSkill(files, source) {
44
40
  .map((file) => {
45
41
  if (!file ||
46
42
  typeof file.path !== "string" ||
47
- file.path.length > 240 ||
43
+ file.path.length > TEXT_LIMITS.skillPath ||
48
44
  !/^[a-zA-Z0-9_. -]+(?:\/[a-zA-Z0-9_. -]+)*$/.test(file.path) ||
49
45
  file.path
50
46
  .split("/")
@@ -91,13 +87,13 @@ export function validateSkill(files, source) {
91
87
  }
92
88
  if (!front || typeof front !== "object" || Array.isArray(front))
93
89
  throw Error("Skill metadata must contain a name and description.");
94
- const name = text(front["name"], 64, "Skill name");
90
+ const name = text(front["name"], TEXT_LIMITS.skillNameBytes, "Skill name");
95
91
  if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name))
96
92
  throw Error("Use a lowercase skill name with hyphens between words.");
97
- const description = text(front["description"], 1024, "Description");
93
+ const description = text(front["description"], TEXT_LIMITS.skillDescriptionBytes, "Description");
98
94
  const requirements = front["compatibility"] === undefined
99
95
  ? ""
100
- : text(front["compatibility"], 500, "Requirements");
96
+ : text(front["compatibility"], TEXT_LIMITS.skillRequirementsBytes, "Requirements");
101
97
  const extensions = Object.keys(front).filter((k) => !["name", "description", "license", "compatibility", "metadata"].includes(k));
102
98
  const warnings = [];
103
99
  if (extensions.length || safe.some((f) => f.path === "agents/openai.yaml"))
@@ -106,14 +102,21 @@ export function validateSkill(files, source) {
106
102
  warnings.push("Dynamic shell substitutions are not evaluated by the skill manager.");
107
103
  if (safe.some((f) => f.path.startsWith("scripts/")))
108
104
  warnings.push("Includes scripts. Agents may run them only within their task permissions.");
109
- return {
105
+ return written(skillPackageSchema, {
110
106
  name,
111
107
  description,
112
- source: text(source, 500, "Source"),
108
+ source: text(source, TEXT_LIMITS.skillSourceBytes, "Source"),
113
109
  requirements,
114
110
  warnings,
115
111
  files: safe,
116
- };
112
+ });
113
+ }
114
+ /** A payload through its schema before it is written; a refusal names the field. */
115
+ function written(schema, value) {
116
+ const read = schema.safeParse(value, { reportInput: true });
117
+ if (!read.success)
118
+ throw Error(`This skill could not be saved: ${contractError(read.error).join("; ")}`);
119
+ return read.data;
117
120
  }
118
121
  function admit(store, repo, actor, write = false) {
119
122
  if (!store.schemaCurrent() ||
@@ -125,18 +128,24 @@ function admit(store, repo, actor, write = false) {
125
128
  /** Revisions under any identity this project accepts, as a bound JSON list. */
126
129
  const IN_ACCEPTED = "identity IN (SELECT value FROM json_each(?))";
127
130
  const listOf = (accepted) => JSON.stringify([...accepted]);
128
- function unpack(payload, sha) {
131
+ /** Saved bytes are checked against their digest first; only then are they parsed through their schema. */
132
+ function unpack(payload, sha, read) {
129
133
  if (typeof payload !== "string" || learningSha(payload) !== sha)
130
134
  throw Error("Saved skills could not be verified.");
131
- return JSON.parse(payload);
135
+ const value = read(JSON.parse(payload));
136
+ if (value === null)
137
+ throw Error("Saved skills could not be verified.");
138
+ return value;
132
139
  }
140
+ const through = (schema) => (input) => { const read = schema.safeParse(input); return read.success ? read.data : null; };
141
+ const unpackSelection = (payload, sha) => unpack(payload, sha, through(skillSelectionSchema));
133
142
  function packageOf(store, sha) {
134
143
  const row = store.handle
135
144
  .prepare("SELECT payload FROM skill_package WHERE sha=?")
136
145
  .get(sha);
137
146
  if (!row)
138
147
  throw Error("That skill version is unavailable.");
139
- return { ...unpack(row["payload"], sha), sha };
148
+ return { ...unpack(row["payload"], sha, through(savedSkillPackageSchema)), sha };
140
149
  }
141
150
  function current(store, repo, accepted) {
142
151
  const row = store.handle
@@ -148,7 +157,7 @@ function current(store, repo, accepted) {
148
157
  throw Error("The project changed. Its previous skills have not been applied.");
149
158
  return {
150
159
  revision: Number(row["revision"]),
151
- selection: unpack(row["payload"], row["sha"]),
160
+ selection: unpackSelection(row["payload"], row["sha"]),
152
161
  };
153
162
  }
154
163
  export function skillsView(store, repo, actor) {
@@ -173,7 +182,7 @@ export function skillsView(store, repo, actor) {
173
182
  }
174
183
  }
175
184
  if (row)
176
- for (const c of Object.values(unpack(row["payload"], row["sha"])))
185
+ for (const c of Object.values(unpackSelection(row["payload"], row["sha"])))
177
186
  visible.add(c.sha);
178
187
  }
179
188
  for (const c of Object.values(value.selection))
@@ -192,7 +201,7 @@ export function skillsView(store, repo, actor) {
192
201
  revision: Number(r["revision"]),
193
202
  actor: String(r["actor"]),
194
203
  at: String(r["at"]),
195
- enabled: Object.entries(unpack(r["payload"], r["sha"]))
204
+ enabled: Object.entries(unpackSelection(r["payload"], r["sha"]))
196
205
  .filter(([, c]) => c.enabled)
197
206
  .map(([name, c]) => ({ name, version: c.sha.slice(0, 10) })),
198
207
  }));
@@ -215,7 +224,7 @@ export function skillsVersion(store, repo, actor, revision) {
215
224
  const row = store.handle.prepare(`SELECT payload,sha FROM project_skill_change WHERE repo=? AND ${IN_ACCEPTED} AND revision=?`).get(repo, listOf(accepted), revision);
216
225
  if (!row)
217
226
  throw Error("That skills version is unavailable.");
218
- const selection = unpack(row["payload"], row["sha"]);
227
+ const selection = unpackSelection(row["payload"], row["sha"]);
219
228
  for (const choice of Object.values(selection))
220
229
  packageOf(store, choice.sha);
221
230
  return selection;
@@ -229,7 +238,7 @@ export function importSkill(store, repo, actor, files, source, now = new Date())
229
238
  .get(sha, actor) &&
230
239
  Number(store.handle
231
240
  .prepare("SELECT COUNT(*) AS n FROM skill_owner WHERE actor=?")
232
- .get(actor)?.["n"]) >= 100)
241
+ .get(actor)?.["n"]) >= SKILL_COUNTS.library)
233
242
  throw Error("Your library has 100 saved versions. Reuse an existing version.");
234
243
  store.handle
235
244
  .prepare("INSERT OR IGNORE INTO skill_package VALUES (?,?)")
@@ -255,7 +264,7 @@ export function changeSkills(store, args, now = new Date()) {
255
264
  .get(args.repo, listOf(accepted), args.restore ?? -1);
256
265
  if (!row)
257
266
  throw Error("That version is unavailable.");
258
- selection = unpack(row["payload"], row["sha"]);
267
+ selection = unpackSelection(row["payload"], row["sha"]);
259
268
  }
260
269
  else {
261
270
  const skill = view.library.find((p) => p.sha === args.sha);
@@ -274,7 +283,7 @@ export function changeSkills(store, args, now = new Date()) {
274
283
  if (enabled.length > SKILL_LIMITS.enabled ||
275
284
  Buffer.byteLength(JSON.stringify(enabled)) > SKILL_LIMITS.selectionBytes)
276
285
  throw Error("Enable up to 8 skills, totaling at most 2 MB.");
277
- const payload = JSON.stringify(selection);
286
+ const payload = JSON.stringify(written(skillSelectionSchema, selection));
278
287
  store.handle
279
288
  .prepare("INSERT INTO project_skill_change VALUES (?,?,?,?,?,?,?)")
280
289
  .run(args.repo, identity, view.revision + 1, args.actor, now.toISOString(), payload, learningSha(payload));
@@ -316,7 +325,7 @@ export function readSkillsSnapshot(store, runId) {
316
325
  const run = store.getRun(runId);
317
326
  if (!run || store.refForId(run.taskRef)?.repo !== row["repo"])
318
327
  throw Error("Saved skills belong to another project.");
319
- const saved = unpack(row["payload"], row["sha"]);
328
+ const saved = unpack(row["payload"], row["sha"], (input) => { const read = readSkillsSnapshotPayload(input); return read.ok ? read.value : null; });
320
329
  const { packageShas, ...facts } = saved;
321
330
  if (packageShas.length &&
322
331
  !acceptedIdentities(store, String(row["repo"])).has(facts.identity))
@@ -401,10 +410,10 @@ export function freezeSkills(store, runId) {
401
410
  }
402
411
  }
403
412
  const { packages, ...facts } = snapshot;
404
- const payload = JSON.stringify({
413
+ const payload = JSON.stringify(written(savedSkillsSnapshotSchema, {
405
414
  ...facts,
406
415
  packageShas: packages.map((p) => p.sha),
407
- });
416
+ }));
408
417
  store.handle
409
418
  .prepare("INSERT INTO skill_snapshot VALUES (?,?,?,?)")
410
419
  .run(runId, ref.repo, payload, learningSha(payload));
@@ -474,11 +483,11 @@ export function testSkill(store, args, now = new Date()) {
474
483
  const skill = view.library.find((p) => p.sha === args.sha);
475
484
  if (!skill)
476
485
  throw Error("Choose an available skill.");
477
- const sample = text(args.sample, 4000, "Sample request");
478
- if (sample.length > 800)
486
+ const sample = text(args.sample, TEXT_LIMITS.skillSampleBytes, "Sample request");
487
+ if (sample.length > TEXT_LIMITS.skillSample)
479
488
  throw Error("Keep the sample request to 800 characters.");
480
- const feedback = args.feedback === undefined ? null : text(args.feedback, 2000, "Feedback");
481
- if (feedback && feedback.length > 500)
489
+ const feedback = args.feedback === undefined ? null : text(args.feedback, TEXT_LIMITS.skillFeedbackBytes, "Feedback");
490
+ if (feedback && feedback.length > TEXT_LIMITS.skillFeedback)
482
491
  throw Error("Keep feedback to 500 characters.");
483
492
  if (args.sourceRun !== undefined) {
484
493
  const source = skillTestResult(store, args.sourceRun, args.actor);
@@ -201,6 +201,7 @@ export declare function prepareRunTools(store: Pick<Store, "projectTools" | "get
201
201
  now: Date;
202
202
  includeModel: boolean;
203
203
  readOnly?: Readonly<Record<string, readonly string[]>>;
204
+ withheld?: Readonly<Record<string, string>>;
204
205
  }): ToolLaunchArgs;
205
206
  /** When a launch's tools cannot be prepared, it still gets none of anything else's: the same isolation with an empty list. */
206
207
  export declare function noToolsArgs(provider: "claude" | "codex" | "openrouter" | "gemini", includeModel: boolean): ToolLaunchArgs;
@@ -694,7 +694,7 @@ export function toolLaunchFor(store, runId, home = homedir()) {
694
694
  * with `argv`/`env` and calls `cleanup` when the process is done.
695
695
  */
696
696
  export function prepareRunTools(store, runId, provider, options) {
697
- const launch = limitedTo(toolLaunchFor(store, runId, options.home), options.readOnly);
697
+ const launch = limitedTo(toolLaunchFor(store, runId, options.home), options.readOnly, options.withheld);
698
698
  const enabledTools = options.readOnly === undefined ? {} : { enabledTools: options.readOnly };
699
699
  const prepared = provider === "claude" ? claudeToolArgs(launch)
700
700
  : provider === "codex" ? codexToolArgs(launch, { includeModel: options.includeModel, ...enabledTools })
@@ -710,14 +710,14 @@ export function prepareRunTools(store, runId, provider, options) {
710
710
  }), options.now);
711
711
  return prepared;
712
712
  }
713
- /** A research step's launch: only the servers it may read, each limited to its read-only actions; the rest left out, saying why. */
714
- function limitedTo(launch, readOnly) {
713
+ /** A research step's launch: only the servers it may read, each limited to its read-only actions; the rest left out, saying why (`withheld`, when a service has its own reason). */
714
+ function limitedTo(launch, readOnly, withheld = {}) {
715
715
  if (readOnly === undefined)
716
716
  return launch;
717
717
  const readable = (name) => (readOnly[name] ?? []).length > 0;
718
718
  return {
719
719
  tools: launch.tools.filter(one => readable(one.spec.name)),
720
- skipped: [...launch.skipped, ...launch.tools.filter(one => !readable(one.spec.name)).map(one => ({ name: one.spec.name, reason: "research reads only connected services' read-only actions" }))],
720
+ skipped: [...launch.skipped, ...launch.tools.filter(one => !readable(one.spec.name)).map(one => ({ name: one.spec.name, reason: withheld[one.spec.name] ?? "research reads only connected services' read-only actions" }))],
721
721
  };
722
722
  }
723
723
  /** When a launch's tools cannot be prepared, it still gets none of anything else's: the same isolation with an empty list. */
package/dist/proof.d.ts CHANGED
@@ -18,31 +18,12 @@
18
18
  * returned — is gathered by the caller (`builder.ts`) and handed in as data,
19
19
  * so the review itself stays testable without a filesystem or a database.
20
20
  */
21
- import { type EvidenceKind } from "./scope.js";
21
+ import type { EvidenceKind } from "./scope.js";
22
+ import { type ContractProblem } from "./contracts/contract.js";
23
+ import type { VerifyCommandFacts } from "./contracts/verification-receipt.js";
24
+ import { type CriterionEvidenceRef, type ParsedProof } from "./contracts/proof.js";
25
+ export { PROOF_LIMITS, type CriterionEvidenceRef, type ParsedCheck, type ParsedCriterion, type ParsedProof, type ParsedScreenshot } from "./contracts/proof.js";
22
26
  export type ProofVerdict = "verified" | "attested" | "short" | "refuted";
23
- /** One typed reference the proof cites to answer a criterion's required
24
- * evidence: `ref` names an existing check's command, an existing
25
- * screenshot's path, a path inside `changed`, or (kind `manual-review`)
26
- * free-text pointing at nothing machine-checkable. Additive (v39): a
27
- * criterion with no `evidence` array parses the same as one that always
28
- * had none — legacy proofs, and every proof against a rubric-less scope,
29
- * are untouched. */
30
- export type CriterionEvidenceRef = {
31
- kind: EvidenceKind;
32
- ref: string;
33
- };
34
- export type ParsedCriterion = {
35
- id: string;
36
- statement: string;
37
- /** pending-verification asserts all agent-owned work is met; only the
38
- * machine-owned final check remains. It never upgrades a legacy failure. */
39
- verdict: "met" | "not-met" | "not-checked" | "pending-verification";
40
- how: string;
41
- /** v39: typed references answering a SIGNED criterion by exact id.
42
- * `[]` for a criterion the agent added beyond the rubric, or for any
43
- * proof written before this migration. */
44
- evidence: CriterionEvidenceRef[];
45
- };
46
27
  /** v39: the rubric side of a criterion, as `adjudicate` reads it — the
47
28
  * SIGNED id, statement, and required evidence kinds. Never `how` (never
48
29
  * signed). Empty = nothing signed: `adjudicate` runs the v1 rules,
@@ -54,31 +35,7 @@ export type ApprovedCriterion = {
54
35
  };
55
36
  /** Only submission defects. A truthful not-met answer is not malformed. */
56
37
  export declare function proofSubmissionProblems(proof: ParsedProof, rubric: readonly ApprovedCriterion[]): string[];
57
- export type ParsedCheck = {
58
- command: string;
59
- exitCode: number;
60
- summary: string;
61
- };
62
- /** A screenshot the agent claims proves UI-facing work. `path` is the
63
- * repository-relative path the file lived at in the worktree when the
64
- * agent wrote the proof — validated as a path shape here; validated as an
65
- * actual bounded PNG/JPEG, and read, by the caller. */
66
- export type ParsedScreenshot = {
67
- path: string;
68
- caption: string;
69
- };
70
- export type ParsedProof = {
71
- version: 1;
72
- criteria: ParsedCriterion[];
73
- checks: ParsedCheck[];
74
- changed: string[];
75
- caveats: string[];
76
- screenshots: ParsedScreenshot[];
77
- };
78
- export type ProofProblem = {
79
- reason: string;
80
- message: string;
81
- };
38
+ export type ProofProblem = ContractProblem;
82
39
  export type ProofParseResult = {
83
40
  ok: true;
84
41
  proof: ParsedProof;
@@ -86,31 +43,14 @@ export type ProofParseResult = {
86
43
  ok: false;
87
44
  problems: ProofProblem[];
88
45
  };
89
- /** Caps are BYTES of UTF-8, matching the scout report's rule: a payload is
90
- * the same size whatever script it is written in. */
91
- export declare const PROOF_LIMITS: {
92
- readonly payload: number;
93
- readonly criteria: 12;
94
- readonly criterionId: 40;
95
- readonly criterionStatement: 300;
96
- readonly criterionHow: 500;
97
- readonly evidencePerCriterion: 4;
98
- readonly evidenceRef: 300;
99
- readonly checks: 12;
100
- readonly checkCommand: 300;
101
- readonly checkSummary: 300;
102
- readonly changed: 64;
103
- readonly changedPath: 300;
104
- readonly caveats: 8;
105
- readonly caveat: 300;
106
- readonly screenshots: 8;
107
- readonly screenshotPath: 300;
108
- readonly screenshotCaption: 300;
109
- };
46
+ /**
47
+ * Read a proof: the payload byte cap and JSON first, then the proof schema (version 2 as itself, the version 1 a
48
+ * builder writes upgraded, a newer one refused plainly), then the plain-code rules. Every problem names its path and
49
+ * is reported at once; fail closed.
50
+ */
110
51
  export declare function parseProof(raw: string): ProofParseResult;
111
- /** Re-serialize the validated shape, never the agent's raw bytes (the
112
- * scout report's rule, `scout.ts`): what is stored and later hash-verified
113
- * is exactly what this parser admitted, key order and all. */
52
+ /** Serialize the validated shape, never the agent's raw bytes (the scout report's rule, `scout.ts`): what is stored
53
+ * and later hash-verified is exactly what the schema admitted, in its key order. */
114
54
  export declare function serializeProof(proof: ParsedProof): string;
115
55
  /** One caveat that admits an exception to a criterion the same proof marks
116
56
  * `met` — the proof's own verdict disagreeing with its own words (atomic
@@ -255,24 +195,8 @@ export declare function frozenCriterionProblems(submitted: ParsedProof, correcte
255
195
  * correction and re-reads it after that correction and after the final
256
196
  * gate; a reading that differs is never adjudicated from the cached one. */
257
197
  export declare function sameDiffStatFacts(a: DiffStatFacts | null, b: DiffStatFacts | null): boolean;
258
- /** The plane's own re-run of the repository's approved verification
259
- * command, when one is configured. `ran: false` covers both "none
260
- * configured" and "configured but the run could not attempt it" — the
261
- * latter is distinguished by `attemptFailed`, which downgrades to `short`
262
- * rather than `refuted`: "we could not check" is not "the claim is false". */
263
- export type VerifyCommandFacts = {
264
- configured: false;
265
- } | {
266
- configured: true;
267
- ran: false;
268
- attemptFailed: true;
269
- failure?: "spawn-failed" | "timed-out" | "dependency-missing" | "setup-stale" | "setup-failed" | "own-install-failed" | "tracked-files-changed" | "setup-changed-files" | "checkout-moved" | "cleanliness-unavailable" | "dependency-still-missing" | "retry-spawn-failed" | "retry-timed-out" | "custody-lost";
270
- } | {
271
- configured: true;
272
- ran: true;
273
- exitCode: number;
274
- setupReplayed?: true;
275
- };
198
+ /** What the approved verification command did (the receipt's `result`); its schema lives with the receipt. */
199
+ export type { VerifyCommandFacts } from "./contracts/verification-receipt.js";
276
200
  export type AdjudicateInput = {
277
201
  /** New captures may assess the signed goal directly when the builder wrote
278
202
  * no optional proof. Historical calls retain their original contract. */