toolroll 0.9.62 → 0.9.65
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 +80 -0
- package/README.md +66 -8
- package/dist/acp-agents.d.ts +43 -0
- package/dist/acp-agents.js +62 -0
- package/dist/acp-attest.d.ts +44 -0
- package/dist/acp-attest.js +269 -0
- package/dist/acp-check.d.ts +28 -0
- package/dist/acp-check.js +410 -0
- package/dist/acp-client.d.ts +163 -0
- package/dist/acp-client.js +738 -0
- package/dist/acp-inspect.d.ts +23 -0
- package/dist/acp-inspect.js +109 -0
- package/dist/agent-board.d.ts +19 -6
- package/dist/agent-board.js +30 -9
- package/dist/agent-fence.d.ts +203 -10
- package/dist/agent-fence.js +623 -41
- package/dist/agent-pulse.js +9 -2
- package/dist/agent-state-words.d.ts +19 -0
- package/dist/agent-state-words.js +20 -0
- package/dist/agent-state.d.ts +65 -0
- package/dist/agent-state.js +229 -0
- package/dist/agentconfig.js +36 -13
- package/dist/agents-board.d.ts +34 -2
- package/dist/agents-board.js +110 -1
- package/dist/approval-rules-ui.js +2 -2
- package/dist/assignment-delivery.d.ts +14 -0
- package/dist/assignment-delivery.js +13 -0
- package/dist/assignment.js +13 -0
- package/dist/attest.js +7 -0
- package/dist/backup-ui.js +2 -2
- package/dist/browser/THIRD_PARTY_NOTICES.txt +48 -0
- package/dist/browser/terminal.css +37 -0
- package/dist/browser/terminal.js +117 -0
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +42 -38
- package/dist/browser-shell.js +6 -3
- package/dist/browser-workspace.d.ts +263 -1
- package/dist/browser-workspace.js +60 -0
- package/dist/builder.d.ts +6 -1
- package/dist/builder.js +34 -13
- package/dist/chat-actions.d.ts +13 -1
- package/dist/chat-actions.js +199 -17
- package/dist/chat-ask.d.ts +4 -0
- package/dist/chat-ask.js +14 -0
- package/dist/chat-channel.js +20 -0
- package/dist/chat-continuity.js +5 -4
- package/dist/chat-decide.d.ts +0 -14
- package/dist/chat-decide.js +4 -1
- package/dist/chat-delivery.d.ts +9 -0
- package/dist/chat-delivery.js +45 -6
- package/dist/chat-messages.d.ts +8 -0
- package/dist/chat-messages.js +36 -4
- package/dist/check-levels-ui.js +2 -2
- package/dist/check-levels.js +3 -0
- package/dist/checkout-proof.d.ts +28 -0
- package/dist/checkout-proof.js +62 -0
- package/dist/claim.d.ts +12 -0
- package/dist/claim.js +20 -1
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +5 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +24 -2
- package/dist/coding-ui.js +6 -4
- package/dist/console-instance.d.ts +124 -0
- package/dist/console-instance.js +337 -0
- package/dist/contracts/chat-actions.d.ts +16 -0
- package/dist/contracts/chat-actions.js +4 -0
- package/dist/contracts/chat-content.d.ts +19 -0
- package/dist/contracts/chat-content.js +6 -0
- package/dist/contracts/cli.d.ts +8 -0
- package/dist/contracts/cli.js +3 -1
- package/dist/contracts/console-api.d.ts +30 -4
- package/dist/contracts/console-api.js +13 -4
- package/dist/contracts/flow-card.d.ts +4 -0
- package/dist/contracts/flow-card.js +3 -0
- package/dist/contracts/flow.d.ts +46 -0
- package/dist/contracts/flow.js +11 -2
- package/dist/contracts/integration-metadata.d.ts +2 -1
- package/dist/contracts/integration-metadata.js +2 -1
- package/dist/contracts/lead-tools.d.ts +92 -0
- package/dist/contracts/lead-tools.js +13 -0
- package/dist/contracts/provider.d.ts +11 -1
- package/dist/contracts/provider.js +1 -1
- package/dist/contracts/route.d.ts +76 -1
- package/dist/contracts/route.js +1 -1
- package/dist/contracts/store-json.d.ts +2 -0
- package/dist/control-setup.d.ts +1 -1
- package/dist/control-ui.js +2 -2
- package/dist/converse.d.ts +16 -0
- package/dist/converse.js +32 -4
- package/dist/demo-chat.js +4 -4
- package/dist/demo.js +2 -2
- package/dist/desktop-update-gate.js +6 -0
- package/dist/discord-chat.js +4 -1
- package/dist/dispatch.js +7 -4
- package/dist/doctor.d.ts +53 -0
- package/dist/doctor.js +427 -0
- package/dist/egress-bridge.d.ts +17 -0
- package/dist/egress-bridge.js +111 -0
- package/dist/egress.d.ts +119 -0
- package/dist/egress.js +423 -0
- package/dist/evidence-pack.d.ts +1 -1
- package/dist/evidence-pack.js +2 -2
- package/dist/exec.d.ts +81 -0
- package/dist/exec.js +368 -9
- package/dist/export-ui.js +2 -2
- package/dist/flow-code.d.ts +2 -2
- package/dist/flow-code.js +4 -15
- package/dist/flow-engine.js +35 -11
- package/dist/flow-gallery-ui.js +2 -2
- package/dist/flow-gallery.js +27 -8
- package/dist/flow-share.js +16 -5
- package/dist/flow-triggers.d.ts +84 -11
- package/dist/flow-triggers.js +554 -87
- package/dist/flow-unattended-words.d.ts +28 -0
- package/dist/flow-unattended-words.js +50 -0
- package/dist/flow-unattended.d.ts +227 -0
- package/dist/flow-unattended.js +776 -0
- package/dist/flows-cli.d.ts +28 -1
- package/dist/flows-cli.js +63 -12
- package/dist/flows-ui.d.ts +2 -3
- package/dist/flows-ui.js +56 -5
- package/dist/flows.d.ts +4 -0
- package/dist/flows.js +9 -1
- package/dist/google-mail.d.ts +1 -0
- package/dist/google-mail.js +61 -18
- package/dist/html.d.ts +9 -0
- package/dist/html.js +11 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +6 -3
- package/dist/integrations.d.ts +17 -3
- package/dist/integrations.js +38 -18
- package/dist/invoke.d.ts +17 -0
- package/dist/invoke.js +510 -182
- package/dist/keys.d.ts +18 -14
- package/dist/keys.js +5 -0
- package/dist/landed-cleanup.d.ts +3 -2
- package/dist/landed-cleanup.js +12 -5
- package/dist/lead-capabilities.js +3 -2
- package/dist/lead-contract.js +2 -0
- package/dist/lead-doors.d.ts +2 -0
- package/dist/lead-doors.js +7 -0
- package/dist/lead-follow.d.ts +2 -0
- package/dist/lead-follow.js +58 -2
- package/dist/lead-progress.js +1 -0
- package/dist/lead-queue-runtime.d.ts +46 -0
- package/dist/lead-queue-runtime.js +191 -0
- package/dist/lead-queue.d.ts +104 -0
- package/dist/lead-queue.js +187 -0
- package/dist/lead-sweep.d.ts +67 -0
- package/dist/lead-sweep.js +99 -0
- package/dist/lead-tools.d.ts +22 -0
- package/dist/lead-tools.js +163 -4
- package/dist/lead.d.ts +13 -5
- package/dist/lead.js +89 -29
- package/dist/limits-ui.d.ts +8 -1
- package/dist/limits-ui.js +26 -0
- package/dist/live-bus.d.ts +8 -0
- package/dist/live-bus.js +40 -4
- package/dist/live-detail.d.ts +27 -0
- package/dist/live-detail.js +57 -0
- package/dist/live-notes.d.ts +20 -0
- package/dist/live-notes.js +47 -0
- package/dist/live-records.d.ts +140 -0
- package/dist/live-records.js +935 -0
- package/dist/live-terminal.d.ts +258 -0
- package/dist/live-terminal.js +649 -0
- package/dist/live.d.ts +38 -27
- package/dist/live.js +142 -124
- package/dist/mcp-connect.d.ts +8 -7
- package/dist/mcp-connect.js +49 -51
- package/dist/mcp-oauth.d.ts +6 -3
- package/dist/mcp-oauth.js +8 -4
- package/dist/memory-pass.js +2 -2
- package/dist/mobile-viewport.d.ts +5 -1
- package/dist/mobile-viewport.js +18 -2
- package/dist/model-catalog.js +4 -0
- package/dist/monitoring-ui.js +2 -2
- package/dist/needs-you.d.ts +1 -1
- package/dist/needs-you.js +11 -4
- package/dist/oauth-run-token.d.ts +51 -0
- package/dist/oauth-run-token.js +127 -0
- package/dist/operate.d.ts +2 -0
- package/dist/operate.js +282 -18
- package/dist/passwordless.d.ts +23 -0
- package/dist/passwordless.js +26 -0
- package/dist/peek-cli.d.ts +12 -4
- package/dist/peek-cli.js +19 -11
- package/dist/phase-routing.js +10 -3
- package/dist/plan-auto.d.ts +11 -0
- package/dist/plan-auto.js +62 -11
- package/dist/planner-source.d.ts +3 -0
- package/dist/planner-source.js +14 -0
- package/dist/planner.d.ts +2 -1
- package/dist/planner.js +7 -1
- package/dist/policy-ui.js +2 -2
- package/dist/policy.d.ts +1 -20
- package/dist/policy.js +29 -2
- package/dist/process-recovery-eligibility.d.ts +1 -1
- package/dist/project-access.d.ts +3 -0
- package/dist/project-access.js +3 -0
- package/dist/project-delete-ui.d.ts +12 -0
- package/dist/project-delete-ui.js +41 -9
- package/dist/project-delete.d.ts +3 -1
- package/dist/project-delete.js +12 -6
- package/dist/project-file.d.ts +3 -0
- package/dist/project-file.js +16 -0
- package/dist/project-memory.d.ts +3 -1
- package/dist/project-memory.js +57 -25
- package/dist/project-tools.d.ts +103 -27
- package/dist/project-tools.js +399 -100
- package/dist/provider-auth.d.ts +4 -3
- package/dist/provider-auth.js +5 -4
- package/dist/provider-connection.d.ts +2 -1
- package/dist/provider-connection.js +5 -0
- package/dist/provider-home.d.ts +22 -0
- package/dist/provider-home.js +99 -0
- package/dist/provider.d.ts +42 -5
- package/dist/provider.js +97 -19
- package/dist/pull-request-ui.js +2 -2
- package/dist/push.js +1 -1
- package/dist/quick-start.d.ts +24 -0
- package/dist/quick-start.js +127 -0
- package/dist/release.d.ts +3 -0
- package/dist/release.js +14 -8
- package/dist/remote-main.d.ts +4 -0
- package/dist/remote-main.js +3 -3
- package/dist/request-budget-ui.js +2 -2
- package/dist/result-review.d.ts +1 -1
- package/dist/result-review.js +9 -3
- package/dist/retention-ui.js +2 -2
- package/dist/retention.js +10 -1
- package/dist/run-efficiency.d.ts +73 -0
- package/dist/run-efficiency.js +228 -0
- package/dist/runner.d.ts +5 -1
- package/dist/runner.js +22 -1
- package/dist/scope.d.ts +171 -6
- package/dist/scope.js +251 -31
- package/dist/scout-net.d.ts +4 -1
- package/dist/scout-net.js +37 -12
- package/dist/scout.d.ts +20 -6
- package/dist/scout.js +27 -3
- package/dist/serve.js +258 -43
- package/dist/server/chat.d.ts +1 -1
- package/dist/server/chat.js +122 -31
- package/dist/server/chrome.d.ts +6 -1
- package/dist/server/chrome.js +18 -7
- package/dist/server/console.css +52 -38
- package/dist/server/flows.js +65 -13
- package/dist/server/guards.d.ts +1 -0
- package/dist/server/guards.js +23 -9
- package/dist/server/http.d.ts +7 -0
- package/dist/server/http.js +3 -2
- package/dist/server/live.d.ts +34 -1
- package/dist/server/live.js +39 -17
- package/dist/server/pages-assets.js +5 -0
- package/dist/server/pages.js +90 -13
- package/dist/server/people-tokens.d.ts +3 -0
- package/dist/server/people-tokens.js +55 -17
- package/dist/server/remote-hooks.js +12 -6
- package/dist/server/remote.d.ts +2 -1
- package/dist/server/remote.js +14 -5
- package/dist/server/render-chat.d.ts +12 -3
- package/dist/server/render-chat.js +47 -16
- package/dist/server/render-pages.d.ts +4 -1
- package/dist/server/render-pages.js +5 -4
- package/dist/server/render-people.d.ts +3 -2
- package/dist/server/render-people.js +3 -2
- package/dist/server/render-results.d.ts +18 -2
- package/dist/server/render-results.js +37 -28
- package/dist/server/render-settings.js +6 -5
- package/dist/server/render-tasks.d.ts +35 -10
- package/dist/server/render-tasks.js +110 -27
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.js +2 -1
- package/dist/server/route-table.d.ts +3 -0
- package/dist/server/route-table.js +49 -5
- package/dist/server/runtime.d.ts +34 -3
- package/dist/server/session.d.ts +25 -1
- package/dist/server/session.js +18 -4
- package/dist/server/settings.js +132 -13
- package/dist/server/sweeps.d.ts +4 -0
- package/dist/server/sweeps.js +58 -0
- package/dist/server/task-views.d.ts +2 -1
- package/dist/server/task-views.js +96 -6
- package/dist/server/tasks.js +320 -74
- package/dist/server/terminals.d.ts +31 -0
- package/dist/server/terminals.js +365 -0
- package/dist/setup-guide.js +3 -2
- package/dist/slack-chat.js +4 -1
- package/dist/spend-ui.js +3 -3
- package/dist/spend.js +2 -1
- package/dist/steer-capabilities.d.ts +32 -0
- package/dist/steer-capabilities.js +60 -0
- package/dist/steer-controls.d.ts +14 -0
- package/dist/steer-controls.js +36 -0
- package/dist/steer-status.js +2 -2
- package/dist/storage-sweep-child.js +3 -1
- package/dist/storage-sweep-process.d.ts +12 -5
- package/dist/storage-sweep-process.js +23 -6
- package/dist/storage-ui.js +4 -4
- package/dist/store-baseline.d.ts +1 -1
- package/dist/store-baseline.js +1 -1
- package/dist/store.d.ts +466 -19
- package/dist/store.js +1185 -63
- package/dist/subagent-desk.js +1 -1
- package/dist/subagent-tools.d.ts +1 -1
- package/dist/summary.js +3 -0
- package/dist/surface.js +6 -4
- package/dist/task-source.d.ts +58 -0
- package/dist/task-source.js +93 -0
- package/dist/team-leads.js +1 -1
- package/dist/teams-chat.js +4 -1
- package/dist/teardown-git.d.ts +14 -0
- package/dist/teardown-git.js +119 -0
- package/dist/telegram-lead.d.ts +3 -0
- package/dist/telegram-lead.js +44 -7
- package/dist/telegram.d.ts +11 -2
- package/dist/telegram.js +51 -17
- package/dist/terminal-catalog.d.ts +11 -0
- package/dist/terminal-catalog.js +129 -0
- package/dist/text-limits.d.ts +2 -0
- package/dist/text-limits.js +2 -0
- package/dist/tool-broker.d.ts +39 -0
- package/dist/tool-broker.js +370 -0
- package/dist/tool-launcher.js +5 -4
- package/dist/tool-secret-store.d.ts +170 -0
- package/dist/tool-secret-store.js +834 -0
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +14 -3
- package/dist/tools-ui.d.ts +7 -1
- package/dist/tools-ui.js +19 -10
- package/dist/webhook-limits.d.ts +23 -0
- package/dist/webhook-limits.js +30 -0
- package/dist/webhook-readers.d.ts +56 -0
- package/dist/webhook-readers.js +138 -0
- package/dist/webhook-signing.d.ts +27 -0
- package/dist/webhook-signing.js +119 -0
- package/dist/work-index.d.ts +29 -0
- package/dist/work-index.js +21 -5
- package/dist/workspace-revision.js +3 -1
- package/dist/worktree.d.ts +10 -4
- package/dist/worktree.js +70 -29
- package/package.json +13 -2
- package/scripts/provider-canary.mjs +210 -31
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BARE `toolroll` IN A REPOSITORY (docs/plans/agents-cockpit.md B1): the two-action start.
|
|
3
|
+
*
|
|
4
|
+
* Inside a git repository, `toolroll` with nothing else (or only --json) either starts the console for it (`up`), or —
|
|
5
|
+
* when this installation's console is already running and PROVES it is (console-instance.ts: a fresh challenge on the
|
|
6
|
+
* discovery socket and on its HTTP listener, answered with the secret in the database this CLI opened itself) —
|
|
7
|
+
* adds the repository through the ordinary project admission and opens that proved console. Under an agent, or with
|
|
8
|
+
* --json, it starts nothing and changes nothing: it says what it would do. Outside a repository, it scans as before
|
|
9
|
+
* (the scan is also `toolroll scan`).
|
|
10
|
+
*/
|
|
11
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
12
|
+
import { proveLiveConsole } from "./console-instance.js";
|
|
13
|
+
import { underAgent } from "./prompt.js";
|
|
14
|
+
import { envelopeJson } from "./envelope.js";
|
|
15
|
+
import { createRequire } from "node:module";
|
|
16
|
+
import { openStoreReadOnly, readSchemaVersion, SCHEMA_VERSION } from "./store.js";
|
|
17
|
+
const EXIT = { ok: 0, refused: 3 };
|
|
18
|
+
/** Whether argv is a bare `toolroll` (nothing, or only --json). */
|
|
19
|
+
export const isBareInvocation = (argv) => argv.every(one => one === "--json");
|
|
20
|
+
/** The database's schema version by the store's own strict reader, read without changing anything. */
|
|
21
|
+
function schemaOf(file) {
|
|
22
|
+
try {
|
|
23
|
+
// Loaded only here, as the store loads it: the CLI's other commands never pay for (or warn about) it.
|
|
24
|
+
const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
25
|
+
const db = new DatabaseSync(file, { readOnly: true });
|
|
26
|
+
try {
|
|
27
|
+
const read = readSchemaVersion(db);
|
|
28
|
+
return read.ok ? read : { ok: false };
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
db.close();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { ok: false };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Whether the database file is there: "absent" only when the system says so (ENOENT), never for a path it won't show. */
|
|
39
|
+
function databasePresence(file) {
|
|
40
|
+
try {
|
|
41
|
+
lstatSync(file);
|
|
42
|
+
return "present";
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
return error.code === "ENOENT" ? "absent" : "unknown";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function prove(seams) {
|
|
49
|
+
// Read only, never created or migrated, never cleaned up: proving changes nothing. "None" only when nothing of this
|
|
50
|
+
// build can be running on it (no database yet, or one older than this build, which `up` brings up to date); a
|
|
51
|
+
// database that can't be read, is mid-upgrade or is newer than this build can't be checked, so it is refused.
|
|
52
|
+
const none = { ok: false, state: "none", message: "no console is running" };
|
|
53
|
+
const unverifiable = (why) => ({ ok: false, state: "refused", message: `${why}, so a running console can't be checked — run \`toolroll up\` to see what's wrong` });
|
|
54
|
+
const presence = databasePresence(seams.databaseFile);
|
|
55
|
+
if (presence === "absent")
|
|
56
|
+
return none;
|
|
57
|
+
if (presence === "unknown")
|
|
58
|
+
return unverifiable("Toolroll's database can't be reached");
|
|
59
|
+
const schema = schemaOf(seams.databaseFile);
|
|
60
|
+
if (!schema.ok)
|
|
61
|
+
return unverifiable("Toolroll's database can't be read");
|
|
62
|
+
if (schema.version === null || (schema.version > 0 && schema.version < SCHEMA_VERSION))
|
|
63
|
+
return none;
|
|
64
|
+
if (schema.version !== SCHEMA_VERSION)
|
|
65
|
+
return unverifiable("Toolroll's database is being upgraded");
|
|
66
|
+
const store = openStoreReadOnly(seams.databaseFile);
|
|
67
|
+
if (store === null)
|
|
68
|
+
return unverifiable("Toolroll's database can't be read");
|
|
69
|
+
try {
|
|
70
|
+
return await proveLiveConsole(seams.databaseFile, store, seams.build, seams.attach ?? {});
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return unverifiable("the running console couldn't be checked");
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
store.close();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** null: not this command (outside a repository) — the caller scans as before. */
|
|
80
|
+
export async function runQuickStart(argv, write, seams) {
|
|
81
|
+
const found = await seams.findRepo(seams.cwd);
|
|
82
|
+
if (found === null)
|
|
83
|
+
return null;
|
|
84
|
+
let repo = found;
|
|
85
|
+
try {
|
|
86
|
+
repo = realpathSync(found);
|
|
87
|
+
}
|
|
88
|
+
catch { /* as found */ }
|
|
89
|
+
const json = argv.includes("--json");
|
|
90
|
+
const dry = json || (seams.underAgent ?? underAgent(seams.env));
|
|
91
|
+
const proof = await prove(seams);
|
|
92
|
+
const enrolled = await seams.enrolled(repo);
|
|
93
|
+
const would = proof.ok ? (enrolled ? "open" : "add-and-open") : proof.state === "none" ? "start" : "refuse";
|
|
94
|
+
if (dry) {
|
|
95
|
+
// Nothing starts, nothing is added, nothing opens: what a person would get, in words or one envelope.
|
|
96
|
+
const words = would === "start" ? `Would start Toolroll for ${repo} (toolroll up).`
|
|
97
|
+
: would === "refuse" ? `Would refuse: ${proof.message}.`
|
|
98
|
+
: `Would ${would === "add-and-open" ? `add ${repo} and ` : ""}open the running console at ${proof.url}.`;
|
|
99
|
+
if (json)
|
|
100
|
+
write(envelopeJson({ ok: would !== "refuse", command: "toolroll", repo, would, ...(proof.ok ? { url: proof.url } : { console: proof.state, message: proof.message }), dryRun: true }));
|
|
101
|
+
else
|
|
102
|
+
write(words);
|
|
103
|
+
return would === "refuse" ? EXIT.refused : EXIT.ok;
|
|
104
|
+
}
|
|
105
|
+
if (!proof.ok && proof.state === "refused") {
|
|
106
|
+
write(`Toolroll can't attach: ${proof.message}.`);
|
|
107
|
+
return EXIT.refused;
|
|
108
|
+
}
|
|
109
|
+
if (!proof.ok)
|
|
110
|
+
return seams.startUp();
|
|
111
|
+
if (!enrolled) {
|
|
112
|
+
const admitted = await seams.admit(repo);
|
|
113
|
+
if (admitted !== 0)
|
|
114
|
+
return admitted;
|
|
115
|
+
}
|
|
116
|
+
// Whatever happened since the first proof (reading the registry, adding the project), the console is proved again,
|
|
117
|
+
// on both channels, right before its address is shown or opened — never a listener that took the port meanwhile.
|
|
118
|
+
const again = await prove(seams);
|
|
119
|
+
if (!again.ok || again.url !== proof.url || again.pid !== proof.pid) {
|
|
120
|
+
write(`Toolroll can't attach: ${again.ok ? "the console changed while the project was being added" : again.message} — run \`toolroll up\`.`);
|
|
121
|
+
return EXIT.refused;
|
|
122
|
+
}
|
|
123
|
+
write(`Toolroll is on ${proof.url}`);
|
|
124
|
+
if (seams.terminal)
|
|
125
|
+
await seams.openBrowser(proof.url);
|
|
126
|
+
return EXIT.ok;
|
|
127
|
+
}
|
package/dist/release.d.ts
CHANGED
|
@@ -226,10 +226,13 @@ export type ReleaseJournal = {
|
|
|
226
226
|
by: string;
|
|
227
227
|
at: string;
|
|
228
228
|
} | null;
|
|
229
|
+
/** The passing result: its run, receipt and checkout, and the commit it built (`head`), which a prepared candidate
|
|
230
|
+
* records as a commit of its own with exactly the candidate's tree (absent in a journal from before that was known). */
|
|
229
231
|
check: {
|
|
230
232
|
run: number;
|
|
231
233
|
receipt: string;
|
|
232
234
|
worktree: string;
|
|
235
|
+
head?: string;
|
|
233
236
|
} | null;
|
|
234
237
|
completion: {
|
|
235
238
|
actor: string;
|
package/dist/release.js
CHANGED
|
@@ -213,9 +213,11 @@ export async function runRelease(options, adapters) {
|
|
|
213
213
|
if (gate.result.check !== "passed")
|
|
214
214
|
throw new Stop("check-failed", `The Full release check of ${j.candidate.sha.slice(0, 7)} did not pass (run ${gate.result.run}: ${gate.result.check}). It stays as it is: fix the branch and release the new commit with --new.`);
|
|
215
215
|
};
|
|
216
|
+
/** The commit the passing build recorded: what the deployed runtime is stamped with. */
|
|
217
|
+
const builtHead = () => j.check?.head ?? j.candidate.sha;
|
|
216
218
|
const checked = (gate) => {
|
|
217
219
|
approved(gate);
|
|
218
|
-
if (gate.result?.head !==
|
|
220
|
+
if (gate.result?.head !== builtHead() || gate.result?.receipt !== j.check?.receipt)
|
|
219
221
|
throw new Stop("drift", `Task ${j.task.id}'s result changed since its check passed.`);
|
|
220
222
|
fullCheck(gate);
|
|
221
223
|
};
|
|
@@ -268,12 +270,16 @@ export async function runRelease(options, adapters) {
|
|
|
268
270
|
throw new Stop("check-failed", `The release build of ${j.task.id} failed: ${gate.failed}. Fix it and release the new commit with --new.`);
|
|
269
271
|
if (gate.result === null || gate.result.check === "running" || gate.result.check === "pending")
|
|
270
272
|
return null;
|
|
271
|
-
|
|
272
|
-
|
|
273
|
+
// The build records a prepared candidate as a commit of its own (its message names the task): it must hold
|
|
274
|
+
// exactly the candidate's tree, or it isn't the release.
|
|
275
|
+
const head = gate.result.head;
|
|
276
|
+
if (head === null || (head !== j.candidate.sha && await adapters.repo.tree(head) !== await adapters.repo.tree(j.candidate.sha))) {
|
|
277
|
+
throw new Stop("drift", `The release result is for ${head?.slice(0, 7) ?? "no commit"}, which doesn't hold exactly ${j.candidate.sha.slice(0, 7)}'s files.`);
|
|
278
|
+
}
|
|
273
279
|
fullCheck(gate);
|
|
274
280
|
if (gate.result.worktree === null)
|
|
275
281
|
throw new Stop("worktree", `Run ${gate.result.run} names no checkout to deploy from.`);
|
|
276
|
-
return { run: gate.result.run, receipt: gate.result.receipt, worktree: gate.result.worktree };
|
|
282
|
+
return { run: gate.result.run, receipt: gate.result.receipt, worktree: gate.result.worktree, head };
|
|
277
283
|
});
|
|
278
284
|
j.check = result;
|
|
279
285
|
say(` run ${result.run} passed on ${j.candidate.sha.slice(0, 7)}`);
|
|
@@ -310,7 +316,7 @@ export async function runRelease(options, adapters) {
|
|
|
310
316
|
await recoverDeploy();
|
|
311
317
|
checked(await adapters.toolroll.gate(j.task.id));
|
|
312
318
|
// A deployment that finished but whose answer was lost: the services already run a runtime of this commit.
|
|
313
|
-
let runtime = await served(adapters,
|
|
319
|
+
let runtime = await served(adapters, builtHead());
|
|
314
320
|
if (runtime === null) {
|
|
315
321
|
await pinned();
|
|
316
322
|
j.deployAttempt = { stage: join(options.stateDir, "staged-upgrades", `browser-${j.candidate.sha.slice(0, 7)}-${randomUUID()}`) };
|
|
@@ -326,7 +332,7 @@ export async function runRelease(options, adapters) {
|
|
|
326
332
|
save();
|
|
327
333
|
}
|
|
328
334
|
const want = runtime;
|
|
329
|
-
await waitFor("deploy", `the console and worker to run the gated commit from ${want}`, async () => (await served(adapters,
|
|
335
|
+
await waitFor("deploy", `the console and worker to run the gated commit from ${want}`, async () => (await served(adapters, builtHead())) === want ? true : null);
|
|
330
336
|
j.deploy = { runtime: want, at: j.deploy?.runtime === want ? j.deploy.at : adapters.now().toISOString() };
|
|
331
337
|
j.deployAttempt = null;
|
|
332
338
|
delete j.intents.deploy;
|
|
@@ -336,7 +342,7 @@ export async function runRelease(options, adapters) {
|
|
|
336
342
|
}
|
|
337
343
|
case "link": {
|
|
338
344
|
const runtime = j.deploy.runtime;
|
|
339
|
-
if (await served(adapters,
|
|
345
|
+
if (await served(adapters, builtHead()) !== runtime)
|
|
340
346
|
throw new Stop("drift", `The console and worker no longer run ${runtime}; the CLI names were not moved.`);
|
|
341
347
|
if (j.links === undefined || j.links === null) {
|
|
342
348
|
j.links = await adapters.toolroll.cliLinks();
|
|
@@ -348,7 +354,7 @@ export async function runRelease(options, adapters) {
|
|
|
348
354
|
catch (error) {
|
|
349
355
|
throw new Stop("link", `The CLI names were not moved to ${runtime} (they point where they did): ${error.message}. The service already runs the new build; rerun to try again.`);
|
|
350
356
|
}
|
|
351
|
-
const everywhere = await deployed(adapters,
|
|
357
|
+
const everywhere = await deployed(adapters, builtHead());
|
|
352
358
|
if (everywhere !== runtime)
|
|
353
359
|
throw new Stop("mixed-runtime", `After relinking, the console, worker and both CLI names don't all run ${runtime} at ${j.candidate.sha.slice(0, 7)}.`);
|
|
354
360
|
say(` toolroll and standing-orders run ${join(runtime, "bin.js")}`);
|
package/dist/remote-main.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type ExecResult } from "./exec.js";
|
|
2
2
|
import type { Store } from "./store.js";
|
|
3
3
|
import type { Runner } from "./worktree.js";
|
|
4
|
+
/** What the private directory's git may see of this process's environment: nothing that names a repository, an
|
|
5
|
+
* object store or config. The fixed settings below go on top. Teardown git (teardown-git.ts) uses the same. */
|
|
6
|
+
export declare const ENV_ALLOWLIST: string[];
|
|
7
|
+
export declare const ENV: Record<string, string>;
|
|
4
8
|
/** The only credential helper https may use: the system keychain on macOS; elsewhere none, so a private https remote
|
|
5
9
|
* fails closed instead of asking. */
|
|
6
10
|
export declare const CREDENTIAL_HELPER: string;
|
package/dist/remote-main.js
CHANGED
|
@@ -21,9 +21,9 @@ const REMOTE_MAIN = "refs/toolroll/remote-main";
|
|
|
21
21
|
const SHA = /^[0-9a-f]{40}$/;
|
|
22
22
|
const FETCH_TIMEOUT_MS = 120_000;
|
|
23
23
|
/** What the private directory's git may see of this process's environment: nothing that names a repository, an
|
|
24
|
-
* object store or config. The fixed settings below go on top. */
|
|
25
|
-
const ENV_ALLOWLIST = ["PATH", "HOME", "TMPDIR", "LANG", "LC_ALL", "SSH_AUTH_SOCK", "HTTPS_PROXY", "https_proxy", "NO_PROXY", "no_proxy"];
|
|
26
|
-
const ENV = {
|
|
24
|
+
* object store or config. The fixed settings below go on top. Teardown git (teardown-git.ts) uses the same. */
|
|
25
|
+
export const ENV_ALLOWLIST = ["PATH", "HOME", "TMPDIR", "LANG", "LC_ALL", "SSH_AUTH_SOCK", "HTTPS_PROXY", "https_proxy", "NO_PROXY", "no_proxy"];
|
|
26
|
+
export const ENV = {
|
|
27
27
|
GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: "/dev/null", GIT_NO_REPLACE_OBJECTS: "1", GIT_TERMINAL_PROMPT: "0",
|
|
28
28
|
GIT_ASKPASS: "", SSH_ASKPASS: "", GIT_SSH_COMMAND: "ssh -o BatchMode=yes",
|
|
29
29
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { html, postForm } from "./html.js";
|
|
1
|
+
import { html, postForm, reauth } from "./html.js";
|
|
2
2
|
import { effectiveLimits, limitOverrides, PER_DAY_MAX, PER_MINUTE_MAX, REQUEST_BUDGET_DEFAULTS } from "./request-budget.js";
|
|
3
3
|
const n = (value) => value.toLocaleString("en-US");
|
|
4
4
|
export const REQUEST_LIMITS_CSS = `.credentials .limits{display:grid;gap:14px}.credentials .limits form{display:grid;gap:10px}.credentials .limits label{display:grid;gap:6px}` +
|
|
@@ -14,7 +14,7 @@ export function requestLimitsHtml(db, tokens, now) {
|
|
|
14
14
|
const overrides = limitOverrides(db);
|
|
15
15
|
const everyone = overrides.get("*") ?? { readPerMinute: null, actPerMinute: null, perDay: null };
|
|
16
16
|
const field = (name, label, value, placeholder, max) => html `<label>${label}<input type="number" name="${name}" min="1" max="${max}" step="1" inputmode="numeric" value="${value === null ? "" : value}" placeholder="${placeholder}"></label>`;
|
|
17
|
-
const password = html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label
|
|
17
|
+
const password = html `${reauth(html `<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password"></label>`)}`;
|
|
18
18
|
const buttons = html `<div class="actions"><button name="action" value="save">Save limits</button><button class="secondary" name="action" value="clear">Use defaults</button></div>`;
|
|
19
19
|
const live = tokens.filter(one => one.revokedAt === null && Date.parse(one.expiresAt) > now);
|
|
20
20
|
const installation = postForm("/settings/request-limits", html `\
|
package/dist/result-review.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ export declare const RESULT_FACT_KEYS: readonly ["run", "head", "base", "head-so
|
|
|
149
149
|
export declare function resultFactsFromHtml(html: string): Record<string, string>[];
|
|
150
150
|
/** Where a result form may send its reader back: the review cockpit's
|
|
151
151
|
* own deep link, the chat's result detail, the page of a task named in
|
|
152
|
-
* `tasks` (the run's own), or the run page. Anything else lands on the run
|
|
152
|
+
* `tasks` (the run's own) or its Result tab at this run, or the run page. Anything else lands on the run
|
|
153
153
|
* page. Matched exactly — never a bare open redirect. */
|
|
154
154
|
export declare function resultReturnTarget(raw: string | null | undefined, runId: number, tasks?: readonly string[]): string;
|
|
155
155
|
/** A form's own request token, minted per render — the same shape the
|
package/dist/result-review.js
CHANGED
|
@@ -147,7 +147,7 @@ export function resultFactsFromHtml(html) {
|
|
|
147
147
|
}
|
|
148
148
|
/** Where a result form may send its reader back: the review cockpit's
|
|
149
149
|
* own deep link, the chat's result detail, the page of a task named in
|
|
150
|
-
* `tasks` (the run's own), or the run page. Anything else lands on the run
|
|
150
|
+
* `tasks` (the run's own) or its Result tab at this run, or the run page. Anything else lands on the run
|
|
151
151
|
* page. Matched exactly — never a bare open redirect. */
|
|
152
152
|
export function resultReturnTarget(raw, runId, tasks = []) {
|
|
153
153
|
if (raw !== null && raw !== undefined) {
|
|
@@ -160,6 +160,10 @@ export function resultReturnTarget(raw, runId, tasks = []) {
|
|
|
160
160
|
// The run's own task page, which offered Run checks in place; never another task's.
|
|
161
161
|
if (tasks.some(task => raw === `/t/${encodeURIComponent(task)}`))
|
|
162
162
|
return raw;
|
|
163
|
+
// That task page's Result tab at this run (docs/plans/one-page-task-and-agent.md), its version and view kept.
|
|
164
|
+
const tab = /^\/t\/([A-Za-z0-9._~%-]{1,200})\?(?:version=[A-Za-z0-9._~%-]{1,200}&)?tab=result&run=([0-9]{1,15})(?:§ion=(?:summary|changes|checks))?$/.exec(raw);
|
|
165
|
+
if (tab !== null && Number(tab[2]) === runId && tasks.some(task => tab[1] === encodeURIComponent(task)))
|
|
166
|
+
return raw;
|
|
163
167
|
}
|
|
164
168
|
return `/r/${runId}`;
|
|
165
169
|
}
|
|
@@ -240,6 +244,8 @@ export const RESULT_REVIEW_SCRIPT = String.raw `
|
|
|
240
244
|
var user=panel?panel.getAttribute('data-result-user')||'':'';
|
|
241
245
|
var task=panel?panel.getAttribute('data-result-task')||'':'';
|
|
242
246
|
var run=panel?panel.getAttribute('data-result-run')||'':'';
|
|
247
|
+
// The address parameter that holds the result's own view: 'tab' on its page, 'section' on a task page's Result tab.
|
|
248
|
+
var viewParam=panel&&panel.getAttribute('data-result-param')==='section'?'section':'tab';
|
|
243
249
|
var draftPrefix='standing-orders:review-draft:',scrollPrefix='standing-orders:result-scroll:';
|
|
244
250
|
var day=86400000,storage=true,rememberPosition=null;
|
|
245
251
|
function read(key){try{return JSON.parse(sessionStorage.getItem(key)||'null');}catch(e){return null;}}
|
|
@@ -262,7 +268,7 @@ export const RESULT_REVIEW_SCRIPT = String.raw `
|
|
|
262
268
|
tab.addEventListener('click',function(ev){
|
|
263
269
|
if(ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.altKey||ev.button!==0)return;
|
|
264
270
|
ev.preventDefault();var name=tab.getAttribute('data-result-tab');show(name);
|
|
265
|
-
try{var url=new URL(location.href);url.searchParams.set(
|
|
271
|
+
try{var url=new URL(location.href);url.searchParams.set(viewParam,name);url.hash='';history.replaceState(history.state,'',url.toString());}catch(e){}
|
|
266
272
|
if(rememberPosition)rememberPosition();
|
|
267
273
|
});
|
|
268
274
|
tab.addEventListener('keydown',function(ev){
|
|
@@ -383,7 +389,7 @@ export const RESULT_REVIEW_SCRIPT = String.raw `
|
|
|
383
389
|
// view the URL now names.
|
|
384
390
|
var returnKey=scrollPrefix+user+':'+task+':return';
|
|
385
391
|
function scrollKeyFor(){var url=null;try{url=new URL(location.href);}catch(e){}
|
|
386
|
-
return scrollPrefix+user+':'+task+':'+(url?(url.searchParams.get('result')||run)+':'+(url.searchParams.get(
|
|
392
|
+
return scrollPrefix+user+':'+task+':'+(url?(url.searchParams.get('result')||run)+':'+(url.searchParams.get(viewParam)||'summary'):run);}
|
|
387
393
|
// Once a navigation has begun (pageswap / beforeunload) the document's
|
|
388
394
|
// scroll is no longer the reader's — a cross-document transition can
|
|
389
395
|
// move it to the top while it is captured — so remembering stops.
|
package/dist/retention-ui.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* the next daily sweep would remove. An instance operator's page; changes
|
|
4
4
|
* take a step-up.
|
|
5
5
|
*/
|
|
6
|
-
import { html, postForm } from "./html.js";
|
|
6
|
+
import { html, postForm, reauth } from "./html.js";
|
|
7
7
|
import { bytesWords } from "./storage.js";
|
|
8
8
|
import { RETENTION_KINDS, countWords, periodChoices, periodLabel } from "./retention.js";
|
|
9
9
|
export const RETENTION_CSS = `.retention{max-width:720px;min-width:0}.retention-next{margin:0 0 16px}` +
|
|
@@ -31,5 +31,5 @@ export function retentionHtml(view, notice) {
|
|
|
31
31
|
return html `<div class="kind" data-kind="${kind}"><label class="name" for="keep-${kind}">${label}</label><p class="meta">${detail}</p><select id="keep-${kind}" name="${kind}">${options}</select></div>`;
|
|
32
32
|
});
|
|
33
33
|
const last = view.lastSweep === null ? "" : ` Last sweep ${view.lastSweep.slice(0, 10)}.`;
|
|
34
|
-
return html `<article class="retention">${note}<p class="retention-next" data-retention-next>${nextWords(view)}${last}</p>${postForm("/settings/retention", html `${rows}
|
|
34
|
+
return html `<article class="retention">${note}<p class="retention-next" data-retention-next>${nextWords(view)}${last}</p>${postForm("/settings/retention", html `${rows}${reauth(html `<label class="step-up">Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label>`)}<button type="submit">Save</button>`)}<p class="meta">Never removed: the action ledger, and anything a task still needs (unfinished tasks, results Ready for review, anything on hold).</p></article>`;
|
|
35
35
|
}
|
package/dist/retention.js
CHANGED
|
@@ -24,6 +24,10 @@ import { RETENTION_NOTE } from "./evidence.js";
|
|
|
24
24
|
import { COMPLETION_ACTION } from "./result-completion.js";
|
|
25
25
|
import { bytesWords, treeBytes } from "./storage.js";
|
|
26
26
|
import { RETENTION_DAYS, retentionDaysSchema, retentionKindSchema } from "./contracts/retention.js";
|
|
27
|
+
/** A personal lead-queue row the sweep keeps (with its message): one still waiting, running or uncertain, and any of a
|
|
28
|
+
* conversation that is still open — its request id is the tombstone that stops a removed message being sent again. */
|
|
29
|
+
const KEPT_QUEUE_ROW = (message) => `lead_queue lq WHERE lq.message = ${message}
|
|
30
|
+
AND (lq.status IN ('queued', 'running', 'uncertain') OR EXISTS (SELECT 1 FROM lead_session ls WHERE ls.id = lq.session AND ls.ended_at IS NULL))`;
|
|
27
31
|
const RETENTION_TABLE = (name) => `
|
|
28
32
|
CREATE TABLE IF NOT EXISTS ${name} (
|
|
29
33
|
kind TEXT PRIMARY KEY CHECK (kind IN ('evidence', 'checkouts', 'chat', 'notifications')),
|
|
@@ -177,6 +181,7 @@ export function retentionPlan(store, evidenceRoot, now, periods = store.retentio
|
|
|
177
181
|
const rows = db.prepare(`SELECT m.id AS id, length(m.text) + COALESCE(length(m.activity), 0) + 64 AS bytes FROM lead_message m JOIN lead_thread th ON th.id = m.thread
|
|
178
182
|
WHERE m.created_at < ?
|
|
179
183
|
AND NOT EXISTS (SELECT 1 FROM team_message tm WHERE tm.message = m.id AND tm.status IN ('queued', 'running', 'uncertain'))
|
|
184
|
+
AND NOT EXISTS (SELECT 1 FROM ${KEPT_QUEUE_ROW("m.id")})
|
|
180
185
|
AND NOT EXISTS (SELECT 1 FROM mate_turn turn WHERE turn.id = m.turn AND turn.state IN ('queued', 'running'))
|
|
181
186
|
AND NOT (th.scope_kind = 'task' AND NOT EXISTS (SELECT 1 FROM task_ref r WHERE r.external_id = th.scope_key AND ${finishedTask("r")}))
|
|
182
187
|
ORDER BY m.id LIMIT ?`).all(cutoff(now, periods.chat), SWEEP_BATCH + 1);
|
|
@@ -263,14 +268,18 @@ export function sweepRetention(store, evidenceRoot, now, actor = "worker") {
|
|
|
263
268
|
}
|
|
264
269
|
if (periods.chat !== null) {
|
|
265
270
|
const team = db.prepare("DELETE FROM team_message WHERE message = ? AND status NOT IN ('queued', 'running', 'uncertain')");
|
|
266
|
-
const message = db.prepare(
|
|
271
|
+
const message = db.prepare(`DELETE FROM lead_message WHERE id = ? AND NOT EXISTS (SELECT 1 FROM team_message WHERE message = ?)
|
|
272
|
+
AND NOT EXISTS (SELECT 1 FROM ${KEPT_QUEUE_ROW("lead_message.id")})`);
|
|
267
273
|
const asked = db.prepare("SELECT turn FROM lead_message WHERE id = ? AND role = 'assistant' AND turn IS NOT NULL");
|
|
274
|
+
const searchCopy = db.prepare("DELETE FROM memory_search WHERE kind = 'conversation' AND ref = ?");
|
|
268
275
|
// The lead's question goes with the reply that asked it; its buttons then say it expired.
|
|
269
276
|
const ask = db.prepare("DELETE FROM lead_ask WHERE turn = ? AND NOT EXISTS (SELECT 1 FROM lead_message WHERE turn = ? AND role = 'assistant')");
|
|
270
277
|
for (const one of plan.items.chat) {
|
|
271
278
|
team.run(one.id);
|
|
272
279
|
const turn = asked.get(one.id)?.["turn"];
|
|
273
280
|
if (Number(message.run(one.id, one.id).changes) === 1) {
|
|
281
|
+
// Its search copy goes with it (search never shows words the store no longer keeps).
|
|
282
|
+
searchCopy.run(`message:${one.id}`);
|
|
274
283
|
done.chat.count++;
|
|
275
284
|
done.chat.bytes += one.bytes;
|
|
276
285
|
if (turn !== undefined && turn !== null)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a run went (docs/plans/run-efficiency.md): derived from the run's own records, display only. It never changes a
|
|
3
|
+
* completion, an approval, a charge or a check verdict, and it claims nothing its sources don't hold — an unreported
|
|
4
|
+
* number is unknown (null, shown as a dash), never zero.
|
|
5
|
+
*
|
|
6
|
+
* Sources, and what each can say: the run row (wall times, tokens, the provider's raw usage with its cache counts, the
|
|
7
|
+
* agent's turns where reported) is kept with the run; the live records (`<evidence>/live/<run>.jsonl`, display-only,
|
|
8
|
+
* kept 24 hours) are read once, bounded, through the descriptor-safe live reader, for step counts and observed step
|
|
9
|
+
* times. No command text is ever stored here: repeats are counted, never quoted.
|
|
10
|
+
*/
|
|
11
|
+
import type { Run, Store } from "./store.js";
|
|
12
|
+
import type { LiveActivityKind, LiveRecord } from "./live-records.js";
|
|
13
|
+
export declare const RUN_EFFICIENCY_VERSION = 3;
|
|
14
|
+
/** Budgets for one derivation: never more than the live file's own cap, and a bounded record count. */
|
|
15
|
+
export declare const EFFICIENCY_READ_BYTES: number;
|
|
16
|
+
export declare const EFFICIENCY_RECORDS = 20000;
|
|
17
|
+
export type StepsState = "complete" | "truncated" | "expired" | "absent";
|
|
18
|
+
export type RunEfficiency = {
|
|
19
|
+
version: number;
|
|
20
|
+
/** Waiting to start (claimed → provider started) and the agent (provider started → finished); null when unrecorded. */
|
|
21
|
+
time: {
|
|
22
|
+
waitMs: number | null;
|
|
23
|
+
agentMs: number | null;
|
|
24
|
+
};
|
|
25
|
+
turns: number | null;
|
|
26
|
+
/** Tokens in counts everything the model read (cached included); `cacheShare` is read-from-cache ÷ that, 0–1. */
|
|
27
|
+
usage: {
|
|
28
|
+
in: number | null;
|
|
29
|
+
out: number | null;
|
|
30
|
+
cacheRead: number | null;
|
|
31
|
+
cacheWrite: number | null;
|
|
32
|
+
cacheShare: number | null;
|
|
33
|
+
provider: string;
|
|
34
|
+
model: string | null;
|
|
35
|
+
};
|
|
36
|
+
steps: {
|
|
37
|
+
state: StepsState;
|
|
38
|
+
reason: string | null;
|
|
39
|
+
total: number | null;
|
|
40
|
+
failed: number | null;
|
|
41
|
+
unknownDuration: number | null;
|
|
42
|
+
byKind: Partial<Record<LiveActivityKind, number>>;
|
|
43
|
+
longest: {
|
|
44
|
+
kind: LiveActivityKind;
|
|
45
|
+
ms: number;
|
|
46
|
+
}[];
|
|
47
|
+
/** Repeated activity: the same step (kind and its full recorded input) at least three times. Null when the inputs
|
|
48
|
+
* can't be compared (command detail off, or a target hidden or shortened) — said, never guessed. */
|
|
49
|
+
repeats: {
|
|
50
|
+
kind: LiveActivityKind;
|
|
51
|
+
count: number;
|
|
52
|
+
}[] | null;
|
|
53
|
+
repeatsReason: string | null;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
/** Tokens and cache from the provider's own usage report, read per provider (their counts mean different things). */
|
|
57
|
+
export declare function usageOf(run: Pick<Run, "provider" | "model" | "tokensIn" | "tokensOut"> & {
|
|
58
|
+
usageJson?: string | null;
|
|
59
|
+
}): RunEfficiency["usage"];
|
|
60
|
+
/** The live records' steps, bounded: counts by kind, failures, observed times and repeats (never their words). */
|
|
61
|
+
/** `measured`: the recorder saw this provider's steps start and end as they happened (Claude's stream does); for the
|
|
62
|
+
* others their times are partly made up (Codex reports a step when it completes, ACP agents may report late), so no
|
|
63
|
+
* duration is claimed for them. */
|
|
64
|
+
export declare function stepsOf(records: Iterable<LiveRecord>, truncated: string | null, measured?: boolean): RunEfficiency["steps"];
|
|
65
|
+
/** Derive a finished run's How it ran from its records. */
|
|
66
|
+
export declare function deriveRunEfficiency(run: Run & {
|
|
67
|
+
usageJson?: string | null;
|
|
68
|
+
}, evidenceRoot: string, now: Date): RunEfficiency;
|
|
69
|
+
/**
|
|
70
|
+
* A finished run's How it ran: the saved one when it was derived by this version, else derived now and saved (once:
|
|
71
|
+
* a row whose steps were complete or have expired is final). An unfinished run is derived but never saved.
|
|
72
|
+
*/
|
|
73
|
+
export declare function runEfficiencyOf(store: Store, evidenceRoot: string, runId: number, now: Date): RunEfficiency | null;
|