toolroll 0.9.63 → 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 +51 -0
- package/README.md +15 -5
- 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 +50 -2
- package/dist/agent-fence.js +157 -10
- 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 +235 -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 +197 -15
- 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/checkout-proof.d.ts +28 -0
- package/dist/checkout-proof.js +62 -0
- package/dist/claim.d.ts +12 -0
- package/dist/claim.js +19 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +4 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +21 -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/console-api.d.ts +12 -4
- package/dist/contracts/console-api.js +12 -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/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/desktop-update.d.ts +1 -1
- package/dist/discord-chat.js +4 -1
- package/dist/doctor.js +1 -1
- 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/exec.d.ts +78 -0
- package/dist/exec.js +367 -9
- package/dist/export-ui.js +2 -2
- package/dist/flow-engine.js +24 -5
- 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 +77 -8
- package/dist/flow-triggers.js +517 -70
- package/dist/flows-cli.js +8 -2
- package/dist/flows-ui.d.ts +0 -2
- package/dist/flows-ui.js +52 -4
- package/dist/flows.d.ts +4 -0
- package/dist/flows.js +9 -1
- package/dist/html.d.ts +9 -0
- package/dist/html.js +11 -0
- package/dist/invoke.d.ts +17 -0
- package/dist/invoke.js +217 -21
- package/dist/keys.d.ts +18 -14
- package/dist/keys.js +5 -0
- 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 +152 -1
- 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-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/operate.d.ts +2 -0
- package/dist/operate.js +275 -17
- 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/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/project-delete-ui.d.ts +12 -0
- package/dist/project-delete-ui.js +41 -9
- package/dist/project-delete.js +2 -2
- package/dist/project-memory.d.ts +3 -1
- package/dist/project-memory.js +57 -25
- package/dist/project-tools.d.ts +5 -3
- package/dist/project-tools.js +12 -9
- 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.d.ts +25 -2
- package/dist/provider.js +63 -9
- 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/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 +170 -5
- 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 +247 -40
- 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 +38 -8
- 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 +46 -5
- package/dist/server/runtime.d.ts +33 -2
- package/dist/server/session.d.ts +25 -1
- package/dist/server/session.js +18 -4
- package/dist/server/settings.js +121 -10
- 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-ui.js +4 -4
- package/dist/store-baseline.d.ts +1 -1
- package/dist/store-baseline.js +1 -1
- package/dist/store.d.ts +430 -15
- package/dist/store.js +1041 -52
- package/dist/subagent-desk.js +1 -1
- package/dist/summary.js +3 -0
- 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/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 +2 -0
- package/dist/tool-broker.js +1 -0
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +13 -3
- package/dist/tools-ui.js +2 -2
- 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 +16 -2
- package/dist/workspace-revision.js +3 -1
- package/package.json +11 -2
package/dist/browser-shell.js
CHANGED
|
@@ -4,6 +4,9 @@ import { readFileSync } from 'node:fs';
|
|
|
4
4
|
import {} from './browser-workspace.js';
|
|
5
5
|
import { html, jsonScript, replaceMarkup, scriptElement } from './html.js';
|
|
6
6
|
const assets = new Map();
|
|
7
|
+
/** The fixed public assets: the workspace, Live mode's own small bundle, and the notices. */
|
|
8
|
+
const BROWSER_ASSETS = [['workspace.js', 'text/javascript; charset=utf-8'], ['workspace.css', 'text/css; charset=utf-8'], ['terminal.js', 'text/javascript; charset=utf-8'],
|
|
9
|
+
['terminal.css', 'text/css; charset=utf-8'], ['THIRD_PARTY_NOTICES.txt', 'text/plain; charset=utf-8']];
|
|
7
10
|
function readAsset(name) {
|
|
8
11
|
// Compiled installation first; the second location supports source-based
|
|
9
12
|
// development/tests after the browser build. No request supplies a file path.
|
|
@@ -16,9 +19,9 @@ function readAsset(name) {
|
|
|
16
19
|
return null;
|
|
17
20
|
}
|
|
18
21
|
export function browserAssetsAvailable() {
|
|
19
|
-
if (assets.size ===
|
|
22
|
+
if (assets.size === BROWSER_ASSETS.length)
|
|
20
23
|
return true;
|
|
21
|
-
for (const [name, type] of
|
|
24
|
+
for (const [name, type] of BROWSER_ASSETS) {
|
|
22
25
|
const body = readAsset(name);
|
|
23
26
|
if (body === null)
|
|
24
27
|
return false;
|
|
@@ -27,7 +30,7 @@ export function browserAssetsAvailable() {
|
|
|
27
30
|
return true;
|
|
28
31
|
}
|
|
29
32
|
export function serveBrowserAsset(request, response, path) {
|
|
30
|
-
if (
|
|
33
|
+
if (!BROWSER_ASSETS.some(([name]) => path === `/assets/${name}`))
|
|
31
34
|
return false;
|
|
32
35
|
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
33
36
|
response.writeHead(405, { allow: 'GET, HEAD', 'cache-control': 'no-store' });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** The browser consumes this contract with a type-only import. All HTML is
|
|
2
2
|
* produced by the existing trusted server renderers, never by a model-supplied
|
|
3
3
|
* fragment. These projections do not authenticate, mutate or grant authority. */
|
|
4
|
+
import { type DisplayState, type StateCounts } from './agent-state-words.js';
|
|
4
5
|
import type { TeamSnapshot } from './team-contract.js';
|
|
5
6
|
import type { RunActivity } from './activity-line.js';
|
|
6
7
|
import type { BrandIconId } from './brand-icons.js';
|
|
@@ -21,6 +22,50 @@ export type BrowserProject = {
|
|
|
21
22
|
href: string;
|
|
22
23
|
knowledgeHref: string;
|
|
23
24
|
};
|
|
25
|
+
/** A project's state for one person (agent-state.ts): the strongest of its counts, the counts, and its tasks with
|
|
26
|
+
* something live, asking, failed or unread (strongest first, `more` beyond those shown). `path` null: work with no
|
|
27
|
+
* project yet. */
|
|
28
|
+
export type BrowserProjectState = {
|
|
29
|
+
path: string | null;
|
|
30
|
+
name: string;
|
|
31
|
+
href: string;
|
|
32
|
+
state: DisplayState;
|
|
33
|
+
counts: StateCounts;
|
|
34
|
+
tasks: BrowserRailTask[];
|
|
35
|
+
more: number;
|
|
36
|
+
/** Everything here that needs this person, as opaque keys (one per obligation and version: the chime's subjects),
|
|
37
|
+
* with the task and agent each is about so a tab already showing one stays quiet. */
|
|
38
|
+
asks: BrowserAsk[];
|
|
39
|
+
/** The projects folded together to keep a snapshot inside one live frame: their counts summed, `more` of them. */
|
|
40
|
+
others?: true;
|
|
41
|
+
};
|
|
42
|
+
/** The most a summary snapshot may take in UTF-8 bytes, as the summary room sends it (JSON inside JSON, plus the
|
|
43
|
+
* frame's envelope), well inside one live frame (live-bus.ts STREAM_LIMIT_BYTES). */
|
|
44
|
+
export declare const SUMMARY_BUDGET = 24000;
|
|
45
|
+
/** A snapshot's size on the wire: UTF-8 bytes of the JSON string the frame carries, plus its envelope. */
|
|
46
|
+
export declare function summaryFrameBytes(value: unknown): number;
|
|
47
|
+
/**
|
|
48
|
+
* A summary snapshot that fits one live frame, with every count kept: long words are clipped, then rail tasks become
|
|
49
|
+
* `more` (from the project listing most), then the quietest projects fold into one `others` entry with their counts
|
|
50
|
+
* summed. Nothing is dropped silently: whatever is not listed is counted.
|
|
51
|
+
*/
|
|
52
|
+
export declare function boundProjectSummary(rows: readonly BrowserProjectState[], budget?: number): BrowserProjectState[];
|
|
53
|
+
/** One thing that needs this person, as the chime knows it: an opaque key (never words), and what it is about. */
|
|
54
|
+
export type BrowserAsk = {
|
|
55
|
+
key: string;
|
|
56
|
+
task: string | null;
|
|
57
|
+
run: number | null;
|
|
58
|
+
/** When it last changed (ISO): one older than the chime's memory reaches back is never news. */
|
|
59
|
+
at: string;
|
|
60
|
+
};
|
|
61
|
+
/** One task on the rail: its state, and its agent's last act when one is at work (else the state's words). */
|
|
62
|
+
export type BrowserRailTask = {
|
|
63
|
+
id: string;
|
|
64
|
+
title: string;
|
|
65
|
+
href: string;
|
|
66
|
+
state: DisplayState;
|
|
67
|
+
line: string;
|
|
68
|
+
};
|
|
24
69
|
/** count: tasks waiting on a person, shown beside Tasks when above zero. */
|
|
25
70
|
export type BrowserNavigationItem = {
|
|
26
71
|
label: string;
|
|
@@ -185,6 +230,14 @@ export type BrowserLimitTile = {
|
|
|
185
230
|
export type BrowserLimits = {
|
|
186
231
|
tiles: BrowserLimitTile[];
|
|
187
232
|
};
|
|
233
|
+
/** The sidebar's usage chip (limits-ui.ts usageChipOf): the most-used subscription window, stale when its reading is old. */
|
|
234
|
+
export type BrowserUsageChip = {
|
|
235
|
+
text: string;
|
|
236
|
+
tone: BrowserLimitTile['tone'];
|
|
237
|
+
stale: boolean;
|
|
238
|
+
href: string;
|
|
239
|
+
title: string;
|
|
240
|
+
};
|
|
188
241
|
export type BrowserSettingsView = {
|
|
189
242
|
kind: 'settings';
|
|
190
243
|
said: string | null;
|
|
@@ -440,6 +493,18 @@ export type BrowserTaskView = {
|
|
|
440
493
|
action: string;
|
|
441
494
|
run: number;
|
|
442
495
|
} | null;
|
|
496
|
+
/** The running attempt's composer (steer-controls.ts): what it takes, said plainly, and its note box when it takes
|
|
497
|
+
* notes. Pause and Stop stay as `pause` and `stop`. */
|
|
498
|
+
steering?: {
|
|
499
|
+
controls: BrowserAgentControls;
|
|
500
|
+
steer: {
|
|
501
|
+
action: string;
|
|
502
|
+
run: number;
|
|
503
|
+
} | null;
|
|
504
|
+
} | null;
|
|
505
|
+
/** This task's latest attempts, newest first: a draft this tab wrote for one that has since ended shows with a way
|
|
506
|
+
* to send it to the next attempt. */
|
|
507
|
+
steerRecent?: number[];
|
|
443
508
|
/** Pause and Pause and steer, beside Stop: the same exact live Claude build, one request id per form (Pause, the note,
|
|
444
509
|
* Resume), where its latest pause stands (null: running), and until when a paused build can wait before it ends. */
|
|
445
510
|
pause?: {
|
|
@@ -486,7 +551,47 @@ export type BrowserTaskView = {
|
|
|
486
551
|
details?: BrowserTaskDetailGroup[];
|
|
487
552
|
/** Where to message the agent when this page carries no conversation (null: messaging isn't available here). */
|
|
488
553
|
chatHref?: string | null;
|
|
554
|
+
/** One page per task (docs/plans/one-page-task-and-agent.md): the tab the address names (Activity when none). */
|
|
555
|
+
tab?: BrowserTaskTab;
|
|
556
|
+
/** The Result tab: the selected attempt's result exactly as its result page shows it, whether it is the task's
|
|
557
|
+
* current one (the header then owns its status and ceremonies), and every result attempt to pick from. Null: none yet. */
|
|
558
|
+
result?: {
|
|
559
|
+
selected: NonNullable<BrowserResultView["selected"]>;
|
|
560
|
+
current: boolean;
|
|
561
|
+
attempts: {
|
|
562
|
+
label: string;
|
|
563
|
+
href: string;
|
|
564
|
+
current: boolean;
|
|
565
|
+
}[];
|
|
566
|
+
/** What the result shows, as one stamp (every check, note and control in it; never a form's fresh request token): the
|
|
567
|
+
* page holds the result it loaded and says when a newer one is ready, so its evidence and decision always agree. */
|
|
568
|
+
revision: string;
|
|
569
|
+
} | null;
|
|
570
|
+
/** Where the approval sits: under the header when it is the thing to do now, else at the top of the Plan tab. */
|
|
571
|
+
approvalPlacement?: "lead" | "plan";
|
|
572
|
+
/** ⋯ More actions: the task's secondary acts, the same order on the task and agent pages, destructive last. */
|
|
573
|
+
more?: BrowserTaskMore[];
|
|
489
574
|
};
|
|
575
|
+
export type BrowserTaskTab = "activity" | "result" | "plan";
|
|
576
|
+
/** One ⋯ item: a plain link, a copy of this page's address, a one-click POST (never a ceremony), or a go-to that switches
|
|
577
|
+
* to the tab holding the item's own form, opens it and focuses it (`target`: that element's id). */
|
|
578
|
+
export type BrowserTaskMore = {
|
|
579
|
+
group: "work" | "share" | "danger";
|
|
580
|
+
label: string;
|
|
581
|
+
} & ({
|
|
582
|
+
kind: "link";
|
|
583
|
+
href: string;
|
|
584
|
+
} | {
|
|
585
|
+
kind: "copy";
|
|
586
|
+
} | {
|
|
587
|
+
kind: "post";
|
|
588
|
+
action: string;
|
|
589
|
+
fields: Record<string, string>;
|
|
590
|
+
} | {
|
|
591
|
+
kind: "goto";
|
|
592
|
+
tab: BrowserTaskTab;
|
|
593
|
+
target: string;
|
|
594
|
+
});
|
|
490
595
|
/** One project on the Projects page; opening it is a POST to /projects/open. */
|
|
491
596
|
export type BrowserProjectRow = {
|
|
492
597
|
name: string;
|
|
@@ -689,7 +794,12 @@ export type BrowserResultView = {
|
|
|
689
794
|
accept?: {
|
|
690
795
|
note: string | null;
|
|
691
796
|
} | null;
|
|
797
|
+
returnTo?: string;
|
|
692
798
|
} | null;
|
|
799
|
+
/** How its run went (docs/plans/run-efficiency.md): recorded numbers only, unknowns null. */
|
|
800
|
+
efficiency?: import("./run-efficiency.js").RunEfficiency | null;
|
|
801
|
+
/** What its network was and what its proxy saw (egress.ts): display only. */
|
|
802
|
+
network?: import("./egress.js").RunNetworkRecord | null;
|
|
693
803
|
/** Words for the result's Accept: Accept and finish when offered, else the Needs you acceptance. */
|
|
694
804
|
decision: BrowserResultDecision | null;
|
|
695
805
|
checks: {
|
|
@@ -882,6 +992,14 @@ export type BrowserFlowCard = {
|
|
|
882
992
|
task: {
|
|
883
993
|
id: string;
|
|
884
994
|
href: string;
|
|
995
|
+
/** Its running attempt's composer (steer-controls.ts), for an approver: what it takes, its controls, its note box. */
|
|
996
|
+
composer?: {
|
|
997
|
+
controls: BrowserAgentControls;
|
|
998
|
+
steer: {
|
|
999
|
+
action: string;
|
|
1000
|
+
run: number;
|
|
1001
|
+
} | null;
|
|
1002
|
+
};
|
|
885
1003
|
} | null;
|
|
886
1004
|
createdBy: string;
|
|
887
1005
|
updatedAt: string;
|
|
@@ -896,10 +1014,15 @@ export type BrowserFlowCard = {
|
|
|
896
1014
|
at: string;
|
|
897
1015
|
}[];
|
|
898
1016
|
/** Where a trigger found it: a GitHub or Linear issue, another flow's card, a button, a schedule. */
|
|
1017
|
+
/** `proved` and `host` (v126): how an outside event's delivery was proved ("signed by Sentry", "unsigned") and its
|
|
1018
|
+
* link's host, always shown beside the link. */
|
|
899
1019
|
source: {
|
|
900
1020
|
kind: string;
|
|
901
1021
|
label: string;
|
|
902
1022
|
url: string | null;
|
|
1023
|
+
proved?: string;
|
|
1024
|
+
host?: string | null;
|
|
1025
|
+
shown?: string | null;
|
|
903
1026
|
} | null;
|
|
904
1027
|
/** Who is responsible for it, who follows it, and whether the viewer does. */
|
|
905
1028
|
owner: string | null;
|
|
@@ -1017,10 +1140,27 @@ export type BrowserFlowTrigger = {
|
|
|
1017
1140
|
label: string;
|
|
1018
1141
|
questions: string[];
|
|
1019
1142
|
} | null;
|
|
1020
|
-
/** A webhook trigger: whether it can prove deliveries yet (Linear
|
|
1143
|
+
/** A webhook trigger: whether it can prove deliveries yet (Linear, Sentry and Vercel need their signing secret pasted).
|
|
1144
|
+
* v126: a webhook's sender (who signs it; "none" is the address alone), whether Toolroll makes its secret, and a
|
|
1145
|
+
* warning in words when anyone could add cards (unsigned) or any project could (a Sentry or Vercel webhook unscoped). */
|
|
1021
1146
|
hook: {
|
|
1022
1147
|
ready: boolean;
|
|
1023
1148
|
needsSecret: boolean;
|
|
1149
|
+
sender: string | null;
|
|
1150
|
+
makesSecret: boolean;
|
|
1151
|
+
warning: string | null;
|
|
1152
|
+
readerNote: string | null;
|
|
1153
|
+
/** v126: deliveries turned away because too many were already held, until a person clears it, and how to resend them. */
|
|
1154
|
+
dropped: {
|
|
1155
|
+
count: number;
|
|
1156
|
+
since: string;
|
|
1157
|
+
resend: string;
|
|
1158
|
+
} | null;
|
|
1159
|
+
/** v126: the Sentry or Vercel project (and Vercel team) it takes deliveries from; null: any the secret covers. */
|
|
1160
|
+
scope: {
|
|
1161
|
+
project: string | null;
|
|
1162
|
+
team: string | null;
|
|
1163
|
+
} | null;
|
|
1024
1164
|
} | null;
|
|
1025
1165
|
checkable: boolean;
|
|
1026
1166
|
/** A button shared as a public form (its link works). */
|
|
@@ -1183,6 +1323,22 @@ export type BrowserAgentQuestion = {
|
|
|
1183
1323
|
text: string;
|
|
1184
1324
|
action: string;
|
|
1185
1325
|
};
|
|
1326
|
+
export type BrowserAgentControls = {
|
|
1327
|
+
send: "live" | "mailbox" | null;
|
|
1328
|
+
words: string;
|
|
1329
|
+
pause: {
|
|
1330
|
+
action: string;
|
|
1331
|
+
run: number;
|
|
1332
|
+
state: "pausing" | "paused" | null;
|
|
1333
|
+
requests: [string, string, string];
|
|
1334
|
+
until: string | null;
|
|
1335
|
+
} | null;
|
|
1336
|
+
stop: {
|
|
1337
|
+
action: string;
|
|
1338
|
+
run: number;
|
|
1339
|
+
label: string;
|
|
1340
|
+
} | null;
|
|
1341
|
+
};
|
|
1186
1342
|
export type BrowserAgentDetail = BrowserAgentRow & {
|
|
1187
1343
|
live: boolean;
|
|
1188
1344
|
question: BrowserAgentQuestion | null;
|
|
@@ -1201,11 +1357,39 @@ export type BrowserAgentDetail = BrowserAgentRow & {
|
|
|
1201
1357
|
action: string;
|
|
1202
1358
|
run: number;
|
|
1203
1359
|
} | null;
|
|
1360
|
+
/** What this running attempt takes (steer-capabilities.ts): how a note reaches it (or why none does), Pause and
|
|
1361
|
+
* Stop for the exact run each names. Null when it is not running or this person may not act. */
|
|
1362
|
+
controls?: BrowserAgentControls | null;
|
|
1363
|
+
/** Cockpit E: this running attempt's checkout, proved to be on this machine — the cd command to copy, and where Show
|
|
1364
|
+
* in Finder posts. Absent off this machine, for a viewer, or once it ends. Nothing is ever launched in it. */
|
|
1365
|
+
/** `reveal` is null where Finder can't be asked (not a Mac): the path and the command stand alone. */
|
|
1366
|
+
checkout?: {
|
|
1367
|
+
path: string;
|
|
1368
|
+
cd: string;
|
|
1369
|
+
reveal: string | null;
|
|
1370
|
+
} | null;
|
|
1204
1371
|
/** Whether this person may reply or steer (an approver, outside the demo); a viewer sees the question but no composer. */
|
|
1205
1372
|
canAct: boolean;
|
|
1206
1373
|
/** The task, and once finished the run's own page (its result page when it built one). */
|
|
1207
1374
|
taskHref: string;
|
|
1208
1375
|
resultHref: string | null;
|
|
1376
|
+
/** The task this agent works on, as its page heads it: the status words, and its one action as a way to the task page's
|
|
1377
|
+
* tab that holds it (never a form here: the task page's own form is the one that acts). Null when it can't be read. */
|
|
1378
|
+
task?: {
|
|
1379
|
+
headline: string;
|
|
1380
|
+
sentence: string;
|
|
1381
|
+
tone: string;
|
|
1382
|
+
action: {
|
|
1383
|
+
label: string;
|
|
1384
|
+
href: string;
|
|
1385
|
+
};
|
|
1386
|
+
} | null;
|
|
1387
|
+
/** Where this run opens on its task's page: a result → its Result tab at this run, a plan → the Plan tab, anything
|
|
1388
|
+
* else (a review, an attempt that isn't a result) → its own record. Null while it runs. */
|
|
1389
|
+
open?: {
|
|
1390
|
+
label: string;
|
|
1391
|
+
href: string;
|
|
1392
|
+
} | null;
|
|
1209
1393
|
/** The exact-run live room: updates, and a watch that keeps this person's pings quiet. */
|
|
1210
1394
|
room: string;
|
|
1211
1395
|
said: {
|
|
@@ -1213,6 +1397,42 @@ export type BrowserAgentDetail = BrowserAgentRow & {
|
|
|
1213
1397
|
text: string;
|
|
1214
1398
|
} | null;
|
|
1215
1399
|
};
|
|
1400
|
+
/** One run on the timeline: its role, and when it started and ended (null: still running). */
|
|
1401
|
+
export type BrowserLaneSegment = {
|
|
1402
|
+
runId: number;
|
|
1403
|
+
role: 'planner' | 'builder' | 'reviewer' | 'scout';
|
|
1404
|
+
agent: string;
|
|
1405
|
+
startedAt: string;
|
|
1406
|
+
endedAt: string | null;
|
|
1407
|
+
outcome: string | null;
|
|
1408
|
+
href: string;
|
|
1409
|
+
};
|
|
1410
|
+
/** One task's row on the timeline: its runs in order, and the board's word for where it stands ('planning' before a build). */
|
|
1411
|
+
export type BrowserAgentLane = {
|
|
1412
|
+
taskId: string;
|
|
1413
|
+
title: string;
|
|
1414
|
+
project: string | null;
|
|
1415
|
+
href: string;
|
|
1416
|
+
group: AgentGroupKey | 'planning';
|
|
1417
|
+
segments: BrowserLaneSegment[];
|
|
1418
|
+
};
|
|
1419
|
+
/** The agent timeline (after the "Agent lanes" pattern): one row per task over a window ending now. */
|
|
1420
|
+
export type BrowserAgentLanes = {
|
|
1421
|
+
since: string;
|
|
1422
|
+
now: string;
|
|
1423
|
+
windows: {
|
|
1424
|
+
key: AgentLaneWindow;
|
|
1425
|
+
label: string;
|
|
1426
|
+
href: string;
|
|
1427
|
+
active: boolean;
|
|
1428
|
+
}[];
|
|
1429
|
+
lanes: BrowserAgentLane[];
|
|
1430
|
+
/** Tasks in the window past the rows shown. */
|
|
1431
|
+
more: number;
|
|
1432
|
+
/** Every task in the window with a live run, not just the rows shown. */
|
|
1433
|
+
running: number;
|
|
1434
|
+
};
|
|
1435
|
+
export type AgentLaneWindow = '30m' | '2h' | '24h';
|
|
1216
1436
|
export type BrowserAgentsView = {
|
|
1217
1437
|
kind: 'agents';
|
|
1218
1438
|
groups: {
|
|
@@ -1220,6 +1440,8 @@ export type BrowserAgentsView = {
|
|
|
1220
1440
|
label: string;
|
|
1221
1441
|
rows: BrowserAgentRow[];
|
|
1222
1442
|
}[];
|
|
1443
|
+
/** The timeline above the board; empty lanes when nothing ran in the window but something did today; null when nothing ran in a day. */
|
|
1444
|
+
lanes?: BrowserAgentLanes | null;
|
|
1223
1445
|
selected: BrowserAgentDetail | null;
|
|
1224
1446
|
/** Shown when nothing is on the board. */
|
|
1225
1447
|
empty: string | null;
|
|
@@ -1232,6 +1454,8 @@ export type BrowserWorkspace = {
|
|
|
1232
1454
|
user: string;
|
|
1233
1455
|
csrf: string;
|
|
1234
1456
|
sensitive: boolean;
|
|
1457
|
+
/** Passwordless is on for this signed-in browser: ceremony password fields are left out (docs/plans/passwordless.md). */
|
|
1458
|
+
passwordless?: boolean;
|
|
1235
1459
|
/** What this person named their lead (Settings → Lead): the chat header and every lead message say it. */
|
|
1236
1460
|
leadName?: string;
|
|
1237
1461
|
refreshUrl: string;
|
|
@@ -1242,6 +1466,16 @@ export type BrowserWorkspace = {
|
|
|
1242
1466
|
projects: BrowserProject[];
|
|
1243
1467
|
crew: BrowserCrewItem[];
|
|
1244
1468
|
crewTruncated: boolean;
|
|
1469
|
+
/** The sidebar's project states; absent on a sensitive page. The summary room keeps them current. */
|
|
1470
|
+
projectStates?: BrowserProjectState[];
|
|
1471
|
+
/** Cockpit B2: this session's remembered password — minutes left, and where Forget posts. Absent unless it is
|
|
1472
|
+
* live on a direct local request; never on a sensitive page. */
|
|
1473
|
+
fresh?: {
|
|
1474
|
+
minutes: number;
|
|
1475
|
+
forget: string;
|
|
1476
|
+
};
|
|
1477
|
+
/** The most-used subscription window, for an operator; absent for everyone else and on a sensitive page. */
|
|
1478
|
+
usage?: BrowserUsageChip;
|
|
1245
1479
|
conversation: BrowserConversation | null;
|
|
1246
1480
|
team?: TeamSnapshot;
|
|
1247
1481
|
focus: {
|
|
@@ -1,6 +1,66 @@
|
|
|
1
|
+
/** The browser consumes this contract with a type-only import. All HTML is
|
|
2
|
+
* produced by the existing trusted server renderers, never by a model-supplied
|
|
3
|
+
* fragment. These projections do not authenticate, mutate or grant authority. */
|
|
4
|
+
import { DISPLAY_STATES as DISPLAY_ORDER } from './agent-state-words.js';
|
|
1
5
|
import { browserCrewFromIndex } from './browser-crew.js';
|
|
2
6
|
export { browserCrewFromIndex, browserWorkActionHref } from './browser-crew.js';
|
|
3
7
|
import { workIndexPage } from './work-index.js';
|
|
8
|
+
/** The most a summary snapshot may take in UTF-8 bytes, as the summary room sends it (JSON inside JSON, plus the
|
|
9
|
+
* frame's envelope), well inside one live frame (live-bus.ts STREAM_LIMIT_BYTES). */
|
|
10
|
+
export const SUMMARY_BUDGET = 24_000;
|
|
11
|
+
/** The frame around a snapshot: its event line, room, revision and the JSON around `at`. Generous on purpose. */
|
|
12
|
+
const SUMMARY_ENVELOPE_BYTES = 512;
|
|
13
|
+
const utf8 = new TextEncoder();
|
|
14
|
+
/** A snapshot's size on the wire: UTF-8 bytes of the JSON string the frame carries, plus its envelope. */
|
|
15
|
+
export function summaryFrameBytes(value) {
|
|
16
|
+
return utf8.encode(JSON.stringify({ at: JSON.stringify(value) })).length + SUMMARY_ENVELOPE_BYTES;
|
|
17
|
+
}
|
|
18
|
+
const clip = (text, max) => text.length <= max ? text : `${text.slice(0, max - 1)}…`;
|
|
19
|
+
/**
|
|
20
|
+
* A summary snapshot that fits one live frame, with every count kept: long words are clipped, then rail tasks become
|
|
21
|
+
* `more` (from the project listing most), then the quietest projects fold into one `others` entry with their counts
|
|
22
|
+
* summed. Nothing is dropped silently: whatever is not listed is counted.
|
|
23
|
+
*/
|
|
24
|
+
export function boundProjectSummary(rows, budget = SUMMARY_BUDGET) {
|
|
25
|
+
const size = summaryFrameBytes;
|
|
26
|
+
let out = rows.map(one => ({ ...one, name: clip(one.name, 80), tasks: one.tasks.map(task => ({ ...task, title: clip(task.title, 120), line: clip(task.line, 120) })) }));
|
|
27
|
+
while (size(out) > budget) {
|
|
28
|
+
const fullest = out.reduce((best, one, index) => one.tasks.length > (out[best]?.tasks.length ?? -1) ? index : best, -1);
|
|
29
|
+
if (fullest === -1 || out[fullest].tasks.length === 0)
|
|
30
|
+
break;
|
|
31
|
+
const one = out[fullest];
|
|
32
|
+
out[fullest] = { ...one, tasks: one.tasks.slice(0, -1), more: one.more + 1 };
|
|
33
|
+
}
|
|
34
|
+
if (size(out) <= budget)
|
|
35
|
+
return out;
|
|
36
|
+
// Fold the quietest projects (weakest state last in the list) into one entry until it fits.
|
|
37
|
+
const strength = (one) => DISPLAY_ORDER.indexOf(one.state);
|
|
38
|
+
const order = out.map((one, index) => ({ one, index })).sort((a, b) => strength(b.one) - strength(a.one) || b.index - a.index);
|
|
39
|
+
const folded = new Set();
|
|
40
|
+
const othersOf = () => {
|
|
41
|
+
if (folded.size === 0)
|
|
42
|
+
return null;
|
|
43
|
+
const counts = Object.fromEntries(DISPLAY_ORDER.map(key => [key, [...folded].reduce((sum, index) => sum + out[index].counts[key], 0)]));
|
|
44
|
+
const state = DISPLAY_ORDER.find(key => key !== 'idle' && counts[key] > 0) ?? 'idle';
|
|
45
|
+
return { path: null, name: `${folded.size} more ${folded.size === 1 ? 'project' : 'projects'}`, href: '/projects', state, counts, tasks: [], more: folded.size, others: true,
|
|
46
|
+
asks: [...folded].flatMap(index => out[index].asks) };
|
|
47
|
+
};
|
|
48
|
+
const assemble = () => { const others = othersOf(); return [...out.filter((_, index) => !folded.has(index)), ...(others === null ? [] : [others])]; };
|
|
49
|
+
for (const { index } of order) {
|
|
50
|
+
if (size(assemble()) <= budget)
|
|
51
|
+
break;
|
|
52
|
+
folded.add(index);
|
|
53
|
+
}
|
|
54
|
+
// Still too large: the oldest asks go last (their counts stay; only their chimes are lost).
|
|
55
|
+
let assembled = assemble();
|
|
56
|
+
while (size(assembled) > budget) {
|
|
57
|
+
const fullest = assembled.reduce((best, one, index) => one.asks.length > (assembled[best]?.asks.length ?? -1) ? index : best, -1);
|
|
58
|
+
if (fullest === -1 || assembled[fullest].asks.length === 0)
|
|
59
|
+
break;
|
|
60
|
+
assembled = assembled.map((one, index) => index === fullest ? { ...one, asks: one.asks.slice(0, -1) } : one);
|
|
61
|
+
}
|
|
62
|
+
return assembled;
|
|
63
|
+
}
|
|
4
64
|
/** The Tasks badge's words: the count and the projects it covers
|
|
5
65
|
* ("3 need you in shop", "1 needs you across all your projects"). */
|
|
6
66
|
export function needsYouLabelOf(count, projectName, saturated = false) {
|
package/dist/builder.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { LaunchNetwork } from "./invoke.js";
|
|
2
|
+
import type { ProviderId } from "./contracts/provider.js";
|
|
1
3
|
import { type PreparedEvidence } from "./prepared-evidence.js";
|
|
2
4
|
import { type ExecResult, type RunOptions } from "./exec.js";
|
|
3
5
|
import type { Decision, Store } from "./store.js";
|
|
@@ -85,7 +87,7 @@ export type BuildRequest = {
|
|
|
85
87
|
skipPermissions?: boolean;
|
|
86
88
|
/** The harness this build runs on. Repair ALWAYS inherits it — a session
|
|
87
89
|
* resumed across providers is not a session (Codex provider review, Q3). */
|
|
88
|
-
provider?:
|
|
90
|
+
provider?: ProviderId;
|
|
89
91
|
model?: string;
|
|
90
92
|
/**
|
|
91
93
|
* The model repair turns run on. Repair is a few-k, one-job resumption —
|
|
@@ -181,6 +183,9 @@ export declare const SETUP_ENV_DENYLIST: readonly string[];
|
|
|
181
183
|
export declare function redactSecretText(text: string): string;
|
|
182
184
|
/** The same blanking with no length cap, for a log that keeps its length (a flow script's output). */
|
|
183
185
|
export declare function redactSecretAssignments(text: string): string;
|
|
186
|
+
/** A build's network (egress.ts): the one its approval sealed, or — sealed before network policies existed — the
|
|
187
|
+
* narrowed legacy one (provider hosts and the repository's registries, nothing added since). */
|
|
188
|
+
export declare function launchNetworkOf(store: Store, taskRef: number, profile: ExecutionProfile): LaunchNetwork;
|
|
184
189
|
export declare function proveApprovedProfile(scope: Scope | null, given: {
|
|
185
190
|
provider: string;
|
|
186
191
|
model: string | undefined;
|
package/dist/builder.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { legacyNetwork, repositoryEcosystems } from "./egress.js";
|
|
2
|
+
import { isAcpProvider } from "./acp-agents.js";
|
|
1
3
|
import { OBSERVATION_MAILBOX, observationBrief, parseObservationCases, collectObservations } from "./observations.js";
|
|
2
4
|
import { checkCommandFor, effectiveCheckLevel, recordRunCheckLevel } from "./check-levels.js";
|
|
3
5
|
import { queueBatchCheck } from "./batch-checks.js";
|
|
@@ -47,7 +49,7 @@ import { stopRequestedFor, stopWords, underStopWatch } from "./task-control.js";
|
|
|
47
49
|
import { witnessedRunner } from "./process-custody.js";
|
|
48
50
|
import { runWithIsolatedDatabase } from "./child-database.js";
|
|
49
51
|
import { recordWorktreeProcess, saveWorkPatch } from "./worktree.js";
|
|
50
|
-
import { approvalOf, digestOf, profileDigestOf, routeParityProblem } from "./scope.js";
|
|
52
|
+
import { approvalOf, digestOf, idleClock, isAcpProfile, profileDigestOf, routeParityProblem, watchdogsOf } from "./scope.js";
|
|
51
53
|
import { legOf, routeDigestOf, routeFromJson } from "./phase-routing.js";
|
|
52
54
|
import { execFileSync } from "node:child_process";
|
|
53
55
|
import { currentClaim, heartbeat, SYNC_MAX_AGE_MS, finalize } from "./claim.js";
|
|
@@ -59,6 +61,7 @@ import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
|
59
61
|
import { invokeAgent } from "./invoke.js";
|
|
60
62
|
import { TELEGRAM_TOKEN_ENVS } from "./names.js";
|
|
61
63
|
import { OPENROUTER_ENV_KEY, auditOf, ALL_CREDENTIAL_ENV } from "./provider.js";
|
|
64
|
+
import { liveLogContext } from "./live-detail.js";
|
|
62
65
|
import { openLiveLog } from "./live.js";
|
|
63
66
|
import { fence } from "./brief-fence.js";
|
|
64
67
|
import { closeSteerMailbox, openSteerMailbox, STEER_HANDLED } from "./steer-mailbox.js";
|
|
@@ -199,12 +202,17 @@ function repairModelOf(profile, request) {
|
|
|
199
202
|
function profileWantsSkip(profile) {
|
|
200
203
|
return ((profile.provider === "claude" && profile.permissionArgv === "bypassPermissions") ||
|
|
201
204
|
((profile.provider === "codex" || profile.provider === "openrouter") && profile.sandboxMode === "danger-full-access") ||
|
|
202
|
-
(profile.provider === "gemini" && profile.approvalArgv === "yolo")
|
|
205
|
+
(profile.provider === "gemini" && profile.approvalArgv === "yolo") ||
|
|
206
|
+
// An ACP agent's only posture is full access inside the fence.
|
|
207
|
+
isAcpProfile(profile));
|
|
203
208
|
}
|
|
204
209
|
const PROVIDER_VERSIONS = new Map();
|
|
205
210
|
/** Provenance only (finding 20): a best-effort `--version` probe, cached
|
|
206
211
|
* per process, null on any failure — never authority, never a refusal. */
|
|
207
212
|
function providerVersionOf(provider) {
|
|
213
|
+
// An ACP agent is never run outside the gateway, not even for --version: its version is what its check recorded.
|
|
214
|
+
if (isAcpProvider(provider))
|
|
215
|
+
return null;
|
|
208
216
|
if (PROVIDER_VERSIONS.has(provider))
|
|
209
217
|
return PROVIDER_VERSIONS.get(provider) ?? null;
|
|
210
218
|
let version = null;
|
|
@@ -221,6 +229,14 @@ function providerVersionOf(provider) {
|
|
|
221
229
|
PROVIDER_VERSIONS.set(provider, version);
|
|
222
230
|
return version;
|
|
223
231
|
}
|
|
232
|
+
/** A build's network (egress.ts): the one its approval sealed, or — sealed before network policies existed — the
|
|
233
|
+
* narrowed legacy one (provider hosts and the repository's registries, nothing added since). */
|
|
234
|
+
export function launchNetworkOf(store, taskRef, profile) {
|
|
235
|
+
if (profile.network !== undefined)
|
|
236
|
+
return { policy: profile.network };
|
|
237
|
+
const repo = store.refForId(taskRef)?.repo ?? null;
|
|
238
|
+
return { policy: legacyNetwork(profile.provider, repo === null ? [] : repositoryEcosystems(repo)) };
|
|
239
|
+
}
|
|
224
240
|
export function proveApprovedProfile(scope, given) {
|
|
225
241
|
// The raw terms first (raw authority repair): a scope whose stored terms
|
|
226
242
|
// do not read back exactly proves nothing — not the filtered reading.
|
|
@@ -293,7 +309,7 @@ export function proveApprovedProfile(scope, given) {
|
|
|
293
309
|
if (given.timeoutMs !== undefined && given.timeoutMs !== snapshot.timeoutSeconds * 1000) {
|
|
294
310
|
return {
|
|
295
311
|
ok: false,
|
|
296
|
-
message: `approved with a ${snapshot.timeoutSeconds}s ${snapshot
|
|
312
|
+
message: `approved with a ${snapshot.timeoutSeconds}s ${idleClock(snapshot) ? "no-progress window" : "clock"}, asked for ${Math.round(given.timeoutMs / 1000)}s — re-approve to change it (stale-approval)`,
|
|
297
313
|
};
|
|
298
314
|
}
|
|
299
315
|
return {
|
|
@@ -1123,7 +1139,7 @@ export async function build(store, request) {
|
|
|
1123
1139
|
maxTurns: effective.maxTurns ?? maxTurns,
|
|
1124
1140
|
finished: () => handoffFiles.some(name => existsSync(join(worktree, name))),
|
|
1125
1141
|
// A paused build can wait as long as the idle limit allows (live-input.ts idleLimit); a wall-clock profile has none.
|
|
1126
|
-
onOpen: () => store.markLiveInputOpened(request.runId, clock(), effective.profile
|
|
1142
|
+
onOpen: () => store.markLiveInputOpened(request.runId, clock(), idleClock(effective.profile) ? effective.timeoutMs : null),
|
|
1127
1143
|
onClose: () => store.markLiveInputClosed(request.runId, clock()),
|
|
1128
1144
|
onPaused: () => store.markRunPaused(request.runId, clock()),
|
|
1129
1145
|
});
|
|
@@ -1153,7 +1169,7 @@ export async function build(store, request) {
|
|
|
1153
1169
|
// Every streaming transport emits events now (peek); a file that cannot
|
|
1154
1170
|
// open is a null, and a null never costs a build.
|
|
1155
1171
|
// What the agent did last rides the same stream into one row (live tasks).
|
|
1156
|
-
const liveLog = withAgentTurns(withRunActivity(openLiveLog(root, request.runId), store, request.runId, clock), (state, at) => { if (attemptKey !== null)
|
|
1172
|
+
const liveLog = withAgentTurns(withRunActivity(openLiveLog(root, request.runId, liveLogContext(store, taskRef, worktree)), store, request.runId, clock), (state, at) => { if (attemptKey !== null)
|
|
1157
1173
|
recordAgentTurn(store, { run: request.runId, attemptKey, state, at }); }, clock, (open, at) => { if (attemptKey !== null)
|
|
1158
1174
|
noteOpenTool(store, request.runId, attemptKey, open, at); });
|
|
1159
1175
|
// The retry base (steering fix for run 1465's proof): the SAME pinned
|
|
@@ -1291,10 +1307,9 @@ export async function build(store, request) {
|
|
|
1291
1307
|
...(liveSession === null ? {} : { liveInput: liveSession }),
|
|
1292
1308
|
// New approvals bind a no-progress watchdog, not a deadline. Legacy
|
|
1293
1309
|
// snapshots carry no timeoutKind and retain their wall-clock terms.
|
|
1294
|
-
...(effective.profile.
|
|
1295
|
-
? { idleTimeoutMs: effective.timeoutMs }
|
|
1296
|
-
: { timeoutMs: effective.timeoutMs }),
|
|
1310
|
+
...watchdogsOf(effective.profile, effective.timeoutMs),
|
|
1297
1311
|
omitEnv: AGENT_ENV_DENYLIST,
|
|
1312
|
+
network: launchNetworkOf(store, request.taskRef, effective.profile),
|
|
1298
1313
|
...(agent === undefined ? {} : { runner: agent }),
|
|
1299
1314
|
onSpawn: (pid) => { spawned = true; request.onProviderSpawn?.(pid); },
|
|
1300
1315
|
onStreamEvent: (event) => liveLog.observe(event),
|
|
@@ -1490,7 +1505,7 @@ export async function settleProviderOutcome(captured, result) {
|
|
|
1490
1505
|
return {
|
|
1491
1506
|
ok: false,
|
|
1492
1507
|
reason: "timeout",
|
|
1493
|
-
message: effective.profile
|
|
1508
|
+
message: idleClock(effective.profile)
|
|
1494
1509
|
? `the builder made no observable progress for ${Math.round(timeoutMs / 60_000)} minutes and was stopped — whatever it wrote is still in ${worktree}`
|
|
1495
1510
|
: `the builder ran past ${Math.round(timeoutMs / 60_000)} minutes and was stopped — whatever it wrote is still in ${worktree}`,
|
|
1496
1511
|
};
|
|
@@ -2614,7 +2629,8 @@ async function resumeUnhandedWork(captured, sessionId) {
|
|
|
2614
2629
|
if (request.leaseId !== undefined && !heartbeat(store, request.leaseId, clock()).ok) {
|
|
2615
2630
|
return { ok: false, reason: "fenced", message: `${taskId}'s lease did not survive the resumed turn — the work is still in ${worktree}` };
|
|
2616
2631
|
}
|
|
2617
|
-
|
|
2632
|
+
// An ACP agent's turn bills as its own model's declaration on this runner, never as the attempt it continues.
|
|
2633
|
+
if (store.budgetGate(clock())({ ...store.budgetSubject(request.taskRef), agents: [isAcpProvider(provider) ? store.agentFor(provider, model ?? null, request.runner) : { provider, billing: store.runBilling(request.runId) ?? store.agentsFor([provider])[0].billing }] }).over !== null)
|
|
2618
2634
|
break;
|
|
2619
2635
|
if (store.agentPolicyRefusal(provider, model ?? null) !== null)
|
|
2620
2636
|
break;
|
|
@@ -2634,8 +2650,9 @@ async function resumeUnhandedWork(captured, sessionId) {
|
|
|
2634
2650
|
...(request.maxBudgetUsd === undefined ? {} : { maxBudgetUsd: request.maxBudgetUsd }),
|
|
2635
2651
|
}, {
|
|
2636
2652
|
cwd: worktree,
|
|
2637
|
-
...(effective.profile
|
|
2653
|
+
...watchdogsOf(effective.profile, effective.timeoutMs),
|
|
2638
2654
|
omitEnv: AGENT_ENV_DENYLIST,
|
|
2655
|
+
network: launchNetworkOf(store, request.taskRef, effective.profile),
|
|
2639
2656
|
...(agent === undefined ? {} : { runner: agent }),
|
|
2640
2657
|
...(request.onProviderSpawn === undefined ? {} : { onSpawn: request.onProviderSpawn }),
|
|
2641
2658
|
clock,
|
|
@@ -2811,7 +2828,8 @@ async function ingestPark(args) {
|
|
|
2811
2828
|
}
|
|
2812
2829
|
// v105: a repair turn spends too — a budget used up since the build began stops further turns (billed to a key).
|
|
2813
2830
|
// It bills as the attempt it mends did.
|
|
2814
|
-
|
|
2831
|
+
// An ACP repair bills as its own model's declaration on this runner, never as the attempt it mends.
|
|
2832
|
+
if (store.budgetGate(clock())({ ...store.budgetSubject(request.taskRef), agents: [isAcpProvider(repairProvider) ? store.agentFor(repairProvider, repairModel ?? null, request.runner) : { provider: repairProvider, billing: store.runBilling(request.runId) ?? store.agentsFor([repairProvider])[0].billing }] }).over !== null)
|
|
2815
2833
|
break;
|
|
2816
2834
|
// Sprint 8: nor does a repair run on a provider or model the organisation policy doesn't allow.
|
|
2817
2835
|
if (store.agentPolicyRefusal(repairProvider, repairModel ?? null) !== null)
|
|
@@ -2845,8 +2863,11 @@ async function ingestPark(args) {
|
|
|
2845
2863
|
: {}),
|
|
2846
2864
|
}, {
|
|
2847
2865
|
cwd: worktree,
|
|
2848
|
-
|
|
2866
|
+
...(args.profile !== undefined && isAcpProfile(args.profile)
|
|
2867
|
+
? watchdogsOf(args.profile, args.profile.repairTimeoutSeconds * 1000, true)
|
|
2868
|
+
: { timeoutMs: args.profile !== undefined ? args.profile.repairTimeoutSeconds * 1000 : REPAIR_TIMEOUT_MS }),
|
|
2849
2869
|
omitEnv: AGENT_ENV_DENYLIST,
|
|
2870
|
+
...(args.profile === undefined ? {} : { network: launchNetworkOf(store, request.taskRef, args.profile) }),
|
|
2850
2871
|
...(agent === undefined ? {} : { runner: agent }),
|
|
2851
2872
|
...(request.onProviderSpawn === undefined ? {} : { onSpawn: request.onProviderSpawn }),
|
|
2852
2873
|
clock,
|
package/dist/chat-actions.d.ts
CHANGED
|
@@ -68,6 +68,16 @@ export declare const CHAT_ACTIONS: {
|
|
|
68
68
|
readonly protected: false;
|
|
69
69
|
readonly password: false;
|
|
70
70
|
};
|
|
71
|
+
readonly sweep_file: {
|
|
72
|
+
readonly label: "Start sweep";
|
|
73
|
+
readonly protected: true;
|
|
74
|
+
readonly password: true;
|
|
75
|
+
};
|
|
76
|
+
readonly sweep_cancel_rest: {
|
|
77
|
+
readonly label: "Cancel the rest";
|
|
78
|
+
readonly protected: false;
|
|
79
|
+
readonly password: false;
|
|
80
|
+
};
|
|
71
81
|
readonly flow_edit: {
|
|
72
82
|
readonly label: "Save flow";
|
|
73
83
|
readonly protected: false;
|
|
@@ -256,7 +266,7 @@ export declare function sharedActionReviewPath(id: number): string;
|
|
|
256
266
|
export declare function mintSharedActionReview(store: Store, who: VerifiedApprover, id: number, root: string, now: Date): {
|
|
257
267
|
payload: {
|
|
258
268
|
version: 1;
|
|
259
|
-
operation: "decision_record" | "decision_retire" | "flow_card_add" | "flow_card_approve" | "flow_card_assign" | "flow_card_cancel" | "flow_card_choose" | "flow_card_comment" | "flow_card_move" | "flow_card_send_back" | "flow_card_watch" | "flow_create" | "flow_edit" | "flow_script_save" | "flow_starter" | "flow_trigger_add" | "flow_trigger_pause" | "flow_trigger_remove" | "flow_trigger_resume" | "kit_setup" | "knowledge_instructions" | "knowledge_remove" | "knowledge_restore" | "knowledge_save" | "lead_about_you" | "result_accept" | "scope_approve" | "skill_disable" | "skill_enable" | "skill_import" | "skill_restore" | "skill_test" | "subagent_answer" | "subagent_ask" | "subagent_create" | "subagent_memory" | "subagent_note" | "subagent_routine" | "subagent_soul" | "subagent_state" | "subagent_tools" | "subagent_undo" | "task_cancel" | "task_resume" | "tool_add" | "tool_remove";
|
|
269
|
+
operation: "decision_record" | "decision_retire" | "flow_card_add" | "flow_card_approve" | "flow_card_assign" | "flow_card_cancel" | "flow_card_choose" | "flow_card_comment" | "flow_card_move" | "flow_card_send_back" | "flow_card_watch" | "flow_create" | "flow_edit" | "flow_script_save" | "flow_starter" | "flow_trigger_add" | "flow_trigger_pause" | "flow_trigger_remove" | "flow_trigger_resume" | "kit_setup" | "knowledge_instructions" | "knowledge_remove" | "knowledge_restore" | "knowledge_save" | "lead_about_you" | "result_accept" | "scope_approve" | "skill_disable" | "skill_enable" | "skill_import" | "skill_restore" | "skill_test" | "subagent_answer" | "subagent_ask" | "subagent_create" | "subagent_memory" | "subagent_note" | "subagent_routine" | "subagent_soul" | "subagent_state" | "subagent_tools" | "subagent_undo" | "sweep_cancel_rest" | "sweep_file" | "task_cancel" | "task_resume" | "tool_add" | "tool_remove";
|
|
260
270
|
request: {
|
|
261
271
|
[x: string]: unknown;
|
|
262
272
|
};
|
|
@@ -286,6 +296,8 @@ export declare function executeSharedAction(store: Store, who: VerifiedApprover,
|
|
|
286
296
|
said: string;
|
|
287
297
|
taskId: string | null;
|
|
288
298
|
href?: string;
|
|
299
|
+
awaiting?: true;
|
|
300
|
+
already?: true;
|
|
289
301
|
} | {
|
|
290
302
|
ok: false;
|
|
291
303
|
reason: "needs-confirm" | "stale" | "refused";
|