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.
- package/CHANGELOG.md +102 -0
- package/README.md +7 -0
- package/dist/assignment-adapters.d.ts +12 -48
- package/dist/assignment-adapters.js +33 -43
- package/dist/assignment.d.ts +1 -0
- package/dist/assignment.js +2 -2
- package/dist/browser-workspace.d.ts +3 -3
- package/dist/build-review.d.ts +1 -1
- package/dist/build-review.js +2 -1
- package/dist/builder.js +4 -7
- package/dist/chat-acceptance.d.ts +2 -2
- package/dist/chat-actions.d.ts +18 -12
- package/dist/chat-actions.js +15 -65
- package/dist/chat-ask.js +5 -5
- package/dist/chat-decide.d.ts +14 -1
- package/dist/chat-decide.js +12 -6
- package/dist/chat-delivery-state.d.ts +12 -70
- package/dist/chat-delivery-state.js +17 -135
- package/dist/chat-delivery.js +58 -30
- package/dist/chat-flow.js +8 -6
- package/dist/chat-inbox.js +1 -1
- package/dist/coding-context.d.ts +2 -39
- package/dist/coding-context.js +2 -1
- package/dist/coding-handoff.d.ts +6 -25
- package/dist/coding-handoff.js +11 -5
- package/dist/coding-types.d.ts +2 -26
- package/dist/coding-workspace.d.ts +2 -0
- package/dist/coding-workspace.js +50 -14
- package/dist/contracts/acceptance-terms.d.ts +14 -0
- package/dist/contracts/acceptance-terms.js +16 -0
- package/dist/contracts/chat-actions.d.ts +328 -0
- package/dist/contracts/chat-actions.js +133 -0
- package/dist/contracts/chat-callback-rows.d.ts +59 -0
- package/dist/contracts/chat-callback-rows.js +46 -0
- package/dist/contracts/chat-content.d.ts +276 -0
- package/dist/contracts/chat-content.js +127 -0
- package/dist/contracts/chat-tables.d.ts +6 -0
- package/dist/contracts/chat-tables.js +136 -0
- package/dist/contracts/coding-context.d.ts +97 -0
- package/dist/contracts/coding-context.js +60 -0
- package/dist/contracts/coding-handoff.d.ts +44 -0
- package/dist/contracts/coding-handoff.js +47 -0
- package/dist/contracts/coding-workspace.d.ts +165 -0
- package/dist/contracts/coding-workspace.js +71 -0
- package/dist/contracts/contract.d.ts +40 -7
- package/dist/contracts/contract.js +155 -19
- package/dist/contracts/decision.d.ts +45 -0
- package/dist/contracts/decision.js +45 -0
- package/dist/contracts/discord-callback.d.ts +45 -0
- package/dist/contracts/discord-callback.js +34 -0
- package/dist/contracts/flow-card.d.ts +50 -0
- package/dist/contracts/flow-card.js +46 -0
- package/dist/contracts/flow-propose.d.ts +325 -0
- package/dist/contracts/flow-propose.js +41 -0
- package/dist/contracts/flow-send.d.ts +119 -0
- package/dist/contracts/flow-send.js +112 -0
- package/dist/contracts/flow.d.ts +19405 -0
- package/dist/contracts/flow.js +364 -0
- package/dist/contracts/gateway-tools.d.ts +374 -0
- package/dist/contracts/gateway-tools.js +94 -0
- package/dist/contracts/handoff.d.ts +91 -0
- package/dist/contracts/handoff.js +82 -0
- package/dist/contracts/lead-context.d.ts +165 -0
- package/dist/contracts/lead-context.js +73 -0
- package/dist/contracts/lead-tools.d.ts +1905 -0
- package/dist/contracts/lead-tools.js +265 -0
- package/dist/contracts/memory-pass.d.ts +158 -0
- package/dist/contracts/memory-pass.js +102 -0
- package/dist/contracts/project-knowledge.d.ts +126 -0
- package/dist/contracts/project-knowledge.js +93 -0
- package/dist/contracts/project-memory.d.ts +117 -0
- package/dist/contracts/project-memory.js +51 -0
- package/dist/contracts/project-skills.d.ts +121 -0
- package/dist/contracts/project-skills.js +76 -0
- package/dist/contracts/proof.d.ts +136 -0
- package/dist/contracts/proof.js +110 -0
- package/dist/contracts/review-findings.d.ts +46 -0
- package/dist/contracts/review-findings.js +48 -0
- package/dist/contracts/route.d.ts +484 -0
- package/dist/contracts/route.js +128 -0
- package/dist/contracts/scope.d.ts +105 -0
- package/dist/contracts/scope.js +114 -0
- package/dist/contracts/scout-report.d.ts +234 -0
- package/dist/contracts/scout-report.js +141 -0
- package/dist/contracts/slack-callback.d.ts +43 -0
- package/dist/contracts/slack-callback.js +35 -0
- package/dist/contracts/sort-answer.d.ts +83 -0
- package/dist/contracts/sort-answer.js +77 -0
- package/dist/contracts/stage-output.d.ts +127 -0
- package/dist/contracts/stage-output.js +166 -0
- package/dist/contracts/task-sizing.d.ts +24 -0
- package/dist/contracts/task-sizing.js +28 -0
- package/dist/contracts/teammate-turn.d.ts +43 -0
- package/dist/contracts/teammate-turn.js +51 -0
- package/dist/contracts/teams-callback.d.ts +14 -0
- package/dist/contracts/teams-callback.js +14 -0
- package/dist/contracts/telegram-callback.d.ts +120 -0
- package/dist/contracts/telegram-callback.js +97 -0
- package/dist/contracts/verification-receipt.d.ts +148 -0
- package/dist/contracts/verification-receipt.js +87 -0
- package/dist/decision.d.ts +11 -20
- package/dist/decision.js +86 -167
- package/dist/demo.js +28 -11
- package/dist/discord-chat.js +31 -20
- package/dist/evidence.d.ts +3 -40
- package/dist/evidence.js +5 -1
- package/dist/flow-engine.js +14 -17
- package/dist/flow-gallery.d.ts +3 -2
- package/dist/flow-items.d.ts +4 -13
- package/dist/flow-items.js +1 -15
- package/dist/flow-send.d.ts +6 -37
- package/dist/flow-send.js +18 -14
- package/dist/flow-share.d.ts +10 -32
- package/dist/flow-share.js +72 -84
- package/dist/flow-sort.d.ts +7 -26
- package/dist/flow-sort.js +25 -20
- package/dist/flow-starters.d.ts +2 -1
- package/dist/flow-steps.js +3 -2
- package/dist/flow-triggers.d.ts +15 -72
- package/dist/flow-triggers.js +94 -83
- package/dist/flows.d.ts +37 -220
- package/dist/flows.js +356 -387
- package/dist/invoke.js +4 -4
- package/dist/lead-context.d.ts +4 -2
- package/dist/lead-context.js +24 -17
- package/dist/mate-tools.d.ts +4 -0
- package/dist/mate-tools.js +111 -308
- package/dist/mcp-connect.d.ts +27 -4
- package/dist/mcp-connect.js +92 -17
- package/dist/mcp.js +84 -216
- package/dist/memory-pass.d.ts +17 -42
- package/dist/memory-pass.js +54 -26
- package/dist/operate.js +31 -2
- package/dist/phase-routing.d.ts +19 -72
- package/dist/phase-routing.js +34 -164
- package/dist/plan.d.ts +5 -5
- package/dist/plan.js +5 -25
- package/dist/process-recovery-eligibility.d.ts +2 -2
- package/dist/process-recovery-eligibility.js +13 -8
- package/dist/project-knowledge.d.ts +16 -35
- package/dist/project-knowledge.js +42 -21
- package/dist/project-memory.d.ts +2 -28
- package/dist/project-memory.js +28 -13
- package/dist/project-skills.d.ts +16 -38
- package/dist/project-skills.js +41 -32
- package/dist/project-tools.d.ts +1 -0
- package/dist/project-tools.js +4 -4
- package/dist/proof.d.ts +15 -91
- package/dist/proof.js +90 -249
- package/dist/provider.d.ts +2 -0
- package/dist/provider.js +4 -16
- package/dist/result-evidence-readers.d.ts +42 -0
- package/dist/result-evidence-readers.js +91 -0
- package/dist/result-shots.d.ts +1 -1
- package/dist/result-shots.js +2 -1
- package/dist/review-switch.d.ts +3 -8
- package/dist/reviewer.d.ts +8 -12
- package/dist/reviewer.js +11 -35
- package/dist/scope.d.ts +21 -43
- package/dist/scope.js +42 -128
- package/dist/scout-report.d.ts +9 -194
- package/dist/scout-report.js +113 -264
- package/dist/scout.js +15 -11
- package/dist/serve.js +17 -101
- package/dist/slack-chat.js +26 -20
- package/dist/slack-state.js +2 -1
- package/dist/store.d.ts +9 -32
- package/dist/store.js +18 -15
- package/dist/structured-output.js +2 -1
- package/dist/subscription-chat.d.ts +4 -0
- package/dist/subscription-chat.js +4 -1
- package/dist/surface.js +8 -1
- package/dist/task-review-brief.d.ts +69 -0
- package/dist/task-review-brief.js +179 -0
- package/dist/task-sizing.d.ts +3 -27
- package/dist/task-sizing.js +11 -26
- package/dist/task-text.d.ts +0 -5
- package/dist/task-text.js +1 -3
- package/dist/teammate-question.js +7 -5
- package/dist/teammate-work.js +9 -5
- package/dist/teammates.d.ts +13 -64
- package/dist/teammates.js +32 -33
- package/dist/teams-chat.js +20 -11
- package/dist/telegram-flow.js +4 -3
- package/dist/telegram-mate.d.ts +4 -14
- package/dist/telegram-mate.js +8 -7
- package/dist/telegram-team.d.ts +2 -19
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +52 -42
- package/dist/text-limits.d.ts +212 -1
- package/dist/text-limits.js +214 -1
- package/dist/tools-ui.d.ts +2 -1
- package/dist/tools-ui.js +7 -4
- package/dist/verification-evidence.js +24 -12
- package/package.json +1 -1
package/dist/proof.js
CHANGED
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
* so the review itself stays testable without a filesystem or a database.
|
|
20
20
|
*/
|
|
21
21
|
import { hasForbiddenControls } from "./decision.js";
|
|
22
|
-
import {
|
|
22
|
+
import { contractProblemOf } from "./contracts/contract.js";
|
|
23
|
+
import { PROOF_LIMITS, proofPayloadBody, readProofPayload } from "./contracts/proof.js";
|
|
24
|
+
export { PROOF_LIMITS } from "./contracts/proof.js";
|
|
23
25
|
/** Shared by preflight and final adjudication; presentation text is never a rubric. */
|
|
24
26
|
function criterionContractProblems(approved, answer) {
|
|
25
27
|
if (answer === undefined)
|
|
@@ -57,248 +59,96 @@ export function proofSubmissionProblems(proof, rubric) {
|
|
|
57
59
|
problems.push(...failedMetChecks(proof).map(failedCheckWords));
|
|
58
60
|
return problems;
|
|
59
61
|
}
|
|
60
|
-
/** Caps are BYTES of UTF-8, matching the scout report's rule: a payload is
|
|
61
|
-
* the same size whatever script it is written in. */
|
|
62
|
-
export const PROOF_LIMITS = {
|
|
63
|
-
payload: 64 * 1024,
|
|
64
|
-
criteria: 12,
|
|
65
|
-
criterionId: 40,
|
|
66
|
-
criterionStatement: 300,
|
|
67
|
-
criterionHow: 500,
|
|
68
|
-
evidencePerCriterion: 4,
|
|
69
|
-
evidenceRef: 300,
|
|
70
|
-
checks: 12,
|
|
71
|
-
checkCommand: 300,
|
|
72
|
-
checkSummary: 300,
|
|
73
|
-
changed: 64,
|
|
74
|
-
changedPath: 300,
|
|
75
|
-
caveats: 8,
|
|
76
|
-
caveat: 300,
|
|
77
|
-
screenshots: 8,
|
|
78
|
-
screenshotPath: 300,
|
|
79
|
-
screenshotCaption: 300,
|
|
80
|
-
};
|
|
81
62
|
function refuse(reason, message) {
|
|
82
63
|
return { ok: false, problems: [{ reason, message }] };
|
|
83
64
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
if (hasForbiddenControls(value)) {
|
|
107
|
-
problems.push({ reason: `${field}-controls`, message: `${field} carries control characters that could become terminal escapes` });
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
/** A repository-relative path: no leading slash, no drive letter, no `.`/`..`
|
|
113
|
-
* segment, no backslash, no control character. The same shape
|
|
114
|
-
* `readVerifiedArtifact` enforces on an evidence key, applied here to a
|
|
115
|
-
* path an agent claims rather than one the machine already wrote. */
|
|
116
|
-
function relativePath(value, field, cap, problems) {
|
|
117
|
-
const raw = prose(value, field, cap, problems);
|
|
118
|
-
if (raw === null)
|
|
119
|
-
return null;
|
|
120
|
-
const segments = raw.split("/");
|
|
121
|
-
const wellFormed = !raw.startsWith("/") &&
|
|
122
|
-
segments.every(segment => segment.length > 0 && segment !== "." && segment !== ".." && !segment.includes("\\"));
|
|
123
|
-
if (!wellFormed) {
|
|
124
|
-
problems.push({ reason: `${field}-not-relative`, message: `${field} must be a normalized repository-relative path (got ${describe(value)})` });
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
return raw;
|
|
128
|
-
}
|
|
129
|
-
/** `evidence` is optional on a criterion (absent → `[]`, exactly like every
|
|
130
|
-
* other list here) — the mandatory PRESENCE of an answer for a SIGNED
|
|
131
|
-
* criterion is `adjudicate`'s concern, not the parser's; this only proves
|
|
132
|
-
* the shape of what is there. */
|
|
133
|
-
function parseEvidenceRefs(value, field, problems) {
|
|
134
|
-
if (value === undefined || value === null)
|
|
135
|
-
return [];
|
|
136
|
-
if (!Array.isArray(value)) {
|
|
137
|
-
problems.push({ reason: `bad-${field}`, message: `${field} must be an array (got ${describe(value)})` });
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
if (value.length > PROOF_LIMITS.evidencePerCriterion) {
|
|
141
|
-
problems.push({ reason: `${field}-too-many`, message: `${field} lists ${value.length} — cap is ${PROOF_LIMITS.evidencePerCriterion}` });
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
const refs = [];
|
|
145
|
-
let bad = false;
|
|
146
|
-
for (const [index, entry] of value.entries()) {
|
|
147
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
148
|
-
problems.push({ reason: `${field}[${index}]-shape`, message: `${field}[${index}] must be an object` });
|
|
149
|
-
bad = true;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
const one = entry;
|
|
153
|
-
const kind = one["kind"];
|
|
154
|
-
if (typeof kind !== "string" || !EVIDENCE_KINDS.includes(kind)) {
|
|
155
|
-
problems.push({
|
|
156
|
-
reason: `${field}[${index}]-bad-kind`,
|
|
157
|
-
message: `${field}[${index}].kind must draw from ${EVIDENCE_KINDS.join(", ")} (got ${describe(kind)})`,
|
|
158
|
-
});
|
|
159
|
-
bad = true;
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
const ref = prose(one["ref"], `${field}[${index}].ref`, PROOF_LIMITS.evidenceRef, problems);
|
|
163
|
-
if (ref === null) {
|
|
164
|
-
bad = true;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
refs.push({ kind: kind, ref });
|
|
168
|
-
}
|
|
169
|
-
return bad ? null : refs;
|
|
170
|
-
}
|
|
171
|
-
function parseCriteria(value, problems) {
|
|
172
|
-
if (value === undefined || value === null)
|
|
173
|
-
return [];
|
|
174
|
-
if (!Array.isArray(value)) {
|
|
175
|
-
problems.push({ reason: "bad-criteria", message: `criteria must be an array (got ${describe(value)})` });
|
|
176
|
-
return [];
|
|
177
|
-
}
|
|
178
|
-
if (value.length > PROOF_LIMITS.criteria) {
|
|
179
|
-
problems.push({ reason: "criteria-too-many", message: `criteria lists ${value.length} — cap is ${PROOF_LIMITS.criteria}` });
|
|
180
|
-
return [];
|
|
181
|
-
}
|
|
182
|
-
const criteria = [];
|
|
183
|
-
const seen = new Set();
|
|
184
|
-
for (const [index, entry] of value.entries()) {
|
|
185
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
186
|
-
problems.push({ reason: `criteria[${index}]-shape`, message: `criteria[${index}] must be an object` });
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
const one = entry;
|
|
190
|
-
const id = prose(one["id"], `criteria[${index}].id`, PROOF_LIMITS.criterionId, problems);
|
|
191
|
-
if (id !== null && seen.has(id)) {
|
|
192
|
-
problems.push({ reason: `criteria[${index}]-duplicate-id`, message: `criterion id "${id}" appears twice` });
|
|
193
|
-
}
|
|
194
|
-
else if (id !== null) {
|
|
195
|
-
seen.add(id);
|
|
196
|
-
}
|
|
197
|
-
const statement = prose(one["statement"], `criteria[${index}].statement`, PROOF_LIMITS.criterionStatement, problems);
|
|
198
|
-
const how = prose(one["how"], `criteria[${index}].how`, PROOF_LIMITS.criterionHow, problems);
|
|
199
|
-
const verdict = one["verdict"];
|
|
200
|
-
if (verdict !== "met" && verdict !== "not-met" && verdict !== "not-checked" && verdict !== "pending-verification") {
|
|
201
|
-
problems.push({
|
|
202
|
-
reason: `criteria[${index}]-bad-verdict`,
|
|
203
|
-
message: `criteria[${index}].verdict must be "met", "not-met", "not-checked", or "pending-verification" (got ${describe(verdict)})`,
|
|
204
|
-
});
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
const evidence = parseEvidenceRefs(one["evidence"], `criteria[${index}].evidence`, problems);
|
|
208
|
-
if (id === null || statement === null || how === null || evidence === null)
|
|
209
|
-
continue;
|
|
210
|
-
criteria.push({ id, statement, how, verdict, evidence });
|
|
211
|
-
}
|
|
212
|
-
return criteria;
|
|
213
|
-
}
|
|
214
|
-
function parseChecks(value, problems) {
|
|
215
|
-
if (value === undefined || value === null)
|
|
216
|
-
return [];
|
|
217
|
-
if (!Array.isArray(value)) {
|
|
218
|
-
problems.push({ reason: "bad-checks", message: `checks must be an array (got ${describe(value)})` });
|
|
219
|
-
return [];
|
|
220
|
-
}
|
|
221
|
-
if (value.length > PROOF_LIMITS.checks) {
|
|
222
|
-
problems.push({ reason: "checks-too-many", message: `checks lists ${value.length} — cap is ${PROOF_LIMITS.checks}` });
|
|
223
|
-
return [];
|
|
224
|
-
}
|
|
225
|
-
const checks = [];
|
|
226
|
-
for (const [index, entry] of value.entries()) {
|
|
227
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
228
|
-
problems.push({ reason: `checks[${index}]-shape`, message: `checks[${index}] must be an object` });
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
const one = entry;
|
|
232
|
-
const command = prose(one["command"], `checks[${index}].command`, PROOF_LIMITS.checkCommand, problems);
|
|
233
|
-
const summary = prose(one["summary"], `checks[${index}].summary`, PROOF_LIMITS.checkSummary, problems);
|
|
234
|
-
const exitCode = one["exitCode"];
|
|
235
|
-
if (typeof exitCode !== "number" || !Number.isInteger(exitCode) || exitCode < 0 || exitCode > 255) {
|
|
236
|
-
problems.push({
|
|
237
|
-
reason: `checks[${index}]-bad-exit-code`,
|
|
238
|
-
message: `checks[${index}].exitCode must be an integer 0-255 (got ${describe(exitCode)})`,
|
|
65
|
+
/** Every text field of a proof body (version 2 shape) that the schema saw as a string. */
|
|
66
|
+
function textFields(body) {
|
|
67
|
+
const out = [];
|
|
68
|
+
const text = (path, value, bytes, relative) => {
|
|
69
|
+
if (typeof value === "string")
|
|
70
|
+
out.push({ path, value, bytes, ...(relative ? { relative } : {}) });
|
|
71
|
+
};
|
|
72
|
+
const records = (field) => {
|
|
73
|
+
const list = body[field];
|
|
74
|
+
return Array.isArray(list) ? list.flatMap((one, index) => (typeof one === "object" && one !== null && !Array.isArray(one) ? [[index, one]] : [])) : [];
|
|
75
|
+
};
|
|
76
|
+
for (const [index, one] of records("criteria")) {
|
|
77
|
+
text(`criteria[${index}].id`, one["id"], PROOF_LIMITS.criterionId);
|
|
78
|
+
text(`criteria[${index}].statement`, one["statement"], PROOF_LIMITS.criterionStatement);
|
|
79
|
+
text(`criteria[${index}].how`, one["how"], PROOF_LIMITS.criterionHow);
|
|
80
|
+
const evidence = one["evidence"];
|
|
81
|
+
if (Array.isArray(evidence)) {
|
|
82
|
+
evidence.forEach((ref, at) => {
|
|
83
|
+
if (typeof ref === "object" && ref !== null)
|
|
84
|
+
text(`criteria[${index}].evidence[${at}].ref`, ref["ref"], PROOF_LIMITS.evidenceRef);
|
|
239
85
|
});
|
|
240
|
-
continue;
|
|
241
86
|
}
|
|
242
|
-
if (command === null || summary === null)
|
|
243
|
-
continue;
|
|
244
|
-
checks.push({ command, summary, exitCode });
|
|
245
87
|
}
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (value === undefined || value === null)
|
|
250
|
-
return [];
|
|
251
|
-
if (!Array.isArray(value)) {
|
|
252
|
-
problems.push({ reason: `bad-${field}`, message: `${field} must be an array (got ${describe(value)})` });
|
|
253
|
-
return [];
|
|
88
|
+
for (const [index, one] of records("checks")) {
|
|
89
|
+
text(`checks[${index}].command`, one["command"], PROOF_LIMITS.checkCommand);
|
|
90
|
+
text(`checks[${index}].summary`, one["summary"], PROOF_LIMITS.checkSummary);
|
|
254
91
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
92
|
+
for (const field of ["changed", "caveats"]) {
|
|
93
|
+
const list = body[field];
|
|
94
|
+
if (Array.isArray(list))
|
|
95
|
+
list.forEach((one, index) => text(`${field}[${index}]`, one, field === "changed" ? PROOF_LIMITS.changedPath : PROOF_LIMITS.caveat));
|
|
258
96
|
}
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (item !== null)
|
|
263
|
-
out.push(item);
|
|
97
|
+
for (const [index, one] of records("screenshots")) {
|
|
98
|
+
text(`screenshots[${index}].path`, one["path"], PROOF_LIMITS.screenshotPath, true);
|
|
99
|
+
text(`screenshots[${index}].caption`, one["caption"], PROOF_LIMITS.screenshotCaption);
|
|
264
100
|
}
|
|
265
101
|
return out;
|
|
266
102
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const screenshots = [];
|
|
279
|
-
const seen = new Set();
|
|
280
|
-
for (const [index, entry] of value.entries()) {
|
|
281
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
282
|
-
problems.push({ reason: `screenshots[${index}]-shape`, message: `screenshots[${index}] must be an object` });
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
const one = entry;
|
|
286
|
-
const path = relativePath(one["path"], `screenshots[${index}].path`, PROOF_LIMITS.screenshotPath, problems);
|
|
287
|
-
const caption = prose(one["caption"], `screenshots[${index}].caption`, PROOF_LIMITS.screenshotCaption, problems);
|
|
288
|
-
if (path !== null && seen.has(path)) {
|
|
289
|
-
problems.push({ reason: `screenshots[${index}]-duplicate-path`, message: `screenshot path "${path}" appears twice` });
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (path === null || caption === null)
|
|
103
|
+
/**
|
|
104
|
+
* The rules JSON Schema cannot state, in plain code with path-named errors: blank text, UTF-8 byte limits, control
|
|
105
|
+
* characters, normalized repository-relative screenshot paths (no leading slash, `.`/`..` segment or backslash — the
|
|
106
|
+
* shape `readVerifiedArtifact` enforces on an evidence key), and unique criterion ids and screenshot paths. A field
|
|
107
|
+
* the schema already refused is not reported twice.
|
|
108
|
+
*/
|
|
109
|
+
function proofRuleProblems(body, contract) {
|
|
110
|
+
const named = (path) => contract.some(problem => problem.message.startsWith(`${path}:`));
|
|
111
|
+
const problems = [];
|
|
112
|
+
for (const field of textFields(body)) {
|
|
113
|
+
if (named(field.path))
|
|
293
114
|
continue;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
115
|
+
const { path, value } = field;
|
|
116
|
+
if (value.trim() === "")
|
|
117
|
+
problems.push({ reason: `missing-${path}`, message: `${path}: must not be blank` });
|
|
118
|
+
else if (Buffer.byteLength(value, "utf8") > field.bytes)
|
|
119
|
+
problems.push({ reason: `${path}-too-long`, message: `${path}: over ${field.bytes.toLocaleString("en-US")} bytes` });
|
|
120
|
+
else if (hasForbiddenControls(value))
|
|
121
|
+
problems.push({ reason: `${path}-controls`, message: `${path}: carries control characters that could become terminal escapes` });
|
|
122
|
+
else if (field.relative && (value.startsWith("/") || !value.split("/").every(segment => segment.length > 0 && segment !== "." && segment !== ".." && !segment.includes("\\")))) {
|
|
123
|
+
problems.push({ reason: `${path}-not-relative`, message: `${path}: must be a normalized repository-relative path` });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const unique = (field, key, what) => {
|
|
127
|
+
const list = body[field];
|
|
128
|
+
if (!Array.isArray(list) || named(field))
|
|
129
|
+
return;
|
|
130
|
+
const seen = new Set();
|
|
131
|
+
list.forEach((one, index) => {
|
|
132
|
+
const value = typeof one === "object" && one !== null ? one[key] : undefined;
|
|
133
|
+
if (typeof value !== "string")
|
|
134
|
+
return;
|
|
135
|
+
if (seen.has(value))
|
|
136
|
+
problems.push({ reason: `${field}[${index}]-duplicate-${key}`, message: `${field}[${index}].${key}: ${what} ${JSON.stringify(value)} appears twice` });
|
|
137
|
+
seen.add(value);
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
unique("criteria", "id", "criterion id");
|
|
141
|
+
unique("screenshots", "path", "screenshot path");
|
|
142
|
+
return problems;
|
|
298
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Read a proof: the payload byte cap and JSON first, then the proof schema (version 2 as itself, the version 1 a
|
|
146
|
+
* builder writes upgraded, a newer one refused plainly), then the plain-code rules. Every problem names its path and
|
|
147
|
+
* is reported at once; fail closed.
|
|
148
|
+
*/
|
|
299
149
|
export function parseProof(raw) {
|
|
300
150
|
if (Buffer.byteLength(raw, "utf8") > PROOF_LIMITS.payload) {
|
|
301
|
-
return refuse("too-large", `
|
|
151
|
+
return refuse("too-large", `payload: over ${PROOF_LIMITS.payload.toLocaleString("en-US")} bytes`);
|
|
302
152
|
}
|
|
303
153
|
let parsed;
|
|
304
154
|
try {
|
|
@@ -307,29 +157,20 @@ export function parseProof(raw) {
|
|
|
307
157
|
catch (error) {
|
|
308
158
|
return refuse("not-json", `the payload is not JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
309
159
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
const
|
|
315
|
-
if (
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const checks = parseChecks(body["checks"], problems);
|
|
320
|
-
const changed = parseStringList(body["changed"], "changed", PROOF_LIMITS.changed, PROOF_LIMITS.changedPath, problems);
|
|
321
|
-
const caveats = parseStringList(body["caveats"], "caveats", PROOF_LIMITS.caveats, PROOF_LIMITS.caveat, problems);
|
|
322
|
-
const screenshots = parseScreenshots(body["screenshots"], problems);
|
|
323
|
-
if (problems.length > 0)
|
|
160
|
+
const body = proofPayloadBody(parsed);
|
|
161
|
+
if (body === null)
|
|
162
|
+
return refuse("not-an-object", "payload: must be one JSON object");
|
|
163
|
+
const read = readProofPayload(parsed);
|
|
164
|
+
const contract = read.ok ? [] : read.issues.map(contractProblemOf);
|
|
165
|
+
if (contract.some(problem => problem.reason === "newer-version" || problem.reason === "bad-version"))
|
|
166
|
+
return { ok: false, problems: contract };
|
|
167
|
+
const problems = [...contract, ...proofRuleProblems(body, contract)];
|
|
168
|
+
if (!read.ok || problems.length > 0)
|
|
324
169
|
return { ok: false, problems };
|
|
325
|
-
return {
|
|
326
|
-
ok: true,
|
|
327
|
-
proof: { version: 1, criteria, checks, changed, caveats, screenshots },
|
|
328
|
-
};
|
|
170
|
+
return { ok: true, proof: read.value };
|
|
329
171
|
}
|
|
330
|
-
/**
|
|
331
|
-
*
|
|
332
|
-
* is exactly what this parser admitted, key order and all. */
|
|
172
|
+
/** Serialize the validated shape, never the agent's raw bytes (the scout report's rule, `scout.ts`): what is stored
|
|
173
|
+
* and later hash-verified is exactly what the schema admitted, in its key order. */
|
|
333
174
|
export function serializeProof(proof) {
|
|
334
175
|
return JSON.stringify(proof, null, 2);
|
|
335
176
|
}
|
package/dist/provider.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ export type Invocation = {
|
|
|
81
81
|
/** A research step's project tools: only these servers, each offering only
|
|
82
82
|
* these read-only actions (Codex's `enabled_tools`). Others are left out. */
|
|
83
83
|
readOnlyTools?: Readonly<Record<string, readonly string[]>>;
|
|
84
|
+
/** Why a research step's connected service was left out, by server, when it isn't the usual reason (its grant writes). */
|
|
85
|
+
researchWithheld?: Readonly<Record<string, string>>;
|
|
84
86
|
};
|
|
85
87
|
export type ProviderRunner = (file: string, args: readonly string[], options?: RunOptions) => Promise<ExecResult>;
|
|
86
88
|
/** The harness's own account of how a turn ended. */
|
package/dist/provider.js
CHANGED
|
@@ -22,6 +22,7 @@ import { claudeFenceSettings, codexFenceArgv } from "./agent-fence.js";
|
|
|
22
22
|
import {} from "./exec.js";
|
|
23
23
|
import { runStreamJsonl, runClaudeStreamJsonl, runGeminiStreamJsonl } from "./exec.js";
|
|
24
24
|
import { scanForSecrets } from "./evidence.js";
|
|
25
|
+
import { FINDINGS_MODEL_SCHEMA } from "./contracts/review-findings.js";
|
|
25
26
|
import { REVIEW_OUTPUT_LIMITS } from "./structured-output.js";
|
|
26
27
|
export const PROVIDER_IDS = ["claude", "codex", "openrouter", "gemini"];
|
|
27
28
|
export function isProviderId(value) {
|
|
@@ -169,22 +170,9 @@ const CLAUDE_REVIEW_JSON_SCHEMA = {
|
|
|
169
170
|
additionalProperties: false,
|
|
170
171
|
},
|
|
171
172
|
},
|
|
172
|
-
// The automatic build review's reply (build-review.ts)
|
|
173
|
-
// parseBuildFindings
|
|
174
|
-
findings:
|
|
175
|
-
type: "array",
|
|
176
|
-
items: {
|
|
177
|
-
type: "object",
|
|
178
|
-
properties: {
|
|
179
|
-
severity: { type: "string", enum: ["HIGH", "MEDIUM", "LOW"] },
|
|
180
|
-
file: { type: "string" },
|
|
181
|
-
line: { type: "integer", minimum: 1 },
|
|
182
|
-
scenario: { type: "string" },
|
|
183
|
-
},
|
|
184
|
-
required: ["severity", "file", "line", "scenario"],
|
|
185
|
-
additionalProperties: false,
|
|
186
|
-
},
|
|
187
|
-
},
|
|
173
|
+
// The automatic build review's reply (build-review.ts), from its one
|
|
174
|
+
// schema (src/contracts/review-findings.ts); parseBuildFindings reads it.
|
|
175
|
+
findings: FINDINGS_MODEL_SCHEMA,
|
|
188
176
|
// The read request rides the same structured reply channel and
|
|
189
177
|
// session. The machine validates the exact allowlist/hash/range
|
|
190
178
|
// before supplying bytes; this only shapes the request.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Shared verified readers for result screens and the compact CLI review. */
|
|
2
|
+
import type { Artifact } from "./store.js";
|
|
3
|
+
export declare const SCREENSHOT_CAPTURE: RegExp;
|
|
4
|
+
/** What the run page shows of the terminal diff — verified bytes or a named problem, never silence. */
|
|
5
|
+
export type TerminalDiffView = {
|
|
6
|
+
patch: {
|
|
7
|
+
text: string;
|
|
8
|
+
truncated: boolean;
|
|
9
|
+
artifactId: number;
|
|
10
|
+
} | {
|
|
11
|
+
problem: string;
|
|
12
|
+
} | null;
|
|
13
|
+
stat: {
|
|
14
|
+
base: string;
|
|
15
|
+
head: string;
|
|
16
|
+
fileCount: number;
|
|
17
|
+
additions: number;
|
|
18
|
+
deletions: number;
|
|
19
|
+
binaryCount: number;
|
|
20
|
+
filesTruncated: boolean;
|
|
21
|
+
files: {
|
|
22
|
+
path: string;
|
|
23
|
+
additions: number | null;
|
|
24
|
+
deletions: number | null;
|
|
25
|
+
renamedFrom?: string;
|
|
26
|
+
}[];
|
|
27
|
+
} | {
|
|
28
|
+
problem: string;
|
|
29
|
+
} | null;
|
|
30
|
+
};
|
|
31
|
+
/** A compact, typed view of the agent-authored handoff. Older v1
|
|
32
|
+
* artifacts simply have no lists, while v2 can present the useful answer
|
|
33
|
+
* before the raw diff and evidence below it. */
|
|
34
|
+
export type StructuredHandoffView = {
|
|
35
|
+
conclusion: string;
|
|
36
|
+
changes: string[];
|
|
37
|
+
verification: string[];
|
|
38
|
+
followUps: string[];
|
|
39
|
+
};
|
|
40
|
+
export declare function structuredHandoffView(artifacts: Artifact[], root: string, displayText?: (text: string) => string): StructuredHandoffView | null;
|
|
41
|
+
/** A failed capture or unverifiable bytes keep their problem; absence returns null. */
|
|
42
|
+
export declare function terminalDiffView(artifacts: Artifact[], root: string): TerminalDiffView | null;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { readVerifiedArtifact } from "./evidence.js";
|
|
2
|
+
import { hasForbiddenControls } from "./decision.js";
|
|
3
|
+
import { parseHandoffArtifact } from "./contracts/handoff.js";
|
|
4
|
+
const CAPTURE_EXIT = /\(exit ([0-9]{1,4})\)\s*$/;
|
|
5
|
+
export const SCREENSHOT_CAPTURE = /^agent-claimed screenshot at (.+) \(validated (?:png|jpeg)\)/;
|
|
6
|
+
const oneLineOf = (text, cap) => {
|
|
7
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
8
|
+
return flat.length <= cap ? flat : `${flat.slice(0, cap - 1)}…`;
|
|
9
|
+
};
|
|
10
|
+
export function structuredHandoffView(artifacts, root, displayText = text => text) {
|
|
11
|
+
const artifact = [...artifacts].reverse().find(one => one.kind === "handoff");
|
|
12
|
+
if (artifact === undefined)
|
|
13
|
+
return null;
|
|
14
|
+
const read = readVerifiedArtifact(root, artifact);
|
|
15
|
+
if (!read.ok)
|
|
16
|
+
return null;
|
|
17
|
+
const parsed = parseHandoffArtifact(read.content.toString("utf8"));
|
|
18
|
+
if (!parsed.ok)
|
|
19
|
+
return null;
|
|
20
|
+
const handoff = parsed.value;
|
|
21
|
+
const conclusion = oneLineOf(displayText(handoff.conclusion), 600);
|
|
22
|
+
if (conclusion === "" || hasForbiddenControls(conclusion))
|
|
23
|
+
return null;
|
|
24
|
+
const list = (items) => (items ?? [])
|
|
25
|
+
.filter(one => one.trim() !== "" && !hasForbiddenControls(one))
|
|
26
|
+
.slice(0, 8)
|
|
27
|
+
.map(one => oneLineOf(one, 240));
|
|
28
|
+
return { conclusion, changes: list(handoff.changes), verification: list(handoff.verification), followUps: list(handoff.followUps) };
|
|
29
|
+
}
|
|
30
|
+
/** A failed capture or unverifiable bytes keep their problem; absence returns null. */
|
|
31
|
+
export function terminalDiffView(artifacts, root) {
|
|
32
|
+
const patchArtifact = artifacts.find(one => one.kind === "terminal-diff");
|
|
33
|
+
const statArtifact = artifacts.find(one => one.kind === "diff-stat");
|
|
34
|
+
if (patchArtifact === undefined && statArtifact === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
const view = { patch: null, stat: null };
|
|
37
|
+
if (patchArtifact !== undefined) {
|
|
38
|
+
const exit = CAPTURE_EXIT.exec(patchArtifact.capture);
|
|
39
|
+
if (exit !== null && exit[1] !== "0") {
|
|
40
|
+
view.patch = { problem: `capture failed — ${patchArtifact.capture}` };
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const read = readVerifiedArtifact(root, patchArtifact);
|
|
44
|
+
view.patch = read.ok
|
|
45
|
+
? { text: read.content.toString("utf8"), truncated: patchArtifact.truncated, artifactId: patchArtifact.id }
|
|
46
|
+
: { problem: `stored but unverifiable — ${read.problem}` };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (statArtifact !== undefined) {
|
|
50
|
+
const exit = CAPTURE_EXIT.exec(statArtifact.capture);
|
|
51
|
+
if (exit !== null && exit[1] !== "0") {
|
|
52
|
+
view.stat = { problem: `capture failed — ${statArtifact.capture}` };
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const read = readVerifiedArtifact(root, statArtifact);
|
|
56
|
+
if (!read.ok) {
|
|
57
|
+
view.stat = { problem: `stored but unverifiable — ${read.problem}` };
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(read.content.toString("utf8"));
|
|
62
|
+
// Every field this page renders is type-proved (arc 6, finding 7):
|
|
63
|
+
// "an object with a base key" was accepting any shape at all.
|
|
64
|
+
const count = (value) => typeof value === "number" && Number.isFinite(value);
|
|
65
|
+
const wellFormed = parsed !== null &&
|
|
66
|
+
typeof parsed === "object" &&
|
|
67
|
+
typeof parsed["base"] === "string" &&
|
|
68
|
+
typeof parsed["head"] === "string" &&
|
|
69
|
+
count(parsed["fileCount"]) &&
|
|
70
|
+
count(parsed["additions"]) &&
|
|
71
|
+
count(parsed["deletions"]) &&
|
|
72
|
+
count(parsed["binaryCount"]) &&
|
|
73
|
+
typeof parsed["filesTruncated"] === "boolean" &&
|
|
74
|
+
Array.isArray(parsed["files"]) &&
|
|
75
|
+
parsed["files"].every(one => one !== null &&
|
|
76
|
+
typeof one === "object" &&
|
|
77
|
+
typeof one["path"] === "string" &&
|
|
78
|
+
(count(one["additions"]) || one["additions"] === null) &&
|
|
79
|
+
(count(one["deletions"]) || one["deletions"] === null));
|
|
80
|
+
view.stat = wellFormed
|
|
81
|
+
? parsed
|
|
82
|
+
: { problem: "stat is not the shape this page knows" };
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
view.stat = { problem: "stat did not parse as JSON" };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return view;
|
|
91
|
+
}
|
package/dist/result-shots.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Notification, type ResultScreenshots, type Store } from "./store.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type ChatContent, type ChatState } from "./chat-delivery-state.js";
|
|
3
3
|
/** "Up to 4": the most screenshots one result ever sends. */
|
|
4
4
|
export declare const RESULT_SHOTS_MAX = 4;
|
|
5
5
|
/** The choices in the order Settings and the CLI show them. */
|
package/dist/result-shots.js
CHANGED
|
@@ -21,6 +21,7 @@ import { publicChatText } from "./chat-display.js";
|
|
|
21
21
|
import { chatTitle } from "./chat-voice.js";
|
|
22
22
|
import { itemCaption, readFlowItems } from "./flow-items.js";
|
|
23
23
|
import { FLOW_SHOTS_KIND, RESULT_SHOTS_KIND } from "./store.js";
|
|
24
|
+
import { savedChatPart } from "./chat-delivery-state.js";
|
|
24
25
|
/** "Up to 4": the most screenshots one result ever sends. */
|
|
25
26
|
export const RESULT_SHOTS_MAX = 4;
|
|
26
27
|
/** The choices in the order Settings and the CLI show them. */
|
|
@@ -168,6 +169,6 @@ export function refuseResultShots(state, store, part, content, app, now) {
|
|
|
168
169
|
const title = chatTitle(store, content.image?.taskId ?? content.task ?? "");
|
|
169
170
|
const line = { text: `Screenshots for ${title} weren't sent: the ${app} app isn't allowed to upload files here.`,
|
|
170
171
|
...(content.task === undefined ? {} : { task: content.task }), ...(content.run === undefined ? {} : { run: content.run }) };
|
|
171
|
-
state.prepare("UPDATE chat_part SET payload=?,state='pending',next_at=NULL,problem=NULL,file=NULL,uploaded=0,uncertain=0,created=? WHERE id=?").run(
|
|
172
|
+
state.prepare("UPDATE chat_part SET payload=?,state='pending',next_at=NULL,problem=NULL,file=NULL,uploaded=0,uncertain=0,created=? WHERE id=?").run(savedChatPart(line), now.toISOString(), part.id);
|
|
172
173
|
state.prepare("UPDATE chat_part SET state='dropped',problem='Uploads are not allowed here' WHERE event=? AND id<>? AND state='pending'").run(part.event, part.id);
|
|
173
174
|
}
|
package/dist/review-switch.d.ts
CHANGED
|
@@ -2,15 +2,10 @@
|
|
|
2
2
|
* build gets (build-review.ts runs it): tables, and the read-only views every
|
|
3
3
|
* surface shows. No schema version bump. Kept free of heavy imports so the
|
|
4
4
|
* status readers can use it without an import cycle. */
|
|
5
|
+
import type { BuildFinding } from "./contracts/review-findings.js";
|
|
5
6
|
import type { Store } from "./store.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export type BuildFinding = {
|
|
9
|
-
severity: FindingSeverity;
|
|
10
|
-
file: string;
|
|
11
|
-
line: number;
|
|
12
|
-
scenario: string;
|
|
13
|
-
};
|
|
7
|
+
/** One automatic-review finding: how bad, where, and how it fails (src/contracts/review-findings.ts). */
|
|
8
|
+
export type { BuildFinding, FindingSeverity } from "./contracts/review-findings.js";
|
|
14
9
|
export declare const REVIEW_SCHEMA = "\n-- A project's explicit review switch. No row: on while the project is under a hands-off mode, off otherwise.\nCREATE TABLE IF NOT EXISTS review_switch (\n repo TEXT PRIMARY KEY,\n enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),\n changed_by TEXT NOT NULL,\n changed_at TEXT NOT NULL\n);\n-- One row per reviewed build run: pending until its one reviewer run settles it.\nCREATE TABLE IF NOT EXISTS build_review (\n run INTEGER PRIMARY KEY,\n task_id TEXT NOT NULL,\n repo TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('pending', 'reviewed', 'not-reviewed')),\n request INTEGER,\n reviewer_run INTEGER,\n findings_json TEXT,\n reason TEXT,\n sent_back_as TEXT,\n queued_at TEXT NOT NULL,\n finished_at TEXT\n);\nCREATE INDEX IF NOT EXISTS build_review_pending ON build_review (repo) WHERE state = 'pending';\nCREATE INDEX IF NOT EXISTS build_review_sent_back ON build_review (sent_back_as) WHERE sent_back_as IS NOT NULL;\n";
|
|
15
10
|
export type ReviewSwitch = {
|
|
16
11
|
on: boolean;
|
package/dist/reviewer.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* automatic build review's findings (build-review.ts runs it). This module
|
|
3
3
|
* cannot launch providers, create runs or retry work. */
|
|
4
4
|
import type { CriterionJudgementWord } from "./proof.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type BuildFinding } from "./contracts/review-findings.js";
|
|
6
6
|
/** The files the pass writes INTO the scratch directory for the agent —
|
|
7
7
|
* the patch always; the rubric, re-serialized proof, check log, and
|
|
8
8
|
* screenshots only when this run actually has one (v40) — a grandfathered
|
|
@@ -97,18 +97,14 @@ export declare function parseReview(raw: string, patchPaths: ReadonlySet<string>
|
|
|
97
97
|
ok: false;
|
|
98
98
|
problems: ReviewProblem[];
|
|
99
99
|
};
|
|
100
|
-
export type { BuildFinding, FindingSeverity } from "./review-
|
|
101
|
-
export declare const FINDING_LIMITS: {
|
|
102
|
-
readonly findings: 40;
|
|
103
|
-
readonly file: 300;
|
|
104
|
-
readonly scenario: 500;
|
|
105
|
-
};
|
|
100
|
+
export type { BuildFinding, FindingSeverity } from "./contracts/review-findings.js";
|
|
106
101
|
/**
|
|
107
|
-
* The automatic build review's reply,
|
|
108
|
-
* `{"version":1,"findings":[{"severity","file","line","scenario"}]}`. Any
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* to one line so it can travel in a
|
|
102
|
+
* The automatic build review's reply, read through its contract (src/contracts/review-findings.ts), with all findings
|
|
103
|
+
* checked together: `{"version":1,"findings":[{"severity","file","line","scenario"}]}`. Any invalid
|
|
104
|
+
* finding refuses the whole reply — a review that did not answer what it was asked is "not reviewed", never a partial
|
|
105
|
+
* pass — and the refusal names each path (`findings[0].line: at least 1`). The reply shares Claude's review channel
|
|
106
|
+
* (provider.ts), so only its version and findings are read, as always. Text is kept to one line so it can travel in a
|
|
107
|
+
* revision note and a terminal; its limits are checked after whitespace collapses, as before.
|
|
112
108
|
*/
|
|
113
109
|
export declare function parseBuildFindings(raw: string): {
|
|
114
110
|
ok: true;
|