toolroll 0.9.94 → 0.9.95
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 +12 -1
- package/dist/agent-fence.d.ts +6 -0
- package/dist/agent-fence.js +2 -2
- package/dist/assignment-status.d.ts +1 -1
- package/dist/assignment-ui.js +2 -0
- package/dist/attest.d.ts +3 -0
- package/dist/attest.js +10 -0
- package/dist/browser/terminal.js +1 -1
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +24 -24
- package/dist/browser-crew.js +2 -0
- package/dist/browser-workspace.d.ts +5 -0
- package/dist/build-review.js +2 -0
- package/dist/builder.d.ts +7 -2
- package/dist/builder.js +183 -79
- package/dist/card-catalog.d.ts +209 -0
- package/dist/card-catalog.js +133 -0
- package/dist/card-cli.d.ts +43 -0
- package/dist/card-cli.js +44 -0
- package/dist/card-render.d.ts +26 -0
- package/dist/card-render.js +223 -0
- package/dist/card-sources.d.ts +68 -0
- package/dist/card-sources.js +234 -0
- package/dist/chat-actions.d.ts +95 -8
- package/dist/chat-actions.js +449 -45
- package/dist/chat-approval.d.ts +13 -0
- package/dist/chat-approval.js +39 -9
- package/dist/chat-card-part.d.ts +11 -0
- package/dist/chat-card-part.js +18 -0
- package/dist/chat-card.d.ts +46 -0
- package/dist/chat-card.js +99 -0
- package/dist/chat-channel.d.ts +2 -0
- package/dist/chat-channel.js +26 -14
- package/dist/chat-controls.d.ts +4 -0
- package/dist/chat-controls.js +4 -0
- package/dist/chat-decide.d.ts +3 -14
- package/dist/chat-decide.js +43 -54
- package/dist/chat-delivery.js +13 -4
- package/dist/chat-flow.d.ts +0 -27
- package/dist/chat-flow.js +31 -2
- package/dist/chat-quiet.js +1 -1
- package/dist/chat-task-actions.d.ts +3 -2
- package/dist/chat-task-actions.js +19 -5
- package/dist/chat-terms.d.ts +14 -2
- package/dist/chat-terms.js +35 -0
- package/dist/check-failure.d.ts +2 -0
- package/dist/check-failure.js +34 -2
- package/dist/check-repair.d.ts +47 -0
- package/dist/check-repair.js +240 -0
- package/dist/claim.d.ts +6 -0
- package/dist/claim.js +13 -2
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +2 -0
- package/dist/cli.js +4 -0
- package/dist/coding-provider.d.ts +1 -1
- package/dist/coding-provider.js +9 -5
- package/dist/coding-workspace.d.ts +1 -1
- package/dist/coding-workspace.js +4 -4
- package/dist/contracts/chat-actions.d.ts +83 -0
- package/dist/contracts/chat-actions.js +18 -0
- package/dist/contracts/chat-card.d.ts +91 -0
- package/dist/contracts/chat-card.js +54 -0
- package/dist/contracts/chat-content.d.ts +191 -0
- package/dist/contracts/chat-content.js +4 -0
- package/dist/contracts/console-api.d.ts +2 -0
- package/dist/contracts/console-api.js +2 -0
- package/dist/contracts/flow-propose.d.ts +8 -1
- package/dist/contracts/flow-propose.js +3 -1
- package/dist/contracts/flow-send.d.ts +126 -0
- package/dist/contracts/flow-send.js +3 -0
- package/dist/contracts/lead-tools.d.ts +173 -0
- package/dist/contracts/lead-tools.js +15 -0
- package/dist/contracts/store-json.d.ts +16 -0
- package/dist/discord-chat.js +14 -0
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +7 -1
- package/dist/dispose.d.ts +19 -0
- package/dist/dispose.js +47 -7
- package/dist/eval-oracle.js +4 -1
- package/dist/evidence-pair.d.ts +53 -0
- package/dist/evidence-pair.js +128 -0
- package/dist/exhaustion.d.ts +17 -4
- package/dist/exhaustion.js +44 -4
- package/dist/export.js +1 -1
- package/dist/failing-first.d.ts +31 -0
- package/dist/failing-first.js +44 -0
- package/dist/fallback-schema.d.ts +8 -0
- package/dist/fallback-schema.js +40 -0
- package/dist/fallback.d.ts +138 -0
- package/dist/fallback.js +605 -0
- package/dist/findings.d.ts +224 -0
- package/dist/findings.js +449 -0
- package/dist/fleet-schema.d.ts +17 -0
- package/dist/fleet-schema.js +135 -0
- package/dist/flow-browser.js +2 -2
- package/dist/flow-code.d.ts +2 -2
- package/dist/flow-code.js +9 -5
- package/dist/flow-result-card.d.ts +22 -0
- package/dist/flow-result-card.js +55 -0
- package/dist/flow-send.js +12 -9
- package/dist/flow-steps.js +1 -1
- package/dist/flow-triggers.js +1 -1
- package/dist/flow-unattended.d.ts +26 -0
- package/dist/flow-unattended.js +12 -3
- package/dist/flows-ui.js +10 -2
- package/dist/follow-through-brief.d.ts +12 -0
- package/dist/follow-through-brief.js +31 -0
- package/dist/follow-through-cli.d.ts +23 -0
- package/dist/follow-through-cli.js +153 -0
- package/dist/git-incident.d.ts +16 -0
- package/dist/git-incident.js +69 -6
- package/dist/handover-note.d.ts +33 -0
- package/dist/handover-note.js +106 -0
- package/dist/invoke.d.ts +20 -1
- package/dist/invoke.js +108 -44
- package/dist/lead-cli.js +26 -24
- package/dist/lead-contract.js +1 -0
- package/dist/lead-doors.d.ts +4 -0
- package/dist/lead-doors.js +2 -2
- package/dist/lead-progress.js +2 -0
- package/dist/lead-tools.js +111 -32
- package/dist/lead.js +1 -1
- package/dist/local-owner.js +5 -0
- package/dist/modes.d.ts +6 -6
- package/dist/modes.js +3 -1
- package/dist/needs-you.d.ts +5 -2
- package/dist/needs-you.js +14 -2
- package/dist/operate-remote-arguments.js +1 -0
- package/dist/operate-remote.js +1 -1
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +165 -14
- package/dist/plan-login.d.ts +14 -0
- package/dist/plan-login.js +58 -0
- package/dist/planner.d.ts +1 -1
- package/dist/planner.js +2 -1
- package/dist/project-delete-ui.d.ts +12 -0
- package/dist/project-delete-ui.js +18 -1
- package/dist/project-delete.js +6 -0
- package/dist/project-knowledge.d.ts +6 -6
- package/dist/project-tools.d.ts +4 -4
- package/dist/project-tools.js +23 -7
- package/dist/protected-storage-look.d.ts +1 -0
- package/dist/protected-storage-look.js +13 -0
- package/dist/protected-storage.d.ts +70 -39
- package/dist/protected-storage.js +196 -147
- package/dist/provider-capture.d.ts +34 -0
- package/dist/provider-capture.js +53 -0
- package/dist/release-carry.js +10 -1
- package/dist/release.js +9 -1
- package/dist/scope.d.ts +22 -3
- package/dist/scope.js +71 -20
- package/dist/scout.d.ts +1 -1
- package/dist/scout.js +2 -1
- package/dist/serve.js +2 -0
- package/dist/server/chat.js +2 -2
- package/dist/server/console.css +50 -0
- package/dist/server/render-chat.js +14 -1
- package/dist/server/render-follow-through.d.ts +11 -0
- package/dist/server/render-follow-through.js +68 -0
- package/dist/server/render-results.js +1 -1
- package/dist/server/render-tasks.d.ts +3 -0
- package/dist/server/render-tasks.js +24 -5
- package/dist/server/route-table.js +3 -0
- package/dist/server/settings.js +37 -12
- package/dist/server/task-views.js +5 -0
- package/dist/server/tasks.js +76 -0
- package/dist/settings-groups-ui.d.ts +1 -0
- package/dist/settings-groups-ui.js +3 -1
- package/dist/settings-kit.js +3 -2
- package/dist/settings-proofs.js +3 -1
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-chat.js +14 -1
- package/dist/steer-mailbox.d.ts +8 -1
- package/dist/steer-mailbox.js +164 -6
- package/dist/store.d.ts +11 -4
- package/dist/store.js +93 -30
- package/dist/surface.js +24 -4
- package/dist/task-control.d.ts +2 -1
- package/dist/task-status.js +5 -0
- package/dist/teardown-git.d.ts +2 -0
- package/dist/teardown-git.js +42 -16
- package/dist/telegram-lead.js +23 -6
- package/dist/telegram.js +12 -1
- package/dist/toolroll-update.js +2 -0
- package/dist/work-index.js +22 -7
- package/dist/work-summary.d.ts +1 -1
- package/dist/work-summary.js +5 -2
- package/dist/workspace-ui.d.ts +3 -1
- package/dist/workspace-ui.js +10 -1
- package/dist/worktree.js +23 -1
- package/package.json +2 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Before-and-after evidence (docs/plans/fleet-follow-through.md, part 4), and a bug fix's optional failing test first.
|
|
3
|
+
*
|
|
4
|
+
* The before side is saved from a sealed failed check: its run, commit, receipt digest and command digest. The after
|
|
5
|
+
* side is never stored. It is read each time from the family's newest result, so a newer commit reads as out of date
|
|
6
|
+
* without anything having to notice. Rerunning uses the follow-up check road (result-follow-ups.ts): the same approved
|
|
7
|
+
* command, in a fresh checkout, on the latest commit, with no agent.
|
|
8
|
+
*
|
|
9
|
+
* A failing-test-first report is the agent's own words, shown as that. It is not a check Toolroll ran.
|
|
10
|
+
*/
|
|
11
|
+
import { readVerificationView } from "./contracts/verification-view.js";
|
|
12
|
+
import { followUpChecksOf, requestFollowUpChecks } from "./result-follow-ups.js";
|
|
13
|
+
import { readingFleet } from "./fleet-schema.js";
|
|
14
|
+
import { cleanFindingText, familyRootOf, NOT_ON_TASK, runOnTask } from "./findings.js";
|
|
15
|
+
import { runCheckLevel } from "./check-levels.js";
|
|
16
|
+
import { failedVerificationEvidence, verificationEvidence } from "./verification-evidence.js";
|
|
17
|
+
/** The family's builder runs that finished with a commit, newest first. */
|
|
18
|
+
function familyRuns(store, taskId) {
|
|
19
|
+
const family = store.taskFamilyOf(taskId, null, true);
|
|
20
|
+
const ids = family === null || family.problem !== null ? [taskId] : family.versions.map(one => one.id);
|
|
21
|
+
return ids.flatMap(id => {
|
|
22
|
+
const ref = store.lookupRef(id);
|
|
23
|
+
return ref === null ? [] : store.runsFor(ref.id).filter(one => one.role === "builder" && one.finishedAt !== null && one.headRevision !== null);
|
|
24
|
+
}).sort((a, b) => b.id - a.id);
|
|
25
|
+
}
|
|
26
|
+
const screenshotsOf = (store, runId) => store.artifactsFor(runId).filter(one => one.kind === "screenshot").map(one => one.id);
|
|
27
|
+
/** The command a run's sealed receipt ran, and whether it passed. Null when it has no readable receipt. */
|
|
28
|
+
function sealedCheck(store, root, runId) {
|
|
29
|
+
const gate = verificationEvidence(store, root, runId);
|
|
30
|
+
if (!gate.ok || gate.bytes === null)
|
|
31
|
+
return null;
|
|
32
|
+
const view = readVerificationView(gate.bytes);
|
|
33
|
+
if (!view.ok)
|
|
34
|
+
return null;
|
|
35
|
+
const result = view.value.result;
|
|
36
|
+
return { digest: view.value.command.digest, passed: result.configured && result.ran === true && result.exitCode === 0 };
|
|
37
|
+
}
|
|
38
|
+
/** The newest result of the family that ran `digest`, by the build's own check or a follow-up check on its commit. */
|
|
39
|
+
function afterSide(store, root, runs, beforeRun, digest, now) {
|
|
40
|
+
let otherCommand = false;
|
|
41
|
+
for (const run of runs) {
|
|
42
|
+
if (run.id < beforeRun)
|
|
43
|
+
break;
|
|
44
|
+
const follow = followUpChecksOf(store, run.id, now).filter(one => (one.state === "passed" || one.state === "failed") && one.head === run.headRevision).at(-1);
|
|
45
|
+
if (follow !== undefined && (digest === null || follow.digest === digest))
|
|
46
|
+
return { run: run.id, head: follow.head, status: follow.state, via: "follow-up", screenshots: screenshotsOf(store, run.id) };
|
|
47
|
+
if (follow !== undefined)
|
|
48
|
+
otherCommand = true;
|
|
49
|
+
if (run.id === beforeRun)
|
|
50
|
+
continue;
|
|
51
|
+
const own = sealedCheck(store, root, run.id);
|
|
52
|
+
if (own === null)
|
|
53
|
+
continue;
|
|
54
|
+
if (digest !== null && own.digest !== digest) {
|
|
55
|
+
otherCommand = true;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
return { run: run.id, head: run.headRevision, status: own.passed ? "passed" : "failed", via: "build", screenshots: screenshotsOf(store, run.id) };
|
|
59
|
+
}
|
|
60
|
+
return otherCommand ? "check-changed" : null;
|
|
61
|
+
}
|
|
62
|
+
function pairOf(store, root, row, taskId, now) {
|
|
63
|
+
const runs = familyRuns(store, taskId);
|
|
64
|
+
const beforeRun = Number(row["before_run"]);
|
|
65
|
+
const commandDigest = row["command_digest"] === null ? null : String(row["command_digest"]);
|
|
66
|
+
const found = afterSide(store, root, runs, beforeRun, commandDigest, now);
|
|
67
|
+
const latest = runs[0] ?? null;
|
|
68
|
+
const after = found === "check-changed" ? null : found;
|
|
69
|
+
const reading = found === "check-changed" ? "check-changed"
|
|
70
|
+
: after === null ? latest !== null && latest.headRevision !== String(row["before_head"]) ? "out-of-date" : "failing"
|
|
71
|
+
: after.head !== latest?.headRevision ? "out-of-date"
|
|
72
|
+
: after.status === "passed" ? "fixed" : "still-failing";
|
|
73
|
+
return {
|
|
74
|
+
id: Number(row["id"]), familyRoot: String(row["family_root"]),
|
|
75
|
+
before: { run: beforeRun, head: String(row["before_head"]), status: "failed", via: "build", screenshots: screenshotsOf(store, beforeRun) },
|
|
76
|
+
receiptDigest: String(row["receipt_digest"]), commandDigest, savedBy: String(row["saved_by"]), savedAt: String(row["saved_at"]),
|
|
77
|
+
after, latestHead: latest?.headRevision ?? null, latestRun: latest?.id ?? null, reading,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function evidencePairsOf(store, root, taskId, now) {
|
|
81
|
+
return readingFleet(() => store.handle.prepare("SELECT * FROM evidence_pair WHERE family_root = ? ORDER BY id DESC").all(familyRootOf(store, taskId)).map(row => pairOf(store, root, row, taskId, now)), []);
|
|
82
|
+
}
|
|
83
|
+
/** Save a run's failed check as the before side. Only a sealed failure can be saved: there's nothing else to compare. */
|
|
84
|
+
export function saveEvidencePair(store, root, input, now) {
|
|
85
|
+
const ref = store.lookupRef(input.taskId);
|
|
86
|
+
if (ref === null)
|
|
87
|
+
return { ok: false, reason: "unknown", message: `no task \`${input.taskId}\`` };
|
|
88
|
+
// A run named by a caller is checked first, and said plainly: every road (the CLI's --run, the console's form) comes here.
|
|
89
|
+
if (input.runId !== undefined && !runOnTask(store, input.runId, input.taskId))
|
|
90
|
+
return { ok: false, reason: "not-on-task", message: NOT_ON_TASK };
|
|
91
|
+
const runId = input.runId ?? familyRuns(store, input.taskId)[0]?.id;
|
|
92
|
+
const run = runId === undefined ? null : store.getRun(runId);
|
|
93
|
+
const root1 = familyRootOf(store, input.taskId);
|
|
94
|
+
if (run === null || run.headRevision === null)
|
|
95
|
+
return { ok: false, reason: "no-failed-check", message: `${input.taskId} has no finished attempt to save.` };
|
|
96
|
+
const failure = failedVerificationEvidence(store, root, run.id);
|
|
97
|
+
if (failure.kind !== "failed")
|
|
98
|
+
return { ok: false, reason: "no-failed-check", message: `Attempt #${run.id} has no failed check to save.` };
|
|
99
|
+
const view = readVerificationView(failure.receipt);
|
|
100
|
+
const made = store.handle.prepare(`INSERT INTO evidence_pair (family_root, repo, before_run, before_head, receipt_digest, command_digest, saved_by, saved_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
101
|
+
ON CONFLICT (family_root, before_run) DO NOTHING`).run(root1, ref.repo, run.id, run.headRevision, failure.digest, view.ok ? view.value.command.digest : null, input.by, now.toISOString());
|
|
102
|
+
if (Number(made.changes) === 1)
|
|
103
|
+
return { ok: true, id: Number(made.lastInsertRowid), existing: false };
|
|
104
|
+
const row = store.handle.prepare("SELECT id FROM evidence_pair WHERE family_root = ? AND before_run = ?").get(root1, run.id);
|
|
105
|
+
return { ok: true, id: Number(row?.["id"]), existing: true };
|
|
106
|
+
}
|
|
107
|
+
/** Ask for the same check on the latest commit. Its level is the one the saved failure ran at. The caller proves the person. */
|
|
108
|
+
export function rerunEvidence(store, taskId, actor, now) {
|
|
109
|
+
const latest = familyRuns(store, taskId)[0];
|
|
110
|
+
if (latest === undefined)
|
|
111
|
+
return { ok: false, message: `${taskId} has no finished attempt to check.` };
|
|
112
|
+
const level = runCheckLevel(store, latest.id);
|
|
113
|
+
const asked = requestFollowUpChecks(store, { runId: latest.id, level: (level === "off" || level === null ? "full" : level), actor }, now);
|
|
114
|
+
return asked.ok ? { ok: true, run: latest.id, head: latest.headRevision, request: asked.request, existing: asked.existing } : { ok: false, message: asked.message };
|
|
115
|
+
}
|
|
116
|
+
const short = (head) => head === null ? "no commit" : head.slice(0, 7);
|
|
117
|
+
/** How a pair reads, in one sentence. */
|
|
118
|
+
export function evidenceWords(pair) {
|
|
119
|
+
const before = `Failed on ${short(pair.before.head)} (build #${pair.before.run})`;
|
|
120
|
+
switch (pair.reading) {
|
|
121
|
+
case "failing": return `${before}. Not checked since.`;
|
|
122
|
+
case "fixed": return `${before}, passes on ${short(pair.after.head)} (build #${pair.after.run}).`;
|
|
123
|
+
case "still-failing": return `${before}, still fails on ${short(pair.after.head)} (build #${pair.after.run}).`;
|
|
124
|
+
case "check-changed": return `${before}. The project's check changed since, so the two can't be compared.`;
|
|
125
|
+
case "out-of-date": return `${before}. Out of date: the code is now at ${short(pair.latestHead)}${pair.after === null ? "" : `, and the last check ran on ${short(pair.after.head)}`}.`;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export { askFailingFirst, dropFailingFirst, FAILING_FIRST_FILE, failingFirstOf, failingFirstReportSchema, failingFirstWords, saveFailingFirstReport } from "./failing-first.js";
|
package/dist/exhaustion.d.ts
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
* someone signs in, instead of burning attempts. Everything else is the
|
|
7
7
|
* ordinary failure road.
|
|
8
8
|
*
|
|
9
|
-
* `usage-exhausted
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* `usage-exhausted` moves the work to the next agent a person approved
|
|
10
|
+
* (fallback.ts), so it comes only from a recogniser below, and a recogniser
|
|
11
|
+
* comes only from a real run (docs/plans/fallback-chains.md). A provider with
|
|
12
|
+
* none never reads as exhausted. `credits-depleted` and `transient-throttle`
|
|
13
|
+
* are only ever read from older runs' records.
|
|
12
14
|
*/
|
|
13
15
|
export type TerminalClass = "usage-exhausted" | "credits-depleted" | "transient-throttle"
|
|
14
16
|
/** The provider's sign-in or API key no longer works — no retry:
|
|
@@ -31,15 +33,26 @@ export type StructuralTerminal = {
|
|
|
31
33
|
code: string | null;
|
|
32
34
|
};
|
|
33
35
|
/** Classify a finished attempt: a sign-in that no longer works first, for
|
|
34
|
-
* any provider or version; then a
|
|
36
|
+
* any provider or version; then a recognised plan limit, on the exact provider,
|
|
37
|
+
* auth mode and CLI line it was seen on; then a structural failure terminal is
|
|
35
38
|
* `not-exhausted`, and anything else `unknown`. */
|
|
36
39
|
export declare function classifyTerminal(args: {
|
|
37
40
|
terminal: StructuralTerminal | null;
|
|
41
|
+
/** The run's own provider, its auth mode, and the version the installed CLI reports to the gateway: never the checkout's word. */
|
|
42
|
+
run?: {
|
|
43
|
+
provider: string;
|
|
44
|
+
authMode: string;
|
|
45
|
+
version: string | null;
|
|
46
|
+
};
|
|
38
47
|
/** What a run that failed within seconds, having produced nothing, said
|
|
39
48
|
* on its way out (stderr and unstructured stdout) — read ONLY for the
|
|
40
49
|
* sign-in signal: a CLI that is not logged in often exits before its
|
|
41
50
|
* structured stream begins. */
|
|
42
51
|
earlyExit?: string | null;
|
|
43
52
|
}): TerminalClass;
|
|
53
|
+
/** Whether a terminal reads as a limit for this provider and auth mode, before its CLI version is asked. */
|
|
54
|
+
export declare function terminalMatchesLimit(provider: string, authMode: string, terminal: StructuralTerminal | null): boolean;
|
|
55
|
+
/** Whether Toolroll can recognise this agent running out at all: the words every surface shows beside an entry. */
|
|
56
|
+
export declare function limitRecognised(provider: string, authMode: string): boolean;
|
|
44
57
|
/** Whether a provider's own words say its sign-in or key no longer works. */
|
|
45
58
|
export declare function isAuthFailure(text: string): boolean;
|
package/dist/exhaustion.js
CHANGED
|
@@ -6,12 +6,15 @@
|
|
|
6
6
|
* someone signs in, instead of burning attempts. Everything else is the
|
|
7
7
|
* ordinary failure road.
|
|
8
8
|
*
|
|
9
|
-
* `usage-exhausted
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* `usage-exhausted` moves the work to the next agent a person approved
|
|
10
|
+
* (fallback.ts), so it comes only from a recogniser below, and a recogniser
|
|
11
|
+
* comes only from a real run (docs/plans/fallback-chains.md). A provider with
|
|
12
|
+
* none never reads as exhausted. `credits-depleted` and `transient-throttle`
|
|
13
|
+
* are only ever read from older runs' records.
|
|
12
14
|
*/
|
|
13
15
|
/** Classify a finished attempt: a sign-in that no longer works first, for
|
|
14
|
-
* any provider or version; then a
|
|
16
|
+
* any provider or version; then a recognised plan limit, on the exact provider,
|
|
17
|
+
* auth mode and CLI line it was seen on; then a structural failure terminal is
|
|
15
18
|
* `not-exhausted`, and anything else `unknown`. */
|
|
16
19
|
export function classifyTerminal(args) {
|
|
17
20
|
const { terminal } = args;
|
|
@@ -21,8 +24,45 @@ export function classifyTerminal(args) {
|
|
|
21
24
|
return "auth-expired";
|
|
22
25
|
if (terminal === null || terminal.failed !== true)
|
|
23
26
|
return "unknown";
|
|
27
|
+
if (args.run !== undefined && terminal.text !== null && planLimitReached(args.run, terminal.text))
|
|
28
|
+
return "usage-exhausted";
|
|
24
29
|
return "not-exhausted";
|
|
25
30
|
}
|
|
31
|
+
const RECOGNISERS = Object.freeze([
|
|
32
|
+
{
|
|
33
|
+
provider: "claude", authMode: "subscription", from: [2, 1, 290], below: [2, 2, 0],
|
|
34
|
+
terminal: /^You've hit your (?:session|weekly|Opus|Sonnet) limit · resets [^\n]{1,64}$/,
|
|
35
|
+
},
|
|
36
|
+
]);
|
|
37
|
+
function versionOf(version) {
|
|
38
|
+
const parts = version === null ? null : /^(\d{1,6})\.(\d{1,6})\.(\d{1,6})(?:\s|$)/.exec(version);
|
|
39
|
+
return parts === null ? null : [Number(parts[1]), Number(parts[2]), Number(parts[3])];
|
|
40
|
+
}
|
|
41
|
+
function before(a, b) {
|
|
42
|
+
for (let at = 0; at < 3; at++)
|
|
43
|
+
if (a[at] !== b[at])
|
|
44
|
+
return a[at] < b[at];
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function planLimitReached(run, text) {
|
|
48
|
+
const version = versionOf(run.version);
|
|
49
|
+
if (version === null)
|
|
50
|
+
return false;
|
|
51
|
+
const words = text.trim();
|
|
52
|
+
return RECOGNISERS.some(one => one.provider === run.provider && one.authMode === run.authMode
|
|
53
|
+
&& !before(version, one.from) && before(version, one.below) && one.terminal.test(words));
|
|
54
|
+
}
|
|
55
|
+
/** Whether a terminal reads as a limit for this provider and auth mode, before its CLI version is asked. */
|
|
56
|
+
export function terminalMatchesLimit(provider, authMode, terminal) {
|
|
57
|
+
if (terminal === null || terminal.failed !== true || terminal.text === null)
|
|
58
|
+
return false;
|
|
59
|
+
const words = terminal.text.trim();
|
|
60
|
+
return RECOGNISERS.some(one => one.provider === provider && one.authMode === authMode && one.terminal.test(words));
|
|
61
|
+
}
|
|
62
|
+
/** Whether Toolroll can recognise this agent running out at all: the words every surface shows beside an entry. */
|
|
63
|
+
export function limitRecognised(provider, authMode) {
|
|
64
|
+
return RECOGNISERS.some(one => one.provider === provider && one.authMode === authMode);
|
|
65
|
+
}
|
|
26
66
|
/**
|
|
27
67
|
* The sign-in signals, provider-neutral: Claude's expired or unrefreshable
|
|
28
68
|
* OAuth session and its "Please run /login", an API key the provider calls
|
package/dist/export.js
CHANGED
|
@@ -57,7 +57,7 @@ export function categoryOf(table) {
|
|
|
57
57
|
[/^(flow|workflow_)/, "flows"],
|
|
58
58
|
[/^(chat_|lead_|team_|notification|push_)/, "chats"],
|
|
59
59
|
[/^(approver|credential$|invite|sso_identity|coordinator_|oauth_)/, "people"],
|
|
60
|
-
[/^(run|artifact|claim|worktree$|execution_slot|criterion_review|diff_comment|proof_|review_request|repair_chain|incident|publication$|merge_|side_spend|knowledge_snapshot|learning_snapshot|skill_snapshot)/, "runs"],
|
|
60
|
+
[/^(run|artifact|claim|worktree$|execution_slot|criterion_review|diff_comment|proof_|review_request|repair_chain|check_repair|evidence_pair|failing_first|finding|provider_capture|incident|publication$|merge_|side_spend|knowledge_snapshot|learning_snapshot|skill_snapshot)/, "runs"],
|
|
61
61
|
[/^(task|hold$|plan_|scope_|tool_seal|decision|external_|skill_test)/, "tasks"],
|
|
62
62
|
[/^(project|approval_policy|capability|verify_command|worktree_setup|backend_grant|intake_grant|publication_grant|operating_mode|knowledge_|learning_|memory_|skill_)/, "projects"],
|
|
63
63
|
[/(_config|_default|_defaults)$|^(budget|model_|provider_|installation_fact|runtime_check|monitoring_status|integration_check|quota|mode_rail|schema_version)/, "settings"],
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Failing test first (docs/plans/fleet-follow-through.md), on its own so the steering mailbox can read it. Evidence pairs
|
|
2
|
+
* reach the builder through follow-up checks, and the mailbox loads with the provider table: importing them from there
|
|
3
|
+
* is a cycle that fails at load in every built command. */
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import type { Store } from "./store.js";
|
|
6
|
+
export declare const FAILING_FIRST_OUTPUT_LIMIT = 2000;
|
|
7
|
+
/** Where the agent writes its report, in the attempt's own mailbox folder. */
|
|
8
|
+
export declare const FAILING_FIRST_FILE = "failing-first.json";
|
|
9
|
+
export declare const failingFirstReportSchema: z.ZodObject<{
|
|
10
|
+
key: z.ZodString;
|
|
11
|
+
test: z.ZodString;
|
|
12
|
+
output: z.ZodString;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
export type FailingFirst = {
|
|
15
|
+
askedBy: string;
|
|
16
|
+
askedAt: string;
|
|
17
|
+
reportRun: number | null;
|
|
18
|
+
test: string | null;
|
|
19
|
+
output: string | null;
|
|
20
|
+
reportedAt: string | null;
|
|
21
|
+
};
|
|
22
|
+
export declare function failingFirstOf(store: Store, taskId: string): FailingFirst | null;
|
|
23
|
+
export declare function askFailingFirst(store: Store, taskId: string, by: string, now: Date): boolean;
|
|
24
|
+
export declare function dropFailingFirst(store: Store, taskId: string): void;
|
|
25
|
+
/** The agent's report, as data. Only a task that asked takes one. */
|
|
26
|
+
export declare function saveFailingFirstReport(store: Store, taskRef: number, runId: number, report: {
|
|
27
|
+
test: string;
|
|
28
|
+
output: string;
|
|
29
|
+
}, now: Date): boolean;
|
|
30
|
+
/** How the step stands, or null when this task didn't ask for it. */
|
|
31
|
+
export declare function failingFirstWords(step: FailingFirst | null): string | null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Failing test first (docs/plans/fleet-follow-through.md), on its own so the steering mailbox can read it. Evidence pairs
|
|
2
|
+
* reach the builder through follow-up checks, and the mailbox loads with the provider table: importing them from there
|
|
3
|
+
* is a cycle that fails at load in every built command. */
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { readingFleet } from "./fleet-schema.js";
|
|
6
|
+
import { cleanFindingText, familyRootOf } from "./findings.js";
|
|
7
|
+
export const FAILING_FIRST_OUTPUT_LIMIT = 2_000;
|
|
8
|
+
/** Where the agent writes its report, in the attempt's own mailbox folder. */
|
|
9
|
+
export const FAILING_FIRST_FILE = "failing-first.json";
|
|
10
|
+
export const failingFirstReportSchema = z.strictObject({ key: z.string().min(1).max(64), test: z.string().min(1).max(300), output: z.string().min(1).max(FAILING_FIRST_OUTPUT_LIMIT) });
|
|
11
|
+
export function failingFirstOf(store, taskId) {
|
|
12
|
+
return readingFleet(() => {
|
|
13
|
+
const row = store.handle.prepare("SELECT * FROM failing_first WHERE family_root = ?").get(familyRootOf(store, taskId));
|
|
14
|
+
if (row === undefined)
|
|
15
|
+
return null;
|
|
16
|
+
const text = (key) => row[key] === null ? null : String(row[key]);
|
|
17
|
+
return { askedBy: String(row["asked_by"]), askedAt: String(row["asked_at"]), reportRun: row["report_run"] === null ? null : Number(row["report_run"]), test: text("test"), output: text("output"), reportedAt: text("reported_at") };
|
|
18
|
+
}, null);
|
|
19
|
+
}
|
|
20
|
+
export function askFailingFirst(store, taskId, by, now) {
|
|
21
|
+
const ref = store.lookupRef(taskId);
|
|
22
|
+
if (ref === null)
|
|
23
|
+
return false;
|
|
24
|
+
store.handle.prepare("INSERT INTO failing_first (family_root, repo, asked_by, asked_at) VALUES (?, ?, ?, ?) ON CONFLICT (family_root) DO NOTHING").run(familyRootOf(store, taskId), ref.repo, by, now.toISOString());
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
export function dropFailingFirst(store, taskId) {
|
|
28
|
+
store.handle.prepare("DELETE FROM failing_first WHERE family_root = ?").run(familyRootOf(store, taskId));
|
|
29
|
+
}
|
|
30
|
+
/** The agent's report, as data. Only a task that asked takes one. */
|
|
31
|
+
export function saveFailingFirstReport(store, taskRef, runId, report, now) {
|
|
32
|
+
const taskId = store.refById(taskRef)?.externalId;
|
|
33
|
+
if (taskId === undefined)
|
|
34
|
+
return false;
|
|
35
|
+
const saved = store.handle.prepare("UPDATE failing_first SET report_run = ?, test = ?, output = ?, reported_at = ? WHERE family_root = ?")
|
|
36
|
+
.run(runId, cleanFindingText(report.test, 300), cleanFindingText(report.output, FAILING_FIRST_OUTPUT_LIMIT), now.toISOString(), familyRootOf(store, taskId));
|
|
37
|
+
return Number(saved.changes) === 1;
|
|
38
|
+
}
|
|
39
|
+
/** How the step stands, or null when this task didn't ask for it. */
|
|
40
|
+
export function failingFirstWords(step) {
|
|
41
|
+
if (step === null)
|
|
42
|
+
return null;
|
|
43
|
+
return step.reportedAt === null ? "Failing test first was asked for. No report yet." : `The agent reports it wrote ${step.test ?? "a test"} first and saw it fail. Toolroll didn't run this itself.`;
|
|
44
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v156: fallback chains (docs/plans/fallback-chains.md). New tables only, so a saved row reads as it did. Their names
|
|
3
|
+
* differ from the tables v115 dropped: nothing old comes back under an old name. Kept beside nothing else so the update
|
|
4
|
+
* road can read the list without loading the store.
|
|
5
|
+
*/
|
|
6
|
+
export declare const V156_SCHEMA = "\nCREATE TABLE IF NOT EXISTS fallback_setting (\n repo TEXT PRIMARY KEY,\n entries_json TEXT NOT NULL,\n paid_granted_by TEXT,\n paid_granted_at TEXT,\n updated_by TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS fallback_walk (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n task_ref INTEGER NOT NULL,\n scope_digest TEXT NOT NULL,\n chain_digest TEXT NOT NULL,\n cursor INTEGER NOT NULL DEFAULT 0,\n tail_run INTEGER NOT NULL,\n state TEXT NOT NULL DEFAULT 'open' CHECK (state IN ('open','closed')),\n closed_reason TEXT,\n opened_at TEXT NOT NULL,\n closed_at TEXT\n);\nCREATE UNIQUE INDEX IF NOT EXISTS fallback_walk_one_open ON fallback_walk (task_ref) WHERE state = 'open';\nCREATE TABLE IF NOT EXISTS fallback_move (\n walk INTEGER NOT NULL REFERENCES fallback_walk(id),\n to_index INTEGER NOT NULL,\n from_run INTEGER NOT NULL UNIQUE,\n to_run INTEGER UNIQUE,\n terminal_class TEXT NOT NULL,\n paid INTEGER NOT NULL DEFAULT 0,\n moved_at TEXT NOT NULL,\n PRIMARY KEY (walk, to_index)\n);\n";
|
|
7
|
+
export declare const V156_TABLES: readonly ["fallback_setting", "fallback_walk", "fallback_move"];
|
|
8
|
+
export declare const V156_STEPS: readonly ["fallback-tables"];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v156: fallback chains (docs/plans/fallback-chains.md). New tables only, so a saved row reads as it did. Their names
|
|
3
|
+
* differ from the tables v115 dropped: nothing old comes back under an old name. Kept beside nothing else so the update
|
|
4
|
+
* road can read the list without loading the store.
|
|
5
|
+
*/
|
|
6
|
+
export const V156_SCHEMA = `
|
|
7
|
+
CREATE TABLE IF NOT EXISTS fallback_setting (
|
|
8
|
+
repo TEXT PRIMARY KEY,
|
|
9
|
+
entries_json TEXT NOT NULL,
|
|
10
|
+
paid_granted_by TEXT,
|
|
11
|
+
paid_granted_at TEXT,
|
|
12
|
+
updated_by TEXT NOT NULL,
|
|
13
|
+
updated_at TEXT NOT NULL
|
|
14
|
+
);
|
|
15
|
+
CREATE TABLE IF NOT EXISTS fallback_walk (
|
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
17
|
+
task_ref INTEGER NOT NULL,
|
|
18
|
+
scope_digest TEXT NOT NULL,
|
|
19
|
+
chain_digest TEXT NOT NULL,
|
|
20
|
+
cursor INTEGER NOT NULL DEFAULT 0,
|
|
21
|
+
tail_run INTEGER NOT NULL,
|
|
22
|
+
state TEXT NOT NULL DEFAULT 'open' CHECK (state IN ('open','closed')),
|
|
23
|
+
closed_reason TEXT,
|
|
24
|
+
opened_at TEXT NOT NULL,
|
|
25
|
+
closed_at TEXT
|
|
26
|
+
);
|
|
27
|
+
CREATE UNIQUE INDEX IF NOT EXISTS fallback_walk_one_open ON fallback_walk (task_ref) WHERE state = 'open';
|
|
28
|
+
CREATE TABLE IF NOT EXISTS fallback_move (
|
|
29
|
+
walk INTEGER NOT NULL REFERENCES fallback_walk(id),
|
|
30
|
+
to_index INTEGER NOT NULL,
|
|
31
|
+
from_run INTEGER NOT NULL UNIQUE,
|
|
32
|
+
to_run INTEGER UNIQUE,
|
|
33
|
+
terminal_class TEXT NOT NULL,
|
|
34
|
+
paid INTEGER NOT NULL DEFAULT 0,
|
|
35
|
+
moved_at TEXT NOT NULL,
|
|
36
|
+
PRIMARY KEY (walk, to_index)
|
|
37
|
+
);
|
|
38
|
+
`;
|
|
39
|
+
export const V156_TABLES = Object.freeze(["fallback_setting", "fallback_walk", "fallback_move"]);
|
|
40
|
+
export const V156_STEPS = Object.freeze(["fallback-tables"]);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { type ChainEntry, type ExecutionProfile, type Scope } from "./scope.js";
|
|
2
|
+
import type { Store } from "./store.js";
|
|
3
|
+
export declare const MAX_FALLBACK_ENTRIES = 3;
|
|
4
|
+
/** What a project's setting names: the rest of each entry's terms resolve at filing and seal with the approval. */
|
|
5
|
+
export type FallbackEntry = {
|
|
6
|
+
provider: string;
|
|
7
|
+
model: string;
|
|
8
|
+
authMode: "subscription" | "api-key";
|
|
9
|
+
};
|
|
10
|
+
export type FallbackSetting = {
|
|
11
|
+
repo: string;
|
|
12
|
+
entries: FallbackEntry[];
|
|
13
|
+
paidGrant: {
|
|
14
|
+
by: string;
|
|
15
|
+
at: string;
|
|
16
|
+
} | null;
|
|
17
|
+
updatedBy: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function entryDigestOf(entry: ChainEntry): string;
|
|
21
|
+
/** An entry in the words every surface uses. */
|
|
22
|
+
export declare function entryWords(entry: FallbackEntry): string;
|
|
23
|
+
/** Whether Toolroll can see this entry run out, in plain words: an entry it can't recognise ends the chain there. */
|
|
24
|
+
export declare function entryMovesOnWords(entry: Pick<FallbackEntry, "provider" | "authMode">): string;
|
|
25
|
+
/** Whether this entry spends money, by what it was pinned to: an API key, or a provider that only bills by use. A plan
|
|
26
|
+
* entry is never paid: where its login can't be proved to be that plan, it doesn't run (invoke.ts), it is never
|
|
27
|
+
* reinterpreted as a paid agent. */
|
|
28
|
+
export declare function entryPaid(_store: Store, entry: Pick<FallbackEntry, "provider" | "authMode">): boolean;
|
|
29
|
+
/** Parse `provider:model:plan|api-key`. The model is everything between the first and last colon, so ":free" ids work. */
|
|
30
|
+
export declare function parseEntry(text: string): FallbackEntry | string;
|
|
31
|
+
export declare function entriesProblem(entries: readonly FallbackEntry[]): string | null;
|
|
32
|
+
export declare function fallbackSettingOf(store: Store, repo: string): FallbackSetting | null;
|
|
33
|
+
export declare function setFallbackChain(store: Store, repo: string, entries: readonly FallbackEntry[], by: string, now: Date): {
|
|
34
|
+
ok: true;
|
|
35
|
+
} | {
|
|
36
|
+
ok: false;
|
|
37
|
+
problem: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function clearFallbackChain(store: Store, repo: string, by: string, now: Date): {
|
|
40
|
+
ok: true;
|
|
41
|
+
} | {
|
|
42
|
+
ok: false;
|
|
43
|
+
problem: string;
|
|
44
|
+
};
|
|
45
|
+
/** The paid grant: the one explicit yes a paid entry spends under, read again at every money moment. */
|
|
46
|
+
export declare function setPaidGrant(store: Store, repo: string, allowed: boolean, by: string, now: Date): {
|
|
47
|
+
ok: true;
|
|
48
|
+
} | {
|
|
49
|
+
ok: false;
|
|
50
|
+
problem: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The chain a new scope files with: its base agent, then the project's entries. Null means no chain. A setting that can't
|
|
54
|
+
* resolve is a stated problem: the scope files unresolved in those words, and nothing runs on half a chain.
|
|
55
|
+
*/
|
|
56
|
+
export declare function chainForFiling(store: Store, repo: string | null, base: ExecutionProfile, baseAuth: string, lower: (profile: ExecutionProfile) => ExecutionProfile): {
|
|
57
|
+
ok: true;
|
|
58
|
+
chain: ChainEntry[] | null;
|
|
59
|
+
} | {
|
|
60
|
+
ok: false;
|
|
61
|
+
problem: string;
|
|
62
|
+
};
|
|
63
|
+
export declare const chainJsonOf: (chain: readonly ChainEntry[]) => string;
|
|
64
|
+
/**
|
|
65
|
+
* Why this chain can't seal on this yes, or null. A paid entry takes a person's own yes: the ceremony or their chat tap,
|
|
66
|
+
* never a mode, grant, schedule, lead or automatic seal, and no machine's credential. A chat tap is bound to the scope's
|
|
67
|
+
* digest, which covers the chain, and the card shows the chain in full (chainTermsLines).
|
|
68
|
+
*/
|
|
69
|
+
export declare function chainSealProblem(store: Store, scope: Scope, basis: {
|
|
70
|
+
kind: string;
|
|
71
|
+
} | undefined): string | null;
|
|
72
|
+
/** Each tick, before any dispatch: settle every open walk. */
|
|
73
|
+
export declare function reconcileWalks(store: Store, now: Date): void;
|
|
74
|
+
export type FallbackDispatch = {
|
|
75
|
+
index: number;
|
|
76
|
+
entry: ChainEntry;
|
|
77
|
+
paid: boolean;
|
|
78
|
+
} | {
|
|
79
|
+
problem: string;
|
|
80
|
+
} | null;
|
|
81
|
+
/**
|
|
82
|
+
* Which entry the next build of this task runs as, read by the tick before anything is claimed: null is the ordinary
|
|
83
|
+
* road (no chain, or the base agent). A move whose paid grant has since gone closes here and says so: nothing runs on it.
|
|
84
|
+
*/
|
|
85
|
+
export declare function dispatchEntryOf(store: Store, taskRef: number, taskId: string, now: Date): FallbackDispatch;
|
|
86
|
+
/** A route stamp for a fallback entry, checked against the sealed chain: the admission's proof of `fallback` provenance. */
|
|
87
|
+
export declare function fallbackStampProblem(store: Store, taskRef: number, taskId: string, stamp: {
|
|
88
|
+
routeDigest: string;
|
|
89
|
+
phase: string;
|
|
90
|
+
provider: string;
|
|
91
|
+
model: string | null;
|
|
92
|
+
}, parentRun: number | null): string | null;
|
|
93
|
+
/**
|
|
94
|
+
* Inside the run's admission transaction: bind it to its walk, or say why not (the caller rolls the row back). A base run
|
|
95
|
+
* opens a walk; a pending entry consumes its edge exactly once, with the paid grant re-read; a parked tail hands custody to
|
|
96
|
+
* its resumption; a repair inherits its parent's binding verbatim. Nothing else opens on a chain approval.
|
|
97
|
+
*/
|
|
98
|
+
export declare function bindRunToWalk(store: Store, runId: number, now: Date): string | null;
|
|
99
|
+
/** The pinned entry a bound run spends as, or null for a run with no binding. */
|
|
100
|
+
export declare function pinnedEntryOf(store: Store, runId: number): {
|
|
101
|
+
index: number;
|
|
102
|
+
entry: ChainEntry;
|
|
103
|
+
} | {
|
|
104
|
+
problem: string;
|
|
105
|
+
} | null;
|
|
106
|
+
/**
|
|
107
|
+
* THE LAST LOOK AT THE SPAWN: one read of every authority a chain run spends under. A builder or repair on a chain
|
|
108
|
+
* approval with no binding spends nothing; a bound run must hold the walk's current place, under the live approval, as its
|
|
109
|
+
* exact entry; a paid entry must still hold the live grant. Null means go.
|
|
110
|
+
*/
|
|
111
|
+
export declare function chainCustodyProblem(store: Store, runId: number): string | null;
|
|
112
|
+
/** Whether this finished attempt is about to move on: it holds a walk's place and the gateway classed it exhausted. */
|
|
113
|
+
export declare function ranOutOnChain(store: Store, runId: number): boolean;
|
|
114
|
+
/** The gateway refused this bound run: its plan login isn't proved. The walk closes, a person is told, no strike. */
|
|
115
|
+
export declare function closeWalkSignedOut(store: Store, runId: number, now: Date): void;
|
|
116
|
+
/**
|
|
117
|
+
* After the dispatch road finished a refused run: when it was a fallback agent refused for not being signed in to its
|
|
118
|
+
* plan, the task stops and waits for a person (task state failed, the run's reason saying why), until they retry it.
|
|
119
|
+
* Nothing expires it. True when it did.
|
|
120
|
+
*/
|
|
121
|
+
export declare function blockAfterSignedOut(store: Store, runId: number, now: Date): boolean;
|
|
122
|
+
export type MoveResult = {
|
|
123
|
+
moved: true;
|
|
124
|
+
to: FallbackEntry;
|
|
125
|
+
paid: boolean;
|
|
126
|
+
} | null;
|
|
127
|
+
/**
|
|
128
|
+
* THE MOVE, inside sealFailure's transaction (the claim is already released, the run still open): only the walk's own tail,
|
|
129
|
+
* started and classed exhausted by the gateway, on the exact entry it was pinned to. Null means the ordinary failure road
|
|
130
|
+
* runs, with the walk closed in words when it can't go on. The caller finishes the run either way; a walk that moved leaves
|
|
131
|
+
* no strike.
|
|
132
|
+
*/
|
|
133
|
+
export declare function moveOnIfExhausted(store: Store, runId: number, taskId: string, now: Date): MoveResult;
|
|
134
|
+
/**
|
|
135
|
+
* What the next agent is told about the move, for its brief. The one place the handover note plugs in: once it merges, a
|
|
136
|
+
* fallback run gets that note here. Null for any run that isn't continuing another agent's work.
|
|
137
|
+
*/
|
|
138
|
+
export declare function fallbackBriefFor(store: Store, runId: number): string | null;
|