@xingular/harness 1.1.1 → 1.3.1-unstable.0
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 +48 -0
- package/README.md +36 -28
- package/dist/cli.js +10837 -6159
- package/dist/sdk/accounts/accounts.d.ts +27 -3
- package/dist/sdk/accounts/accounts.js +78 -24
- package/dist/sdk/accounts/secrets.d.ts +12 -0
- package/dist/sdk/accounts/secrets.js +114 -7
- package/dist/sdk/accounts/store.d.ts +26 -1
- package/dist/sdk/accounts/store.js +1 -1
- package/dist/sdk/agents/builtin.js +18 -4
- package/dist/sdk/agents/planResearch.d.ts +27 -0
- package/dist/sdk/agents/planResearch.js +82 -0
- package/dist/sdk/agents/profiles.d.ts +5 -1
- package/dist/sdk/agents/profiles.js +21 -5
- package/dist/sdk/annotations/pageScript.js +349 -48
- package/dist/sdk/annotations/part.js +34 -23
- package/dist/sdk/annotations/store.d.ts +7 -0
- package/dist/sdk/annotations/store.js +13 -5
- package/dist/sdk/browser/backend.d.ts +16 -0
- package/dist/sdk/browser/backend.js +17 -0
- package/dist/sdk/browser/contracts.d.ts +19 -0
- package/dist/sdk/browser/contracts.js +116 -0
- package/dist/sdk/browser/tools.d.ts +1 -4
- package/dist/sdk/browser/tools.js +14 -91
- package/dist/sdk/capabilities/runSnapshot.js +10 -4
- package/dist/sdk/cli.js +5 -4
- package/dist/sdk/commands/list.d.ts +3 -0
- package/dist/sdk/commands/list.js +75 -0
- package/dist/sdk/commands/registry.d.ts +258 -0
- package/dist/sdk/commands/registry.js +48 -0
- package/dist/sdk/commands/routes.d.ts +16 -0
- package/dist/sdk/commands/routes.js +33 -0
- package/dist/sdk/core/commandBudget.d.ts +23 -0
- package/dist/sdk/core/commandBudget.js +57 -0
- package/dist/sdk/core/index.js +17 -1
- package/dist/sdk/core/interactiveProfile.d.ts +46 -0
- package/dist/sdk/core/interactiveProfile.js +143 -0
- package/dist/sdk/core/shell.d.ts +20 -0
- package/dist/sdk/core/shell.js +73 -0
- package/dist/sdk/core/workspace.d.ts +13 -0
- package/dist/sdk/core/workspace.js +88 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +20 -0
- package/dist/sdk/core/workspaceBashTool.js +50 -0
- package/dist/sdk/core/workspaceSandbox.d.ts +41 -0
- package/dist/sdk/core/workspaceSandbox.js +360 -0
- package/dist/sdk/core/workspaceWriteOperations.d.ts +33 -0
- package/dist/sdk/core/workspaceWriteOperations.js +224 -0
- package/dist/sdk/doctor/checks.js +71 -12
- package/dist/sdk/doctor/types.d.ts +2 -2
- package/dist/sdk/harness.d.ts +7 -0
- package/dist/sdk/harness.js +42 -2
- package/dist/sdk/hub/hub.js +5 -3
- package/dist/sdk/index.d.ts +8 -3
- package/dist/sdk/index.js +4 -1
- package/dist/sdk/pi/runtime.d.ts +2 -1
- package/dist/sdk/pi/runtime.js +2 -2
- package/dist/sdk/plugins/builtin.js +32 -15
- package/dist/sdk/plugins/builtinRegistry.d.ts +10 -3
- package/dist/sdk/plugins/builtinRegistry.js +30 -8
- package/dist/sdk/plugins/catalogue.js +2 -1
- package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
- package/dist/sdk/plugins/commandPrefix.js +21 -0
- package/dist/sdk/plugins/firstParty.d.ts +1 -1
- package/dist/sdk/plugins/firstParty.js +8 -2
- package/dist/sdk/plugins/install.d.ts +6 -2
- package/dist/sdk/plugins/install.js +29 -5
- package/dist/sdk/plugins/inventory.js +6 -5
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +2 -1
- package/dist/sdk/plugins/surfaces.d.ts +5 -0
- package/dist/sdk/plugins/surfaces.js +11 -0
- package/dist/sdk/plugins/types.d.ts +15 -0
- package/dist/sdk/prompt/compile.d.ts +14 -0
- package/dist/sdk/prompt/compile.js +65 -31
- package/dist/sdk/prompt/standard.d.ts +17 -0
- package/dist/sdk/prompt/standard.js +21 -0
- package/dist/sdk/server/methods.js +22 -2
- package/dist/sdk/server/remote.js +36 -11
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
- package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
- package/dist/sdk/sessions/continuation.d.ts +7 -2
- package/dist/sdk/sessions/continuation.js +11 -6
- package/dist/sdk/sessions/contracts.d.ts +190 -4
- package/dist/sdk/sessions/contracts.js +71 -8
- package/dist/sdk/sessions/control.d.ts +72 -0
- package/dist/sdk/sessions/control.js +158 -0
- package/dist/sdk/sessions/initialBash.d.ts +7 -0
- package/dist/sdk/sessions/initialBash.js +7 -0
- package/dist/sdk/sessions/planMode.d.ts +14 -3
- package/dist/sdk/sessions/planMode.js +74 -17
- package/dist/sdk/sessions/registry.d.ts +1 -1
- package/dist/sdk/sessions/registry.js +2 -2
- package/dist/sdk/sessions/runStore.d.ts +14 -0
- package/dist/sdk/sessions/runStore.js +38 -1
- package/dist/sdk/sessions/runner.d.ts +40 -2
- package/dist/sdk/sessions/runner.js +161 -13
- package/dist/sdk/sessions/sessions.d.ts +23 -3
- package/dist/sdk/sessions/sessions.js +225 -22
- package/dist/sdk/sessions/subagentService.d.ts +24 -0
- package/dist/sdk/sessions/subagentService.js +225 -26
- package/dist/sdk/sessions/subagents.d.ts +10 -1
- package/dist/sdk/sessions/subagents.js +4 -0
- package/dist/sdk/sessions/workSlice.d.ts +106 -0
- package/dist/sdk/sessions/workSlice.js +329 -0
- package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
- package/dist/sdk/sessions/workspaceBoundary.js +46 -0
- package/dist/sdk/terminal/browserControl.js +2 -1
- package/dist/sdk/terminal/controller.d.ts +31 -3
- package/dist/sdk/terminal/controller.js +81 -29
- package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
- package/dist/sdk/terminal/opentui/ansi.js +192 -0
- package/dist/sdk/terminal/opentui/model.d.ts +163 -0
- package/dist/sdk/terminal/opentui/model.js +482 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
- package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
- package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
- package/dist/sdk/terminal/opentui/theme.js +88 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -1
- package/dist/sdk/terminal/piExtension.js +177 -63
- package/dist/sdk/terminal/standalone.d.ts +7 -0
- package/dist/sdk/terminal/standalone.js +72 -13
- package/dist/sdk/terminal/subagentMonitor.d.ts +28 -6
- package/dist/sdk/terminal/subagentMonitor.js +61 -9
- package/dist/sdk/terminal/terminals.d.ts +26 -2
- package/dist/sdk/terminal/terminals.js +325 -43
- package/dist/sdk/terminal/trajectory.d.ts +6 -1
- package/dist/sdk/terminal/trajectory.js +8 -0
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +1 -1
- package/dist/sdk/terminal/tui/annotateCommand.js +3 -3
- package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
- package/dist/sdk/terminal/tui/chrome.js +13 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +3 -1
- package/dist/sdk/terminal/tui/commandPages.js +17 -4
- package/dist/sdk/terminal/tui/commands.d.ts +6 -0
- package/dist/sdk/terminal/tui/commands.js +213 -124
- package/dist/sdk/terminal/tui/list.d.ts +14 -1
- package/dist/sdk/terminal/tui/list.js +96 -14
- package/dist/sdk/terminal/tui/pageOverlay.js +21 -5
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +1 -1
- package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
- package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
- package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +5 -5
- package/dist/sdk/terminal/tui/pages/notesPage.js +18 -18
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +8 -6
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +206 -28
- package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +1 -0
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +104 -19
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
- package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
- package/dist/sdk/terminal/tui/piAdapter.js +3 -5
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +2 -0
- package/dist/sdk/terminal/tui/pluginCommands.js +13 -9
- package/dist/sdk/terminal/tui/runtime.js +23 -3
- package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
- package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
- package/dist/sdk/tools/checkpoint.d.ts +27 -0
- package/dist/sdk/tools/checkpoint.js +154 -0
- package/dist/sdk/tools/getCapabilities.d.ts +31 -0
- package/dist/sdk/tools/getCapabilities.js +34 -0
- package/dist/sdk/tools/sessionName.d.ts +2 -0
- package/dist/sdk/tools/sessionName.js +5 -3
- package/dist/sdk/tools/spawnSubagent.js +11 -8
- package/dist/sdk/tools/todo.d.ts +15 -0
- package/dist/sdk/tools/todo.js +64 -0
- package/dist/sdk/usage/analytics.d.ts +20 -0
- package/dist/sdk/usage/analytics.js +151 -0
- package/dist/sdk/usage/ledger.d.ts +38 -0
- package/dist/sdk/usage/ledger.js +142 -0
- package/dist/sdk/usage/limits/adapters.d.ts +11 -0
- package/dist/sdk/usage/limits/adapters.js +349 -0
- package/dist/sdk/usage/limits/capture.d.ts +8 -0
- package/dist/sdk/usage/limits/capture.js +47 -0
- package/dist/sdk/usage/limits/http.d.ts +12 -0
- package/dist/sdk/usage/limits/http.js +51 -0
- package/dist/sdk/usage/limits/normalize.d.ts +15 -0
- package/dist/sdk/usage/limits/normalize.js +211 -0
- package/dist/sdk/usage/limits/service.d.ts +30 -0
- package/dist/sdk/usage/limits/service.js +176 -0
- package/dist/sdk/usage/limits/types.d.ts +65 -0
- package/dist/sdk/usage/limits/types.js +1 -0
- package/dist/sdk/usage/serverMethods.d.ts +3 -0
- package/dist/sdk/usage/serverMethods.js +22 -0
- package/dist/sdk/usage/service.d.ts +32 -0
- package/dist/sdk/usage/service.js +66 -0
- package/dist/sdk/usage/settings.d.ts +7 -0
- package/dist/sdk/usage/settings.js +28 -0
- package/dist/sdk/usage/types.d.ts +60 -0
- package/dist/sdk/usage/types.js +4 -0
- package/dist/terminal-opentui.js +9204 -4812
- package/dist/terminal-pi.js +1848 -272
- package/docs/architecture/00-overview.md +1 -1
- package/docs/architecture/01-extension-points.md +1 -1
- package/docs/architecture/02-sessions-and-runs.md +169 -36
- package/docs/architecture/04-prompt.md +55 -15
- package/docs/architecture/06-plugins-and-capabilities.md +36 -15
- package/docs/architecture/07-tools-and-gate.md +131 -25
- package/docs/architecture/08-memory-and-history.md +4 -2
- package/docs/architecture/09-accounts-and-connectors.md +39 -3
- package/docs/architecture/10-server-protocol.md +71 -9
- package/docs/architecture/11-terminal.md +148 -60
- package/docs/architecture/12-storage.md +30 -2
- package/docs/architecture/13-world-tools.md +22 -1
- package/docs/architecture/14-surfaces-and-parity.md +58 -8
- package/docs/architecture/README.md +20 -17
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
- package/docs/architecture/proposals/PROP-0017-page-annotations.md +6 -2
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +1 -1
- package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
- package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
- package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
- package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
- package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
- package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
- package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
- package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
- package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
- package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +258 -0
- package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
- package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
- package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
- package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
- package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
- package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
- package/docs/architecture/proposals/README.md +24 -6
- package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
- package/docs/decisions/ADR-0021-required-command-namespaces.md +1 -1
- package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
- package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
- package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
- package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
- package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
- package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
- package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
- package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
- package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
- package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
- package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
- package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
- package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
- package/docs/doctor.md +14 -1
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
- package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
- package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
- package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
- package/docs/parity.md +83 -27
- package/docs/releases/1.1.1.md +28 -0
- package/docs/releases/1.2.0.md +49 -0
- package/docs/releases/1.3.0.md +21 -0
- package/docs/releases/4.0.0.md +10 -9
- package/docs/releases/README.md +35 -30
- package/docs/study/00-index.md +3 -0
- package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
- package/docs/terminal-tui.md +162 -82
- package/package.json +4 -3
- package/dist/sdk/tools/checklist.d.ts +0 -9
- package/dist/sdk/tools/checklist.js +0 -54
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// A reply's work slice (PROP-0041): a bounded amount of work, then a handoff checkpoint, then a
|
|
2
|
+
// continuation. The guard here refuses the call that would run past the budget, once with a
|
|
3
|
+
// request for the checkpoint, and ends the reply if the model keeps calling tools. It also names
|
|
4
|
+
// repeated work before it becomes a loop. All decisions are deterministic; no model is consulted.
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import { findRun } from "./runStore.js";
|
|
7
|
+
export const WORK_SLICE_EXTENSION = 'work-slice';
|
|
8
|
+
/** The foundation defaults: enough for one meaningful step of work, short enough to report. */
|
|
9
|
+
export const DEFAULT_SLICE_POLICY = {
|
|
10
|
+
enabled: true,
|
|
11
|
+
// A chapter of a task, not an interruption every few edits: roughly 80 minutes of ordinary work
|
|
12
|
+
// (about 15 s a call), with 60 minutes of wall clock as the ceiling, whichever comes first. A task
|
|
13
|
+
// still gets eight slices before it returns to the person.
|
|
14
|
+
maxToolCalls: 320,
|
|
15
|
+
maxMinutes: 60,
|
|
16
|
+
// No token cap: the tool calls and the clock are the bound. Counting new input, cache writes and
|
|
17
|
+
// output made a few large reads end a reply before useful work (see the "Confirm plan model
|
|
18
|
+
// support" thread), so a cap is available to whoever asks for one and off unless they do.
|
|
19
|
+
maxNewTokens: 0,
|
|
20
|
+
maxSlices: 8,
|
|
21
|
+
continue: true
|
|
22
|
+
};
|
|
23
|
+
const LIMITS = {
|
|
24
|
+
maxToolCalls: { min: 1, max: 2_000 },
|
|
25
|
+
maxMinutes: { min: 1, max: 480 },
|
|
26
|
+
maxNewTokens: { min: 1_000, max: 5_000_000 },
|
|
27
|
+
maxSlices: { min: 1, max: 100 }
|
|
28
|
+
};
|
|
29
|
+
export class WorkSliceError extends Error {
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The policy a run asked for, or the defaults. `XINGULAR_WORK_SLICE=off` at launch turns the guard
|
|
33
|
+
* off for every run in this process; nothing is persisted, so restarting without it restores the
|
|
34
|
+
* defaults.
|
|
35
|
+
*/
|
|
36
|
+
export function parseWorkSlice(input) {
|
|
37
|
+
if (input === undefined || input === null) {
|
|
38
|
+
const launch = process.env.XINGULAR_WORK_SLICE?.trim().toLowerCase();
|
|
39
|
+
return { ...DEFAULT_SLICE_POLICY, ...(launch === 'off' || launch === '0' || launch === 'false' ? { enabled: false } : {}) };
|
|
40
|
+
}
|
|
41
|
+
if (typeof input !== 'object' || Array.isArray(input))
|
|
42
|
+
throw new WorkSliceError('workSlice must be an object.');
|
|
43
|
+
const record = input;
|
|
44
|
+
const policy = { ...DEFAULT_SLICE_POLICY };
|
|
45
|
+
for (const key of Object.keys(record)) {
|
|
46
|
+
if (key === 'enabled') {
|
|
47
|
+
if (typeof record.enabled !== 'boolean')
|
|
48
|
+
throw new WorkSliceError('workSlice.enabled must be true or false.');
|
|
49
|
+
policy.enabled = record.enabled;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (key === 'continue') {
|
|
53
|
+
if (typeof record.continue !== 'boolean')
|
|
54
|
+
throw new WorkSliceError('workSlice.continue must be true or false.');
|
|
55
|
+
policy.continue = record.continue;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const limits = LIMITS[key];
|
|
59
|
+
if (!limits)
|
|
60
|
+
throw new WorkSliceError(`workSlice has no field ${key}.`);
|
|
61
|
+
const value = record[key];
|
|
62
|
+
if (typeof value !== 'number' || !Number.isInteger(value))
|
|
63
|
+
throw new WorkSliceError(`workSlice.${key} must be a whole number.`);
|
|
64
|
+
// 0 switches one limit off, as the settings page says.
|
|
65
|
+
if (value === 0) {
|
|
66
|
+
policy[key] = 0;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (value < limits.min || value > limits.max)
|
|
70
|
+
throw new WorkSliceError(`workSlice.${key} must be between ${limits.min} and ${limits.max}, or 0 for no limit.`);
|
|
71
|
+
policy[key] = value;
|
|
72
|
+
}
|
|
73
|
+
return policy;
|
|
74
|
+
}
|
|
75
|
+
export function createSliceState(_policy, slice = 1, now = Date.now()) {
|
|
76
|
+
return { slice, steps: 0, tokens: 0, startedAt: now, lastTool: null, compactions: 0, checkpointWritten: false, endedBy: null, endedByLimit: null, refusedAt: null };
|
|
77
|
+
}
|
|
78
|
+
/** Counters start again for each reply; a terminal session keeps one guard across replies. */
|
|
79
|
+
export function resetSliceState(state, now = Date.now()) {
|
|
80
|
+
state.steps = 0;
|
|
81
|
+
state.tokens = 0;
|
|
82
|
+
state.startedAt = now;
|
|
83
|
+
state.lastTool = null;
|
|
84
|
+
state.compactions = 0;
|
|
85
|
+
state.checkpointWritten = false;
|
|
86
|
+
state.endedBy = null;
|
|
87
|
+
state.endedByLimit = null;
|
|
88
|
+
state.refusedAt = null;
|
|
89
|
+
}
|
|
90
|
+
/** The first limit this reply has passed, named as a person would say it. */
|
|
91
|
+
export function sliceLimitReached(policy, state, now = Date.now()) {
|
|
92
|
+
if (policy.maxToolCalls > 0 && state.steps >= policy.maxToolCalls)
|
|
93
|
+
return `${policy.maxToolCalls} tool calls`;
|
|
94
|
+
if (policy.maxMinutes > 0 && now - state.startedAt >= policy.maxMinutes * 60_000)
|
|
95
|
+
return `${policy.maxMinutes} minutes`;
|
|
96
|
+
if (policy.maxNewTokens > 0 && state.tokens >= policy.maxNewTokens)
|
|
97
|
+
return `${Math.round(policy.maxNewTokens / 1000)}k new tokens`;
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
/** Tools a reply may still call while it writes its handoff. A plan update waits for the next slice. */
|
|
101
|
+
const HANDOFF_TOOLS = new Set(['checkpoint_write', 'session_name']);
|
|
102
|
+
/** Tools whose repetition is how waiting works, not a loop. */
|
|
103
|
+
const POLLING_TOOLS = new Set(['wait_subagents', 'subagents.list', 'subagents.status']);
|
|
104
|
+
/** Commands that read as a check for the repeated-failure rule. */
|
|
105
|
+
export function looksLikeCheck(command) {
|
|
106
|
+
return /\b(test|tests|typecheck|tsc|vitest|jest|cargo|check:|prove|lint|ci|build)\b/u.test(command);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A stable rendering of a value: object keys sorted, so argument order never changes the result.
|
|
110
|
+
* Depth is bounded so a cyclic or absurdly nested input cannot recurse forever.
|
|
111
|
+
*/
|
|
112
|
+
function canonical(value, depth = 0) {
|
|
113
|
+
if (depth > 8)
|
|
114
|
+
return '…';
|
|
115
|
+
if (value === null || typeof value !== 'object')
|
|
116
|
+
return JSON.stringify(value) ?? 'null';
|
|
117
|
+
if (Array.isArray(value))
|
|
118
|
+
return `[${value.map((item) => canonical(item, depth + 1)).join(',')}]`;
|
|
119
|
+
const entries = Object.entries(value).filter(([, item]) => item !== undefined);
|
|
120
|
+
entries.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
121
|
+
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonical(item, depth + 1)}`).join(',')}}`;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A call's identity: its name and every argument, hashed so the key stays small even when an
|
|
125
|
+
* argument is a whole file. A changed argument is a different call; only an identical one repeats.
|
|
126
|
+
* Reading a fixed handful of fields made every `todo_write` look identical, so a reply that
|
|
127
|
+
* reported its progress was told it was repeating work.
|
|
128
|
+
*/
|
|
129
|
+
const signature = (name, input) => `${name}\u0000${createHash('sha256').update(canonical(input ?? null)).digest('hex')}`;
|
|
130
|
+
const clip = (value, limit) => (value.length <= limit ? value : `${value.slice(0, limit - 1)}…`);
|
|
131
|
+
function handoffRequest(limit, state, checkpointAvailable = true) {
|
|
132
|
+
const handoff = checkpointAvailable
|
|
133
|
+
? 'Call checkpoint_write now with what is done, the single next step, anything blocking, the files you touched and the checks that matter. Then tell the user in a few lines where you stopped.'
|
|
134
|
+
: 'Stop using tools and return a concise partial research report with findings, blockers and the next useful research step. The Harness records an evidence-derived checkpoint.';
|
|
135
|
+
return clip(`This reply reached its work-slice limit (${limit}; step ${state.steps}). ${handoff} Do not call other tools.`, 600);
|
|
136
|
+
}
|
|
137
|
+
function stalledNote(reason, checkpointAvailable = true) {
|
|
138
|
+
const handoff = checkpointAvailable
|
|
139
|
+
? 'Choose a different approach, read what the earlier attempt returned, or call checkpoint_write with the blocker so the next slice can decide.'
|
|
140
|
+
: 'Do not use more tools. Return concise findings and blockers in your final response; the Harness records an evidence-derived checkpoint.';
|
|
141
|
+
return clip(`You are repeating work: ${reason}. Do not repeat it. ${handoff}`, 600);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Bounds one reply and names repeated work. Refusals request a checkpoint when available; without
|
|
145
|
+
* one, they ask for a partial report and prohibit further tools. A repeated call or failing command
|
|
146
|
+
* is named once, then ends the reply.
|
|
147
|
+
*/
|
|
148
|
+
export function workSliceGuard(options) {
|
|
149
|
+
const { policy, state } = options;
|
|
150
|
+
const calls = new Map();
|
|
151
|
+
const checkCalls = new Set();
|
|
152
|
+
const edits = new Map();
|
|
153
|
+
const failures = new Map();
|
|
154
|
+
let nudged = false;
|
|
155
|
+
const checkpointAvailable = () => typeof options.checkpointAvailable === 'function'
|
|
156
|
+
? options.checkpointAvailable()
|
|
157
|
+
: options.checkpointAvailable !== false;
|
|
158
|
+
/** Repetition is judged inside one reply; the next reply starts from a clean count. */
|
|
159
|
+
const resetRepetition = () => {
|
|
160
|
+
calls.clear();
|
|
161
|
+
checkCalls.clear();
|
|
162
|
+
edits.clear();
|
|
163
|
+
failures.clear();
|
|
164
|
+
nudged = false;
|
|
165
|
+
};
|
|
166
|
+
const end = (kind, limit) => {
|
|
167
|
+
state.endedBy = kind;
|
|
168
|
+
state.endedByLimit = limit;
|
|
169
|
+
options.onEnd?.(kind, limit);
|
|
170
|
+
const canCheckpoint = checkpointAvailable();
|
|
171
|
+
const reason = kind === 'stuck'
|
|
172
|
+
? stalledNote(limit, canCheckpoint)
|
|
173
|
+
: kind === 'compaction-thrash'
|
|
174
|
+
? handoffRequest('three context compactions in one reply', state, canCheckpoint)
|
|
175
|
+
: handoffRequest(limit, state, canCheckpoint);
|
|
176
|
+
return { block: true, terminate: true, reason };
|
|
177
|
+
};
|
|
178
|
+
const nudge = (reason) => {
|
|
179
|
+
if (nudged)
|
|
180
|
+
return end('stuck', reason);
|
|
181
|
+
nudged = true;
|
|
182
|
+
const canCheckpoint = checkpointAvailable();
|
|
183
|
+
if (!canCheckpoint) {
|
|
184
|
+
state.endedBy = 'stuck';
|
|
185
|
+
state.endedByLimit = reason;
|
|
186
|
+
}
|
|
187
|
+
return { block: true, reason: stalledNote(reason, canCheckpoint) };
|
|
188
|
+
};
|
|
189
|
+
const repeated = (name, input) => {
|
|
190
|
+
if (POLLING_TOOLS.has(name))
|
|
191
|
+
return null;
|
|
192
|
+
const key = signature(name, input);
|
|
193
|
+
if (name === 'bash') {
|
|
194
|
+
const command = input && typeof input === 'object' ? String(input.command ?? '') : '';
|
|
195
|
+
if (command && looksLikeCheck(command))
|
|
196
|
+
checkCalls.add(key);
|
|
197
|
+
}
|
|
198
|
+
const count = (calls.get(key) ?? 0) + 1;
|
|
199
|
+
calls.set(key, count);
|
|
200
|
+
if (count < 3)
|
|
201
|
+
return null;
|
|
202
|
+
return name === 'bash' ? `the same Bash command ${count} times (steps ending at ${state.steps})` : `the same ${name} call ${count} times (steps ending at ${state.steps})`;
|
|
203
|
+
};
|
|
204
|
+
const failing = (name, input) => {
|
|
205
|
+
if (name !== 'bash')
|
|
206
|
+
return null;
|
|
207
|
+
const command = input && typeof input === 'object' ? String(input.command ?? '') : '';
|
|
208
|
+
if (!command || !looksLikeCheck(command))
|
|
209
|
+
return null;
|
|
210
|
+
const count = failures.get(command) ?? 0;
|
|
211
|
+
return count >= 2 ? `the check ${command} failed ${count} times` : null;
|
|
212
|
+
};
|
|
213
|
+
return (pi) => {
|
|
214
|
+
pi.on('agent_start', () => {
|
|
215
|
+
resetSliceState(state);
|
|
216
|
+
resetRepetition();
|
|
217
|
+
});
|
|
218
|
+
pi.on('message_end', (event) => {
|
|
219
|
+
const usage = event.message.usage;
|
|
220
|
+
if (event.message.role !== 'assistant' || !usage)
|
|
221
|
+
return;
|
|
222
|
+
// New tokens only: the cached prefix was sent before and is not new context or new cost.
|
|
223
|
+
state.tokens += (usage.input ?? 0) + (usage.cacheWrite ?? 0) + (usage.output ?? 0);
|
|
224
|
+
});
|
|
225
|
+
pi.on('tool_result', (event) => {
|
|
226
|
+
if (event.toolName === 'checkpoint_write' && !event.isError) {
|
|
227
|
+
state.checkpointWritten = true;
|
|
228
|
+
nudged = false;
|
|
229
|
+
}
|
|
230
|
+
if ((event.toolName === 'edit' || event.toolName === 'write') && event.isError === false) {
|
|
231
|
+
const path = event.input && typeof event.input === 'object' ? String(event.input.path ?? '') : '';
|
|
232
|
+
if (path) {
|
|
233
|
+
edits.set(path, (edits.get(path) ?? 0) + 1);
|
|
234
|
+
failures.clear();
|
|
235
|
+
for (const key of checkCalls)
|
|
236
|
+
calls.delete(key);
|
|
237
|
+
checkCalls.clear();
|
|
238
|
+
nudged = false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (event.toolName !== 'bash')
|
|
242
|
+
return;
|
|
243
|
+
const command = event.input && typeof event.input === 'object' ? String(event.input.command ?? '') : '';
|
|
244
|
+
if (!command || !looksLikeCheck(command))
|
|
245
|
+
return;
|
|
246
|
+
if (event.isError) {
|
|
247
|
+
failures.set(command, (failures.get(command) ?? 0) + 1);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
// A passing check is progress: the repetition rules start over.
|
|
251
|
+
failures.delete(command);
|
|
252
|
+
edits.clear();
|
|
253
|
+
calls.clear();
|
|
254
|
+
checkCalls.clear();
|
|
255
|
+
nudged = false;
|
|
256
|
+
});
|
|
257
|
+
pi.on('tool_call', (event) => {
|
|
258
|
+
const name = event.toolName;
|
|
259
|
+
state.steps += 1;
|
|
260
|
+
state.lastTool = name;
|
|
261
|
+
const canCheckpoint = checkpointAvailable();
|
|
262
|
+
const handoff = canCheckpoint && HANDOFF_TOOLS.has(name);
|
|
263
|
+
// A handoff is callable only when checkpoint_write is active; after the slice ended it is the only one.
|
|
264
|
+
if (state.endedBy) {
|
|
265
|
+
const reason = state.checkpointWritten
|
|
266
|
+
? 'This reply is over. Its checkpoint is recorded; nothing else runs.'
|
|
267
|
+
: 'This reply is over. The Harness will record an evidence-derived checkpoint; nothing else runs.';
|
|
268
|
+
return handoff ? undefined : { block: true, terminate: true, reason };
|
|
269
|
+
}
|
|
270
|
+
if (state.compactions >= 3) {
|
|
271
|
+
if (handoff) {
|
|
272
|
+
state.endedBy = 'compaction-thrash';
|
|
273
|
+
state.endedByLimit = 'three compactions';
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
return end('compaction-thrash', 'three compactions');
|
|
277
|
+
}
|
|
278
|
+
const limit = sliceLimitReached(policy, state);
|
|
279
|
+
if (limit) {
|
|
280
|
+
// The slice ends here; the model gets one wrap-up request to write the handoff. A handoff
|
|
281
|
+
// call is never refused, including when it is the very first call past the budget.
|
|
282
|
+
state.endedBy = 'budget';
|
|
283
|
+
state.endedByLimit = limit;
|
|
284
|
+
state.refusedAt ??= state.steps;
|
|
285
|
+
return handoff ? undefined : { block: true, reason: handoffRequest(limit, state, canCheckpoint) };
|
|
286
|
+
}
|
|
287
|
+
if (handoff)
|
|
288
|
+
return undefined;
|
|
289
|
+
// Todo updates are bookkeeping, not evidence of progress or a stall. They still count above
|
|
290
|
+
// toward the reply's overall tool-call budget.
|
|
291
|
+
if (name === 'todo_write')
|
|
292
|
+
return undefined;
|
|
293
|
+
const edit = name === 'edit' || name === 'write';
|
|
294
|
+
const path = edit && event.input && typeof event.input === 'object' ? String(event.input.path ?? '') : '';
|
|
295
|
+
if (edit && path) {
|
|
296
|
+
const count = edits.get(path) ?? 0;
|
|
297
|
+
if (count >= 4) {
|
|
298
|
+
const reason = `${path} was edited ${count} times with no passing check between`;
|
|
299
|
+
return nudge(reason);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const repeat = repeated(name, event.input);
|
|
303
|
+
const failure = failing(name, event.input);
|
|
304
|
+
const reason = repeat ?? failure;
|
|
305
|
+
if (!reason)
|
|
306
|
+
return undefined;
|
|
307
|
+
return nudge(reason);
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Which slice of its session a run is, from 1. Counts the recorded continuation chain, so it
|
|
313
|
+
* survives a restart and needs no extra field on the run record.
|
|
314
|
+
*/
|
|
315
|
+
export function sliceOf(root, runId, limit = 100) {
|
|
316
|
+
let current = runId;
|
|
317
|
+
let count = 0;
|
|
318
|
+
const seen = new Set();
|
|
319
|
+
while (current && count < limit && !seen.has(current)) {
|
|
320
|
+
seen.add(current);
|
|
321
|
+
count += 1;
|
|
322
|
+
current = findRun(root, current)?.resumedFromRunId ?? null;
|
|
323
|
+
}
|
|
324
|
+
return Math.max(1, count);
|
|
325
|
+
}
|
|
326
|
+
/** The reason a checkpoint the harness derives (no model handoff) records. */
|
|
327
|
+
export function derivedReason(end) {
|
|
328
|
+
return end ?? 'requested';
|
|
329
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RunRecord } from "./contracts.js";
|
|
2
|
+
import type { ScopeDecision } from "./policy.js";
|
|
3
|
+
export declare const WORKSPACE_FILE_WRITE_TOOLS: Set<string>;
|
|
4
|
+
export interface WorkspaceWriteInspection {
|
|
5
|
+
input: unknown;
|
|
6
|
+
path: string | null;
|
|
7
|
+
outside: boolean;
|
|
8
|
+
reason: string | null;
|
|
9
|
+
}
|
|
10
|
+
/** Canonicalize native file-write arguments and identify an explicit workspace escape. */
|
|
11
|
+
export declare function inspectWorkspaceWrite(workspaceRoot: string, cwd: string, tool: string, input: unknown): WorkspaceWriteInspection;
|
|
12
|
+
/** Adds the mandatory per-operation boundary without allowing it to waive host hard denials. */
|
|
13
|
+
export declare function combineWorkspaceScope(scope: ScopeDecision, inspection: WorkspaceWriteInspection): ScopeDecision;
|
|
14
|
+
/** Resolve a root for pre-boundary run records, then inspect the write using the pinned directory. */
|
|
15
|
+
export declare function inspectRunWorkspaceWrite(run: RunRecord, tool: string, input: unknown): WorkspaceWriteInspection;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { isWithinWorkspace, resolveWorkspaceRoot, resolveWritePath, verifyWorkspaceRoot } from "../core/workspace.js";
|
|
2
|
+
export const WORKSPACE_FILE_WRITE_TOOLS = new Set(['edit', 'write']);
|
|
3
|
+
/** Canonicalize native file-write arguments and identify an explicit workspace escape. */
|
|
4
|
+
export function inspectWorkspaceWrite(workspaceRoot, cwd, tool, input) {
|
|
5
|
+
if (!WORKSPACE_FILE_WRITE_TOOLS.has(tool.toLowerCase()) || !input || typeof input !== 'object' || Array.isArray(input)) {
|
|
6
|
+
return { input, path: null, outside: false, reason: null };
|
|
7
|
+
}
|
|
8
|
+
const args = input;
|
|
9
|
+
if (typeof args.path !== 'string')
|
|
10
|
+
return { input, path: null, outside: false, reason: null };
|
|
11
|
+
const root = verifyWorkspaceRoot(workspaceRoot);
|
|
12
|
+
const path = resolveWritePath(args.path, cwd);
|
|
13
|
+
const outside = !isWithinWorkspace(root, path);
|
|
14
|
+
return {
|
|
15
|
+
input: { ...args, path },
|
|
16
|
+
path,
|
|
17
|
+
outside,
|
|
18
|
+
reason: outside ? `Write target ${path} is outside the active project workspace ${root}.` : null
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Adds the mandatory per-operation boundary without allowing it to waive host hard denials. */
|
|
22
|
+
export function combineWorkspaceScope(scope, inspection) {
|
|
23
|
+
if (!inspection.outside)
|
|
24
|
+
return scope;
|
|
25
|
+
if (!scope.allowed && (scope.automatic || !scope.requiresApproval))
|
|
26
|
+
return scope;
|
|
27
|
+
return {
|
|
28
|
+
...scope,
|
|
29
|
+
allowed: false,
|
|
30
|
+
requiresApproval: true,
|
|
31
|
+
humanOnly: true,
|
|
32
|
+
allowGlobalApproval: scope.humanOnly ? scope.allowGlobalApproval : true,
|
|
33
|
+
reason: inspection.reason
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Resolve a root for pre-boundary run records, then inspect the write using the pinned directory. */
|
|
37
|
+
export function inspectRunWorkspaceWrite(run, tool, input) {
|
|
38
|
+
const cwd = run.workingDirectory;
|
|
39
|
+
const root = run.workspaceRoot ?? (cwd ? resolveWorkspaceRoot(cwd) : null);
|
|
40
|
+
if (!root || !cwd) {
|
|
41
|
+
if (WORKSPACE_FILE_WRITE_TOOLS.has(tool.toLowerCase()))
|
|
42
|
+
throw new Error('The active project workspace could not be resolved; file writes are blocked.');
|
|
43
|
+
return { input, path: null, outside: false, reason: null };
|
|
44
|
+
}
|
|
45
|
+
return inspectWorkspaceWrite(root, cwd, tool, input);
|
|
46
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { constants, closeSync, fstatSync, lstatSync, openSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { describePlugin } from "../plugins/surfaces.js";
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
4
5
|
import { invalid } from "../core/errors.js";
|
|
@@ -46,7 +47,7 @@ export class BrowserControl {
|
|
|
46
47
|
])
|
|
47
48
|
add({ id: `foundation:${id}`, section: 'foundation', name: name, description: description, owner: 'Foundation', origin: 'Built-in', status: 'Read-only' });
|
|
48
49
|
for (const plugin of plugins) {
|
|
49
|
-
add({ id: `plugin:${plugin.id}`, section: 'plugins', name: plugin.title, description: plugin
|
|
50
|
+
add({ id: `plugin:${plugin.id}`, section: 'plugins', name: plugin.title, description: describePlugin(plugin),
|
|
50
51
|
owner: plugin.title, origin: plugin.source, status: plugin.required ? 'Required' : plugin.trust === 'untrusted' ? 'Needs trust' : 'Saved configuration',
|
|
51
52
|
pluginId: plugin.id, path: plugin.path ?? undefined, required: plugin.required });
|
|
52
53
|
for (const entry of plugin.contributions) {
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { type RunEvent, type RunRecord } from "../sessions/contracts.js";
|
|
2
2
|
import type { ActiveRun, ApprovalDecision, QuestionAnswer } from "../sessions/registry.js";
|
|
3
|
-
import { type TerminalSubagentActivity, type TerminalSubagentProfile } from "./subagentMonitor.js";
|
|
3
|
+
import { type TerminalSubagentActivity, type TerminalSubagentProfile, type TerminalSubagentRun } from "./subagentMonitor.js";
|
|
4
|
+
type MonitorRuntime = Pick<TerminalSubagentRun, 'accountLabel' | 'model' | 'effort'>;
|
|
5
|
+
/** A saved run to show in the monitor after the conversation is reopened. */
|
|
6
|
+
export interface MonitorEntry {
|
|
7
|
+
record: RunRecord;
|
|
8
|
+
events: readonly RunEvent[];
|
|
9
|
+
profile?: TerminalSubagentProfile | null;
|
|
10
|
+
runtime?: MonitorRuntime;
|
|
11
|
+
}
|
|
4
12
|
export interface PolicyReply {
|
|
5
13
|
allowed: boolean;
|
|
6
14
|
reason?: string | null;
|
|
15
|
+
workspaceRoot?: string;
|
|
7
16
|
requiresApproval?: boolean;
|
|
8
17
|
rememberable?: boolean;
|
|
9
18
|
standing?: 'full' | 'switch' | 'none';
|
|
@@ -16,13 +25,26 @@ export interface ControllerHooks {
|
|
|
16
25
|
reservedRunId: string | null;
|
|
17
26
|
nativeTurnId: string;
|
|
18
27
|
text: string;
|
|
28
|
+
model?: string | null;
|
|
29
|
+
effort?: string | null;
|
|
19
30
|
}): ActiveRun;
|
|
20
31
|
/** Whether a native tool call may run. */
|
|
21
32
|
policy(run: ActiveRun, tool: string, args: unknown): Promise<PolicyReply>;
|
|
33
|
+
/** The workspace root pinned on the run record. */
|
|
34
|
+
workspaceRoot(run: ActiveRun): string;
|
|
35
|
+
/** One-shot approval before an explicitly broad Bash command runs. */
|
|
36
|
+
workspaceEscape(run: ActiveRun, tool: string, args: unknown, reason: string): Promise<boolean>;
|
|
37
|
+
/** Whether Full Permission may bypass the filesystem boundary for this Bash command. */
|
|
38
|
+
workspaceBoundaryBypass(run: ActiveRun, tool: string, args: unknown): Promise<boolean>;
|
|
22
39
|
/** Saves a user-selected tool grant in the shared local approval store. */
|
|
23
40
|
allowToolGlobally(target: string): void;
|
|
24
41
|
/** The native conversation identity changed. */
|
|
25
42
|
native(nativeSessionId: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* The conversation opened with no turn running: show its latest parent run's rows again. `owners`
|
|
45
|
+
* are the parent run ids recorded on the native branch, oldest first.
|
|
46
|
+
*/
|
|
47
|
+
hydrate?(owners: string[]): void;
|
|
26
48
|
telemetry(event: string): void;
|
|
27
49
|
interrupt?(runId: string): Promise<void>;
|
|
28
50
|
resolveApproval?(runId: string, requestId: string, decision: ApprovalDecision): void;
|
|
@@ -37,6 +59,7 @@ export declare class TerminalController {
|
|
|
37
59
|
private run;
|
|
38
60
|
private readonly pending;
|
|
39
61
|
private readonly subagents;
|
|
62
|
+
private subagentParentRunId;
|
|
40
63
|
private ready;
|
|
41
64
|
private disposed;
|
|
42
65
|
private dirty;
|
|
@@ -67,8 +90,12 @@ export declare class TerminalController {
|
|
|
67
90
|
/** Project registry-owned questions, including grouped requests, into the terminal inbox. */
|
|
68
91
|
observe(event: RunEvent, descendant?: boolean): void;
|
|
69
92
|
/** A child event that belongs to the active terminal parent run. */
|
|
70
|
-
observeSubagent(parentRunId: string, run: RunRecord, event: RunEvent, profile?: TerminalSubagentProfile | null): void;
|
|
71
|
-
/**
|
|
93
|
+
observeSubagent(parentRunId: string, run: RunRecord, event: RunEvent, profile?: TerminalSubagentProfile | null, runtime?: Pick<TerminalSubagentRun, 'accountLabel' | 'model' | 'effort'>): void;
|
|
94
|
+
/** An event of the tracked parent run itself, shown as the `main` row; it outlives settlement. */
|
|
95
|
+
observeMain(run: RunRecord, event: RunEvent, runtime?: MonitorRuntime): void;
|
|
96
|
+
/** Shows a saved parent run and its descendants, as they ended, until another run begins. */
|
|
97
|
+
restoreMonitor(parent: MonitorEntry, children: readonly MonitorEntry[]): void;
|
|
98
|
+
/** Read-only child activity for the latest parent run, retained until another run begins. */
|
|
72
99
|
subagentSnapshot(): TerminalSubagentActivity[];
|
|
73
100
|
/** The socket grants this interface only to the process that owns terminal input. */
|
|
74
101
|
control(call: string, data: Record<string, any>): Promise<unknown>;
|
|
@@ -76,3 +103,4 @@ export declare class TerminalController {
|
|
|
76
103
|
accept(event: string, data: Record<string, any>): Promise<unknown>;
|
|
77
104
|
dispose(): void;
|
|
78
105
|
}
|
|
106
|
+
export {};
|