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/serve.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SCREENSHOT_CAPTURE, structuredHandoffView, terminalDiffView } from "./result-evidence-readers.js";
|
|
1
2
|
import { checkLeadIdentity, leadIdentityOf, leadNameOf, LEAD_NAME_MAX, LEAD_PERSONA_MAX } from "./lead-identity.js";
|
|
2
3
|
import { aboutYouOf, checkAboutYou, saveAboutYou, ABOUT_YOU_LINE_MAX, ABOUT_YOU_MAX_LINES } from "./lead-about.js";
|
|
3
4
|
import { withActor } from "./actor.js";
|
|
@@ -53,7 +54,8 @@ import { FORM_PATH, flowFormPage, receiveFlowForm, shareFlowButton, stopSharingF
|
|
|
53
54
|
import { addFlowTriggerTo, checkFlowTriggerNow, HOOK_PATH, pressFlowButton, receiveFlowHook, removeFlowTrigger, renewFlowHook, removeLinearKey, saveHooksBase, saveLinearKey, saveLinearSigningSecret } from "./flow-triggers.js";
|
|
54
55
|
import { addCardToFlow, advanceFlows, cancelFlowCard, crossProjectProblem, decideFlowCard, FLOW_HREF, flowDefinitionOf, moveCardInFlow } from "./flow-engine.js";
|
|
55
56
|
import { chooseFlowCard } from "./flow-send.js";
|
|
56
|
-
import { FLOW_TEMPLATES, validateFlowDefinition } from "./flows.js";
|
|
57
|
+
import { FlowContractError, FLOW_TEMPLATES, validateFlowDefinition, withZoneNames } from "./flows.js";
|
|
58
|
+
import { stageReferenceProblems } from "./contracts/stage-output.js";
|
|
57
59
|
import { TOOL_CATALOG, addToolTo, catalogTool, discoverTools, localAppOf, projectToolsOf, removeToolFrom, secretsSetFor, setToolSecret, splitCommandLine, testToolOf } from "./project-tools.js";
|
|
58
60
|
import { changeLearning, learningView } from "./project-learning.js";
|
|
59
61
|
import { applySavedKnowledge, changeKnowledge, knowledgeView, knowledgeVersion, readKnowledgeSnapshot } from "./project-knowledge.js";
|
|
@@ -722,7 +724,7 @@ export function createDecisionServer(options) {
|
|
|
722
724
|
tools: tools.map(tool => ({ tool, secretsSet: secretsSetFor(repo, tool.spec, toolHome) })),
|
|
723
725
|
// A service that connects by signing in (or an app's own Connect) is offered only that way.
|
|
724
726
|
catalog: TOOL_CATALOG.filter(one => !names.has(one.name) && oneClickOf(one.name) === null && localConnectOf(one.name) === null),
|
|
725
|
-
connections: connectionsOf(store, repo), kit, wanted,
|
|
727
|
+
connections: connectionsOf(store, repo, toolHome), kit, wanted,
|
|
726
728
|
found: discoverTools(repo, codex, toolHome).filter(one => !names.has(one.spec.name)),
|
|
727
729
|
};
|
|
728
730
|
};
|
|
@@ -1136,6 +1138,8 @@ export function createDecisionServer(options) {
|
|
|
1136
1138
|
response.end(`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="refresh" content="0;url=${escape(to)}"><title>Toolroll</title>${HANDOFF_STYLE}<p>${escape(words)} <a href="${escape(to)}">Back to Toolroll</a></p>`);
|
|
1137
1139
|
};
|
|
1138
1140
|
const state = url.searchParams.get("state") ?? "";
|
|
1141
|
+
// Every arrival is logged (never the code or state): a sign-in that never came back is then visible as an absence.
|
|
1142
|
+
logEvent("info", "connect.callback", { error: url.searchParams.get("error"), known: connectVisits.has(state) });
|
|
1139
1143
|
if (!startedHere(request, state))
|
|
1140
1144
|
return done("/settings/tools", "problem", "That sign-in was started in another browser. Connect again from this one.");
|
|
1141
1145
|
const visit = connectVisits.get(state);
|
|
@@ -7179,12 +7183,17 @@ export function createDecisionServer(options) {
|
|
|
7179
7183
|
return redirect(response, "/flows");
|
|
7180
7184
|
}
|
|
7181
7185
|
if (action === "save") {
|
|
7182
|
-
let saved;
|
|
7186
|
+
let saved, drawn;
|
|
7183
7187
|
try {
|
|
7184
|
-
|
|
7188
|
+
drawn = JSON.parse(body.get("definition") ?? "null");
|
|
7189
|
+
saved = validateFlowDefinition(drawn);
|
|
7190
|
+
// A {{stage.…}} this save adds must be one its zone hands on; ones the saved flow had stay.
|
|
7191
|
+
const references = stageReferenceProblems(saved, flowDefinitionOf(flow));
|
|
7192
|
+
if (references.length > 0)
|
|
7193
|
+
throw new FlowContractError(references.map(one => one.line));
|
|
7185
7194
|
}
|
|
7186
7195
|
catch (error) {
|
|
7187
|
-
return answer(400, { ok: false, said: error instanceof SyntaxError ? "That flow couldn't be read." : error instanceof Error ? error.message : "That flow isn't valid." });
|
|
7196
|
+
return answer(400, { ok: false, said: error instanceof SyntaxError ? "That flow couldn't be read." : error instanceof FlowContractError ? withZoneNames(error.lines, drawn) : error instanceof Error ? error.message : "That flow isn't valid." });
|
|
7188
7197
|
}
|
|
7189
7198
|
const name = (body.get("name") ?? flow.name).replace(/[\u0000-\u001f\u007f]/g, "").trim().slice(0, 80) || flow.name;
|
|
7190
7199
|
// The owner (v86) is whom "the owner decides" zones ask: someone who can approve on this project.
|
|
@@ -7830,7 +7839,9 @@ export function createDecisionServer(options) {
|
|
|
7830
7839
|
const origin = consoleOrigin(request.headers.host);
|
|
7831
7840
|
if (origin === null)
|
|
7832
7841
|
return back("Connect tools from this computer (localhost) or from your https address.");
|
|
7833
|
-
|
|
7842
|
+
// Reconnect read-only (from a connected service's Tools entry): the same sign-in, asking only to read.
|
|
7843
|
+
const readOnly = also === null && body.get("access") === "read";
|
|
7844
|
+
const started = await startConnect({ service: service.id, repo: target, by: who.name, origin, kit: also === null ? kit : null, template, readOnly }, options.connectFetch ?? fetch);
|
|
7834
7845
|
if (!started.ok)
|
|
7835
7846
|
return back(started.said);
|
|
7836
7847
|
for (const [key, visit] of connectVisits)
|
|
@@ -22504,32 +22515,6 @@ function runsPage(chrome, rows, liveIds, nextCursor, verdicts = new Map(), accep
|
|
|
22504
22515
|
const older = nextCursor === null ? "" : `<p><a href="/runs?before=${nextCursor}">older →</a></p>`;
|
|
22505
22516
|
return screen("builds", [`<h1>Builds <a class="badge" href="/peek">Peek at the live ones \u2192</a></h1>`, buildsViews("builds"), `<p class="hint">one build = one attempt by an agent to complete a task, on its own branch</p>`, list, older].join("\n"), { chrome });
|
|
22506
22517
|
}
|
|
22507
|
-
function structuredHandoffView(artifacts, root) {
|
|
22508
|
-
const artifact = [...artifacts].reverse().find(one => one.kind === "handoff");
|
|
22509
|
-
if (artifact === undefined)
|
|
22510
|
-
return null;
|
|
22511
|
-
const read = readVerifiedArtifact(root, artifact);
|
|
22512
|
-
if (!read.ok)
|
|
22513
|
-
return null;
|
|
22514
|
-
try {
|
|
22515
|
-
const parsed = JSON.parse(read.content.toString("utf8"));
|
|
22516
|
-
if (parsed === null || typeof parsed !== "object" || typeof parsed["conclusion"] !== "string")
|
|
22517
|
-
return null;
|
|
22518
|
-
const conclusion = oneLineOf(parsed["conclusion"], 600);
|
|
22519
|
-
if (conclusion === "" || hasForbiddenControls(conclusion))
|
|
22520
|
-
return null;
|
|
22521
|
-
const list = (name) => Array.isArray(parsed[name])
|
|
22522
|
-
? parsed[name]
|
|
22523
|
-
.filter((one) => typeof one === "string" && one.trim() !== "" && !hasForbiddenControls(one))
|
|
22524
|
-
.slice(0, 8)
|
|
22525
|
-
.map(one => oneLineOf(one, 240))
|
|
22526
|
-
: [];
|
|
22527
|
-
return { conclusion, changes: list("changes"), verification: list("verification"), followUps: list("followUps") };
|
|
22528
|
-
}
|
|
22529
|
-
catch {
|
|
22530
|
-
return null;
|
|
22531
|
-
}
|
|
22532
|
-
}
|
|
22533
22518
|
/** What a scout found, each with its link and picture, then any screenshot no item shows. Every link is the cited
|
|
22534
22519
|
* http(s) address the report parser admitted; every picture is served from verified evidence. */
|
|
22535
22520
|
function reportItemsHtml(items, shots, runId) {
|
|
@@ -22606,7 +22591,6 @@ function sharedResultFactsOf(run, proof, terminal, handoff, report, publication)
|
|
|
22606
22591
|
publicationWords: receiptPublicationWords(publication),
|
|
22607
22592
|
};
|
|
22608
22593
|
}
|
|
22609
|
-
const SCREENSHOT_CAPTURE = /^agent-claimed screenshot at (.+) \(validated (?:png|jpeg)\)/;
|
|
22610
22594
|
function proofBundleView(store, run, artifacts, root) {
|
|
22611
22595
|
const verdictRow = store.proofVerdictFor(run.id);
|
|
22612
22596
|
const acceptanceRow = store.proofAcceptance(run.id);
|
|
@@ -22722,74 +22706,6 @@ function completionReceiptView(store, run, artifacts, root, review = null) {
|
|
|
22722
22706
|
facts: sharedResultFactsOf(run, proof, terminal, handoff, report, publication),
|
|
22723
22707
|
};
|
|
22724
22708
|
}
|
|
22725
|
-
const CAPTURE_EXIT = /\(exit ([0-9]{1,4})\)\s*$/;
|
|
22726
|
-
/**
|
|
22727
|
-
* Assemble the terminal-diff card's facts. Every branch names its state:
|
|
22728
|
-
* a failed capture (nonzero exit recorded in the capture string) reads as
|
|
22729
|
-
* the failure it is, unverifiable bytes read as their problem, and absence
|
|
22730
|
-
* returns null so old runs simply show nothing rather than a broken card.
|
|
22731
|
-
*/
|
|
22732
|
-
function terminalDiffView(artifacts, root) {
|
|
22733
|
-
const patchArtifact = artifacts.find(one => one.kind === "terminal-diff");
|
|
22734
|
-
const statArtifact = artifacts.find(one => one.kind === "diff-stat");
|
|
22735
|
-
if (patchArtifact === undefined && statArtifact === undefined)
|
|
22736
|
-
return null;
|
|
22737
|
-
const view = { patch: null, stat: null };
|
|
22738
|
-
if (patchArtifact !== undefined) {
|
|
22739
|
-
const exit = CAPTURE_EXIT.exec(patchArtifact.capture);
|
|
22740
|
-
if (exit !== null && exit[1] !== "0") {
|
|
22741
|
-
view.patch = { problem: `capture failed — ${patchArtifact.capture}` };
|
|
22742
|
-
}
|
|
22743
|
-
else {
|
|
22744
|
-
const read = readVerifiedArtifact(root, patchArtifact);
|
|
22745
|
-
view.patch = read.ok
|
|
22746
|
-
? { text: read.content.toString("utf8"), truncated: patchArtifact.truncated, artifactId: patchArtifact.id }
|
|
22747
|
-
: { problem: `stored but unverifiable — ${read.problem}` };
|
|
22748
|
-
}
|
|
22749
|
-
}
|
|
22750
|
-
if (statArtifact !== undefined) {
|
|
22751
|
-
const exit = CAPTURE_EXIT.exec(statArtifact.capture);
|
|
22752
|
-
if (exit !== null && exit[1] !== "0") {
|
|
22753
|
-
view.stat = { problem: `capture failed — ${statArtifact.capture}` };
|
|
22754
|
-
}
|
|
22755
|
-
else {
|
|
22756
|
-
const read = readVerifiedArtifact(root, statArtifact);
|
|
22757
|
-
if (!read.ok) {
|
|
22758
|
-
view.stat = { problem: `stored but unverifiable — ${read.problem}` };
|
|
22759
|
-
}
|
|
22760
|
-
else {
|
|
22761
|
-
try {
|
|
22762
|
-
const parsed = JSON.parse(read.content.toString("utf8"));
|
|
22763
|
-
// Every field this page renders is type-proved (arc 6, finding 7):
|
|
22764
|
-
// "an object with a base key" was accepting any shape at all.
|
|
22765
|
-
const count = (value) => typeof value === "number" && Number.isFinite(value);
|
|
22766
|
-
const wellFormed = parsed !== null &&
|
|
22767
|
-
typeof parsed === "object" &&
|
|
22768
|
-
typeof parsed["base"] === "string" &&
|
|
22769
|
-
typeof parsed["head"] === "string" &&
|
|
22770
|
-
count(parsed["fileCount"]) &&
|
|
22771
|
-
count(parsed["additions"]) &&
|
|
22772
|
-
count(parsed["deletions"]) &&
|
|
22773
|
-
count(parsed["binaryCount"]) &&
|
|
22774
|
-
typeof parsed["filesTruncated"] === "boolean" &&
|
|
22775
|
-
Array.isArray(parsed["files"]) &&
|
|
22776
|
-
parsed["files"].every(one => one !== null &&
|
|
22777
|
-
typeof one === "object" &&
|
|
22778
|
-
typeof one["path"] === "string" &&
|
|
22779
|
-
(count(one["additions"]) || one["additions"] === null) &&
|
|
22780
|
-
(count(one["deletions"]) || one["deletions"] === null));
|
|
22781
|
-
view.stat = wellFormed
|
|
22782
|
-
? parsed
|
|
22783
|
-
: { problem: "stat is not the shape this page knows" };
|
|
22784
|
-
}
|
|
22785
|
-
catch {
|
|
22786
|
-
view.stat = { problem: "stat did not parse as JSON" };
|
|
22787
|
-
}
|
|
22788
|
-
}
|
|
22789
|
-
}
|
|
22790
|
-
}
|
|
22791
|
-
return view;
|
|
22792
|
-
}
|
|
22793
22709
|
const REVIEW_DIFF_LINE_CAP = 4_000;
|
|
22794
22710
|
/** Parse only the stable structure Git's unified patch format guarantees.
|
|
22795
22711
|
* Unknown metadata remains visible, and a patch that cannot be structured
|
package/dist/slack-chat.js
CHANGED
|
@@ -11,6 +11,9 @@ import { MATE_MESSAGE_MAX_CHARS } from "./mate.js";
|
|
|
11
11
|
import { renderReply } from "./reply-shape.js";
|
|
12
12
|
import {} from "./mate-doors.js";
|
|
13
13
|
import { SlackState, slackHash, } from "./slack-state.js";
|
|
14
|
+
import { ChatDeliveryError, partContent } from "./chat-delivery-state.js";
|
|
15
|
+
import { readChatPart } from "./contracts/chat-content.js";
|
|
16
|
+
import { readSlackBlockActions, readSlackButton, SLACK_LINK_ACTION } from "./contracts/slack-callback.js";
|
|
14
17
|
import { object, slackId, slackTs, slackMember, SlackError, uploadSlackBytes, } from "./slack-api.js";
|
|
15
18
|
import { resultImageFileName, safeResultImageCaption, verifyResultImage, } from "./chat-evidence.js";
|
|
16
19
|
import {} from "./store.js";
|
|
@@ -70,25 +73,23 @@ export function receiveSlack(state, identity, type, raw, now) {
|
|
|
70
73
|
id = slackHash(`${identity.installation}:event:${body.event_id}`);
|
|
71
74
|
}
|
|
72
75
|
else if (type === "interactive" && body.type === "block_actions") {
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
76
|
+
const interaction = readSlackBlockActions(body);
|
|
77
|
+
if (!interaction.ok || interaction.value.container.type !== "message")
|
|
75
78
|
return false;
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
!/^(?:toolroll|standing_orders)_(confirm|dismiss|yes|cancel|flow_approve|flow_edit|flow_send_back|flow_choose_[0-3]|flow_note_(?:yes|no)|question_choice|question_words)$/.test(String(action.action_id)) ||
|
|
80
|
-
typeof action.value !== "string" ||
|
|
81
|
-
!/^[a-f0-9]{32}$/.test(action.value) ||
|
|
82
|
-
!slackTs(action.action_ts) ||
|
|
83
|
-
container.type !== "message")
|
|
79
|
+
const { actions, container, user } = interaction.value;
|
|
80
|
+
// A link button opens its page itself: nothing to do, and nothing to say.
|
|
81
|
+
if (actions.length === 1 && SLACK_LINK_ACTION.test(actions[0].action_id ?? ""))
|
|
84
82
|
return false;
|
|
85
|
-
member =
|
|
83
|
+
member = user.id;
|
|
86
84
|
channel = container.channel_id;
|
|
87
85
|
ts = container.message_ts;
|
|
88
|
-
thread =
|
|
86
|
+
thread = interaction.value.message?.thread_ts ?? ts;
|
|
89
87
|
kind = "action";
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
// A button that isn't one Toolroll made is answered with why, once the tap is proved to be the paired person's below.
|
|
89
|
+
const button = readSlackButton(interaction.value);
|
|
90
|
+
payload = button.ok ? { token: button.value.value } : { problem: button.issues.map(issue => issue.line).join("; ") };
|
|
91
|
+
const tapped = actions[0];
|
|
92
|
+
id = slackHash(`${identity.installation}:action:${member}:${ts}:${tapped?.value ?? ""}:${tapped?.action_ts ?? ""}`);
|
|
92
93
|
}
|
|
93
94
|
else
|
|
94
95
|
return false;
|
|
@@ -101,9 +102,10 @@ export function receiveSlack(state, identity, type, raw, now) {
|
|
|
101
102
|
// A channel or private group is a room: accepted only while it follows a
|
|
102
103
|
// conversation, or for the `/team` words that make it follow one.
|
|
103
104
|
const isRoom = !slackId(channel, "D");
|
|
105
|
+
const words = "text" in payload ? payload.text ?? "" : "";
|
|
104
106
|
// v89: a channel that feeds a flow takes anyone's message (as a card, with no say over anything); "flow 12" connects one.
|
|
105
|
-
const inbox = isRoom && kind === "message" ? channelInbox(state.store, "slack", identity.installation, String(channel),
|
|
106
|
-
const roomish = isRoom && (state.room(identity.installation, String(channel)) !== null || (kind === "message" && roomCommand(
|
|
107
|
+
const inbox = isRoom && kind === "message" ? channelInbox(state.store, "slack", identity.installation, String(channel), words) : { watched: false, command: false };
|
|
108
|
+
const roomish = isRoom && (state.room(identity.installation, String(channel)) !== null || (kind === "message" && roomCommand(words) !== null) || inbox.watched || inbox.command);
|
|
107
109
|
if (isRoom && !roomish)
|
|
108
110
|
return false;
|
|
109
111
|
const binding = state.bindingFor(identity.installation, member);
|
|
@@ -124,7 +126,7 @@ export function receiveSlack(state, identity, type, raw, now) {
|
|
|
124
126
|
member,
|
|
125
127
|
ts,
|
|
126
128
|
thread,
|
|
127
|
-
payload
|
|
129
|
+
payload,
|
|
128
130
|
created: now.toISOString(),
|
|
129
131
|
});
|
|
130
132
|
}
|
|
@@ -227,7 +229,7 @@ export async function deliverSlackPart(options) {
|
|
|
227
229
|
const repos = await access(options, binding, session?.ceilingDigest);
|
|
228
230
|
if (event.kind === "notice" && options.canNotify?.() === false)
|
|
229
231
|
return false;
|
|
230
|
-
const content =
|
|
232
|
+
const content = partContent(row.payload);
|
|
231
233
|
const destination = content.channel ?? binding.channel;
|
|
232
234
|
let text = content.text, buttons = [];
|
|
233
235
|
if (content.task &&
|
|
@@ -435,9 +437,13 @@ export async function deliverSlackPart(options) {
|
|
|
435
437
|
return true;
|
|
436
438
|
}
|
|
437
439
|
catch (error) {
|
|
440
|
+
if (error instanceof ChatDeliveryError && error.permanent) {
|
|
441
|
+
state.prepare("UPDATE chat_part SET state='dropped',next_at=NULL,problem=? WHERE id=?").run(error.message, row.id);
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
438
444
|
// No permission to upload files here: one plain line instead of the result's screenshots.
|
|
439
|
-
const
|
|
440
|
-
if (content.image && content.shot && error instanceof SlackError && ["missing_scope", "no_permission"].includes(error.code)) {
|
|
445
|
+
const saved = readChatPart(row.payload), content = saved.ok ? saved.value : null;
|
|
446
|
+
if (content !== null && content.image && content.shot && error instanceof SlackError && ["missing_scope", "no_permission"].includes(error.code)) {
|
|
441
447
|
refuseResultShots(state, store, row, content, "Slack", nowOf(options));
|
|
442
448
|
return true;
|
|
443
449
|
}
|
package/dist/slack-state.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Slack compatibility names for the shared durable transport state. */
|
|
2
|
-
import { ChatState
|
|
2
|
+
import { ChatState } from "./chat-delivery-state.js";
|
|
3
|
+
import { chatSchema, chatTables } from "./contracts/chat-tables.js";
|
|
3
4
|
export { chatHash as slackHash } from "./chat-delivery-state.js";
|
|
4
5
|
export const SLACK_SCHEMA = chatSchema("slack"), SLACK_TABLES = chatTables("slack");
|
|
5
6
|
export class SlackState extends ChatState {
|
package/dist/store.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { DecisionOption } from "./contracts/decision.js";
|
|
2
|
+
import type { FlowCardChange, FlowCardFields } from "./contracts/flow-card.js";
|
|
1
3
|
import { type Actor } from "./actor.js";
|
|
2
4
|
import { type CriterionMatrixRow, type CriterionJudgementWord } from "./proof.js";
|
|
3
5
|
import { type ExecutionProfile, type ChainEntry, type UnattendedPermissionMode, type AcceptanceCriterion } from "./scope.js";
|
|
@@ -764,24 +766,9 @@ export type FlowCardSource = {
|
|
|
764
766
|
binding: number;
|
|
765
767
|
};
|
|
766
768
|
};
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
flow: number;
|
|
770
|
-
title: string;
|
|
771
|
-
description: string | null;
|
|
772
|
-
stage: string;
|
|
773
|
-
entry: number;
|
|
774
|
-
state: "active" | "done" | "cancelled";
|
|
775
|
-
task: string | null;
|
|
776
|
-
primaryTask: string | null;
|
|
777
|
-
note: string | null;
|
|
778
|
-
waiting: string | null;
|
|
779
|
-
outputs: Record<string, string>;
|
|
780
|
-
createdBy: string;
|
|
781
|
-
createdAt: string;
|
|
782
|
-
updatedAt: string;
|
|
769
|
+
/** A flow card as read (src/contracts/flow-card.ts), and where it came from. */
|
|
770
|
+
export type FlowCardRow = FlowCardFields & {
|
|
783
771
|
source: FlowCardSource | null;
|
|
784
|
-
owner: string | null;
|
|
785
772
|
};
|
|
786
773
|
/** One line of a card's discussion: a comment (and whom it @mentioned), or who became its owner. */
|
|
787
774
|
export type FlowCommentRow = {
|
|
@@ -1361,13 +1348,8 @@ export type PushPair = {
|
|
|
1361
1348
|
lastError: string | null;
|
|
1362
1349
|
acceptedAt: string | null;
|
|
1363
1350
|
};
|
|
1364
|
-
/** One option of a decision. `reversible` is a field so a scheduler can refuse to auto-apply. */
|
|
1365
|
-
export type DecisionOption
|
|
1366
|
-
id: string;
|
|
1367
|
-
label: string;
|
|
1368
|
-
consequence: string;
|
|
1369
|
-
reversible: boolean;
|
|
1370
|
-
};
|
|
1351
|
+
/** One option of a decision (src/contracts/decision.ts). `reversible` is a field so a scheduler can refuse to auto-apply. */
|
|
1352
|
+
export type { DecisionOption };
|
|
1371
1353
|
/** The judgement call an agent refused to guess at (§7). Identity = its run. */
|
|
1372
1354
|
export type Decision = {
|
|
1373
1355
|
id: number;
|
|
@@ -6389,13 +6371,9 @@ export declare class Store {
|
|
|
6389
6371
|
}, now: Date): boolean;
|
|
6390
6372
|
/** What a card's current zone is doing: its task, the card's main work, what it waits on, what zones reported. */
|
|
6391
6373
|
/** Read and written in one transaction, so a pass changing one field never writes back another pass's older task or waiting. */
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
waiting?: string | null;
|
|
6396
|
-
outputs?: Record<string, string>;
|
|
6397
|
-
state?: "done" | "cancelled";
|
|
6398
|
-
}, now: Date): void;
|
|
6374
|
+
/** Outputs are written only when they change (src/contracts/stage-output.ts), never over a row a newer Toolroll wrote;
|
|
6375
|
+
* a zone's attachment stays only while its output does. */
|
|
6376
|
+
updateFlowCard(id: number, change: FlowCardChange, now: Date): void;
|
|
6399
6377
|
flowEvents(card: number): {
|
|
6400
6378
|
fromStage: string | null;
|
|
6401
6379
|
toStage: string;
|
|
@@ -8216,4 +8194,3 @@ export type VerifiedAuthor = string & {
|
|
|
8216
8194
|
readonly __verifiedAuthor: unique symbol;
|
|
8217
8195
|
};
|
|
8218
8196
|
export declare function verifiedAuthor(name: string): VerifiedAuthor;
|
|
8219
|
-
export {};
|
package/dist/store.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { chatSchema, chatTables } from "./chat-
|
|
2
|
-
import { SLACK_SCHEMA, SLACK_TABLES } from "./slack-state.js";
|
|
1
|
+
import { chatSchema, chatTables } from "./contracts/chat-tables.js";
|
|
3
2
|
import { assessmentFromSavedEvidence, verificationEvidence } from "./verification-evidence.js";
|
|
4
3
|
import { LEARNING_SCHEMA, queueLearning } from "./project-learning.js";
|
|
5
4
|
import { SKILLS_SCHEMA } from "./project-skills.js";
|
|
@@ -8,6 +7,7 @@ import { MEMORY_SCHEMA } from "./project-memory.js";
|
|
|
8
7
|
import { MODELS_SCHEMA } from "./model-catalog.js";
|
|
9
8
|
import { validateTaskText } from "./task-text.js";
|
|
10
9
|
import { flowDefinitionForStore, flowDefinitionFromStore } from "./flows.js";
|
|
10
|
+
import { cardOutputsForStore, cardOutputsFromStore } from "./contracts/stage-output.js";
|
|
11
11
|
import { chatControlHref, chatResultHref } from "./chat-controls.js";
|
|
12
12
|
import { actorLabel, currentActor, leadSecretMatches, mintLeadToken, parseLeadToken } from "./actor.js";
|
|
13
13
|
import { scanForSecrets } from "./evidence.js";
|
|
@@ -687,18 +687,11 @@ function readFlowStepRunRow(row) {
|
|
|
687
687
|
durationMs: number("duration_ms"), exitCode: number("exit_code"), result: optional("result"), log: optional("log"), decisionJson: optional("decision_json") };
|
|
688
688
|
}
|
|
689
689
|
function readFlowCardRow(row) {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
const parsed = JSON.parse(String(row["outputs_json"] ?? "{}"));
|
|
693
|
-
if (parsed !== null && typeof parsed === "object")
|
|
694
|
-
outputs = Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === "string"));
|
|
695
|
-
}
|
|
696
|
-
catch {
|
|
697
|
-
outputs = {};
|
|
698
|
-
}
|
|
690
|
+
// What finished zones handed on (src/contracts/stage-output.ts): a row saved before it carried a version reads as it always did.
|
|
691
|
+
const { outputs, attached } = cardOutputsFromStore(String(row["outputs_json"] ?? "{}"));
|
|
699
692
|
const optional = (key) => row[key] === null || row[key] === undefined ? null : String(row[key]);
|
|
700
693
|
return { id: Number(row["id"]), flow: Number(row["flow"]), title: String(row["title"]), description: optional("description"), stage: String(row["stage"]), entry: Number(row["entry"]),
|
|
701
|
-
state: String(row["state"]), task: optional("task"), primaryTask: optional("primary_task"), note: optional("note"), waiting: optional("waiting"), outputs,
|
|
694
|
+
state: String(row["state"]), task: optional("task"), primaryTask: optional("primary_task"), note: optional("note"), waiting: optional("waiting"), outputs, attached,
|
|
702
695
|
createdBy: String(row["created_by"]), createdAt: String(row["created_at"]), updatedAt: String(row["updated_at"]), source: readFlowCardSource(row["source_json"]), owner: optional("owner") };
|
|
703
696
|
}
|
|
704
697
|
function readFlowCardSource(value) {
|
|
@@ -3950,7 +3943,7 @@ function initializeStore(db, file) {
|
|
|
3950
3943
|
throw new Error(`${file}: shared action history has an unknown shape; refusing to recreate it`);
|
|
3951
3944
|
}
|
|
3952
3945
|
if (preflight !== null && Math.abs(preflight) >= 67) {
|
|
3953
|
-
for (const table of
|
|
3946
|
+
for (const table of chatTables("slack"))
|
|
3954
3947
|
if (!tableExists(db, table))
|
|
3955
3948
|
throw new Error(`${file}: Slack history is missing; refusing to recreate receipts`);
|
|
3956
3949
|
}
|
|
@@ -3971,7 +3964,7 @@ function initializeStore(db, file) {
|
|
|
3971
3964
|
db.exec(MEMORY_SCHEMA);
|
|
3972
3965
|
db.exec(MODELS_SCHEMA);
|
|
3973
3966
|
db.exec(SKILLS_SCHEMA);
|
|
3974
|
-
db.exec(
|
|
3967
|
+
db.exec(chatSchema("slack"));
|
|
3975
3968
|
db.exec(chatSchema("discord"));
|
|
3976
3969
|
db.exec(chatSchema("teams"));
|
|
3977
3970
|
db.exec(TEAM_SCHEMA);
|
|
@@ -19362,12 +19355,22 @@ export class Store {
|
|
|
19362
19355
|
}
|
|
19363
19356
|
/** What a card's current zone is doing: its task, the card's main work, what it waits on, what zones reported. */
|
|
19364
19357
|
/** Read and written in one transaction, so a pass changing one field never writes back another pass's older task or waiting. */
|
|
19358
|
+
/** Outputs are written only when they change (src/contracts/stage-output.ts), never over a row a newer Toolroll wrote;
|
|
19359
|
+
* a zone's attachment stays only while its output does. */
|
|
19365
19360
|
updateFlowCard(id, change, now) {
|
|
19366
19361
|
this.transact(() => {
|
|
19367
19362
|
const card = this.getFlowCard(id);
|
|
19368
19363
|
if (card === null)
|
|
19369
19364
|
return;
|
|
19370
|
-
this.db.prepare("UPDATE flow_card SET task = ?, primary_task = ?, waiting = ?,
|
|
19365
|
+
this.db.prepare("UPDATE flow_card SET task = ?, primary_task = ?, waiting = ?, state = ?, updated_at = ? WHERE id = ?").run(change.task === undefined ? card.task : change.task, change.primaryTask ?? card.primaryTask, change.waiting === undefined ? card.waiting : change.waiting, change.state ?? card.state, now.toISOString(), id);
|
|
19366
|
+
if (change.outputs === undefined && change.attached === undefined)
|
|
19367
|
+
return;
|
|
19368
|
+
const saved = this.db.prepare("SELECT outputs_json FROM flow_card WHERE id = ?").get(id);
|
|
19369
|
+
if (cardOutputsFromStore(String(saved?.["outputs_json"] ?? "{}")).newer)
|
|
19370
|
+
return;
|
|
19371
|
+
const outputs = change.outputs ?? card.outputs;
|
|
19372
|
+
const attached = { ...Object.fromEntries(Object.entries(card.attached).filter(([zone]) => outputs[zone] === card.outputs[zone])), ...change.attached };
|
|
19373
|
+
this.db.prepare("UPDATE flow_card SET outputs_json = ? WHERE id = ?").run(cardOutputsForStore(outputs, attached), id);
|
|
19371
19374
|
});
|
|
19372
19375
|
}
|
|
19373
19376
|
flowEvents(card) {
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
* subject to the phase's strict parser.
|
|
9
9
|
*/
|
|
10
10
|
import { redactSecretLines, scanForSecrets, storeEvidence } from "./evidence.js";
|
|
11
|
+
import { TEXT_LIMITS } from "./text-limits.js";
|
|
11
12
|
export const STRUCTURED_REPAIR_ATTEMPTS = 2;
|
|
12
13
|
export const STRUCTURED_REPAIR_MAX_TURNS = 4;
|
|
13
14
|
export const STRUCTURED_REPAIR_TIMEOUT_MS = 5 * 60_000;
|
|
14
15
|
/** Native parsing counts UTF-16 code units. A shorter writing target keeps
|
|
15
16
|
* notes concise without imposing a second, stricter transport contract. */
|
|
16
|
-
export const REVIEW_OUTPUT_LIMITS = { comments: 40, criteria: 12, note:
|
|
17
|
+
export const REVIEW_OUTPUT_LIMITS = { comments: 40, criteria: 12, note: TEXT_LIMITS.reviewNote, path: TEXT_LIMITS.reviewPath };
|
|
17
18
|
export const REVIEW_NOTE_CODE_POINTS = Math.floor(REVIEW_OUTPUT_LIMITS.note / 2);
|
|
18
19
|
export const REVIEW_NOTE_GUIDANCE = `Keep each comment and criterion note to one concise finding and its evidence. Aim for ${REVIEW_NOTE_CODE_POINTS} characters or fewer; the hard limit is ${REVIEW_OUTPUT_LIMITS.note} UTF-16 units. Preserve the conclusion and any needed provenance; omit repeated rubric text.`;
|
|
19
20
|
/** Strip only unambiguous, whole-payload wrappers. */
|
|
@@ -9,6 +9,10 @@ export type SubscriptionMateRequest = {
|
|
|
9
9
|
dataDocument: string;
|
|
10
10
|
history: readonly MateHistoryMessage[];
|
|
11
11
|
tools: readonly MateToolSchema[];
|
|
12
|
+
/** A structured answer of another shape (the memory pass's verdict): this JSON Schema is the harness's
|
|
13
|
+
* `--json-schema` (Codex's `--output-schema`) in place of the mate envelope, and its JSON text comes back as the
|
|
14
|
+
* answer's text, unread, for the caller's own schema to parse. */
|
|
15
|
+
outputSchema?: Record<string, unknown>;
|
|
12
16
|
timeoutMs: number;
|
|
13
17
|
/** The turn's own deadline: aborting it ends the harness's whole process group. */
|
|
14
18
|
signal?: AbortSignal;
|
|
@@ -191,7 +191,7 @@ export async function performSubscriptionMateRequest(request, runner = run) {
|
|
|
191
191
|
try {
|
|
192
192
|
const prompt = composeSubscriptionMatePrompt(request);
|
|
193
193
|
const streaming = request.provider !== "codex-subscription" && request.onText !== undefined;
|
|
194
|
-
const schema = outputSchema(request.tools);
|
|
194
|
+
const schema = request.outputSchema ?? outputSchema(request.tools);
|
|
195
195
|
let command;
|
|
196
196
|
let args;
|
|
197
197
|
if (request.provider === "codex-subscription") {
|
|
@@ -271,6 +271,9 @@ export async function performSubscriptionMateRequest(request, runner = run) {
|
|
|
271
271
|
const output = request.provider === "codex-subscription" ? codexOutput(result.stdout) : claudeOutput(streaming ? lastResultLine(result.stdout) : result.stdout);
|
|
272
272
|
if (output.text === null)
|
|
273
273
|
return { ok: false, problem: "malformed-reply" };
|
|
274
|
+
if (request.outputSchema !== undefined) {
|
|
275
|
+
return { ok: true, answer: { text: output.text, calls: [], tokensIn: output.tokensIn, tokensOut: output.tokensOut, reportedCostMicrousd: null } };
|
|
276
|
+
}
|
|
274
277
|
return parseSubscriptionMateAnswer(output.text, output);
|
|
275
278
|
}
|
|
276
279
|
finally {
|
package/dist/surface.js
CHANGED
|
@@ -278,7 +278,14 @@ export const COMMAND_GUIDE = [
|
|
|
278
278
|
operator("task approve", "the yes — nothing builds without one; binds to the scope digest"),
|
|
279
279
|
operator("task requeue", "exit a stall: incidents resolved, strikes cleared, queued again"),
|
|
280
280
|
operator("task regate", "explicitly rerun the approved check on the last exact commit — no agent or automatic retry"),
|
|
281
|
-
|
|
281
|
+
{ invocation: "task review", synopsis: "read a task's compact result packet with --brief, or a run's automatic findings without it", audience: "agent", agentMayInvoke: true, mutation: "none",
|
|
282
|
+
positionals: [{ name: "id", required: true, meaning: "task id with --brief; run id otherwise" }],
|
|
283
|
+
flags: [jsonFlag, dbFlag,
|
|
284
|
+
{ name: "brief", takesValue: false, meaning: "saved conclusion, changed files, checks, findings, screenshots, plan and next actions; missing fields say not recorded" },
|
|
285
|
+
{ name: "run", takesValue: true, meaning: "with --brief, select an exact finished attempt instead of the latest" },
|
|
286
|
+
{ name: "all", takesValue: false, meaning: "include LOW findings within the compact packet's limit; extra findings are counted" },
|
|
287
|
+
{ name: "token", takesValue: true, meaning: "the lead token (or TOOLROLL_LEAD_TOKEN)" }],
|
|
288
|
+
notableReasons: ["usage", "unauthenticated", "not-found"] },
|
|
282
289
|
operator("task accept", "record an explicit acceptance with limitations; does not change checks or prove deployment"),
|
|
283
290
|
operator("task repair", "inspect or approve an existing historical repair draft; use task revise for new feedback"),
|
|
284
291
|
operator("task route", "which configured agents plan, build and repair this task; phase and risk changes require renewed approval"),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** A read-only packet of saved result facts. Never opens a worktree or emits logs, patches or saved shell commands. */
|
|
2
|
+
import type { Store } from './store.js';
|
|
3
|
+
import { type AssignmentAccess } from './assignment.js';
|
|
4
|
+
import { type BuildFinding as Finding, type FindingSeverity } from './contracts/review-findings.js';
|
|
5
|
+
declare const MISSING: 'not recorded';
|
|
6
|
+
type Missing = typeof MISSING;
|
|
7
|
+
export type ReviewBrief = {
|
|
8
|
+
header: {
|
|
9
|
+
task: string;
|
|
10
|
+
run: number | Missing;
|
|
11
|
+
provider: string;
|
|
12
|
+
model: string;
|
|
13
|
+
minutes: number | Missing;
|
|
14
|
+
outcome: string;
|
|
15
|
+
base: string;
|
|
16
|
+
head: string;
|
|
17
|
+
state: string;
|
|
18
|
+
};
|
|
19
|
+
conclusion: string;
|
|
20
|
+
changedFiles: {
|
|
21
|
+
files: {
|
|
22
|
+
path: string;
|
|
23
|
+
additions: number | Missing;
|
|
24
|
+
deletions: number | Missing;
|
|
25
|
+
}[];
|
|
26
|
+
total: number;
|
|
27
|
+
omitted: number;
|
|
28
|
+
} | Missing;
|
|
29
|
+
check: {
|
|
30
|
+
status: string;
|
|
31
|
+
exit: number | Missing;
|
|
32
|
+
failed: string[] | Missing;
|
|
33
|
+
};
|
|
34
|
+
review: {
|
|
35
|
+
state: string;
|
|
36
|
+
reason: string;
|
|
37
|
+
findings: Finding[];
|
|
38
|
+
counts: Record<FindingSeverity, number>;
|
|
39
|
+
omitted: Record<FindingSeverity, number>;
|
|
40
|
+
} | Missing;
|
|
41
|
+
screenshots: {
|
|
42
|
+
files: {
|
|
43
|
+
path: string;
|
|
44
|
+
bytes: number | Missing;
|
|
45
|
+
}[];
|
|
46
|
+
omitted: number;
|
|
47
|
+
} | Missing;
|
|
48
|
+
plan: {
|
|
49
|
+
titles: string[];
|
|
50
|
+
omitted: number;
|
|
51
|
+
} | Missing;
|
|
52
|
+
nextActions: string[];
|
|
53
|
+
};
|
|
54
|
+
/** Select only finished build/report attempts in the admitted family. An explicit run never crosses that boundary. */
|
|
55
|
+
export declare function taskReviewBrief(store: Store, task: string, root: string, now: Date, access: AssignmentAccess, options?: {
|
|
56
|
+
run?: number;
|
|
57
|
+
all?: boolean;
|
|
58
|
+
secrets?: readonly string[];
|
|
59
|
+
}): {
|
|
60
|
+
ok: true;
|
|
61
|
+
brief: ReviewBrief;
|
|
62
|
+
} | {
|
|
63
|
+
ok: false;
|
|
64
|
+
reason: string;
|
|
65
|
+
message: string;
|
|
66
|
+
};
|
|
67
|
+
/** Text and JSON share this bounded projection; --all includes LOW details within the same line budget. */
|
|
68
|
+
export declare function renderReviewBrief(brief: ReviewBrief): string[];
|
|
69
|
+
export {};
|