@agentproto/runtime 3.5.0 → 4.0.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/README.md +7 -3
- package/dist/app-ui-delivery.d.ts +75 -0
- package/dist/app-ui-delivery.mjs +144 -0
- package/dist/app-ui-delivery.mjs.map +1 -0
- package/dist/catalog-models.d.ts +5 -3
- package/dist/catalog-models.mjs.map +1 -1
- package/dist/config-schema.d.ts +134 -0
- package/dist/config-schema.mjs +3687 -0
- package/dist/config-schema.mjs.map +1 -0
- package/dist/config.d.ts +33 -3
- package/dist/config.mjs +3605 -4
- package/dist/config.mjs.map +1 -1
- package/dist/{context-continuity-ib9_bVYM.d.ts → context-continuity-Bn99UtVC.d.ts} +40 -1
- package/dist/{heartbeat-COGpMrJS.d.ts → heartbeat-BJtxbDb9.d.ts} +13 -1
- package/dist/heartbeat.d.ts +1 -1
- package/dist/index.d.ts +2194 -118
- package/dist/index.mjs +19473 -11004
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-imports.d.ts +2 -1
- package/dist/resume-strategies.d.ts +4 -3
- package/dist/resume-strategies.mjs +36 -8
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/{session-config-DbWP9RRj.d.ts → session-config-ByfVeEQJ.d.ts} +1 -1
- package/dist/session-presence.mjs +3603 -6
- package/dist/session-presence.mjs.map +1 -1
- package/dist/session-story.d.ts +10 -0
- package/dist/{spawn-defaults-CwI9Puwy.d.ts → spawn-defaults-CZj39Znq.d.ts} +146 -2
- package/dist/user-presets.d.ts +8 -2
- package/dist/user-presets.mjs +2 -1
- package/dist/user-presets.mjs.map +1 -1
- package/package.json +36 -23
package/dist/index.d.ts
CHANGED
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
import { DoctypeSpec } from '@agentproto/manifest';
|
|
2
|
-
import { B as BuildHeartbeatAgent } from './heartbeat-
|
|
3
|
-
export { H as HeartbeatAgent, a as HeartbeatRunner, R as RuntimeEvent, b as RuntimeEvents, p as parseDuration } from './heartbeat-
|
|
2
|
+
import { B as BuildHeartbeatAgent } from './heartbeat-BJtxbDb9.js';
|
|
3
|
+
export { H as HeartbeatAgent, a as HeartbeatRunner, R as RuntimeEvent, b as RuntimeEvents, p as parseDuration } from './heartbeat-BJtxbDb9.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { AcpMcpServer, AcpPermissionResolution } from '@agentproto/acp';
|
|
6
6
|
import { SessionMode } from '@agentproto/acp/client';
|
|
7
7
|
export { SessionMode } from '@agentproto/acp/client';
|
|
8
8
|
import { ChildProcess } from 'node:child_process';
|
|
9
|
-
import { R as RouteSpec, S as SessionConfig, P as Posture, C as ContextProfile, E as EffortLevel, A as AuthMethod, a as CanonicalPosture } from './session-config-
|
|
10
|
-
export { D as DeclaredAdapterMode, c as composeMode, d as decomposeMode } from './session-config-
|
|
9
|
+
import { R as RouteSpec, S as SessionConfig, P as Posture, C as ContextProfile, E as EffortLevel, A as AuthMethod, a as CanonicalPosture } from './session-config-ByfVeEQJ.js';
|
|
10
|
+
export { D as DeclaredAdapterMode, c as composeMode, d as decomposeMode } from './session-config-ByfVeEQJ.js';
|
|
11
11
|
import { CostBudget, AuthProfile, CostBudgetScope } from '@agentproto/auth';
|
|
12
12
|
export { CostBudget, CostBudgetScope } from '@agentproto/auth';
|
|
13
|
-
import { R as ResolvedContextContinuityPolicy } from './context-continuity-
|
|
13
|
+
import { S as SpawnBrowserMode, R as ResolveHeadlessBrowser, C as ContextContinuityPolicy, a as ResolvedContextContinuityPolicy } from './context-continuity-Bn99UtVC.js';
|
|
14
14
|
import { SandboxMode } from '@agentproto/command-sandbox';
|
|
15
15
|
import { AdapterHandle, SetupField, AdapterResolver, AdapterLister, CredsStore, HarnessCapabilities, AdapterEntry } from '@agentproto/provider-kit';
|
|
16
|
-
import { R as ResolvedAuthSpec,
|
|
17
|
-
export {
|
|
16
|
+
import { S as SpawnDefaultsConfig, D as DefaultsAdapterAuthConfig, R as ResolvedAuthSpec, a as DeclaredAdapterOption, A as AdapterAuthDescriptor } from './spawn-defaults-CZj39Znq.js';
|
|
17
|
+
export { b as AuthEcho, c as AuthResolutionError, C as CLAUDE_CODE_OAUTH_SOURCE, d as CredentialSource, e as DefaultsAdapterConfig, f as DeferredToolsConfig, g as ResolveSubscriptionCredentialInput, h as ResolvedSpawnAuthMaterial, i as ResolvedSpawnDefaults, j as SubscriptionCredentialResolution, k as SubscriptionSourceError, l as credentialFingerprint, n as normalizeSkillsOption, r as resolveAuthSpec, m as resolveDeferredToolsGatewayOption, o as resolveSpawnDefaults, p as resolveSubscriptionCredential } from './spawn-defaults-CZj39Znq.js';
|
|
18
18
|
import { CatalogModelsQuery, CatalogModelsResponse } from './catalog-models.js';
|
|
19
19
|
export { CatalogAdapterInput, CatalogAdapterModelInput, CatalogPricing, CatalogProduct, CatalogRoute, CatalogRouteSummary, CatalogVendor, buildCatalogModels } from './catalog-models.js';
|
|
20
20
|
import { FooterSession } from './pr-provenance.js';
|
|
21
21
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
22
|
-
import { SandboxProvider } from '@agentproto/sandbox';
|
|
22
|
+
import { SandboxProvider, SandboxSpec } from '@agentproto/sandbox';
|
|
23
23
|
import { BrainManager, ExportedSessionLike } from '@agentproto/workspace-brain';
|
|
24
24
|
export { BrainManager, BrainStats, IngestReport, IngestResult } from '@agentproto/workspace-brain';
|
|
25
25
|
import * as _agentproto_tool from '@agentproto/tool';
|
|
26
26
|
import { ToolContext } from '@agentproto/tool';
|
|
27
27
|
import { DriverHandle } from '@agentproto/driver';
|
|
28
|
-
|
|
28
|
+
import { Attestation, LedgerKey, RubricDigest, ReviewPrRef, LaneResult, ReviewLaneExecutor, LaneOutcome } from '@agentproto/review';
|
|
29
|
+
import { UserPreset } from './user-presets.js';
|
|
30
|
+
export { UserPresetsFile, deleteUserPreset, getUserPreset, listUserPresets, loadUserPresets, saveUserPreset, userPresetsPath } from './user-presets.js';
|
|
31
|
+
import { WorktreeIsolationMode, SpawnAttachMode, SpawnDedupeMode } from './config.js';
|
|
29
32
|
import { ResolvedModel } from '@agentproto/model-catalog';
|
|
30
33
|
import { FrameSink, E2eFrameSink } from '@agentproto/acp/tunnel';
|
|
31
34
|
import { DaemonIdentity } from '@agentproto/secrets/identity';
|
|
32
|
-
import { WorktreeIsolationMode } from './config.js';
|
|
33
35
|
import { WorkspaceFs } from './workspace-fs.js';
|
|
34
36
|
export { createWorkspaceFs } from './workspace-fs.js';
|
|
35
37
|
export { ConversationMeta, ConversationStore, ConversationTurn, fileConversationStore } from './conversations.js';
|
|
@@ -502,6 +504,37 @@ interface UsageDescriptorFields {
|
|
|
502
504
|
*/
|
|
503
505
|
declare function projectSessionUsage(desc: UsageDescriptorFields): SessionUsage;
|
|
504
506
|
|
|
507
|
+
/**
|
|
508
|
+
* McpAppsHostService — the daemon as the MCP client that fetches MCP App
|
|
509
|
+
* UIs (spec 2026-01-26) on behalf of a session's chat UI.
|
|
510
|
+
*
|
|
511
|
+
* In a session the MCP client is the harness (claude-code, codex, …); it
|
|
512
|
+
* keeps a tool's `_meta.ui.resourceUri` and the `ui://` resource to itself,
|
|
513
|
+
* and the transcript only carries `mcp__<server>__<tool>` + input + result.
|
|
514
|
+
* So the chat asks the daemon, which resolves `<server>` for that session
|
|
515
|
+
* (mcp-app-resolve.ts), connects through a config-keyed pool
|
|
516
|
+
* (mcp-client-pool.ts), and answers three questions:
|
|
517
|
+
*
|
|
518
|
+
* uiIndex which of this server's tools declare a UI (+ app-only tools)
|
|
519
|
+
* readUi the HTML + `_meta.ui` of one of those `ui://` resources
|
|
520
|
+
* callTool an iframe-initiated `tools/call`, allowlisted and recorded
|
|
521
|
+
*
|
|
522
|
+
* None of these throw: every failure is a `status` (or an `isError`
|
|
523
|
+
* result). Failures are cached per (session, alias) for 60s so a
|
|
524
|
+
* transcript full of calls to a dead server costs one attempt a minute.
|
|
525
|
+
*/
|
|
526
|
+
|
|
527
|
+
/** Durable record of an iframe-initiated call, appended to the session's
|
|
528
|
+
* events.jsonl as `kind: "mcp_app_tool_call"`. Never carries args or
|
|
529
|
+
* results. */
|
|
530
|
+
interface McpAppToolCallRecord {
|
|
531
|
+
server: string;
|
|
532
|
+
tool: string;
|
|
533
|
+
originToolCallId: string;
|
|
534
|
+
isError: boolean;
|
|
535
|
+
durationMs: number;
|
|
536
|
+
}
|
|
537
|
+
|
|
505
538
|
/**
|
|
506
539
|
* ONE normalized shape for a finished tool/command call — the unification
|
|
507
540
|
* target for the two disjoint logs this repo has today: `recordCommand`'s
|
|
@@ -1685,6 +1718,41 @@ declare function createTaskLedger(opts: {
|
|
|
1685
1718
|
persist?: boolean;
|
|
1686
1719
|
}): TaskLedger;
|
|
1687
1720
|
|
|
1721
|
+
/**
|
|
1722
|
+
* The single place every stable `SessionDescriptor.endedReason` /
|
|
1723
|
+
* `SessionOutcome.termination.reason` value is declared, so a UI can render
|
|
1724
|
+
* a label for each one without chasing the call site that set it.
|
|
1725
|
+
*
|
|
1726
|
+
* Two families:
|
|
1727
|
+
* - operator-issued — set ONLY by an explicit `POST /sessions/:id/kill`
|
|
1728
|
+
* or the `agent_kill` MCP tool, distinguishing an operator's deliberate
|
|
1729
|
+
* stop from every automatic teardown below;
|
|
1730
|
+
* - internal/automatic — set by the daemon itself, without an operator
|
|
1731
|
+
* in the loop, for a reason the operator couldn't have expressed.
|
|
1732
|
+
*
|
|
1733
|
+
* Backward compatible by construction: this is a value list, not a closed
|
|
1734
|
+
* validator. A descriptor persisted by an older daemon (or a newer one an
|
|
1735
|
+
* older UI doesn't know about yet) carries a `reason` string outside this
|
|
1736
|
+
* list — {@link isKnownSessionEndReason} says so, and callers should fall
|
|
1737
|
+
* back to a generic label rather than throw.
|
|
1738
|
+
*/
|
|
1739
|
+
declare const SESSION_END_REASONS: readonly ["daemon-restart", "idle-reaped", "crashed", "operator-completed", "operator-stopped", "cost-cap-exceeded", "policy-cleanup", "parent-exited", "provider-limit", "forgotten"];
|
|
1740
|
+
type SessionEndReason = (typeof SESSION_END_REASONS)[number];
|
|
1741
|
+
/** True when `reason` is one of {@link SESSION_END_REASONS}. A label
|
|
1742
|
+
* lookup, not a wire-format gate — an unrecognized string is still a
|
|
1743
|
+
* valid `endedReason` from a daemon version this build doesn't know
|
|
1744
|
+
* about; callers should render it with a generic fallback, never reject
|
|
1745
|
+
* it. */
|
|
1746
|
+
declare function isKnownSessionEndReason(reason: string | undefined): reason is SessionEndReason;
|
|
1747
|
+
/**
|
|
1748
|
+
* Classify a driver-reported error message as a provider/subscription
|
|
1749
|
+
* usage cap rather than an ordinary tool/turn failure. Used wherever the
|
|
1750
|
+
* daemon would otherwise tag a dead session with the generic `"crashed"` /
|
|
1751
|
+
* `"error"` reason, so an operator sees "wait for your quota to reset"
|
|
1752
|
+
* instead of chasing a phantom bug.
|
|
1753
|
+
*/
|
|
1754
|
+
declare function isProviderLimitError(message: string | undefined): boolean;
|
|
1755
|
+
|
|
1688
1756
|
/**
|
|
1689
1757
|
* In-process pub/sub bus for session lifecycle events. Separate from
|
|
1690
1758
|
* RuntimeEvents (global daemon bus) — session events are scoped to
|
|
@@ -1695,7 +1763,7 @@ declare function createTaskLedger(opts: {
|
|
|
1695
1763
|
* and session_monitor MCP tool (long-poll multiplexed).
|
|
1696
1764
|
*/
|
|
1697
1765
|
|
|
1698
|
-
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:awaiting-input-flagged" | "session:awaiting-question-answered" | "session:permission-request" | "session:permission-resolved" | "session:exited" | "session:reaped" | "session:stalled" | "session:stall-cleared" | "session:watcher-attached" | "session:watcher-detached" | "session:bg-tasks-parked" | "session:bg-tasks-cleared" | "session:resumed" | "session:spawned" | "session:command-done" | "session:model-changed" | "session:config-changed" | "session:renamed" | "session:pinned-changed" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed" | "activity:changed" | "task:changed" | "workflow:gate-report" | "workflow:suspended" | "workflow:suspend-resumed" | "session:harness-warning";
|
|
1766
|
+
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:awaiting-input-flagged" | "session:awaiting-question-answered" | "session:permission-request" | "session:permission-resolved" | "session:exited" | "session:reaped" | "session:stalled" | "session:stall-cleared" | "session:watcher-attached" | "session:watcher-detached" | "session:bg-tasks-parked" | "session:bg-tasks-cleared" | "session:bg-task" | "session:resumed" | "session:spawned" | "session:command-done" | "session:model-changed" | "session:config-changed" | "session:renamed" | "session:pinned-changed" | "session:message" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed" | "activity:changed" | "task:changed" | "workflow:gate-report" | "workflow:suspended" | "workflow:suspend-resumed" | "session:harness-warning";
|
|
1699
1767
|
/**
|
|
1700
1768
|
* Fixed severity vocabulary for a judge-gate finding (WP-D). Deliberately
|
|
1701
1769
|
* small and fixed so `policy_status` output is comparable across different
|
|
@@ -1769,6 +1837,13 @@ interface SessionTurnEndEvent {
|
|
|
1769
1837
|
* a normal, productive turn.
|
|
1770
1838
|
*/
|
|
1771
1839
|
empty?: boolean;
|
|
1840
|
+
/**
|
|
1841
|
+
* True when the turn was not started by a prompt: the agent woke on its
|
|
1842
|
+
* own (Claude Code's task-notification cycle after a background task
|
|
1843
|
+
* settled) and the registry tracked that work as a turn. Absent on an
|
|
1844
|
+
* ordinary prompted turn.
|
|
1845
|
+
*/
|
|
1846
|
+
autonomous?: boolean;
|
|
1772
1847
|
}
|
|
1773
1848
|
interface SessionAwaitingInputEvent {
|
|
1774
1849
|
type: "session:awaiting-input";
|
|
@@ -1865,15 +1940,14 @@ interface SessionExitedEvent {
|
|
|
1865
1940
|
status: "exited" | "killed" | "error";
|
|
1866
1941
|
label?: string;
|
|
1867
1942
|
ts: string;
|
|
1868
|
-
/** Mirrors `SessionDescriptor.endedReason` —
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
1871
|
-
* `"
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
*
|
|
1875
|
-
|
|
1876
|
-
reason?: "daemon-restart" | "idle-reaped" | "crashed";
|
|
1943
|
+
/** Mirrors `SessionDescriptor.endedReason` — see {@link SessionEndReason}
|
|
1944
|
+
* for the full, single-source enum (automatic teardowns like
|
|
1945
|
+
* `"daemon-restart"` / `"idle-reaped"` / `"crashed"` / `"cost-cap-exceeded"`
|
|
1946
|
+
* / `"provider-limit"`, and operator-issued `"operator-completed"` /
|
|
1947
|
+
* `"operator-stopped"`). Lets a watcher (completion-policy supervisor,
|
|
1948
|
+
* `session_monitor`) tell WHY this exit happened rather than just that it
|
|
1949
|
+
* did. Absent for a plain natural exit or an ordinary turn error. */
|
|
1950
|
+
reason?: SessionEndReason;
|
|
1877
1951
|
}
|
|
1878
1952
|
/**
|
|
1879
1953
|
* Emitted when the idle-session reaper (PR-6) retires a long-idle agent-cli
|
|
@@ -2024,6 +2098,29 @@ interface SessionBgTasksClearedEvent {
|
|
|
2024
2098
|
label?: string;
|
|
2025
2099
|
ts: string;
|
|
2026
2100
|
}
|
|
2101
|
+
/**
|
|
2102
|
+
* One lifecycle edge of an agent's background task (a backgrounded Bash
|
|
2103
|
+
* command, a monitor, ...) as the agent itself reported it — over ACP, the
|
|
2104
|
+
* AIR `asyncTasks` extension (see @agentproto/acp's `background-task`
|
|
2105
|
+
* StreamEvent). Unlike {@link SessionBgTasksParkedEvent} (a turn-end
|
|
2106
|
+
* heuristic) this is the real lifecycle: `"started"` when the task is
|
|
2107
|
+
* announced, `"settled"` when it reaches a terminal `status`. Mid-life
|
|
2108
|
+
* progress updates only refresh `SessionDescriptor.backgroundTasks` and are
|
|
2109
|
+
* not emitted. Same bus distribution as every other lifecycle event.
|
|
2110
|
+
*/
|
|
2111
|
+
interface SessionBgTaskEvent {
|
|
2112
|
+
type: "session:bg-task";
|
|
2113
|
+
sessionId: string;
|
|
2114
|
+
phase: "started" | "settled";
|
|
2115
|
+
taskId: string;
|
|
2116
|
+
taskKind?: string;
|
|
2117
|
+
description?: string;
|
|
2118
|
+
outputFile?: string;
|
|
2119
|
+
status?: string;
|
|
2120
|
+
summary?: string;
|
|
2121
|
+
label?: string;
|
|
2122
|
+
ts: string;
|
|
2123
|
+
}
|
|
2027
2124
|
/**
|
|
2028
2125
|
* Emitted when a dead agent-cli row is brought back IN PLACE — same session
|
|
2029
2126
|
* id, same descriptor — by the lazy resume-on-prompt path (`maybeResumeAgent`)
|
|
@@ -2163,6 +2260,27 @@ interface SessionRenamedEvent {
|
|
|
2163
2260
|
renamedByUser?: boolean;
|
|
2164
2261
|
ts: string;
|
|
2165
2262
|
}
|
|
2263
|
+
/**
|
|
2264
|
+
* A typed inter-session message (`session-message.ts`) was accepted for
|
|
2265
|
+
* `sessionId` (the RECIPIENT) — once at send (no `delivered`) and again when
|
|
2266
|
+
* it's delivered into the recipient's context (`delivered` set). Lets
|
|
2267
|
+
* `session_monitor` / SSE / the VS Code panel react without polling.
|
|
2268
|
+
*/
|
|
2269
|
+
interface SessionMessageEvent {
|
|
2270
|
+
type: "session:message";
|
|
2271
|
+
sessionId: string;
|
|
2272
|
+
messageId: string;
|
|
2273
|
+
fromSessionId?: string;
|
|
2274
|
+
relation: "child" | "parent" | "sibling" | "human" | "system";
|
|
2275
|
+
kind: "report" | "question" | "blocker" | "done" | "notice";
|
|
2276
|
+
urgency: "fyi" | "next-turn" | "steer" | "interrupt";
|
|
2277
|
+
delivered?: {
|
|
2278
|
+
via: "wait" | "steer" | "turn" | "interrupt" | "inbox";
|
|
2279
|
+
at: string;
|
|
2280
|
+
turnSeq?: number;
|
|
2281
|
+
};
|
|
2282
|
+
ts: string;
|
|
2283
|
+
}
|
|
2166
2284
|
/**
|
|
2167
2285
|
* Emitted when an operator pins or unpins a session for list visibility
|
|
2168
2286
|
* (`POST /sessions/:id/pin`, the `session_set_pinned` MCP verb). Like
|
|
@@ -2356,16 +2474,22 @@ interface WorkflowApprovalResolvedEvent {
|
|
|
2356
2474
|
}
|
|
2357
2475
|
/**
|
|
2358
2476
|
* Emitted by the workflow runner (`workflow-runner.ts`) when a `kind:
|
|
2359
|
-
* "suspend"` step parks its run awaiting an external event
|
|
2360
|
-
*
|
|
2361
|
-
* (
|
|
2362
|
-
*
|
|
2477
|
+
* "suspend"` step parks its run awaiting an external event (`on` set, no
|
|
2478
|
+
* `reason`) — OR when an agent-backed step signals AIP-58 §3(a)
|
|
2479
|
+
* `run.requestInput` (`reason: "input-required"` + `prompt`/`schema?`, no
|
|
2480
|
+
* `on`). Either way the run's status flips to `awaiting-input` with a
|
|
2481
|
+
* durable `awaitingSuspend` record, and `workflow_escalation_resolve`'s
|
|
2482
|
+
* suspend form resumes it. Same bus distribution as every other lifecycle
|
|
2483
|
+
* event.
|
|
2363
2484
|
*/
|
|
2364
2485
|
interface WorkflowSuspendedEvent {
|
|
2365
2486
|
type: "workflow:suspended";
|
|
2366
2487
|
runId: string;
|
|
2367
2488
|
stepId: string;
|
|
2368
|
-
on
|
|
2489
|
+
on?: readonly string[];
|
|
2490
|
+
reason?: "input-required";
|
|
2491
|
+
prompt?: string;
|
|
2492
|
+
schema?: Record<string, unknown>;
|
|
2369
2493
|
ts: string;
|
|
2370
2494
|
}
|
|
2371
2495
|
/**
|
|
@@ -2393,7 +2517,7 @@ interface SessionHarnessWarningEvent {
|
|
|
2393
2517
|
label?: string;
|
|
2394
2518
|
ts: string;
|
|
2395
2519
|
}
|
|
2396
|
-
type SessionEvent = SessionTurnEndEvent | SessionAwaitingInputEvent | SessionAwaitingInputFlaggedEvent | SessionAwaitingQuestionAnsweredEvent | SessionPermissionRequestEvent | SessionPermissionResolvedEvent | SessionExitedEvent | SessionReapedEvent | SessionStalledEvent | SessionStallClearedEvent | SessionWatcherAttachedEvent | SessionWatcherDetachedEvent | SessionBgTasksParkedEvent | SessionBgTasksClearedEvent | SessionResumedEvent | SessionSpawnedEvent | SessionCommandDoneEvent | SessionModelChangedEvent | SessionConfigChangedEvent | SessionRenamedEvent | SessionPinnedEvent | PolicyPassedEvent | PolicyFailedEvent | PolicyCommitReadyEvent | PolicyCommittedEvent | CronFiredEvent | CronSucceededEvent | CronFailedEvent | ActivityChangedEvent | TaskChangedEvent | WorkflowGateReportEvent | WorkflowApprovalRequestedEvent | WorkflowApprovalResolvedEvent | WorkflowSuspendedEvent | WorkflowSuspendResumedEvent | SessionHarnessWarningEvent;
|
|
2520
|
+
type SessionEvent = SessionTurnEndEvent | SessionAwaitingInputEvent | SessionAwaitingInputFlaggedEvent | SessionAwaitingQuestionAnsweredEvent | SessionPermissionRequestEvent | SessionPermissionResolvedEvent | SessionExitedEvent | SessionReapedEvent | SessionStalledEvent | SessionStallClearedEvent | SessionWatcherAttachedEvent | SessionWatcherDetachedEvent | SessionBgTasksParkedEvent | SessionBgTasksClearedEvent | SessionBgTaskEvent | SessionResumedEvent | SessionSpawnedEvent | SessionCommandDoneEvent | SessionModelChangedEvent | SessionConfigChangedEvent | SessionRenamedEvent | SessionPinnedEvent | SessionMessageEvent | PolicyPassedEvent | PolicyFailedEvent | PolicyCommitReadyEvent | PolicyCommittedEvent | CronFiredEvent | CronSucceededEvent | CronFailedEvent | ActivityChangedEvent | TaskChangedEvent | WorkflowGateReportEvent | WorkflowApprovalRequestedEvent | WorkflowApprovalResolvedEvent | WorkflowSuspendedEvent | WorkflowSuspendResumedEvent | SessionHarnessWarningEvent;
|
|
2397
2521
|
interface SessionEventBus {
|
|
2398
2522
|
emit(ev: SessionEvent): void;
|
|
2399
2523
|
/** Subscribe to a specific event type. Returns an unsubscribe fn. */
|
|
@@ -2639,50 +2763,192 @@ declare class TunnelRegistry {
|
|
|
2639
2763
|
private loadFromDisk;
|
|
2640
2764
|
}
|
|
2641
2765
|
|
|
2766
|
+
/**
|
|
2767
|
+
* RemoteController — owns the gateway's "publish to the internet" state.
|
|
2768
|
+
*
|
|
2769
|
+
* One singleton per gateway. Holds:
|
|
2770
|
+
* - the current tunnel provider's child process (cloudflared, …)
|
|
2771
|
+
* - the bearer token gating /mcp once the tunnel is up
|
|
2772
|
+
* - persisted state in `<workspace>/.agentproto/remote.json`
|
|
2773
|
+
*
|
|
2774
|
+
* The controller is the *only* component that mutates auth at runtime.
|
|
2775
|
+
* The HTTP server reads auth via a getter (see `AuthSource` in
|
|
2776
|
+
* http-server.ts), so flipping `enable() / disable()` here takes effect
|
|
2777
|
+
* on the next request — no restart, no race.
|
|
2778
|
+
*
|
|
2779
|
+
* ## Provider model
|
|
2780
|
+
*
|
|
2781
|
+
* Each provider implements `RemoteProvider` (start / stop / status).
|
|
2782
|
+
* v1 ships only `quick` (Cloudflare Quick Tunnel — no API key, no DNS,
|
|
2783
|
+
* ephemeral `*.trycloudflare.com` URL). Named CF Tunnel and Tailscale
|
|
2784
|
+
* land as additional implementations.
|
|
2785
|
+
*
|
|
2786
|
+
* ## Token model
|
|
2787
|
+
*
|
|
2788
|
+
* On enable we generate a 32-byte random bearer token, return it once
|
|
2789
|
+
* to the caller, and persist only its sha256 hash to disk. Same model
|
|
2790
|
+
* as a Stripe API key — losing the plaintext means rotating, not
|
|
2791
|
+
* recovering. This keeps `.agentproto/remote.json` safe to commit by
|
|
2792
|
+
* accident (it leaks the URL, not the credential).
|
|
2793
|
+
*
|
|
2794
|
+
* ## Security note
|
|
2795
|
+
*
|
|
2796
|
+
* The CF API token (when used by named-tunnel provider) is *never*
|
|
2797
|
+
* accepted as MCP tool input. The controller reads it from
|
|
2798
|
+
* `~/.config/agentproto/cloudflare.json` or `$CLOUDFLARE_API_TOKEN`.
|
|
2799
|
+
* Otherwise a remote agent could exfiltrate it through `remote_enable`.
|
|
2800
|
+
*/
|
|
2801
|
+
|
|
2802
|
+
interface EnableInput {
|
|
2803
|
+
provider?: "quick";
|
|
2804
|
+
/**
|
|
2805
|
+
* Local port to expose. Defaults to the gateway's own port — i.e.
|
|
2806
|
+
* "publish this MCP server." Pass any other port to expose a
|
|
2807
|
+
* different local service (Supabase 54371, a Vite dev server, …)
|
|
2808
|
+
* without spinning up a separate tunnel manager.
|
|
2809
|
+
*/
|
|
2810
|
+
targetPort?: number;
|
|
2811
|
+
/**
|
|
2812
|
+
* Host the tunnel forwards to. Defaults to `127.0.0.1`. Setting it
|
|
2813
|
+
* to `localhost` resolves through DNS (IPv6 first on most systems);
|
|
2814
|
+
* keep `127.0.0.1` unless the target is explicitly IPv6-bound.
|
|
2815
|
+
*/
|
|
2816
|
+
targetHost?: string;
|
|
2817
|
+
}
|
|
2818
|
+
interface EnableResult {
|
|
2819
|
+
publicUrl: string;
|
|
2820
|
+
/**
|
|
2821
|
+
* Bearer token issued by this gateway. Only meaningful when the
|
|
2822
|
+
* tunnel exposes the gateway itself (default). For arbitrary-target
|
|
2823
|
+
* tunnels (`targetPort != gateway.port`) the daemon does not gate
|
|
2824
|
+
* the proxied service, and this is omitted.
|
|
2825
|
+
*/
|
|
2826
|
+
bearerToken?: string;
|
|
2827
|
+
/**
|
|
2828
|
+
* `<publicUrl>/mcp`. Only emitted when exposing the gateway.
|
|
2829
|
+
*/
|
|
2830
|
+
mcpEndpoint?: string;
|
|
2831
|
+
/**
|
|
2832
|
+
* Paste-ready `.mcp.json` snippet. Only emitted when exposing the
|
|
2833
|
+
* gateway.
|
|
2834
|
+
*/
|
|
2835
|
+
mcpConfigSnippet?: string;
|
|
2836
|
+
/**
|
|
2837
|
+
* A single link to open on a phone (PHONE-PLAN.md P1.2) — the token rides
|
|
2838
|
+
* in a URL *fragment* (`#token=`), never a `?` query string, since
|
|
2839
|
+
* fragments never reach a server (no Referer, no access/proxy log, no CDN
|
|
2840
|
+
* cache key). Two shapes, chosen by whether this daemon has the
|
|
2841
|
+
* `@agentik/session-chat` app installed with a UI:
|
|
2842
|
+
* - installed: `<publicUrl>/apps/@agentik/session-chat/ui#token=<t>` —
|
|
2843
|
+
* the phone lands directly in Control Center.
|
|
2844
|
+
* - not installed: `https://cli.agentproto.sh/panel#daemon=<publicUrl>&token=<t>`
|
|
2845
|
+
* — the hosted panel, which speaks the same fragment shape (see
|
|
2846
|
+
* agentproto/cli-site's `readFragmentConnection`).
|
|
2847
|
+
* Only emitted when exposing the gateway (same condition as `bearerToken`)
|
|
2848
|
+
* — a passthrough tunnel has no daemon UI to link to.
|
|
2849
|
+
*/
|
|
2850
|
+
phoneUrl?: string;
|
|
2851
|
+
provider: "quick";
|
|
2852
|
+
target: {
|
|
2853
|
+
host: string;
|
|
2854
|
+
port: number;
|
|
2855
|
+
};
|
|
2856
|
+
exposesGateway: boolean;
|
|
2857
|
+
/**
|
|
2858
|
+
* Present ONLY for passthrough tunnels (`exposesGateway === false`):
|
|
2859
|
+
* the daemon does not gate that traffic, so the public URL reaches the
|
|
2860
|
+
* upstream service with no auth from the daemon. A machine-readable flag
|
|
2861
|
+
* so UIs/agents can surface the exposure instead of it being buried in
|
|
2862
|
+
* the tool's prose description.
|
|
2863
|
+
*/
|
|
2864
|
+
warning?: string;
|
|
2865
|
+
}
|
|
2866
|
+
interface RemoteStatus {
|
|
2867
|
+
enabled: boolean;
|
|
2868
|
+
provider?: "quick";
|
|
2869
|
+
publicUrl?: string;
|
|
2870
|
+
pid?: number | null;
|
|
2871
|
+
createdAt?: string;
|
|
2872
|
+
target?: {
|
|
2873
|
+
host: string;
|
|
2874
|
+
port: number;
|
|
2875
|
+
};
|
|
2876
|
+
exposesGateway?: boolean;
|
|
2877
|
+
/** Last error from the provider, if any (since last enable). */
|
|
2878
|
+
lastError?: string;
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2642
2881
|
/**
|
|
2643
2882
|
* Daemon-side pairing registry (design: DESIGN §3/§4, PLAN deliverable 2).
|
|
2644
2883
|
*
|
|
2645
2884
|
* Owns everything the daemon needs to be *paired with* over an untrusted
|
|
2646
2885
|
* rendezvous:
|
|
2647
2886
|
*
|
|
2648
|
-
* - **Offer store** — in-memory, single-use, expiry-checked one-time
|
|
2649
|
-
* minted by `pair offer`. A daemon restart voids outstanding offers
|
|
2650
|
-
* (acceptable + documented). The
|
|
2651
|
-
*
|
|
2887
|
+
* - **Offer store** — in-memory, single-use, expiry-checked one-time offer
|
|
2888
|
+
* secrets minted by `pair offer`. A daemon restart voids outstanding offers
|
|
2889
|
+
* (acceptable + documented). The daemon parks on the offer's ROUTE token and
|
|
2890
|
+
* the handshake's `verifyAuthToken` predicate checks the sealed AUTH token,
|
|
2891
|
+
* SPENDING the offer on the first successful handshake (a wrong token spends
|
|
2892
|
+
* nothing).
|
|
2652
2893
|
* - **Pairings store** — `~/.agentproto/pairings.json` (0600, atomic write),
|
|
2653
2894
|
* one record per paired client: `{clientPub, name, fingerprint, createdAt,
|
|
2654
2895
|
* lastSeen, pairRoot, rendezvousUrl}`. `pairRoot` is the long-term shared
|
|
2655
2896
|
* secret (`derivePairRoot`) from which reconnect routing tokens derive.
|
|
2656
2897
|
* - **Rendezvous connections** — for a fresh offer, and for every persisted
|
|
2657
2898
|
* pairing on boot (autoconnect), the daemon dials the rendezvous *outbound*
|
|
2658
|
-
* (`side=daemon&t=<
|
|
2899
|
+
* (`side=daemon&t=<route>`), runs `daemonHandshakeOverSink` with the P1
|
|
2659
2900
|
* crypto, and — on success — serves the spliced, E2E-wrapped channel exactly
|
|
2660
2901
|
* like `serve --connect` serves a tunnel host. The serving path itself is
|
|
2661
2902
|
* injected (`serve`) so this module stays free of pty/adapter concerns and
|
|
2662
2903
|
* the CLI can reuse its `createTunnelServer` config verbatim.
|
|
2663
|
-
* - **Reconnect epochs** — a persisted pairing's standing connection
|
|
2664
|
-
* pairing-derived
|
|
2665
|
-
*
|
|
2904
|
+
* - **Reconnect epochs** — a persisted pairing's standing connection parks on
|
|
2905
|
+
* the pairing-derived route `HKDF(pairRoot, "rv-route"‖epoch)`, rotated per
|
|
2906
|
+
* UTC day. The daemon parks on BOTH the current and previous
|
|
2666
2907
|
* epoch tokens so a client whose clock straddles midnight still finds it;
|
|
2667
2908
|
* reconnect-with-backoff keeps the standing connection alive.
|
|
2668
|
-
* - **Revocation** — removing a pairing drops its rendezvous connections
|
|
2669
|
-
*
|
|
2909
|
+
* - **Revocation** — removing a pairing drops its rendezvous connections, so
|
|
2910
|
+
* it can no longer be served. For a grace period (`revokedGraceMs`, default
|
|
2911
|
+
* 14 days) the daemon keeps a *tombstone*: it still parks on the pairing's
|
|
2912
|
+
* epoch ROUTES, completes the (daemon-signed) handshake only for a hello
|
|
2913
|
+
* carrying that epoch's AUTH token, and answers with a single E2E-encrypted
|
|
2914
|
+
* `error{code:"pairing_revoked"}` frame before closing — never serving the
|
|
2915
|
+
* channel. That is what lets a client tell "unpaired" from "daemon
|
|
2916
|
+
* offline" (which both otherwise look like a park timeout at the broker)
|
|
2917
|
+
* and stop retrying. The signal is authenticated like every tunnel frame:
|
|
2918
|
+
* it arrives inside the AEAD channel of a handshake whose transcript the
|
|
2919
|
+
* client verified against the pinned daemon key, so the broker can't forge
|
|
2920
|
+
* it; and the broker, which knows the routes, can't elicit it either (no
|
|
2921
|
+
* auth token). A tombstone keeps only the per-epoch route + auth tokens for
|
|
2922
|
+
* its window — the pair root is dropped at revoke.
|
|
2670
2923
|
*
|
|
2671
2924
|
* ## Reconnect authentication (why no stable client key)
|
|
2672
2925
|
*
|
|
2673
|
-
*
|
|
2674
|
-
* handshake) — there is no persistent client identity key
|
|
2675
|
-
*
|
|
2676
|
-
*
|
|
2677
|
-
*
|
|
2678
|
-
*
|
|
2679
|
-
* `
|
|
2680
|
-
*
|
|
2681
|
-
*
|
|
2682
|
-
*
|
|
2926
|
+
* The handshake carries only a client *ephemeral* key (regenerated per
|
|
2927
|
+
* handshake) — there is no persistent client identity key. So a reconnect
|
|
2928
|
+
* authenticates the client by **possession of the epoch AUTH token**
|
|
2929
|
+
* `HKDF(pairRoot, "rv-auth"‖epoch)`, which derives from `pairRoot` — a secret
|
|
2930
|
+
* only the paired client and daemon share (it fell out of the original ECDH).
|
|
2931
|
+
* The daemon parks on the pairing's epoch ROUTE, and on that connection the
|
|
2932
|
+
* `verifyAuthToken` predicate accepts a hello whose sealed auth equals the same
|
|
2933
|
+
* epoch's auth token (constant-time). The route and auth are separate one-way
|
|
2934
|
+
* HKDF outputs: the broker sees every route and can't compute an auth from it.
|
|
2935
|
+
* (pair/v1 used ONE value for both, so a broker could replay a logged route as
|
|
2936
|
+
* the proof and be served.) The stored `fingerprint` (of the first handshake's
|
|
2937
|
+
* ephemeral key) is a stable display/revocation handle, not an auth input.
|
|
2938
|
+
*
|
|
2939
|
+
* ## Legacy (pair/v1) pairings
|
|
2940
|
+
*
|
|
2941
|
+
* A v1 `pairings.json` is loaded with every record flagged `legacy`: listed and
|
|
2942
|
+
* revocable, never served. The daemon still parks on a legacy pairing's routes
|
|
2943
|
+
* (the epoch route is unchanged from v1) so that pairing's not-yet-upgraded
|
|
2944
|
+
* client reaches it and is told to re-pair — see `respondToLegacyHandshake` —
|
|
2945
|
+
* rather than timing out. v1 records are not upgraded in place: v1 let the
|
|
2946
|
+
* broker pair as a client, so any v1 record may be the broker's own.
|
|
2683
2947
|
*/
|
|
2684
2948
|
|
|
2685
|
-
|
|
2949
|
+
/** `pairings.json` format. v2 = pairings made under pair/v2 (route/auth
|
|
2950
|
+
* split). A v1 file still loads, every record flagged `legacy`. */
|
|
2951
|
+
declare const PAIRINGS_VERSION: 2;
|
|
2686
2952
|
/** One persisted pairing. Written verbatim to `pairings.json`. */
|
|
2687
2953
|
interface PairingRecord {
|
|
2688
2954
|
/** The client ephemeral public key from the FIRST handshake (a snapshot —
|
|
@@ -2701,6 +2967,9 @@ interface PairingRecord {
|
|
|
2701
2967
|
pairRoot: string;
|
|
2702
2968
|
/** Rendezvous endpoint to reconnect through. */
|
|
2703
2969
|
rendezvousUrl: string;
|
|
2970
|
+
/** Set on a pairing made under the retired pair/v1 protocol: listed and
|
|
2971
|
+
* revocable, never served — its client is told to re-pair. */
|
|
2972
|
+
legacy?: true;
|
|
2704
2973
|
}
|
|
2705
2974
|
/** Mode of a served channel — first-contact offer vs. an established reconnect. */
|
|
2706
2975
|
type PairingChannelMode = "offer" | "reconnect";
|
|
@@ -2718,8 +2987,9 @@ interface PairingChannelHandle {
|
|
|
2718
2987
|
close(): Promise<void>;
|
|
2719
2988
|
}
|
|
2720
2989
|
interface CreatedOffer {
|
|
2721
|
-
/** The one-time offer
|
|
2722
|
-
|
|
2990
|
+
/** The one-time offer secret (base64url) — the URL's `s`. Never on the wire:
|
|
2991
|
+
* the broker only ever sees its derived route. */
|
|
2992
|
+
secret: string;
|
|
2723
2993
|
/** Offer expiry, unix seconds. */
|
|
2724
2994
|
exp: number;
|
|
2725
2995
|
/** The full `agentproto://pair?…` offer URL. */
|
|
@@ -2772,6 +3042,10 @@ interface PairingRegistryDeps {
|
|
|
2772
3042
|
/** How long a parked daemon socket waits for a client hello before recycling
|
|
2773
3043
|
* the connection. Kept just under the broker's park timeout. Default 110s. */
|
|
2774
3044
|
handshakeTimeoutMs?: number;
|
|
3045
|
+
/** How long a revoked pairing is still answered with `pairing_revoked` (see
|
|
3046
|
+
* "Revocation" above). Default 14 days; `0` disables tombstones, so a
|
|
3047
|
+
* revoked client just stops finding the daemon. */
|
|
3048
|
+
revokedGraceMs?: number;
|
|
2775
3049
|
}
|
|
2776
3050
|
interface PairingRegistry {
|
|
2777
3051
|
/** Mint a one-time offer + start dialing the rendezvous for it. */
|
|
@@ -2832,6 +3106,17 @@ interface SandboxProviderHandle extends AdapterHandle {
|
|
|
2832
3106
|
* credentials (e.g. `local`).
|
|
2833
3107
|
*/
|
|
2834
3108
|
readonly setupFields?: readonly SetupField[];
|
|
3109
|
+
/**
|
|
3110
|
+
* The directory INSIDE the box a spawned agent session should default to
|
|
3111
|
+
* when the caller passed no explicit `cwd` — e.g. e2b/Box's login home
|
|
3112
|
+
* `/home/user`. Absent for a same-machine passthrough provider (`local`),
|
|
3113
|
+
* where the HOST's own resolved cwd is already a valid path in the box
|
|
3114
|
+
* (they're the same filesystem) and forwarding it as-is is correct.
|
|
3115
|
+
* Presence of this field is also the signal `bootSandboxAgentSession`
|
|
3116
|
+
* uses to reject an explicit HOST-only path (e.g. `/Volumes/...`) instead
|
|
3117
|
+
* of forwarding it into a box where it can never resolve.
|
|
3118
|
+
*/
|
|
3119
|
+
readonly defaultCwd?: string;
|
|
2835
3120
|
}
|
|
2836
3121
|
|
|
2837
3122
|
/**
|
|
@@ -3331,12 +3616,21 @@ interface OrchestratorGatewayDeps {
|
|
|
3331
3616
|
* spawn is rejected with `sandbox_provider_not_found`, exactly as the
|
|
3332
3617
|
* root gateway would be without it. */
|
|
3333
3618
|
resolveSandboxProvider?: SandboxProviderResolver;
|
|
3334
|
-
/**
|
|
3335
|
-
*
|
|
3336
|
-
*
|
|
3337
|
-
*
|
|
3338
|
-
*
|
|
3619
|
+
/** EXPLICIT override for config.json `defaults.agentPromptInterrupt` —
|
|
3620
|
+
* wins over the fresh per-call resolve (`resolveMessagingDefaults`,
|
|
3621
|
+
* see the factory body below). Tests inject this to pin a value without
|
|
3622
|
+
* touching the filesystem; production leaves it unset so every request
|
|
3623
|
+
* reads the live config, hot-applying a `config_set` change with no
|
|
3624
|
+
* restart. Forwarded to `registerSessionTools`. */
|
|
3339
3625
|
defaultAgentPromptInterrupt?: boolean;
|
|
3626
|
+
/** EXPLICIT override for config.json `defaults.messaging.allowSiblings` —
|
|
3627
|
+
* see `defaultAgentPromptInterrupt` above for the override/resolve
|
|
3628
|
+
* precedence. Forwarded to `registerAgentTools`. */
|
|
3629
|
+
messagingAllowSiblings?: boolean;
|
|
3630
|
+
/** EXPLICIT override for config.json `defaults.messaging.agentInterrupt` —
|
|
3631
|
+
* see `defaultAgentPromptInterrupt` above for the override/resolve
|
|
3632
|
+
* precedence. Forwarded to `registerAgentTools`. */
|
|
3633
|
+
messagingAgentInterrupt?: "allow" | "deny";
|
|
3340
3634
|
}
|
|
3341
3635
|
type OrchestratorMcpServerFactory = (scope: OrchestratorScope) => Promise<McpServer>;
|
|
3342
3636
|
/**
|
|
@@ -3391,7 +3685,7 @@ interface OrphanReaperRegistry {
|
|
|
3391
3685
|
list(opts?: {
|
|
3392
3686
|
includeArchived?: boolean;
|
|
3393
3687
|
}): readonly SessionDescriptor[];
|
|
3394
|
-
kill(id: string, signal?: NodeJS.Signals): boolean;
|
|
3688
|
+
kill(id: string, signal?: NodeJS.Signals, reason?: SessionEndReason): boolean;
|
|
3395
3689
|
}
|
|
3396
3690
|
/**
|
|
3397
3691
|
* Reap a dying parent's live descendants (WP-B — orphan reaping). A
|
|
@@ -3579,6 +3873,77 @@ declare function createActivityProjector(opts: {
|
|
|
3579
3873
|
resolvePrState?: PrStateResolver;
|
|
3580
3874
|
}): ActivityProjector;
|
|
3581
3875
|
|
|
3876
|
+
/**
|
|
3877
|
+
* Spawn-time role profiles — the primitive that decides whether a
|
|
3878
|
+
* spawned agent may itself delegate (spawn further children).
|
|
3879
|
+
*
|
|
3880
|
+
* A role is 3 layers:
|
|
3881
|
+
* - `disposition` — a system-prompt fragment. Soft: sets the mindset.
|
|
3882
|
+
* - `toolPolicy` — whether delegation tools are injected into the
|
|
3883
|
+
* child at all. HARD: enforced by the daemon at the `agent_start`
|
|
3884
|
+
* injection point (`session-spawn.ts`), not by the child's own
|
|
3885
|
+
* behaviour. A child cannot widen its own `toolPolicy` — not via
|
|
3886
|
+
* `promptAppend`, not by requesting `orchestrator` itself.
|
|
3887
|
+
* - `skills[]` — role-specific skill set (built-ins ship empty/
|
|
3888
|
+
* unset; a future pack-carried role can populate this).
|
|
3889
|
+
*
|
|
3890
|
+
* Why the asymmetry matters: a process can bring its own disposition
|
|
3891
|
+
* and skills (those are portable, could live in a skill/pack), but it
|
|
3892
|
+
* can never strip tools the daemon already injected into it. Only the
|
|
3893
|
+
* spawner controls that — which is exactly why `toolPolicy` must be
|
|
3894
|
+
* resolved and enforced here, at spawn time, rather than left to a
|
|
3895
|
+
* prompt instruction the model could rationalize past.
|
|
3896
|
+
*/
|
|
3897
|
+
|
|
3898
|
+
type DelegationPolicy = "allow" | "deny";
|
|
3899
|
+
interface RoleToolPolicy {
|
|
3900
|
+
delegation: DelegationPolicy;
|
|
3901
|
+
}
|
|
3902
|
+
interface RoleProfile {
|
|
3903
|
+
name: string;
|
|
3904
|
+
disposition: string;
|
|
3905
|
+
toolPolicy: RoleToolPolicy;
|
|
3906
|
+
skills?: string[];
|
|
3907
|
+
/**
|
|
3908
|
+
* Privilege level in the spawn lattice. Higher = more privileged.
|
|
3909
|
+
* The default spawn-gate rule (`canSpawn`) is non-escalation: a
|
|
3910
|
+
* parent may spawn a child only when `child.level <= parent.level`
|
|
3911
|
+
* — peers and subordinates are fine, spawning something MORE
|
|
3912
|
+
* privileged than yourself is not. (Unbounded same-level recursion —
|
|
3913
|
+
* e.g. supervisor spawning supervisor spawning supervisor — is a
|
|
3914
|
+
* pre-existing, deliberate pattern bounded separately by
|
|
3915
|
+
* `maxDepth`/`maxChildren`, not this lattice; see `spawnableRoles`
|
|
3916
|
+
* below for a role that also needs to cap recursion itself.)
|
|
3917
|
+
* `spawnableRoles` (below), when set, opts a role into a closed
|
|
3918
|
+
* allowlist instead — level is then only used for display/ordering.
|
|
3919
|
+
*/
|
|
3920
|
+
level: number;
|
|
3921
|
+
/**
|
|
3922
|
+
* Closed allowlist of role names this role may spawn, by name — the
|
|
3923
|
+
* opt-in "figé pipeline" mode. When set, `canSpawn` checks name
|
|
3924
|
+
* membership instead of the level comparison. Undefined (the
|
|
3925
|
+
* default, open mode) ⇒ non-escalation by `level`.
|
|
3926
|
+
*/
|
|
3927
|
+
spawnableRoles?: string[];
|
|
3928
|
+
/**
|
|
3929
|
+
* Role-level default for the daemon self-mount's deferred/lazy tool
|
|
3930
|
+
* loading (harness-parity item 3 — see `deferred-tools.ts`). Applied to
|
|
3931
|
+
* the injected `mcpServers` entry (`session-spawn.ts`'s
|
|
3932
|
+
* `shouldInjectDaemonSelfMount` path) as `?deferred=1|0` when the spawn
|
|
3933
|
+
* itself didn't pass an explicit `deferredTools` override. Undefined ⇒
|
|
3934
|
+
* no role-level opinion, the gateway's own boot-time default
|
|
3935
|
+
* (`defaults.mcp.deferredTools` in config.json) applies unchanged.
|
|
3936
|
+
*/
|
|
3937
|
+
deferredTools?: boolean;
|
|
3938
|
+
/**
|
|
3939
|
+
* Role-level default for `agent_start.browser` (see `browser-mount.ts`):
|
|
3940
|
+
* `"headless"` gives every spawn of this role its own isolated headless
|
|
3941
|
+
* Chrome. An explicit spawn `browser` wins; undefined ⇒ no opinion (the
|
|
3942
|
+
* user preset, then `defaults.spawn.browser`, decide).
|
|
3943
|
+
*/
|
|
3944
|
+
browser?: SpawnBrowserMode;
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3582
3947
|
/**
|
|
3583
3948
|
* Daemon-side AGENTS.md resolution + injection (WP-R2).
|
|
3584
3949
|
*
|
|
@@ -3607,7 +3972,44 @@ declare function createActivityProjector(opts: {
|
|
|
3607
3972
|
* absent — plus a standing cd-contract sentence regardless of mode.
|
|
3608
3973
|
*/
|
|
3609
3974
|
type AgentsMdMode = "inline" | "pointer" | "absent";
|
|
3975
|
+
/** The resolved AGENTS.md's absolute path; undefined when mode is "absent". */
|
|
3976
|
+
interface AgentsMdResolution {
|
|
3977
|
+
mode: AgentsMdMode;
|
|
3978
|
+
/** Absolute path of the resolved AGENTS.md. Undefined when mode is
|
|
3979
|
+
* `"absent"`. */
|
|
3980
|
+
path?: string;
|
|
3981
|
+
/** Full text of the AGENTS.md (inline mode only). */
|
|
3982
|
+
content?: string;
|
|
3983
|
+
/** The prompt block to inject (full inline text or a pointer), or
|
|
3984
|
+
* undefined when absent. Excludes the always-present cd-contract line. */
|
|
3985
|
+
block?: string;
|
|
3986
|
+
/** The standing cd-contract sentence, present in every mode. */
|
|
3987
|
+
contractLine: string;
|
|
3988
|
+
}
|
|
3989
|
+
|
|
3990
|
+
interface WorkspaceRulesResolution {
|
|
3991
|
+
/** Absolute path of the resolved RULES.md. Undefined when absent (or a
|
|
3992
|
+
* read failure degraded to absent). */
|
|
3993
|
+
path?: string;
|
|
3994
|
+
/** Full text of the RULES.md, inlined. Present exactly when `block` is. */
|
|
3995
|
+
content?: string;
|
|
3996
|
+
/** The prompt block to inject, or undefined when absent. */
|
|
3997
|
+
block?: string;
|
|
3998
|
+
}
|
|
3610
3999
|
|
|
4000
|
+
/** The `appServe` request carried on `agent_start` — an in-box app dir plus
|
|
4001
|
+
* the port to serve its UI on. */
|
|
4002
|
+
interface SandboxAppServeSpec {
|
|
4003
|
+
/** Absolute path to the app's directory INSIDE the box (e.g.
|
|
4004
|
+
* `/home/user/apps/<slug>`). Must not contain a single quote — the
|
|
4005
|
+
* launcher shell-quotes it. */
|
|
4006
|
+
dir: string;
|
|
4007
|
+
/** Port `agentproto app serve` binds inside the box. Must also be exposed
|
|
4008
|
+
* by the provider (the spawn path appends it to `extraPorts` so a
|
|
4009
|
+
* boot-time exposure exists on providers that pre-resolve). Defaults to
|
|
4010
|
+
* `DEFAULT_APP_SERVE_PORT` when omitted. */
|
|
4011
|
+
port?: number;
|
|
4012
|
+
}
|
|
3611
4013
|
/** What a served app records on the session descriptor and echoes in the
|
|
3612
4014
|
* spawn result — non-secret, caller-visible. */
|
|
3613
4015
|
interface SessionAppServeInfo {
|
|
@@ -3833,6 +4235,436 @@ declare function loadWorktreeIsolation(loadCfg?: () => Promise<{
|
|
|
3833
4235
|
};
|
|
3834
4236
|
}>): Promise<WorktreeIsolationMode>;
|
|
3835
4237
|
|
|
4238
|
+
/**
|
|
4239
|
+
* Policy layer for `agent_start.attach` — the config-driven decision of WHO a
|
|
4240
|
+
* spawn nests under, kept deliberately separate (and pure) from the spawn
|
|
4241
|
+
* plumbing in `session-spawn.ts`, exactly as `worktree-isolation.ts` is for
|
|
4242
|
+
* `agent_start.worktree`.
|
|
4243
|
+
*
|
|
4244
|
+
* The problem it fixes: on the plain `/mcp` path (no scoped orchestrator
|
|
4245
|
+
* gateway), a spawn was attributed to a parent ONLY when the caller passed an
|
|
4246
|
+
* explicit `parentSessionId` hint — so a supervisor that spawned an executor
|
|
4247
|
+
* without wiring itself as an orchestrator produced a depth-0 ORPHAN. The
|
|
4248
|
+
* daemon already knows the caller's own id on that path (the trusted
|
|
4249
|
+
* `?callerSessionId=` query the self-ref `mcpServers` URL carries — PR 7 /
|
|
4250
|
+
* Gap 7), it just wasn't being used for lineage. This module decides whether
|
|
4251
|
+
* to use it.
|
|
4252
|
+
*
|
|
4253
|
+
* Trust boundary (unchanged from the hint): the scoped `/mcp/orchestrator`
|
|
4254
|
+
* gateway's token is the UNSPOOFABLE source — when a `callerScope` is present
|
|
4255
|
+
* the caller derives its parent from the token and this whole module is
|
|
4256
|
+
* bypassed (see `session-spawn.ts`). Everything here is descriptor-only
|
|
4257
|
+
* lineage on the anonymous root path; it never moves the gating `childDepth`
|
|
4258
|
+
* and so never relaxes a depth-gated worktree/role guard.
|
|
4259
|
+
*/
|
|
4260
|
+
|
|
4261
|
+
/**
|
|
4262
|
+
* The `agent_start.attach` field. `true` opts in to attaching under the
|
|
4263
|
+
* derived parent (the caller's own id / an explicit hint) even when the
|
|
4264
|
+
* policy is `on-request`; an object additionally pins an explicit parent id;
|
|
4265
|
+
* `false` forces an INDEPENDENT root (no parent, depth 0) regardless of
|
|
4266
|
+
* policy or derivable identity — the deliberate "launch detached" escape
|
|
4267
|
+
* hatch, mirroring `worktree: false`. Omitted ⇒ the policy mode decides.
|
|
4268
|
+
*/
|
|
4269
|
+
type AttachField = boolean | {
|
|
4270
|
+
parent?: string;
|
|
4271
|
+
};
|
|
4272
|
+
|
|
4273
|
+
/**
|
|
4274
|
+
* Shared `agent_start` spawn logic — orchestrator scoped sub-gateway
|
|
4275
|
+
* minting, `mcpServers` merge, hermes default-mcpServers safety net,
|
|
4276
|
+
* depth/quota checks. Extracted from `agent-tools.ts` (the MCP tool)
|
|
4277
|
+
* so the HTTP route can reuse it without re-implementing (and
|
|
4278
|
+
* re-drifting from) the same behaviour.
|
|
4279
|
+
*/
|
|
4280
|
+
|
|
4281
|
+
/** `agent_start.sandbox`'s inline-spec form, plus the PR3 reuse field. See
|
|
4282
|
+
* `SpawnAgentSessionInput.sandbox`. */
|
|
4283
|
+
type SandboxSpecInput = SandboxSpec & {
|
|
4284
|
+
reuse?: string;
|
|
4285
|
+
};
|
|
4286
|
+
/** Matches `RegisterAgentToolsOptions.buildOrchestratorMcp` in
|
|
4287
|
+
* agent-tools.ts — kept as its own alias here since that's the shape
|
|
4288
|
+
* actually passed in (opts required), not the more permissive
|
|
4289
|
+
* `OrchestratorInjector` (opts optional) from orchestrator-gateway.ts. */
|
|
4290
|
+
type BuildOrchestratorMcp = (opts: {
|
|
4291
|
+
tools?: readonly string[];
|
|
4292
|
+
caller?: OrchestratorScope;
|
|
4293
|
+
maxDepth?: number;
|
|
4294
|
+
maxChildren?: number;
|
|
4295
|
+
role?: string;
|
|
4296
|
+
}) => {
|
|
4297
|
+
entry: AcpMcpServer;
|
|
4298
|
+
bindLifecycle: (sessionId: string) => () => void;
|
|
4299
|
+
/** The minted scope — only `tools` (the effective, narrowed allowlist)
|
|
4300
|
+
* is read here, to tell whether the child can actually reach
|
|
4301
|
+
* `agent_start` through it (see `delegationReachFor`). Optional so
|
|
4302
|
+
* minimal injectors (tests) needn't return it. */
|
|
4303
|
+
scope?: {
|
|
4304
|
+
tools: ReadonlySet<string>;
|
|
4305
|
+
};
|
|
4306
|
+
};
|
|
4307
|
+
interface SpawnAgentSessionDeps {
|
|
4308
|
+
registry: SessionsRegistry;
|
|
4309
|
+
/** Required — callers must check for its absence themselves (the MCP
|
|
4310
|
+
* tool and HTTP route each have their own "not enabled" response
|
|
4311
|
+
* shape for the missing-resolver case). */
|
|
4312
|
+
resolveAgentAdapter: AgentAdapterResolver;
|
|
4313
|
+
/** Optional orchestrator-injection builder (WP3). See
|
|
4314
|
+
* `RegisterAgentToolsOptions.buildOrchestratorMcp` for the full
|
|
4315
|
+
* contract. Omitted → `orchestrator` is rejected with
|
|
4316
|
+
* `orchestrator_not_enabled`. */
|
|
4317
|
+
buildOrchestratorMcp?: BuildOrchestratorMcp;
|
|
4318
|
+
/** The daemon's own plain `/mcp` gateway URL. See
|
|
4319
|
+
* `RegisterAgentToolsOptions.daemonMcpUrl`. */
|
|
4320
|
+
daemonMcpUrl?: string;
|
|
4321
|
+
/** Calling orchestrator's scope (orchestrator WP4). See
|
|
4322
|
+
* `RegisterAgentToolsOptions.callerScope`. */
|
|
4323
|
+
callerScope?: OrchestratorScope;
|
|
4324
|
+
/** Optional webhook notifier — see `RegisterAgentToolsOptions.webhookNotifier`. */
|
|
4325
|
+
webhookNotifier?: WebhookNotifier;
|
|
4326
|
+
/** Loads config.json's `defaults` block (global + per-adapter skills/
|
|
4327
|
+
* options auto-applied at every spawn — see `resolveSpawnDefaults`).
|
|
4328
|
+
* Defaults to reading the real `~/.agentproto/config.json` via
|
|
4329
|
+
* `loadConfig` when omitted; tests inject a stub to avoid touching
|
|
4330
|
+
* the real file. */
|
|
4331
|
+
loadDefaultsConfig?: () => Promise<SpawnDefaultsConfig | undefined>;
|
|
4332
|
+
/** Builds the per-session headless-browser mount for `browser:
|
|
4333
|
+
* "headless"` (see `browser-mount.ts`). Defaults to the real resolver
|
|
4334
|
+
* (installs chrome-devtools-mcp on first use); tests inject a stub. */
|
|
4335
|
+
resolveHeadlessBrowser?: ResolveHeadlessBrowser;
|
|
4336
|
+
/** Loads the custom (pack-carried) role registry, merged with the
|
|
4337
|
+
* two built-ins by `resolveRole`/`canSpawn` — see `role.ts`'s
|
|
4338
|
+
* `mergeRoleRegistry`. Defaults to `loadDefaultRoleRegistry()`
|
|
4339
|
+
* (`~/.agentproto/roles/` + adapter-carried packs) when omitted;
|
|
4340
|
+
* tests inject a stub registry to avoid touching the real
|
|
4341
|
+
* filesystem. */
|
|
4342
|
+
loadRoleRegistry?: () => Promise<Record<string, RoleProfile>>;
|
|
4343
|
+
/** Resolves an `agent_start.sandbox` slug (or an inline spec's own
|
|
4344
|
+
* `.provider`) to a concrete sandbox provider handle. Required for
|
|
4345
|
+
* `input.sandbox` — omitted ⇒ `sandbox_provider_not_found`. */
|
|
4346
|
+
resolveSandboxProvider?: SandboxProviderResolver;
|
|
4347
|
+
/** Provision a git worktree and return the cwd the spawn should land in —
|
|
4348
|
+
* the injected port behind `agent_start.worktree` (see
|
|
4349
|
+
* `worktree-isolation.ts`). Wired at the composition root by a host that
|
|
4350
|
+
* depends on `@agentproto/worktree` (the CLI). Omitted ⇒ a spawn the
|
|
4351
|
+
* policy says to isolate fails with `worktree_provisioner_not_enabled`
|
|
4352
|
+
* rather than silently spawning unisolated. */
|
|
4353
|
+
provisionWorktree?: WorktreeProvisioner;
|
|
4354
|
+
/** Resolves the effective `worktrees.isolation` policy (env > config >
|
|
4355
|
+
* `on-request`). Defaults to reading the real `~/.agentproto/config.json`
|
|
4356
|
+
* via `loadWorktreeIsolation` when omitted; tests inject a stub to pin the
|
|
4357
|
+
* mode without touching the real file or env. */
|
|
4358
|
+
resolveWorktreeIsolation?: () => Promise<WorktreeIsolationMode>;
|
|
4359
|
+
/** Resolves the effective `spawn.attach` policy (env > config > `always`).
|
|
4360
|
+
* Defaults to `loadSpawnAttach` (reads the real config) when omitted;
|
|
4361
|
+
* tests inject a stub to pin the mode without touching env or the file. */
|
|
4362
|
+
resolveSpawnAttach?: () => Promise<SpawnAttachMode>;
|
|
4363
|
+
/** Resolves the effective `spawn.dedupe` policy (env > config > `always`).
|
|
4364
|
+
* Defaults to `loadSpawnDedupe` (reads the real config) when omitted;
|
|
4365
|
+
* tests inject a stub to pin the mode without touching env or the file.
|
|
4366
|
+
* See `spawn-dedupe.ts`. */
|
|
4367
|
+
resolveSpawnDedupe?: () => Promise<SpawnDedupeMode>;
|
|
4368
|
+
/** Resolves the effective `provenance.wrapGh` opt-in (env > config >
|
|
4369
|
+
* `false`). When it resolves true, a `gh` PATH shim is prepended to the
|
|
4370
|
+
* spawned session's env so any `gh pr create` it (or an adapter
|
|
4371
|
+
* subprocess) runs gets the daemon's provenance footer appended to the
|
|
4372
|
+
* created PR's body — see `gh-provenance-shim.ts`. Defaults to
|
|
4373
|
+
* `loadProvenanceWrapGh` (reads the real config) when omitted; tests
|
|
4374
|
+
* inject a stub to pin it without touching env or the file. */
|
|
4375
|
+
resolveProvenanceWrapGh?: () => Promise<boolean>;
|
|
4376
|
+
/** Resolves + shapes the AGENTS.md for a spawn's `cwd` (see
|
|
4377
|
+
* `agents-md.ts`): inline / pointer / absent, plus the standing cd-contract
|
|
4378
|
+
* line. Defaults to the real resolver over `loadAgentsMdInlineMaxKb`'s
|
|
4379
|
+
* config-derived threshold when omitted; tests inject a stub to avoid
|
|
4380
|
+
* touching the filesystem, git, and the real config on every spawn. */
|
|
4381
|
+
resolveAgentsMd?: (cwd: string, inlineMaxKb?: number) => Promise<AgentsMdResolution>;
|
|
4382
|
+
/** Resolves + shapes the per-workspace RULES.md for a spawn (see
|
|
4383
|
+
* `workspace-rules.ts`): the path of the workspace's `RULES.md`, inlined
|
|
4384
|
+
* in full when present, absent otherwise. Injected into EVERY spawn in
|
|
4385
|
+
* the workspace (root and nested — no depth gate). Defaults to the real
|
|
4386
|
+
* resolver over the workspace state bucket when omitted; tests inject a
|
|
4387
|
+
* stub to avoid touching the real `~/.agentproto` directory. */
|
|
4388
|
+
resolveWorkspaceRules?: (slug: string | undefined) => Promise<WorkspaceRulesResolution>;
|
|
4389
|
+
/** Feeds the adapter-capability spawn guard (`checkModelAdapterEligibility`)
|
|
4390
|
+
* — the SAME `listCatalogModels` the `catalog_models` MCP tool /
|
|
4391
|
+
* `GET /catalog/models` route already use (`RegisterAgentToolsOptions.
|
|
4392
|
+
* listCatalogModels`), reused here rather than re-derived. Omitted ⇒ the
|
|
4393
|
+
* guard is skipped — a spawn that would 404 upstream on an adapter's
|
|
4394
|
+
* manifest not covering the requested model still reaches the driver,
|
|
4395
|
+
* same as before this guard existed. */
|
|
4396
|
+
listCatalogModels?: CatalogModelsLister;
|
|
4397
|
+
}
|
|
4398
|
+
interface SpawnAgentSessionInput {
|
|
4399
|
+
adapter: string;
|
|
4400
|
+
/** Canonical harness slug — recorded on the descriptor; defaults to `adapter`. */
|
|
4401
|
+
harness?: string;
|
|
4402
|
+
cwd?: string;
|
|
4403
|
+
workspaceSlug?: string;
|
|
4404
|
+
/** Trusted-loopback parent-lineage hint (WP-R1). Attributes this spawn to a
|
|
4405
|
+
* logical parent session so it nests under that node in the sessions tree,
|
|
4406
|
+
* filling the gap that otherwise leaves an anonymous `agent_start` (an
|
|
4407
|
+
* agent-to-agent spawn on the root `/mcp`, or a caller that IS a session but
|
|
4408
|
+
* didn't come through the scoped orchestrator gateway) a depth-0 orphan.
|
|
4409
|
+
*
|
|
4410
|
+
* Trust boundary: the scoped `/mcp/orchestrator` gateway derives parent from
|
|
4411
|
+
* its unspoofable scope token, so a hint arriving WITH a `callerScope` is
|
|
4412
|
+
* IGNORED — the scope always wins. The hint is honoured ONLY on the
|
|
4413
|
+
* anonymous root path (no `callerScope`), where there is no scope to
|
|
4414
|
+
* attribute from. `depth` is derived from the resolved parent descriptor
|
|
4415
|
+
* (parent's `depth + 1`, defaulting to 1 when the parent isn't registered)
|
|
4416
|
+
* rather than trusted from the caller. Descriptor-only: a hint never relaxes
|
|
4417
|
+
* the depth-gated worktree/role guards — declaring a logical parent is not
|
|
4418
|
+
* the same as being a nested (scoped) spawn. */
|
|
4419
|
+
parentSessionId?: string;
|
|
4420
|
+
/** Attach policy override for THIS spawn (`agent_start.attach`). `false`
|
|
4421
|
+
* forces an independent root even when a parent is derivable; `true` opts
|
|
4422
|
+
* in to attaching under the derived parent even under an `on-request`
|
|
4423
|
+
* policy; `{ parent }` pins an explicit parent. Omitted ⇒ the daemon's
|
|
4424
|
+
* `spawn.attach` policy decides. Resolved together with `parentSessionId`
|
|
4425
|
+
* and `autoParentSessionId` in `decideSpawnAttach` — see `spawn-attach.ts`.
|
|
4426
|
+
* Ignored WITH a `callerScope` (the scoped orchestrator token always wins). */
|
|
4427
|
+
attach?: AttachField;
|
|
4428
|
+
/** Daemon-DERIVED caller session id — the spawning session's own id, read
|
|
4429
|
+
* from the trusted `?callerSessionId=` query the self-ref `mcpServers` URL
|
|
4430
|
+
* carries (PR 7 / Gap 7), NOT from the caller's arguments. This is the
|
|
4431
|
+
* implicit auto-parent that makes attach-by-default work without the caller
|
|
4432
|
+
* passing its own id. Threaded from `registerAgentTools`' `callerSessionId`
|
|
4433
|
+
* option; lower precedence than an explicit `parentSessionId` hint. */
|
|
4434
|
+
autoParentSessionId?: string;
|
|
4435
|
+
/** Task-board pin for the spawned child, stamped onto its descriptor as
|
|
4436
|
+
* `meta.boardId`. The Task ledger's board resolution prefers this over
|
|
4437
|
+
* the `parentSessionId` lineage walk (see task-ledger.ts's
|
|
4438
|
+
* `resolveBoardId`), so a client spawning several depth-0 roots — a
|
|
4439
|
+
* cowork/operator harness fanning out executors with no shared lineage —
|
|
4440
|
+
* can join them all onto ONE board. Descriptor-only: it never enters the
|
|
4441
|
+
* depth/quota/role gates, and an explicit `boardId` on a task verb still
|
|
4442
|
+
* wins over it. */
|
|
4443
|
+
boardId?: string;
|
|
4444
|
+
/** Source label for this spawn (channel/harness). Descriptor-only. */
|
|
4445
|
+
origin?: string;
|
|
4446
|
+
/** Installed app id this spawn runs on behalf of (`app_run` sets this to
|
|
4447
|
+
* the app's own id). Forwarded to the child process as `APP_ID_ENV` — a
|
|
4448
|
+
* daemon-tool proxy the child builds (mastra-agent's `daemon-mcp-tools.ts`,
|
|
4449
|
+
* P7) auto-injects it into an `app_*` tool call that omits `appId`, since
|
|
4450
|
+
* the model driving the session has no way to know its own appId unless
|
|
4451
|
+
* told. Absent on a spawn made outside `app_run`. */
|
|
4452
|
+
appId?: string;
|
|
4453
|
+
/** Reattach to a pre-existing adapter-native session (claude-code's
|
|
4454
|
+
* conversation id, hermes' chat handle, …) instead of starting
|
|
4455
|
+
* blank. Not exposed on the MCP `agent_start` tool today — only the
|
|
4456
|
+
* HTTP route (`sessions restart`) passes this. */
|
|
4457
|
+
resumeSessionId?: string;
|
|
4458
|
+
prompt?: string;
|
|
4459
|
+
label?: string;
|
|
4460
|
+
/** Explicit session title (SPEC-3 FIX C, `agentproto sessions start
|
|
4461
|
+
* --title`). When set, it wins over the first-sentence derivation from
|
|
4462
|
+
* `prompt` — so a CLI-named session isn't limited to whatever its opening
|
|
4463
|
+
* prompt happened to say. Unlike `label`, it fills the `title` slot, so a
|
|
4464
|
+
* spawner `label` still out-ranks it in the display chain. */
|
|
4465
|
+
title?: string;
|
|
4466
|
+
mode?: string;
|
|
4467
|
+
/** Manifest-declared option id → value map (AIP-45 `options`), applied
|
|
4468
|
+
* at spawn time alongside `mode`. Forwarded verbatim to the driver's
|
|
4469
|
+
* `startSession({ options })` → `composeSpawn`'s option patches. */
|
|
4470
|
+
options?: Record<string, boolean | number | string>;
|
|
4471
|
+
/** Normalized, adapter-agnostic skill ids for this session. Merged with
|
|
4472
|
+
* config.json's `defaults.skills` / `defaults.adapters.<slug>.skills`
|
|
4473
|
+
* (global < per-adapter < this field, which REPLACES the union rather
|
|
4474
|
+
* than merging into it when provided — a deliberate exact set). Folded
|
|
4475
|
+
* into `options.skills` per the resolved adapter's declared `skills`
|
|
4476
|
+
* option shape (e.g. hermes' comma-joined string); adapters with no
|
|
4477
|
+
* such option (e.g. claude-code, which auto-discovers skills) ignore
|
|
4478
|
+
* it. See `resolveSpawnDefaults` / `normalizeSkillsOption`. */
|
|
4479
|
+
skills?: string[];
|
|
4480
|
+
model?: string;
|
|
4481
|
+
effort?: string;
|
|
4482
|
+
/** Decomposed route identity. This is canonical transport; `mode` remains
|
|
4483
|
+
* a legacy adapter projection only. */
|
|
4484
|
+
route?: RouteSpec;
|
|
4485
|
+
/** Named billing credential. Resolved from auth-profiles + keychain at the
|
|
4486
|
+
* final spawn boundary; the secret never crosses HTTP/MCP. */
|
|
4487
|
+
access?: {
|
|
4488
|
+
profileRef?: string;
|
|
4489
|
+
};
|
|
4490
|
+
posture?: Posture;
|
|
4491
|
+
contextProfile?: ContextProfile;
|
|
4492
|
+
/** A preloaded user preset. Callers resolve its id at their boundary so a
|
|
4493
|
+
* preset can also provide the adapter before this core is invoked. */
|
|
4494
|
+
preset?: UserPreset;
|
|
4495
|
+
/**
|
|
4496
|
+
* Deterministic billing-auth mode + EXPLICIT credential for adapters that
|
|
4497
|
+
* declare an env-var vocabulary for it (today: claude-code — see
|
|
4498
|
+
* `AgentCliAuth.modes` in `@agentproto/driver-agent-cli`). `mode` wins over
|
|
4499
|
+
* `~/.agentproto/config.json`'s `defaults.adapters.<slug>.auth.mode`
|
|
4500
|
+
* (default `"subscription"`); the credential (`token` for `"subscription"`,
|
|
4501
|
+
* `apiKey` for `"api-key"`) wins over the config field matching the
|
|
4502
|
+
* RESOLVED mode — see `resolveSpawnDefaults`. Never read from the ambient
|
|
4503
|
+
* shell env; never logged (only a fingerprint is recorded on the session
|
|
4504
|
+
* descriptor — see `credentialFingerprint`). Adapters that don't declare
|
|
4505
|
+
* the vocabulary ignore this field entirely.
|
|
4506
|
+
*/
|
|
4507
|
+
auth?: DefaultsAdapterAuthConfig;
|
|
4508
|
+
mcpServers?: AcpMcpServer[];
|
|
4509
|
+
orchestrator?: boolean | {
|
|
4510
|
+
tools?: string[];
|
|
4511
|
+
maxDepth?: number;
|
|
4512
|
+
maxChildren?: number;
|
|
4513
|
+
};
|
|
4514
|
+
notifyUrl?: string;
|
|
4515
|
+
wait?: boolean;
|
|
4516
|
+
maxCostUsd?: number;
|
|
4517
|
+
/** Windowed cost-budget cap (phase 4). DISTINCT from the scalar `maxCostUsd`
|
|
4518
|
+
* session-kill: this is recorded on the descriptor/runtime and drives an
|
|
4519
|
+
* auto-attached governance policy (`policy:failed` on windowed overage) — it
|
|
4520
|
+
* never kills the session. Omit ⇒ no windowed budget. */
|
|
4521
|
+
costBudget?: CostBudget;
|
|
4522
|
+
/** Opt-in auto-restart policy (restart-scheduler, PR-2). When set, an
|
|
4523
|
+
* unexpected death (`crashed` and/or `error`, per `restartPolicy.on`) is
|
|
4524
|
+
* proactively revived in place — see `RestartPolicy`'s doc in
|
|
4525
|
+
* `sessions.ts`. Omitted ⇒ today's lazy-resume-only behaviour. */
|
|
4526
|
+
restartPolicy?: RestartPolicy;
|
|
4527
|
+
/** Context-continuity policy for this session — controls warning,
|
|
4528
|
+
* opportunistic compaction, fresh-continuation, and hard-stop thresholds.
|
|
4529
|
+
* Resolved from global → per-adapter → per-model → explicit override. */
|
|
4530
|
+
contextContinuity?: ContextContinuityPolicy;
|
|
4531
|
+
/** Spawn-time role — `"executor"` | `"supervisor"` | omitted. See
|
|
4532
|
+
* `resolveRole` in `role.ts`. Omitted ⇒ derived from spawn depth
|
|
4533
|
+
* against `defaults.defaultRoleDepthCutoff` (default 1). A resolved
|
|
4534
|
+
* role with `toolPolicy.delegation === "deny"` is a HARD gate:
|
|
4535
|
+
* `orchestrator` is ignored outright and the hermes/default
|
|
4536
|
+
* full-gateway injection excludes `DELEGATION_TOOL_NAMES` — neither
|
|
4537
|
+
* this field's own request nor `promptAppend` can re-open it. */
|
|
4538
|
+
role?: string;
|
|
4539
|
+
/** One-off runtime text layered ON TOP of the resolved role's
|
|
4540
|
+
* disposition (never replacing it) and prepended to `prompt`. See
|
|
4541
|
+
* `composeRoleContext`. Cannot widen `toolPolicy` — see `role` above. */
|
|
4542
|
+
promptAppend?: string;
|
|
4543
|
+
/** Per-spawn override for the daemon self-mount's deferred/lazy
|
|
4544
|
+
* `tools/list` loading (harness-parity item 3 — see `deferred-tools.ts`).
|
|
4545
|
+
* Wins over the resolved role's own default (`RoleProfile.deferredTools`
|
|
4546
|
+
* — on for `executor`), which in turn only applies when this is
|
|
4547
|
+
* omitted. Threaded onto the injected `mcpServers` self-mount ref as
|
|
4548
|
+
* `?deferred=1|0` (`shouldInjectDaemonSelfMount` path below); has no
|
|
4549
|
+
* effect on a caller-supplied `mcpServers` (that URL is the caller's to
|
|
4550
|
+
* compose). Omitted entirely ⇒ no override at all — the gateway's own
|
|
4551
|
+
* boot-time `defaults.mcp.deferredTools` default applies unchanged. */
|
|
4552
|
+
deferredTools?: boolean;
|
|
4553
|
+
/** Give the agent its own isolated headless Chrome: a per-session
|
|
4554
|
+
* chrome-devtools-mcp stdio server appended to `mcpServers` (named
|
|
4555
|
+
* `browser`), plus a short prompt hint naming its tools. Wins over the
|
|
4556
|
+
* resolved role's `browser`, then the user preset's, then config
|
|
4557
|
+
* `defaults.spawn.browser`; all unset ⇒ off. Explicit `true` with a
|
|
4558
|
+
* `sandbox` spawn is rejected (no Chrome in the box image yet). */
|
|
4559
|
+
browser?: SpawnBrowserMode;
|
|
4560
|
+
/** Opt this session into Langfuse tracing (prompt/completion + tool spans +
|
|
4561
|
+
* tokens/cost). Effective opt-in is `trace ?? langfuseTracingDefault ?? false`
|
|
4562
|
+
* — see `SpawnAgentInput.trace` in sessions.ts. */
|
|
4563
|
+
trace?: boolean;
|
|
4564
|
+
/** Run this session inside a sandbox instead of on the host — a provider
|
|
4565
|
+
* slug from `list_sandbox_providers` (e.g. `"local"`, `"e2b"`), or an
|
|
4566
|
+
* inline AIP-36 `SandboxSpec`, optionally carrying `reuse: "<sandboxId>"`
|
|
4567
|
+
* to reconnect to an existing box instead of booting fresh. When set,
|
|
4568
|
+
* this branch resolves the provider, boots (or reconnects) the box,
|
|
4569
|
+
* spawns `adapter` on the BOX's own `agent_start`, and wires a
|
|
4570
|
+
* `SandboxAgentSessionProxy` in place of the local `resolveAgentAdapter`
|
|
4571
|
+
* path — see `sandbox-agent-session-proxy.ts`. */
|
|
4572
|
+
sandbox?: string | SandboxSpecInput;
|
|
4573
|
+
/** WP3 — serve an agentproto app's UI from INSIDE the sandbox box and
|
|
4574
|
+
* return its public URL on the descriptor + result. Requires `sandbox`
|
|
4575
|
+
* (a non-sandbox spawn carrying `appServe` is rejected): the app dir is
|
|
4576
|
+
* resolved INSIDE the box (e.g. `/home/user/apps/<slug>` on the
|
|
4577
|
+
* workstation image), installed via the box daemon's `app_install`, and
|
|
4578
|
+
* `agentproto app serve --host 0.0.0.0 --port <port>` is launched
|
|
4579
|
+
* detached through the box's `command_execute`. The port is appended to
|
|
4580
|
+
* the spec's `extraPorts` so the provider resolves its public URL (also
|
|
4581
|
+
* stamped into `sandboxPorts`), and the serve result lands on the
|
|
4582
|
+
* descriptor's `appServe` field. See `sandbox-app-serve.ts`. */
|
|
4583
|
+
appServe?: SandboxAppServeSpec;
|
|
4584
|
+
/** Isolate this session into its own git worktree instead of spawning in
|
|
4585
|
+
* `cwd` directly. `true` provisions a worktree with an auto-minted branch/
|
|
4586
|
+
* slug; `{ slug?, base? }` pins the slug and/or the base ref it's cut from.
|
|
4587
|
+
* Honoured only at spawn depth 0 (a nested spawn inherits the parent's
|
|
4588
|
+
* ground) and only for a `cwd` inside a git repo (nothing to isolate
|
|
4589
|
+
* otherwise ⇒ spawns plain). The daemon's `worktrees.isolation` policy can
|
|
4590
|
+
* force this on (`always`) or off (`never`) regardless — see
|
|
4591
|
+
* `worktree-isolation.ts`. Ignored entirely for a `sandbox` spawn (the box
|
|
4592
|
+
* already isolates). Cleanup is the human's job (`agentproto worktree
|
|
4593
|
+
* rm|archive|gc`); the tree is never auto-removed on session exit. */
|
|
4594
|
+
worktree?: WorktreeField;
|
|
4595
|
+
/** Acknowledge that spawning IN PLACE into a shared, dirty working tree is
|
|
4596
|
+
* intended, silencing the `sharedDirtyCwd` warning a nested implicit spawn
|
|
4597
|
+
* would otherwise emit (see `decideWorktreeIsolation`). Only meaningful for
|
|
4598
|
+
* a nested (depth > 0) spawn with no `worktree` request and no `sandbox`;
|
|
4599
|
+
* ignored everywhere else. Default false — the warning fires. */
|
|
4600
|
+
allowSharedCwd?: boolean;
|
|
4601
|
+
/** Start this session in permission-hold mode: every ACP permission request
|
|
4602
|
+
* is surfaced + parked in the cross-session inbox (`permissions_list` /
|
|
4603
|
+
* `permissions_respond`) instead of auto-answered. Threaded to the driver's
|
|
4604
|
+
* `startSession({ permissionHold })` and recorded on the descriptor. Ignored
|
|
4605
|
+
* for sandbox spawns (the box's own daemon owns permission handling).
|
|
4606
|
+
* Default false — unchanged auto-answer behaviour. */
|
|
4607
|
+
permissionHold?: boolean;
|
|
4608
|
+
/** Opt this child into the direct in-band crash notification: when it
|
|
4609
|
+
* crashes (`markCrashed`), the supervisor-notify subscriber
|
|
4610
|
+
* (`supervisor-notify.ts`) delivers a `[child-crashed] …` notice into its
|
|
4611
|
+
* `parentSessionId`, if any — enqueued immediately when the parent is
|
|
4612
|
+
* alive and idle, queued for its next turn when busy (never
|
|
4613
|
+
* interrupted). Recorded verbatim onto {@link SessionDescriptor
|
|
4614
|
+
* .notifyParentOnCrash}; see that field's doc. Default false — the free
|
|
4615
|
+
* external webhook path (`notifyUrl`) already fires regardless of this
|
|
4616
|
+
* flag. */
|
|
4617
|
+
notifyParentOnCrash?: boolean;
|
|
4618
|
+
/** Exempt this session from the idle-reaper (`isReapable` in
|
|
4619
|
+
* idle-reaper.ts) regardless of how long it sits idle. Stamped straight
|
|
4620
|
+
* onto the descriptor — see `SessionDescriptor.keepAlive`. Default false
|
|
4621
|
+
* — unchanged reap-eligible behaviour. Toggleable later via the
|
|
4622
|
+
* `session_set_keepalive` MCP verb. */
|
|
4623
|
+
keepAlive?: boolean;
|
|
4624
|
+
/** Caller-declared "this is the same logical spawn" token — a PROMISE, not
|
|
4625
|
+
* a guess. A second `agent_start` with the same `(adapter, cwd,
|
|
4626
|
+
* idempotencyKey)` within `SPAWN_CLAIM_WINDOW_MS` of a SUCCESSFUL spawn
|
|
4627
|
+
* returns that spawn's descriptor instead of forking a second process —
|
|
4628
|
+
* the fix for a retried call otherwise silently duplicating a live
|
|
4629
|
+
* agent. Always wins over the daemon's own derived (implicit) key when
|
|
4630
|
+
* both would apply — see `dedupe` and `spawn-dedupe.ts`. Omitting this
|
|
4631
|
+
* does NOT mean "spawn unconditionally" anymore: when the daemon's
|
|
4632
|
+
* `spawn.dedupe` policy is `"always"` (the default) and this spawn
|
|
4633
|
+
* carries a `label`, the daemon derives an implicit key in its place —
|
|
4634
|
+
* see `dedupe` below to opt out per-call. */
|
|
4635
|
+
idempotencyKey?: string;
|
|
4636
|
+
/** Per-call override for the daemon's `spawn.dedupe` policy (implicit
|
|
4637
|
+
* dedupe when no `idempotencyKey` was supplied — see `spawn-dedupe.ts`).
|
|
4638
|
+
* `false` is the escape hatch: never derive an implicit key for THIS
|
|
4639
|
+
* spawn, regardless of policy — mirrors `attach: false` / `worktree:
|
|
4640
|
+
* false`. `true` forces derivation even under an `"on-request"` policy,
|
|
4641
|
+
* mirroring `attach: true`. Omitted ⇒ the policy mode decides. Has no
|
|
4642
|
+
* effect when an explicit `idempotencyKey` is supplied (it already wins
|
|
4643
|
+
* outright) or when this spawn carries no `label` (nothing to derive
|
|
4644
|
+
* from either way). */
|
|
4645
|
+
dedupe?: boolean;
|
|
4646
|
+
/**
|
|
4647
|
+
* OS-level confinement for the adapter's OWN spawned process
|
|
4648
|
+
* (`@agentproto/command-sandbox` — macOS Seatbelt / Linux bubblewrap),
|
|
4649
|
+
* threaded verbatim to `resolved.startSession({ commandSandbox })` →
|
|
4650
|
+
* `AgentCliRuntime.start`. NOT the AIP-36 `sandbox` field above — that
|
|
4651
|
+
* boots a whole nested daemon on a different machine/box (remote-box
|
|
4652
|
+
* session provider); this wraps THIS host's spawn argv so the adapter's
|
|
4653
|
+
* own process tree can't read/write outside `cwd` (and, `"strict"`,
|
|
4654
|
+
* reach the network), confinement an ACP permission seam can never see
|
|
4655
|
+
* since it only covers tool calls the adapter chooses to report. Exposed
|
|
4656
|
+
* on the `agent_start` MCP tool schema (`agent-tools.ts`) as of PR 6b —
|
|
4657
|
+
* when omitted here, the driver falls back to the workspace's
|
|
4658
|
+
* `.agentproto/command-sandbox.json` `adapterSpawn` key (a key distinct
|
|
4659
|
+
* from the top-level `mode` that same file also carries for
|
|
4660
|
+
* `command_execute` — see `@agentproto/command-sandbox`'s module doc for
|
|
4661
|
+
* why the two axes are never shared), or stays unconfined if that's unset
|
|
4662
|
+
* too. Ignored for a `sandbox` spawn (the box's own daemon would need to
|
|
4663
|
+
* apply this itself).
|
|
4664
|
+
*/
|
|
4665
|
+
commandSandbox?: SandboxMode;
|
|
4666
|
+
}
|
|
4667
|
+
|
|
3836
4668
|
/**
|
|
3837
4669
|
* Shared kernel for the daemon's worktree-status query surface.
|
|
3838
4670
|
*
|
|
@@ -3853,9 +4685,28 @@ interface WorktreeStatusView {
|
|
|
3853
4685
|
branch: string | null;
|
|
3854
4686
|
class: "reclaim" | "salvage" | "hold";
|
|
3855
4687
|
reclaimable: boolean;
|
|
4688
|
+
/** Uncommitted work in the tree (modified, staged or untracked paths). */
|
|
4689
|
+
dirty: boolean;
|
|
4690
|
+
/** Per-kind counts, present only when `dirty`. */
|
|
4691
|
+
changes?: {
|
|
4692
|
+
modified: number;
|
|
4693
|
+
staged: number;
|
|
4694
|
+
untracked: number;
|
|
4695
|
+
};
|
|
4696
|
+
/** Ahead/behind vs the base ref the integration check compares against
|
|
4697
|
+
* (the repo's default branch, e.g. `origin/main`). `null` for a detached
|
|
4698
|
+
* tip or when git couldn't resolve the base. */
|
|
4699
|
+
base: null | {
|
|
4700
|
+
ref: string;
|
|
4701
|
+
ahead: number;
|
|
4702
|
+
behind: number;
|
|
4703
|
+
};
|
|
4704
|
+
/** Integration state; `number` whenever the forge matched a PR (open,
|
|
4705
|
+
* merged, partial), `url` when the host knows the forge's web URL. */
|
|
3856
4706
|
pr: null | {
|
|
3857
4707
|
state: string;
|
|
3858
4708
|
number?: number;
|
|
4709
|
+
url?: string;
|
|
3859
4710
|
};
|
|
3860
4711
|
sessions: Array<{
|
|
3861
4712
|
id: string;
|
|
@@ -3869,13 +4720,24 @@ interface WorktreeStatusView {
|
|
|
3869
4720
|
sessionCount: number;
|
|
3870
4721
|
};
|
|
3871
4722
|
}
|
|
4723
|
+
/** Narrows a lister call. `paths` computes only those worktrees (compared
|
|
4724
|
+
* resolved) instead of every worktree of the repo: one forge round-trip for
|
|
4725
|
+
* a per-session lookup, not one per worktree. */
|
|
4726
|
+
interface WorktreeStatusListOptions {
|
|
4727
|
+
paths?: readonly string[];
|
|
4728
|
+
}
|
|
3872
4729
|
/** Injected port: the runtime asks the host to list worktrees for a repo. */
|
|
3873
|
-
type WorktreeStatusLister = (repoRoot: string) => Promise<WorktreeStatusView[]>;
|
|
4730
|
+
type WorktreeStatusLister = (repoRoot: string, options?: WorktreeStatusListOptions) => Promise<WorktreeStatusView[]>;
|
|
4731
|
+
interface ToWorktreeStatusViewOptions {
|
|
4732
|
+
/** Web URL of PR `number` on this repo's forge, when the host can build
|
|
4733
|
+
* one (e.g. from a GitHub `origin` remote). */
|
|
4734
|
+
prUrl?: (number: number) => string | undefined;
|
|
4735
|
+
}
|
|
3874
4736
|
/**
|
|
3875
4737
|
* Pure projection from a raw `WorktreeStatusEntry` to the view the daemon
|
|
3876
4738
|
* surfaces. Kept in one place so the MCP tool and HTTP route cannot drift.
|
|
3877
4739
|
*/
|
|
3878
|
-
declare function toWorktreeStatusView(entry: unknown): WorktreeStatusView;
|
|
4740
|
+
declare function toWorktreeStatusView(entry: unknown, options?: ToWorktreeStatusViewOptions): WorktreeStatusView;
|
|
3879
4741
|
|
|
3880
4742
|
/**
|
|
3881
4743
|
* Shared kernel for the daemon's worktree-`gc` surface — the transport twin of
|
|
@@ -3910,7 +4772,7 @@ type WorktreeGcClass = "reclaim" | "salvage" | "hold";
|
|
|
3910
4772
|
* registration is still there, but the working directory is gone (see
|
|
3911
4773
|
* `WorktreeGcPlanEntryView.prunable`).
|
|
3912
4774
|
*/
|
|
3913
|
-
type WorktreeGcReclaimReason = "dep-bump" | "orphan" | "prunable";
|
|
4775
|
+
type WorktreeGcReclaimReason = "dep-bump" | "orphan" | "prunable" | "squash-merged" | "patch-merged" | "content-merged";
|
|
3914
4776
|
/**
|
|
3915
4777
|
* One entry of the dry-run plan — a runtime-local projection of a
|
|
3916
4778
|
* `GcPlanEntry`. `tree` / `integration` / `liveness` are flattened to their
|
|
@@ -4002,6 +4864,13 @@ interface WorktreeGcRunInput {
|
|
|
4002
4864
|
* command) omits it and gets exactly today's behavior.
|
|
4003
4865
|
*/
|
|
4004
4866
|
protectedPaths?: string[];
|
|
4867
|
+
/**
|
|
4868
|
+
* Worktree-relative paths whose dirt is known noise: a worktree dirty ONLY
|
|
4869
|
+
* on these reads clean (and is removed non-force after they are restored).
|
|
4870
|
+
* Omitted → the engine's default (`.opencode/package-lock.json`); `[]`
|
|
4871
|
+
* disables the allowlist.
|
|
4872
|
+
*/
|
|
4873
|
+
noisePaths?: string[];
|
|
4005
4874
|
}
|
|
4006
4875
|
/**
|
|
4007
4876
|
* Injected port: the runtime asks the host to plan (and, when `apply`, execute)
|
|
@@ -4011,6 +4880,159 @@ interface WorktreeGcRunInput {
|
|
|
4011
4880
|
*/
|
|
4012
4881
|
type WorktreeGcRunner = (input: WorktreeGcRunInput) => Promise<WorktreeGcResult>;
|
|
4013
4882
|
|
|
4883
|
+
/**
|
|
4884
|
+
* Shared kernel for the daemon's branch-`gc` surface — the sibling of
|
|
4885
|
+
* `worktree-gc.ts`. The engine (`planBranchGc` / `applyBranchGc` /
|
|
4886
|
+
* `recordBranchVerdict`) lives in `@agentproto/worktree`, a dependency the
|
|
4887
|
+
* runtime deliberately does NOT take, so — exactly as the worktree gc surface
|
|
4888
|
+
* does — the runtime only defines runtime-local structural result types and
|
|
4889
|
+
* the injected ports. The CLI host wires the real runners. Repo-root
|
|
4890
|
+
* resolution is shared with the worktree surfaces via
|
|
4891
|
+
* `resolveWorktreeQueryRoot` in `worktree-status.ts`.
|
|
4892
|
+
*/
|
|
4893
|
+
type BranchGcKind = "local" | "remote" | "orphan";
|
|
4894
|
+
type BranchGcClass = "reclaim" | "review" | "hold";
|
|
4895
|
+
type BranchGcStatus = "pr-merged" | "merged" | "squash-merged" | "patch-merged" | "content-merged" | "unmerged";
|
|
4896
|
+
type BranchGcReclaimReason = Exclude<BranchGcStatus, "unmerged"> | "reviewed";
|
|
4897
|
+
type BranchGcHoldReason = "protected" | "worktree" | "open-pr" | "pr-check-unavailable" | "young";
|
|
4898
|
+
type BranchGcTriageVerdict = "obsolete" | "superseded" | "salvage" | "in-progress" | "unclear";
|
|
4899
|
+
interface BranchGcCoverageView {
|
|
4900
|
+
residual: number;
|
|
4901
|
+
covered: number;
|
|
4902
|
+
ignored: number;
|
|
4903
|
+
evolved: number;
|
|
4904
|
+
unique: number;
|
|
4905
|
+
deletes: number;
|
|
4906
|
+
}
|
|
4907
|
+
/** One classified ref — mirrors `BranchGcPlanEntry` structurally. */
|
|
4908
|
+
interface BranchGcPlanEntryView {
|
|
4909
|
+
kind: BranchGcKind;
|
|
4910
|
+
name: string;
|
|
4911
|
+
ref: string;
|
|
4912
|
+
sha: string;
|
|
4913
|
+
date: string;
|
|
4914
|
+
author: string;
|
|
4915
|
+
subject: string;
|
|
4916
|
+
remote?: string;
|
|
4917
|
+
status: BranchGcStatus;
|
|
4918
|
+
history: "current" | "pre-rewrite" | "unrelated";
|
|
4919
|
+
ahead: number | null;
|
|
4920
|
+
behind: number | null;
|
|
4921
|
+
conflicts?: boolean;
|
|
4922
|
+
compareBase?: string;
|
|
4923
|
+
mergeBase?: string;
|
|
4924
|
+
mergedTree?: string | null;
|
|
4925
|
+
coverage?: BranchGcCoverageView;
|
|
4926
|
+
residualFiles?: string[];
|
|
4927
|
+
residualFileCount?: number;
|
|
4928
|
+
ageDays: number;
|
|
4929
|
+
class: BranchGcClass;
|
|
4930
|
+
reclaimReason?: BranchGcReclaimReason;
|
|
4931
|
+
mergedPr?: number;
|
|
4932
|
+
holdReason?: BranchGcHoldReason;
|
|
4933
|
+
holdDetail?: string;
|
|
4934
|
+
pushed?: string;
|
|
4935
|
+
verdict?: {
|
|
4936
|
+
triage: BranchGcTriageVerdict;
|
|
4937
|
+
agree: boolean | null;
|
|
4938
|
+
reviewer: string;
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4941
|
+
interface BranchGcPlanView {
|
|
4942
|
+
repoRoot: string;
|
|
4943
|
+
repoName: string;
|
|
4944
|
+
base: string;
|
|
4945
|
+
baseSha: string;
|
|
4946
|
+
baseTree: string;
|
|
4947
|
+
remote: string | null;
|
|
4948
|
+
anchor: string | null;
|
|
4949
|
+
prCheck: {
|
|
4950
|
+
available: boolean;
|
|
4951
|
+
reason?: string;
|
|
4952
|
+
};
|
|
4953
|
+
scopes: BranchGcKind[];
|
|
4954
|
+
minAgeDays: number;
|
|
4955
|
+
includeReviewed: boolean;
|
|
4956
|
+
generatedAt: string;
|
|
4957
|
+
otherRemoteRefs: number;
|
|
4958
|
+
entries: BranchGcPlanEntryView[];
|
|
4959
|
+
}
|
|
4960
|
+
/** kind → class → count, and kind → (status | "protected") → count. */
|
|
4961
|
+
interface BranchGcSummaryView {
|
|
4962
|
+
byClass: Record<BranchGcKind, Record<BranchGcClass, number>>;
|
|
4963
|
+
byStatus: Record<BranchGcKind, Record<string, number>>;
|
|
4964
|
+
}
|
|
4965
|
+
interface BranchGcOutcomeView {
|
|
4966
|
+
kind: BranchGcKind;
|
|
4967
|
+
name: string;
|
|
4968
|
+
sha: string;
|
|
4969
|
+
result: "deleted" | "held" | "skipped-review" | "aborted-moved" | "aborted-vanished" | "aborted-reclassified" | "failed";
|
|
4970
|
+
reclaimReason?: BranchGcReclaimReason;
|
|
4971
|
+
holdReason?: BranchGcHoldReason;
|
|
4972
|
+
currentSha?: string;
|
|
4973
|
+
from?: BranchGcClass;
|
|
4974
|
+
to?: BranchGcClass;
|
|
4975
|
+
message?: string;
|
|
4976
|
+
}
|
|
4977
|
+
type BranchGcResult = {
|
|
4978
|
+
mode: "plan";
|
|
4979
|
+
plan: BranchGcPlanView;
|
|
4980
|
+
summary: BranchGcSummaryView;
|
|
4981
|
+
} | {
|
|
4982
|
+
mode: "apply";
|
|
4983
|
+
plan: BranchGcPlanView;
|
|
4984
|
+
summary: BranchGcSummaryView;
|
|
4985
|
+
outcomes: BranchGcOutcomeView[];
|
|
4986
|
+
/** Restore log written before the first delete; `null` when nothing was deleted. */
|
|
4987
|
+
restoreLog: string | null;
|
|
4988
|
+
};
|
|
4989
|
+
/** Input to the injected runner. `apply` defaults to false at the tool/route
|
|
4990
|
+
* boundary — a bare call is a dry run — and an apply requires `scopes`. */
|
|
4991
|
+
interface BranchGcRunInput {
|
|
4992
|
+
repoRoot: string;
|
|
4993
|
+
apply: boolean;
|
|
4994
|
+
base?: string;
|
|
4995
|
+
scopes?: BranchGcKind[];
|
|
4996
|
+
minAgeDays?: number;
|
|
4997
|
+
includeReviewed: boolean;
|
|
4998
|
+
anchor?: string;
|
|
4999
|
+
}
|
|
5000
|
+
type BranchGcRunner = (input: BranchGcRunInput) => Promise<BranchGcResult>;
|
|
5001
|
+
interface BranchGcVerdictInput {
|
|
5002
|
+
repoRoot: string;
|
|
5003
|
+
/** Validated by the engine (`branchVerdictSchema`) — the runtime only shapes it. */
|
|
5004
|
+
verdict: unknown;
|
|
5005
|
+
}
|
|
5006
|
+
interface BranchGcVerdictRecordView {
|
|
5007
|
+
repo: string;
|
|
5008
|
+
name: string;
|
|
5009
|
+
sha: string;
|
|
5010
|
+
recordedAt: string;
|
|
5011
|
+
triage: {
|
|
5012
|
+
verdict: BranchGcTriageVerdict;
|
|
5013
|
+
confidence: number;
|
|
5014
|
+
reason: string;
|
|
5015
|
+
salvage?: string;
|
|
5016
|
+
};
|
|
5017
|
+
gate?: {
|
|
5018
|
+
agree: boolean;
|
|
5019
|
+
verdict: BranchGcTriageVerdict;
|
|
5020
|
+
reason: string;
|
|
5021
|
+
evidence: string[];
|
|
5022
|
+
};
|
|
5023
|
+
reviewer: string;
|
|
5024
|
+
}
|
|
5025
|
+
/** Injected port: validate + store one reviewer verdict, keyed by repo + tip sha. Throws on an invalid verdict. */
|
|
5026
|
+
type BranchGcVerdictRecorder = (input: BranchGcVerdictInput) => Promise<BranchGcVerdictRecordView>;
|
|
5027
|
+
interface BranchGcVerdictLookupInput {
|
|
5028
|
+
repoRoot: string;
|
|
5029
|
+
/** Full tip sha — the store's key, together with the repo. */
|
|
5030
|
+
sha: string;
|
|
5031
|
+
}
|
|
5032
|
+
/** Injected port: the stored verdict for this exact tip, or `null` — a read-only
|
|
5033
|
+
* lookup, so a caller can check one tip without re-running a whole `branch_gc` plan. */
|
|
5034
|
+
type BranchGcVerdictReader = (input: BranchGcVerdictLookupInput) => Promise<BranchGcVerdictRecordView | null>;
|
|
5035
|
+
|
|
4014
5036
|
/**
|
|
4015
5037
|
* Pluggable adapter resolver — keeps the runtime package free of any
|
|
4016
5038
|
* @agentproto/cli dep. The host (cli `serve`, playground, embedding
|
|
@@ -4319,6 +5341,142 @@ interface AuthOptions {
|
|
|
4319
5341
|
token?: string;
|
|
4320
5342
|
}
|
|
4321
5343
|
|
|
5344
|
+
/** One background task as mirrored onto `SessionDescriptor.backgroundTasks`. */
|
|
5345
|
+
interface SessionBackgroundTask {
|
|
5346
|
+
taskId: string;
|
|
5347
|
+
/** Friendly task type (`"shell"`, `"monitor"`, ...), when the agent says. */
|
|
5348
|
+
taskKind?: string;
|
|
5349
|
+
description?: string;
|
|
5350
|
+
/** Where the task writes its output, when the agent says. */
|
|
5351
|
+
outputFile?: string;
|
|
5352
|
+
status: "running" | "paused" | "completed" | "failed" | "stopped";
|
|
5353
|
+
summary?: string;
|
|
5354
|
+
toolCallId?: string;
|
|
5355
|
+
/** ISO 8601 — when the daemon first heard of the task. */
|
|
5356
|
+
startedAt: string;
|
|
5357
|
+
}
|
|
5358
|
+
|
|
5359
|
+
/**
|
|
5360
|
+
* Typed inter-session message envelope (AIP-46 §Session messages).
|
|
5361
|
+
*
|
|
5362
|
+
* A PROMPT is an instruction from whoever drives a session; a MESSAGE is a
|
|
5363
|
+
* report between sessions in the same tree whose sender the DAEMON attests.
|
|
5364
|
+
* Everything in `from` is computed here from the caller's verified identity
|
|
5365
|
+
* and the session forest — a send request can never set it.
|
|
5366
|
+
*
|
|
5367
|
+
* Pure module: no registry, no I/O. The registry (sessions.ts) carries a
|
|
5368
|
+
* `SessionMessage` on a queued prompt (`QueuedPrompt.envelope`), renders it
|
|
5369
|
+
* into the model's context with `renderSessionMessages`, and records it as
|
|
5370
|
+
* its own `session-message` transcript record — never a `user-prompt`.
|
|
5371
|
+
*/
|
|
5372
|
+
/** Sender's position in the tree, relative to the recipient. */
|
|
5373
|
+
type MessageRelation = "child" | "parent" | "sibling" | "human" | "system";
|
|
5374
|
+
type MessageKind = "report" | "question" | "blocker" | "done" | "notice";
|
|
5375
|
+
type MessageUrgency = "fyi" | "next-turn" | "steer" | "interrupt";
|
|
5376
|
+
type MessageDeliveryVia = "wait" | "steer" | "turn" | "interrupt" | "inbox";
|
|
5377
|
+
declare const MESSAGE_KINDS: readonly MessageKind[];
|
|
5378
|
+
declare const MESSAGE_URGENCIES: readonly MessageUrgency[];
|
|
5379
|
+
interface SessionMessageFrom {
|
|
5380
|
+
/** Absent only for relation `human` | `system`. */
|
|
5381
|
+
sessionId?: string;
|
|
5382
|
+
/** Registry label at send time — display only, never identity. */
|
|
5383
|
+
label?: string;
|
|
5384
|
+
role?: string;
|
|
5385
|
+
adapter?: string;
|
|
5386
|
+
relation: MessageRelation;
|
|
5387
|
+
}
|
|
5388
|
+
interface SessionMessage {
|
|
5389
|
+
/** `msg_<uuid8>`, daemon-minted. */
|
|
5390
|
+
id: string;
|
|
5391
|
+
ts: string;
|
|
5392
|
+
/** Recipient sessionId. */
|
|
5393
|
+
to: string;
|
|
5394
|
+
from: SessionMessageFrom;
|
|
5395
|
+
kind: MessageKind;
|
|
5396
|
+
/** Requested urgency. */
|
|
5397
|
+
urgency: MessageUrgency;
|
|
5398
|
+
/** Stamped on delivery. */
|
|
5399
|
+
delivered?: {
|
|
5400
|
+
via: MessageDeliveryVia;
|
|
5401
|
+
at: string;
|
|
5402
|
+
turnSeq?: number;
|
|
5403
|
+
};
|
|
5404
|
+
/** Thread id; defaults to the first message's id. */
|
|
5405
|
+
correlationId?: string;
|
|
5406
|
+
/** A `SessionMessage.id` this answers. */
|
|
5407
|
+
replyTo?: string;
|
|
5408
|
+
text: string;
|
|
5409
|
+
/** Optional structured payload (≤ `MAX_MESSAGE_DATA_BYTES`). */
|
|
5410
|
+
data?: Record<string, unknown>;
|
|
5411
|
+
ackedAt?: string;
|
|
5412
|
+
}
|
|
5413
|
+
declare const MAX_MESSAGE_DATA_BYTES: number;
|
|
5414
|
+
/** The slice of a session descriptor relation/ACL resolution needs. */
|
|
5415
|
+
interface MessageTreeNode {
|
|
5416
|
+
id: string;
|
|
5417
|
+
parentSessionId?: string;
|
|
5418
|
+
label?: string;
|
|
5419
|
+
role?: string;
|
|
5420
|
+
adapterSlug?: string;
|
|
5421
|
+
}
|
|
5422
|
+
/**
|
|
5423
|
+
* Relation of `sender` to `recipient` in the session forest, or `undefined`
|
|
5424
|
+
* when they're not tree neighbours (cousins, strangers, self). `sender`
|
|
5425
|
+
* absent ⇒ `human` (an HTTP/CLI operator); daemon-originated notices pass
|
|
5426
|
+
* `"system"` explicitly instead of calling this.
|
|
5427
|
+
*/
|
|
5428
|
+
declare function resolveRelation(sender: MessageTreeNode | undefined, recipient: MessageTreeNode): Exclude<MessageRelation, "system"> | undefined;
|
|
5429
|
+
/**
|
|
5430
|
+
* ACL: child→parent, parent→direct child, human/system→any. Sibling↔sibling
|
|
5431
|
+
* only when `allowSiblings` (config-gated, default off). Anything else — a
|
|
5432
|
+
* cousin, a stranger, yourself — is refused.
|
|
5433
|
+
*/
|
|
5434
|
+
declare function isMessageAllowed(relation: MessageRelation | undefined, opts?: {
|
|
5435
|
+
allowSiblings?: boolean;
|
|
5436
|
+
}): relation is MessageRelation;
|
|
5437
|
+
/** Build a `from` block from the verified sender + the resolved relation. */
|
|
5438
|
+
declare function messageFrom(sender: MessageTreeNode | undefined, relation: MessageRelation): SessionMessageFrom;
|
|
5439
|
+
declare function mintMessageId(): string;
|
|
5440
|
+
declare function createSessionMessage(input: {
|
|
5441
|
+
to: string;
|
|
5442
|
+
from: SessionMessageFrom;
|
|
5443
|
+
text: string;
|
|
5444
|
+
kind?: MessageKind;
|
|
5445
|
+
urgency?: MessageUrgency;
|
|
5446
|
+
replyTo?: string;
|
|
5447
|
+
correlationId?: string;
|
|
5448
|
+
data?: Record<string, unknown>;
|
|
5449
|
+
}): SessionMessage;
|
|
5450
|
+
interface MessageFilter {
|
|
5451
|
+
/** Sender session ids, or `"children"` for any message whose relation is
|
|
5452
|
+
* `child` (i.e. from one of the recipient's own children). */
|
|
5453
|
+
from?: readonly string[] | "children";
|
|
5454
|
+
kind?: readonly MessageKind[];
|
|
5455
|
+
correlationId?: string;
|
|
5456
|
+
}
|
|
5457
|
+
declare function matchesMessageFilter(msg: SessionMessage, filter: MessageFilter): boolean;
|
|
5458
|
+
declare const MESSAGE_TAG = "agentproto-message";
|
|
5459
|
+
/** Child-settable label → attribute-safe: `[A-Za-z0-9._-]`, ≤ 48 chars. */
|
|
5460
|
+
declare function sanitizeLabel(label: string | undefined): string | undefined;
|
|
5461
|
+
/** Escape every envelope/body sentinel inside a message body, so a sender
|
|
5462
|
+
* can't close the tag early and forge a second header. */
|
|
5463
|
+
declare function escapeMessageBody(text: string): string;
|
|
5464
|
+
/** A human prompt is NOT wrapped (humans keep today's UX), but a line that
|
|
5465
|
+
* starts with the envelope sentinel is escaped, so the invariant "text
|
|
5466
|
+
* outside an `<agentproto-message>` tag is the human" holds. Nothing else
|
|
5467
|
+
* in human text changes. */
|
|
5468
|
+
declare function escapeHumanPrompt(text: string): string;
|
|
5469
|
+
declare function renderSessionMessage(msg: SessionMessage): string;
|
|
5470
|
+
/** A coalesced batch → sibling tags, one per message, in order. */
|
|
5471
|
+
declare function renderSessionMessages(msgs: readonly SessionMessage[]): string;
|
|
5472
|
+
/** One-line typed digest of `fyi` messages that never woke the session —
|
|
5473
|
+
* prepended (as a `system-prompt` slice) to the next turn it runs anyway. */
|
|
5474
|
+
declare function renderInboxDigest(msgs: readonly SessionMessage[]): string;
|
|
5475
|
+
/** Taught once, the first time a session RECEIVES a message (recorded as a
|
|
5476
|
+
* `system-prompt`). Children also get the same invariant in their lineage
|
|
5477
|
+
* line at spawn. */
|
|
5478
|
+
declare const MESSAGE_PREAMBLE: string;
|
|
5479
|
+
|
|
4322
5480
|
/**
|
|
4323
5481
|
* A per-session observer — the pluggable seam behind the runtime's transcript
|
|
4324
5482
|
* tap. `sessions.ts` drives one observer per turn (prompt in, each stream event,
|
|
@@ -4330,15 +5488,33 @@ interface AuthOptions {
|
|
|
4330
5488
|
* calls, so `TranscriptWriter` IS a `SessionObserver` (see transcript-writer.ts).
|
|
4331
5489
|
*/
|
|
4332
5490
|
|
|
5491
|
+
/** The sender-side trace of a typed message (`session-message-sent`). */
|
|
5492
|
+
interface SessionMessageSentRecord {
|
|
5493
|
+
messageId: string;
|
|
5494
|
+
to: string;
|
|
5495
|
+
kind: MessageKind;
|
|
5496
|
+
urgency: MessageUrgency;
|
|
5497
|
+
}
|
|
4333
5498
|
interface SessionObserver {
|
|
4334
5499
|
/** Record the outgoing message that opens a new turn. `opts.source`, when
|
|
4335
5500
|
* set, is the prompt's provenance — `agent:<sessionId>` for a prompt
|
|
4336
5501
|
* injected by another session (`agent_prompt` from a supervisor), absent
|
|
4337
5502
|
* for a human operator — so a transcript view can attribute the turn to
|
|
4338
|
-
* its real author instead of "you".
|
|
5503
|
+
* its real author instead of "you". `opts.messages`, when set, marks a
|
|
5504
|
+
* typed-message turn: the writer records one `session-message` per
|
|
5505
|
+
* message instead of a `user-prompt`. */
|
|
4339
5506
|
recordPrompt(sessionId: string, message: unknown, opts?: {
|
|
4340
5507
|
source?: string;
|
|
5508
|
+
system?: string;
|
|
5509
|
+
messages?: readonly SessionMessage[];
|
|
4341
5510
|
}): void;
|
|
5511
|
+
/** Record, in the SENDER's transcript, that it sent a typed message.
|
|
5512
|
+
* Optional — observers without a transcript of their own skip it. */
|
|
5513
|
+
recordSessionMessageSent?(sessionId: string, record: SessionMessageSentRecord): void;
|
|
5514
|
+
/** Record a typed message delivered into `sessionId`'s context OUTSIDE a
|
|
5515
|
+
* turn prompt (e.g. as an `inbox_wait` result) — a standalone
|
|
5516
|
+
* `session-message` record. Optional, like `recordSessionMessageSent`. */
|
|
5517
|
+
recordSessionMessage?(sessionId: string, message: SessionMessage): void;
|
|
4342
5518
|
/** Record one structured stream event (text-delta, tool-call, usage_update, …). */
|
|
4343
5519
|
recordEvent(sessionId: string, evt: AgentStreamEvent): void;
|
|
4344
5520
|
/** Record the durable turn-boundary / exit usage snapshot. */
|
|
@@ -4361,6 +5537,106 @@ interface SessionObserver {
|
|
|
4361
5537
|
*/
|
|
4362
5538
|
declare function composeSessionObservers(observers: readonly SessionObserver[]): SessionObserver;
|
|
4363
5539
|
|
|
5540
|
+
/** Where a session's `contextSize` came from — see the module doc. */
|
|
5541
|
+
type ContextSizeSource = "adapter" | "catalog" | "reported";
|
|
5542
|
+
|
|
5543
|
+
/**
|
|
5544
|
+
* Derived session outcome (Level 1) — what an ended agent-cli session
|
|
5545
|
+
* PRODUCED, recorded by the daemon with zero agent cooperation.
|
|
5546
|
+
*
|
|
5547
|
+
* Two axes, never conflated:
|
|
5548
|
+
* - termination — HOW the session stopped (the descriptor's existing
|
|
5549
|
+
* `status` + `endedReason`), copied verbatim into `outcome.termination`;
|
|
5550
|
+
* - outcome — WHAT it produced: its last assistant message, the PRs it
|
|
5551
|
+
* opened, what it cost, and which run / parent it belongs to.
|
|
5552
|
+
*
|
|
5553
|
+
* So a killed or idle-reaped session still shows what it said and did,
|
|
5554
|
+
* instead of a bare "killed".
|
|
5555
|
+
*
|
|
5556
|
+
* Pure by construction (plus one bounded sync tail-read helper for boot
|
|
5557
|
+
* reconcile): no LLM call, no full transcript scan. The registry calls
|
|
5558
|
+
* {@link deriveSessionOutcome} from its single exit funnel (`emitExited`)
|
|
5559
|
+
* and from boot reconcile (`loadHistorySnapshot`).
|
|
5560
|
+
*/
|
|
5561
|
+
|
|
5562
|
+
interface SessionOutcomeArtifact {
|
|
5563
|
+
type: "pr" | "commit" | "url";
|
|
5564
|
+
/** The artifact's canonical reference — a PR url, a commit sha, a url. */
|
|
5565
|
+
ref: string;
|
|
5566
|
+
title?: string;
|
|
5567
|
+
}
|
|
5568
|
+
interface SessionOutcomeLink {
|
|
5569
|
+
/** `run` — the workflow run this session was a step of (`ref` = run id,
|
|
5570
|
+
* `title` = `<workflowId>/<stepId>`); `parent` — the orchestrator session
|
|
5571
|
+
* that spawned it; `review` — reserved for the review ledger (Level 2). */
|
|
5572
|
+
rel: "run" | "parent" | "review";
|
|
5573
|
+
ref: string;
|
|
5574
|
+
title?: string;
|
|
5575
|
+
}
|
|
5576
|
+
interface SessionOutcome {
|
|
5577
|
+
/** Level 1 only ever writes `"derived"`; a declared outcome (Level 2) is a
|
|
5578
|
+
* later addition. */
|
|
5579
|
+
source: "derived";
|
|
5580
|
+
/** `produced` — the session said something or left an artifact;
|
|
5581
|
+
* `empty` — no assistant text and no artifacts. */
|
|
5582
|
+
status: "produced" | "empty";
|
|
5583
|
+
/** Last assistant message of the session, trimmed to
|
|
5584
|
+
* {@link OUTCOME_SUMMARY_MAX} chars (the TAIL is kept — the conclusion,
|
|
5585
|
+
* not the preamble). Absent when the session never said anything. */
|
|
5586
|
+
summary?: string;
|
|
5587
|
+
/** Copy of the descriptor's end state at the moment the outcome was
|
|
5588
|
+
* recorded — the termination axis, never mixed into `status`. */
|
|
5589
|
+
termination: {
|
|
5590
|
+
status: string;
|
|
5591
|
+
/** Copy of `SessionDescriptor.endedReason` — see {@link SessionEndReason}
|
|
5592
|
+
* for the full, single-source enum of values (operator kill, cost cap,
|
|
5593
|
+
* provider limit, …). Absent for a plain natural exit or an ordinary
|
|
5594
|
+
* turn error this file doesn't tag. A value outside the known enum is
|
|
5595
|
+
* still valid (a newer/older daemon) — never gate rendering on it being
|
|
5596
|
+
* a member; see `isKnownSessionEndReason`. */
|
|
5597
|
+
reason?: SessionEndReason;
|
|
5598
|
+
/** The reason this row carried BEFORE an operator's "mark as completed"
|
|
5599
|
+
* (`kill(id, signal, "operator-completed")` on an already-terminal
|
|
5600
|
+
* session — the UI's affordance for relabeling a finished-but-not-
|
|
5601
|
+
* operator-tagged row) overwrote `reason` with `"operator-completed"`.
|
|
5602
|
+
* Set ONLY by that relabel, so the true original mechanism (a natural
|
|
5603
|
+
* exit with no reason, `"crashed"`, `"idle-reaped"`, …) is never lost
|
|
5604
|
+
* under the operator's override. Absent otherwise. */
|
|
5605
|
+
previousReason?: SessionEndReason;
|
|
5606
|
+
exitCode?: number;
|
|
5607
|
+
/** True when the session was killed with a turn in flight. */
|
|
5608
|
+
midTurn?: boolean;
|
|
5609
|
+
};
|
|
5610
|
+
cost?: {
|
|
5611
|
+
usd?: number;
|
|
5612
|
+
tokensIn?: number;
|
|
5613
|
+
tokensOut?: number;
|
|
5614
|
+
durationMs?: number;
|
|
5615
|
+
};
|
|
5616
|
+
artifacts?: SessionOutcomeArtifact[];
|
|
5617
|
+
links?: SessionOutcomeLink[];
|
|
5618
|
+
recordedAt: string;
|
|
5619
|
+
}
|
|
5620
|
+
/** The compact list projection of an outcome (`session_list` default). */
|
|
5621
|
+
interface SessionOutcomeCompact {
|
|
5622
|
+
status: SessionOutcome["status"];
|
|
5623
|
+
summary?: string;
|
|
5624
|
+
}
|
|
5625
|
+
interface DeriveSessionOutcomeInput {
|
|
5626
|
+
/** The last assistant message the registry observed (raw, untrimmed). */
|
|
5627
|
+
lastAssistantText?: string;
|
|
5628
|
+
now?: Date;
|
|
5629
|
+
}
|
|
5630
|
+
/**
|
|
5631
|
+
* Build the derived outcome for a session that has just reached a terminal
|
|
5632
|
+
* status. Reads only the descriptor + the caller-supplied last assistant
|
|
5633
|
+
* text; never touches disk.
|
|
5634
|
+
*/
|
|
5635
|
+
declare function deriveSessionOutcome(desc: SessionDescriptor, input?: DeriveSessionOutcomeInput): SessionOutcome;
|
|
5636
|
+
/** The compact projection: status + the first
|
|
5637
|
+
* {@link OUTCOME_COMPACT_SUMMARY_MAX} chars of the summary. */
|
|
5638
|
+
declare function compactOutcome(o: SessionOutcome | undefined): SessionOutcomeCompact | undefined;
|
|
5639
|
+
|
|
4364
5640
|
/**
|
|
4365
5641
|
* Minimal shape we need from a driver-agent-cli session — kept as a
|
|
4366
5642
|
* structural type so the runtime package doesn't take a hard
|
|
@@ -4384,6 +5660,12 @@ interface AgentSessionLike {
|
|
|
4384
5660
|
* drivers that don't model held permissions (sandbox proxy, future
|
|
4385
5661
|
* transports). */
|
|
4386
5662
|
respondPermission?(requestId: string, resolution: AcpPermissionResolution): boolean | Promise<boolean>;
|
|
5663
|
+
/** Subscribe to events the agent emits while no turn is in flight — its
|
|
5664
|
+
* own wake-up when a background task settles, and the task lifecycle
|
|
5665
|
+
* itself. Mirrors `@agentproto/driver-agent-cli`'s
|
|
5666
|
+
* `AgentCliRuntimeSession.onOutOfTurnEvent`. Returns an unsubscribe
|
|
5667
|
+
* function. Absent for drivers that can't produce such events. */
|
|
5668
|
+
onOutOfTurnEvent?(listener: (event: AgentStreamEvent) => void): () => void;
|
|
4387
5669
|
/**
|
|
4388
5670
|
* Switch the active model on this LIVE session — mirrors
|
|
4389
5671
|
* `@agentproto/driver-agent-cli`'s `AgentCliRuntimeSession.setModel`
|
|
@@ -4420,6 +5702,15 @@ interface AgentSessionLike {
|
|
|
4420
5702
|
* routes to restart.
|
|
4421
5703
|
*/
|
|
4422
5704
|
readonly availableModes?: readonly SessionMode[];
|
|
5705
|
+
/** Whether the agent accepts steering — mirrors
|
|
5706
|
+
* `@agentproto/driver-agent-cli`'s `AgentCliRuntimeSession.steeringSupported`
|
|
5707
|
+
* (ACP `_session/steering`, advertised at initialize). */
|
|
5708
|
+
readonly steeringSupported?: boolean;
|
|
5709
|
+
/** Inject content into the turn in flight — mirrors
|
|
5710
|
+
* `AgentCliRuntimeSession.steer`: `"steered"` (injected), `"promptRequired"`
|
|
5711
|
+
* (no host turn in flight — deliver as a normal prompt), `"unsupported"`.
|
|
5712
|
+
* Never throws. Absent for sessions that can't steer. */
|
|
5713
|
+
steer?(content: unknown): Promise<"steered" | "promptRequired" | "unsupported">;
|
|
4423
5714
|
close(): Promise<void>;
|
|
4424
5715
|
}
|
|
4425
5716
|
/** Result of `SessionsRegistry.setModel` — see that method's doc comment. */
|
|
@@ -4586,6 +5877,16 @@ interface AgentStreamEvent {
|
|
|
4586
5877
|
* but no `cost`). */
|
|
4587
5878
|
tokensIn?: number;
|
|
4588
5879
|
tokensOut?: number;
|
|
5880
|
+
/** "usage_update" model the usage belongs to, when the adapter reports it
|
|
5881
|
+
* (claude-agent-acp's `_meta["_claude/model"]`) — see `context-window.ts`. */
|
|
5882
|
+
model?: string;
|
|
5883
|
+
/** "usage_update" `size` is the adapter's own guess, corrected later by a
|
|
5884
|
+
* cost-bearing frame (claude-agent-acp) — see `context-window.ts`. */
|
|
5885
|
+
sizeInferred?: boolean;
|
|
5886
|
+
/** "usage_update" size as the adapter reported it, recorded only when the
|
|
5887
|
+
* daemon corrected `size` (an inferred window superseded by the catalog or
|
|
5888
|
+
* an earlier authoritative frame) — see `context-window.ts`. */
|
|
5889
|
+
reportedSize?: number;
|
|
4589
5890
|
/** "permission-resolved" outcome for the "agent-prompt" it answers (same
|
|
4590
5891
|
* `toolCallId`) — mirrors `session:permission-resolved`'s `decision` so
|
|
4591
5892
|
* the durable transcript can tell an answered ask from a still-pending
|
|
@@ -4612,6 +5913,24 @@ interface AgentStreamEvent {
|
|
|
4612
5913
|
qualifiedName?: string;
|
|
4613
5914
|
};
|
|
4614
5915
|
}>;
|
|
5916
|
+
/** "background-task" lifecycle edge — see @agentproto/acp's `StreamEvent`'s
|
|
5917
|
+
* `background-task` kind. */
|
|
5918
|
+
phase?: "started" | "updated" | "settled";
|
|
5919
|
+
/** "background-task" task snapshot — see @agentproto/acp's
|
|
5920
|
+
* `BackgroundTaskInfo`. Only `taskId` is guaranteed. */
|
|
5921
|
+
task?: {
|
|
5922
|
+
taskId: string;
|
|
5923
|
+
taskKind?: string;
|
|
5924
|
+
description?: string;
|
|
5925
|
+
outputFile?: string;
|
|
5926
|
+
status?: SessionBackgroundTask["status"];
|
|
5927
|
+
summary?: string;
|
|
5928
|
+
toolCallId?: string;
|
|
5929
|
+
};
|
|
5930
|
+
/** "usage_update" origin of the cycle it closes (claude-agent-acp's
|
|
5931
|
+
* `_meta["_claude/origin"].kind`, e.g. `"task-notification"` for an
|
|
5932
|
+
* autonomous wake) — see @agentproto/acp's `StreamEvent`. */
|
|
5933
|
+
origin?: string;
|
|
4615
5934
|
}
|
|
4616
5935
|
/**
|
|
4617
5936
|
* Env vars the registry injects into every process it spawns on a session's
|
|
@@ -4732,6 +6051,13 @@ interface QueuedPrompt {
|
|
|
4732
6051
|
* daemon restart. Absent for legacy queued items — `promptOriginLabel`
|
|
4733
6052
|
* falls back to `source`, then `"user"`. */
|
|
4734
6053
|
origin?: string;
|
|
6054
|
+
/** Set when this item is a typed inter-session message (`message_parent`,
|
|
6055
|
+
* …) rather than a prompt: the daemon-attested envelope. `message` then
|
|
6056
|
+
* only carries `envelope.text` (for `previewPrompt`); the turn is built
|
|
6057
|
+
* from the envelope — rendered as an `<agentproto-message>` tag, recorded
|
|
6058
|
+
* as a `session-message` transcript record, and coalesced with any
|
|
6059
|
+
* envelope items queued right behind it (never with a plain prompt). */
|
|
6060
|
+
envelope?: SessionMessage;
|
|
4735
6061
|
}
|
|
4736
6062
|
/** What `enqueuePrompt` resolved to — lets a caller (e.g. MCP `agent_prompt`)
|
|
4737
6063
|
* tell the user whether the prompt was delivered/started now or PARKED behind
|
|
@@ -4743,6 +6069,22 @@ interface QueuedPrompt {
|
|
|
4743
6069
|
interface EnqueuePromptResult {
|
|
4744
6070
|
queued: boolean;
|
|
4745
6071
|
}
|
|
6072
|
+
/** What `sendMessage` did with a message — truthful, per AIP-46. */
|
|
6073
|
+
interface SendMessageResult {
|
|
6074
|
+
messageId: string;
|
|
6075
|
+
/** Set when the message already reached the recipient's context (a
|
|
6076
|
+
* waiter, a dispatched turn, an interrupt) or was parked as `fyi`
|
|
6077
|
+
* (`via: "inbox"`); `null` while it's queued behind a busy turn. */
|
|
6078
|
+
delivered: {
|
|
6079
|
+
via: MessageDeliveryVia;
|
|
6080
|
+
} | null;
|
|
6081
|
+
queued: boolean;
|
|
6082
|
+
urgencyApplied: MessageUrgency;
|
|
6083
|
+
}
|
|
6084
|
+
interface WaitForMessagesResult {
|
|
6085
|
+
messages: SessionMessage[];
|
|
6086
|
+
timedOut: boolean;
|
|
6087
|
+
}
|
|
4746
6088
|
/** One entry in the after-the-fact queue listing (`listQueuedPrompts` /
|
|
4747
6089
|
* `session_queue_list` / `GET /sessions/:id/queue`). `position` is the
|
|
4748
6090
|
* array index (0 = next to dispatch). */
|
|
@@ -4756,6 +6098,17 @@ interface QueuedPromptView {
|
|
|
4756
6098
|
queuedAt: string;
|
|
4757
6099
|
position: number;
|
|
4758
6100
|
}
|
|
6101
|
+
/** Provenance stamped onto a `session_continue_fresh` target by
|
|
6102
|
+
* {@link SessionDescriptor.handoff} — which harness the checkpoint moved
|
|
6103
|
+
* from/to and when. `fromHarness === toHarness` for a same-harness
|
|
6104
|
+
* continuation; they differ for a genuine cross-harness handoff
|
|
6105
|
+
* (claude-code -> opencode, etc). */
|
|
6106
|
+
interface SessionHandoff {
|
|
6107
|
+
fromHarness: string;
|
|
6108
|
+
toHarness: string;
|
|
6109
|
+
/** ISO 8601 timestamp the handoff spawn completed. */
|
|
6110
|
+
at: string;
|
|
6111
|
+
}
|
|
4759
6112
|
interface SessionDescriptor {
|
|
4760
6113
|
id: string;
|
|
4761
6114
|
kind: SessionKind;
|
|
@@ -4778,30 +6131,36 @@ interface SessionDescriptor {
|
|
|
4778
6131
|
startedAt: string;
|
|
4779
6132
|
endedAt?: string;
|
|
4780
6133
|
exitCode?: number;
|
|
4781
|
-
/**
|
|
4782
|
-
*
|
|
4783
|
-
*
|
|
4784
|
-
*
|
|
4785
|
-
*
|
|
4786
|
-
*
|
|
4787
|
-
*
|
|
4788
|
-
*
|
|
4789
|
-
*
|
|
4790
|
-
* lazy-resumable
|
|
4791
|
-
*
|
|
4792
|
-
* `
|
|
4793
|
-
*
|
|
4794
|
-
*
|
|
4795
|
-
*
|
|
4796
|
-
*
|
|
4797
|
-
*
|
|
4798
|
-
*
|
|
4799
|
-
*
|
|
4800
|
-
*
|
|
4801
|
-
*
|
|
4802
|
-
*
|
|
4803
|
-
*
|
|
4804
|
-
|
|
6134
|
+
/** WHY the session ended — every stable value + its meaning is declared
|
|
6135
|
+
* once, in {@link SessionEndReason} (`session-end-reason.ts`), so a UI can
|
|
6136
|
+
* render a label for each without chasing the call site that set it.
|
|
6137
|
+
* Three families:
|
|
6138
|
+
* - automatic daemon-lifecycle teardown (unchanged, pre-existing):
|
|
6139
|
+
* `"daemon-restart"` (the daemon process it lived in went away out from
|
|
6140
|
+
* under it — a hard crash discovered at next boot, or a graceful
|
|
6141
|
+
* shutdown/restart that force-kills whatever's still busy),
|
|
6142
|
+
* `"idle-reaped"` (the idle-session reaper retired a long-idle row —
|
|
6143
|
+
* deliberately kept lazy-resumable but NEVER eager-resumed on boot,
|
|
6144
|
+
* since the eager pass gates on `endedReason === "daemon-restart"`),
|
|
6145
|
+
* `"crashed"` (the crash-detect sweep found the adapter's OS process
|
|
6146
|
+
* gone between turns with no exit event ever emitted for it — `status`
|
|
6147
|
+
* is `"error"`, not `"killed"`, since nothing targeted it);
|
|
6148
|
+
* - operator-issued kill: `"operator-completed"` / `"operator-stopped"`,
|
|
6149
|
+
* set ONLY by an explicit `POST /sessions/:id/kill` or the `agent_kill`
|
|
6150
|
+
* MCP tool (never by an internal automatic teardown), so it reads as
|
|
6151
|
+
* deliberate rather than random;
|
|
6152
|
+
* - other internal/automatic reasons: `"cost-cap-exceeded"` (the
|
|
6153
|
+
* turn-granular `maxCostUsd` cap tripped), `"policy-cleanup"` (a
|
|
6154
|
+
* supervisor gate tore down its own ephemeral judge session),
|
|
6155
|
+
* `"parent-exited"` (an orchestrator's dying subtree reap),
|
|
6156
|
+
* `"provider-limit"` (a driver-reported subscription/usage-cap error,
|
|
6157
|
+
* e.g. Claude Code's "hit your session limit"), `"forgotten"` (a live
|
|
6158
|
+
* session killed as part of an operator `DELETE`).
|
|
6159
|
+
* Absent for every terminal path this file doesn't tag (a plain natural
|
|
6160
|
+
* exit, an ordinary turn error) — the session's own fault, or at least
|
|
6161
|
+
* not something worth a special label. A string outside this list is
|
|
6162
|
+
* still valid (a newer/older daemon) — see `isKnownSessionEndReason`. */
|
|
6163
|
+
endedReason?: SessionEndReason;
|
|
4805
6164
|
/** Whether a turn was actually in flight the INSTANT `status` flipped to
|
|
4806
6165
|
* "killed" — captured before anything else runs, because `busy` itself
|
|
4807
6166
|
* cannot be trusted after the fact: `runAgentTurn`'s `finally` is what
|
|
@@ -4819,6 +6178,16 @@ interface SessionDescriptor {
|
|
|
4819
6178
|
* `kill()`, `shutdownImpl`'s force-kill, and `loadHistorySnapshot`'s
|
|
4820
6179
|
* wasAlive reclassification; absent for every other terminal path. */
|
|
4821
6180
|
killedMidTurn?: boolean;
|
|
6181
|
+
/** What this session PRODUCED — the derived outcome (Level 1) the daemon
|
|
6182
|
+
* records once it reaches a terminal status, alongside (never instead of)
|
|
6183
|
+
* the termination fields above: last assistant message, opened PRs, cost,
|
|
6184
|
+
* run/parent links. agent-cli only. Recorded from the one exit funnel
|
|
6185
|
+
* (`emitExited`) and from boot reconcile for rows that died with the
|
|
6186
|
+
* daemon; first write wins unless a later one is for a new death or is
|
|
6187
|
+
* richer (see `shouldReplaceOutcome`). Dropped when an in-place resume
|
|
6188
|
+
* revives the row. Persisted, so it survives restarts and archiving. See
|
|
6189
|
+
* `session-outcome.ts`. */
|
|
6190
|
+
outcome?: SessionOutcome;
|
|
4822
6191
|
/** Last time anything was written to stdout/stderr. Lets the UI
|
|
4823
6192
|
* spot stuck sessions ("running for 2h, last output 12min ago"). */
|
|
4824
6193
|
lastOutputAt?: string;
|
|
@@ -4926,10 +6295,23 @@ interface SessionDescriptor {
|
|
|
4926
6295
|
* session sits `busy:false`, `awaitingInput:false`, background tasks
|
|
4927
6296
|
* pending — a silent dead end. Detection + signal ONLY (same doctrine
|
|
4928
6297
|
* as `stalledSinceMs`): nothing here re-prompts or wakes the session.
|
|
6298
|
+
* Not stamped for an agent that reports its background-task lifecycle
|
|
6299
|
+
* (see `backgroundTasks`) — that one is tracked and woken for real.
|
|
4929
6300
|
* Cleared (deleted, never a stale value) on the next turn start and on
|
|
4930
6301
|
* session exit. Emits `session:bg-tasks-parked` /
|
|
4931
6302
|
* `session:bg-tasks-cleared`. */
|
|
4932
6303
|
pendingBgTasks?: number;
|
|
6304
|
+
/** The agent's background tasks that are still running (a backgrounded
|
|
6305
|
+
* Bash command, a monitor, ...), as the agent itself reports them — over
|
|
6306
|
+
* ACP, the AIR `asyncTasks` lifecycle. Unlike `pendingBgTasks` (a
|
|
6307
|
+
* turn-end heuristic) this is the real set: a task is added when it
|
|
6308
|
+
* starts and removed when it settles, so an idle session with a
|
|
6309
|
+
* non-empty list is "waiting on N background tasks", not parked. When
|
|
6310
|
+
* one settles while the session is idle the registry makes sure the
|
|
6311
|
+
* agent is woken (see `SessionsRegistryOptions.backgroundTaskWake`).
|
|
6312
|
+
* Absent when none are running; dropped on exit and on respawn (a new
|
|
6313
|
+
* process owns none of the old one's tasks). */
|
|
6314
|
+
backgroundTasks?: SessionBackgroundTask[];
|
|
4933
6315
|
/** ISO 8601 timestamp of the last turn that ended because the ADAPTER
|
|
4934
6316
|
* ITSELF reported a failure — `runAgentTurn` observed a `turn-end` event
|
|
4935
6317
|
* with `reason:"error"` (session-event-bus.ts's `SessionTurnEndEvent`,
|
|
@@ -5083,6 +6465,9 @@ interface SessionDescriptor {
|
|
|
5083
6465
|
* field is. Absent (not `false`) for every descriptor from before this
|
|
5084
6466
|
* field existed — treated the same as `false` everywhere it's read. */
|
|
5085
6467
|
archived?: boolean;
|
|
6468
|
+
/** ISO-8601 instant `archiveSession` set `archived: true`; cleared by
|
|
6469
|
+
* `unarchiveSession`. Absent on rows archived before this field existed. */
|
|
6470
|
+
archivedAt?: string;
|
|
5086
6471
|
/** When `true`, the idle-reaper (`isReapable`, `idle-reaper.ts`) never
|
|
5087
6472
|
* retires this session regardless of how long it's sat idle. For a
|
|
5088
6473
|
* supervisor that legitimately parks — waiting on a child, waiting on a
|
|
@@ -5137,6 +6522,12 @@ interface SessionDescriptor {
|
|
|
5137
6522
|
* `worktreePath` without an id identifies a PATH, which a later worktree
|
|
5138
6523
|
* may reuse; the pair identifies one specific worktree. */
|
|
5139
6524
|
worktreeId?: string;
|
|
6525
|
+
/** Absolute path of the PRIMARY checkout `worktreePath` was cut from (the
|
|
6526
|
+
* repo root a `worktree_status` query targets), read at spawn from the
|
|
6527
|
+
* worktree admin dir's `commondir` file (`resolveWorktreeIdentity`).
|
|
6528
|
+
* Absent whenever `worktreePath` is, when `commondir` was unreadable, and
|
|
6529
|
+
* for every session persisted before this field existed. */
|
|
6530
|
+
mainRepoPath?: string;
|
|
5140
6531
|
/** `true` only when `worktreePath` was provisioned by the `worktrees.isolation`
|
|
5141
6532
|
* policy WITHOUT an explicit `worktree` request from the caller (see
|
|
5142
6533
|
* `decideWorktreeIsolation`'s `WorktreeDecision.provision.implicit` in
|
|
@@ -5331,10 +6722,16 @@ interface SessionDescriptor {
|
|
|
5331
6722
|
* usage_update events arrive, not just at turn-end. */
|
|
5332
6723
|
contextSize?: number;
|
|
5333
6724
|
contextUsed?: number;
|
|
6725
|
+
/** Where `contextSize` came from — `"adapter"` (a cost-bearing, authoritative
|
|
6726
|
+
* usage_update; sticky), `"catalog"` (model-catalog window for the model),
|
|
6727
|
+
* or `"reported"` (the adapter's own, possibly inferred, frame size). See
|
|
6728
|
+
* `context-window.ts` for the precedence. */
|
|
6729
|
+
contextSizeSource?: ContextSizeSource;
|
|
5334
6730
|
/** Where `costUsd` came from — `"adapter"` (adapter's own reader or a
|
|
5335
6731
|
* usage_update cost block), `"computed"` (tokens × in-repo catalog price),
|
|
5336
6732
|
* `"no-pricing"` (tokens present but the model isn't in the catalog — cost
|
|
5337
|
-
* deliberately left undefined), or `"none"`. Stamped
|
|
6733
|
+
* deliberately left undefined), or `"none"`. Stamped live on each
|
|
6734
|
+
* cost-bearing usage_update / reader read, and re-derived at turn-end. */
|
|
5338
6735
|
usageSource?: UsageSource;
|
|
5339
6736
|
/** Latest known `available_commands_update` payload (see @agentproto/acp's
|
|
5340
6737
|
* `StreamEvent`'s `available-commands` kind) — the slash-commands/skills
|
|
@@ -5456,7 +6853,7 @@ interface SessionDescriptor {
|
|
|
5456
6853
|
* next assistant `text-delta` (the model has the floor, so nothing is
|
|
5457
6854
|
* pending), at turn start, and in the turn's finally. A claim about the
|
|
5458
6855
|
* present tense — anything that disproves it must clear it. */
|
|
5459
|
-
blockedOn?: "subagent" | "command";
|
|
6856
|
+
blockedOn?: "subagent" | "command" | "inbox";
|
|
5460
6857
|
/** toolCallId of the tool-call that set `blockedOn`. A tool-result only
|
|
5461
6858
|
* clears `blockedOn` when its toolCallId matches — so a nested or
|
|
5462
6859
|
* interleaved tool finishing first can't clear the flag early. */
|
|
@@ -5472,9 +6869,9 @@ interface SessionDescriptor {
|
|
|
5472
6869
|
* (`markCrashed` → `session:exited` with `status:"error"`/
|
|
5473
6870
|
* `reason:"crashed"`), the supervisor-notify subscriber
|
|
5474
6871
|
* (`supervisor-notify.ts`) delivers a `[child-crashed]` notice to its
|
|
5475
|
-
* `parentSessionId`, if any —
|
|
5476
|
-
*
|
|
5477
|
-
*
|
|
6872
|
+
* `parentSessionId`, if any — dispatched now when the parent is alive
|
|
6873
|
+
* and idle, or parked in its `promptQueue` and drained as its own turn
|
|
6874
|
+
* when the parent's current turn ends. The free external
|
|
5478
6875
|
* webhook path (`notifyUrl`) already fires regardless of this flag; this
|
|
5479
6876
|
* only gates the additional IN-BAND signal into the parent's own
|
|
5480
6877
|
* session, which a caller that isn't a delegating supervisor doesn't
|
|
@@ -5483,14 +6880,42 @@ interface SessionDescriptor {
|
|
|
5483
6880
|
notifyParentOnCrash?: boolean;
|
|
5484
6881
|
/** True when the session was spawned in permission-hold mode. */
|
|
5485
6882
|
permissionHold?: boolean;
|
|
5486
|
-
/**
|
|
5487
|
-
*
|
|
5488
|
-
*
|
|
5489
|
-
*
|
|
5490
|
-
*
|
|
5491
|
-
*
|
|
5492
|
-
*
|
|
6883
|
+
/** Effective OS-level confinement of the adapter's own process
|
|
6884
|
+
* (`agent_start.commandSandbox`, else the workspace's
|
|
6885
|
+
* `.agentproto/command-sandbox.json` `adapterSpawn.mode`), resolved at
|
|
6886
|
+
* spawn with the same precedence the driver applies
|
|
6887
|
+
* (`wrapAgentCliSpawn`). Absent when neither engaged the axis (the spawn
|
|
6888
|
+
* ran unconfined without anyone choosing a mode), for a `sandbox` spawn
|
|
6889
|
+
* (confinement is the box's business), and for sessions persisted before
|
|
6890
|
+
* this field existed. Set at spawn time, immutable thereafter. */
|
|
6891
|
+
commandSandbox?: "off" | "workspace" | "strict";
|
|
6892
|
+
/** @deprecated Retired — child reports and `[child-crashed]` notices for a
|
|
6893
|
+
* busy session are now queued as their own `promptQueue` items
|
|
6894
|
+
* (`source:"child:<id>"`) instead of being string-prepended onto the next
|
|
6895
|
+
* prompt. Only read once, at boot, by `migratePendingChildNotices`, which
|
|
6896
|
+
* moves any notices a pre-upgrade daemon persisted into `promptQueue` and
|
|
6897
|
+
* deletes this field. Never written. */
|
|
5493
6898
|
pendingChildCrashNotices?: string[];
|
|
6899
|
+
/** True once this session has been taught the `<agentproto-message>`
|
|
6900
|
+
* invariant (`MESSAGE_PREAMBLE`) — sent as a `system-prompt` slice ahead
|
|
6901
|
+
* of the FIRST message turn it receives, never again. */
|
|
6902
|
+
messagePreambleSent?: boolean;
|
|
6903
|
+
/** Durable, bounded inbox of typed messages NOT yet consumed (AIP-46
|
|
6904
|
+
* §Session messages): every accepted message lands here until it's
|
|
6905
|
+
* delivered into a turn (auto-acked), returned by `inbox_wait` with
|
|
6906
|
+
* `ack`, or acked via `inbox_ack`. `fyi` messages only ever live here
|
|
6907
|
+
* (surfaced as a digest). Capped at `INBOX_CAP`, oldest dropped first
|
|
6908
|
+
* (`[inbox] dropped`). Full history lives in the transcript, not here.
|
|
6909
|
+
* New array on every mutation, like `promptQueue`. */
|
|
6910
|
+
inbox?: SessionMessage[];
|
|
6911
|
+
/** What the live agent session can do, read from its driver at attach
|
|
6912
|
+
* time (spawn / resume) — shown in `session_list` so a sender can predict
|
|
6913
|
+
* a message's delivery tier. `steering`: the agent accepts ACP steering
|
|
6914
|
+
* (`_session/steering`) — a `steer` message can be injected into its
|
|
6915
|
+
* running turn instead of waiting for it to end. */
|
|
6916
|
+
capabilities?: {
|
|
6917
|
+
steering: boolean;
|
|
6918
|
+
};
|
|
5494
6919
|
/** FIFO of prompts that arrived while this session was mid-turn and
|
|
5495
6920
|
* asked to be QUEUED rather than rejected (`enqueuePrompt`'s
|
|
5496
6921
|
* `opts.queue` arm — see its doc comment). Index 0 is next to
|
|
@@ -5505,8 +6930,7 @@ interface SessionDescriptor {
|
|
|
5505
6930
|
* `sessionDescriptorsEqual` diff is a shallow `!==` per field, so an
|
|
5506
6931
|
* in-place `.shift()` here would silently stop propagating queue
|
|
5507
6932
|
* changes to the transcript panel. `[]` (not absent) once anything
|
|
5508
|
-
* has ever been queued
|
|
5509
|
-
* convention above. */
|
|
6933
|
+
* has ever been queued. */
|
|
5510
6934
|
promptQueue?: QueuedPrompt[];
|
|
5511
6935
|
/** Best-effort context-handoff digest (Fix D), stashed on a descriptor
|
|
5512
6936
|
* whose resume degraded to a BLANK spawn — the adapter's own
|
|
@@ -5514,8 +6938,7 @@ interface SessionDescriptor {
|
|
|
5514
6938
|
* false` — built by `buildResumeContextDigest` from the daemon's own
|
|
5515
6939
|
* `events.jsonl` transcript, which survives both cases. Flushed and
|
|
5516
6940
|
* cleared by prepending it onto the first dispatched turn's message
|
|
5517
|
-
* (`runAgentTurn`), exactly once
|
|
5518
|
-
* `pendingChildCrashNotices` above. Gated strictly on the blank-fallback
|
|
6941
|
+
* (`runAgentTurn`), exactly once. Gated strictly on the blank-fallback
|
|
5519
6942
|
* flags at the two sites that set it (`session-restart-core.ts`,
|
|
5520
6943
|
* `maybeResumeAgent` here) — never set for a resume that actually
|
|
5521
6944
|
* restored context, so a real continuation is never double-fed its own
|
|
@@ -5547,6 +6970,12 @@ interface SessionDescriptor {
|
|
|
5547
6970
|
/** When this session was continued fresh into a new session, the target
|
|
5548
6971
|
* session id. */
|
|
5549
6972
|
continuedTo?: string;
|
|
6973
|
+
/** Set alongside `continuedFrom` on the NEW session — the harness the
|
|
6974
|
+
* checkpoint moved from/to and when. Present on every `continue_fresh`
|
|
6975
|
+
* spawn, not just a cross-harness one, so a same-harness continuation
|
|
6976
|
+
* and a genuine handoff are both traceable the same way. See
|
|
6977
|
+
* {@link SessionHandoff}. */
|
|
6978
|
+
handoff?: SessionHandoff;
|
|
5550
6979
|
/** Source label — the channel/harness this session was spawned from
|
|
5551
6980
|
* ("codex", "cowork", "vscode", "cron", …). Descriptor-only; groups the
|
|
5552
6981
|
* session under a source node in the tree. */
|
|
@@ -5678,6 +7107,9 @@ interface SessionSummary {
|
|
|
5678
7107
|
endedAt?: string;
|
|
5679
7108
|
exitCode?: number;
|
|
5680
7109
|
killedMidTurn?: boolean;
|
|
7110
|
+
/** Compact derived outcome (status + 120-char summary preview) — see
|
|
7111
|
+
* `SessionDescriptor.outcome`; the full record is on GET /sessions/:id. */
|
|
7112
|
+
outcome?: SessionOutcomeCompact;
|
|
5681
7113
|
lastOutputAt?: string;
|
|
5682
7114
|
lastActivityAt?: string;
|
|
5683
7115
|
currentPhase?: SessionCurrentPhase;
|
|
@@ -5697,6 +7129,9 @@ interface SessionSummary {
|
|
|
5697
7129
|
renamedByUser?: boolean;
|
|
5698
7130
|
activitySummary?: SessionActivitySummary;
|
|
5699
7131
|
archived?: boolean;
|
|
7132
|
+
/** ISO-8601 instant `archiveSession` set `archived: true`; cleared by
|
|
7133
|
+
* `unarchiveSession`. Absent on rows archived before this field existed. */
|
|
7134
|
+
archivedAt?: string;
|
|
5700
7135
|
keepAlive?: boolean;
|
|
5701
7136
|
pinned?: boolean;
|
|
5702
7137
|
pty?: boolean;
|
|
@@ -5705,6 +7140,7 @@ interface SessionSummary {
|
|
|
5705
7140
|
cwd?: string;
|
|
5706
7141
|
worktreePath?: string;
|
|
5707
7142
|
worktreeId?: string;
|
|
7143
|
+
mainRepoPath?: string;
|
|
5708
7144
|
/** Resolved AGENTS.md path — see `SessionDescriptor.agentsMd`. */
|
|
5709
7145
|
agentsMd?: string;
|
|
5710
7146
|
/** Injection mode — see `SessionDescriptor.agentsMdMode`. */
|
|
@@ -5719,18 +7155,21 @@ interface SessionSummary {
|
|
|
5719
7155
|
tokensOut?: number;
|
|
5720
7156
|
contextSize?: number;
|
|
5721
7157
|
contextUsed?: number;
|
|
7158
|
+
contextSizeSource?: ContextSizeSource;
|
|
5722
7159
|
usageSource?: UsageSource;
|
|
5723
7160
|
awaitingInput?: boolean;
|
|
5724
7161
|
awaitingQuestion?: SessionAwaitingQuestion;
|
|
5725
7162
|
awaitingPermission?: boolean;
|
|
5726
7163
|
turnsCompleted?: number;
|
|
5727
7164
|
busy?: boolean;
|
|
5728
|
-
blockedOn?: "subagent" | "command";
|
|
7165
|
+
blockedOn?: "subagent" | "command" | "inbox";
|
|
5729
7166
|
stalledSinceMs?: number;
|
|
5730
7167
|
/** Parked-with-background-tasks marker — see
|
|
5731
7168
|
* `SessionDescriptor.pendingBgTasks`. Stamped at turn-end, cleared on the
|
|
5732
7169
|
* next turn start / exit. */
|
|
5733
7170
|
pendingBgTasks?: number;
|
|
7171
|
+
/** Running background tasks — see `SessionDescriptor.backgroundTasks`. */
|
|
7172
|
+
backgroundTasks?: SessionBackgroundTask[];
|
|
5734
7173
|
/** Adapter-reported turn-error marker — see
|
|
5735
7174
|
* `SessionDescriptor.lastTurnErroredAt`. Stamped at turn-end, cleared on
|
|
5736
7175
|
* the next turn that completes without one. */
|
|
@@ -5762,6 +7201,8 @@ interface SessionSummary {
|
|
|
5762
7201
|
sandboxTeardown?: "kill" | "pause";
|
|
5763
7202
|
sandboxPorts?: Record<number, string>;
|
|
5764
7203
|
appServe?: SessionAppServeInfo;
|
|
7204
|
+
/** Effective adapter confinement — see `SessionDescriptor.commandSandbox`. */
|
|
7205
|
+
commandSandbox?: "off" | "workspace" | "strict";
|
|
5765
7206
|
/** Read-time projection of the box's ledger liveness verdict — see
|
|
5766
7207
|
* `SessionDescriptor.sandboxAlive`. */
|
|
5767
7208
|
sandboxAlive?: boolean;
|
|
@@ -6096,6 +7537,13 @@ interface SessionsRegistry {
|
|
|
6096
7537
|
queue?: boolean;
|
|
6097
7538
|
force?: boolean;
|
|
6098
7539
|
queueId?: string;
|
|
7540
|
+
/** A typed inter-session message (see `QueuedPrompt.envelope`). When
|
|
7541
|
+
* set, the turn is built from the envelope and `message` is ignored:
|
|
7542
|
+
* rendered as an `<agentproto-message>` tag, recorded as
|
|
7543
|
+
* `session-message` (never `user-prompt`), never matched as a
|
|
7544
|
+
* structured-question answer, and noted in the SENDER's transcript
|
|
7545
|
+
* as `session-message-sent`. */
|
|
7546
|
+
envelope?: SessionMessage;
|
|
6099
7547
|
}): Promise<EnqueuePromptResult>;
|
|
6100
7548
|
/** Cancel one not-yet-dispatched item in `SessionDescriptor.promptQueue`
|
|
6101
7549
|
* by id — the composer's per-item "remove" action. Idempotent: an
|
|
@@ -6106,6 +7554,50 @@ interface SessionsRegistry {
|
|
|
6106
7554
|
removeQueuedPrompt(id: string, queueId: string): {
|
|
6107
7555
|
removed: boolean;
|
|
6108
7556
|
};
|
|
7557
|
+
/** Deliver a daemon-attested typed message (`msg.to` is the recipient;
|
|
7558
|
+
* `from` must already be computed from the verified caller), routed by
|
|
7559
|
+
* `msg.urgency` (AIP-46 §Delivery tiers):
|
|
7560
|
+
* - a matching pending `waitForMessages` wins over every tier (waiter
|
|
7561
|
+
* first — returned as that call's result, never also injected);
|
|
7562
|
+
* - `fyi` — durable inbox only, no wake;
|
|
7563
|
+
* - idle recipient — any other tier starts its own turn now;
|
|
7564
|
+
* - busy + `next-turn` — queued behind the current turn;
|
|
7565
|
+
* - busy + `steer` — injected into the running turn when the daemon's
|
|
7566
|
+
* OWN prompt is in flight (never an autonomous cycle), the agent can
|
|
7567
|
+
* steer, and the per-recipient rate limit allows; else `next-turn`;
|
|
7568
|
+
* - busy + `interrupt` — cancels the turn and delivers — only when
|
|
7569
|
+
* `allowInterrupt` (the caller's grant); otherwise downgraded to
|
|
7570
|
+
* `steer`.
|
|
7571
|
+
* `urgencyApplied` reports the tier actually used. Throws when the
|
|
7572
|
+
* recipient is missing or not alive. */
|
|
7573
|
+
sendMessage(msg: SessionMessage, opts?: {
|
|
7574
|
+
source?: string;
|
|
7575
|
+
origin?: string;
|
|
7576
|
+
allowInterrupt?: boolean;
|
|
7577
|
+
}): Promise<SendMessageResult>;
|
|
7578
|
+
/** Block until a message matching `filter` is in `id`'s inbox (returns at
|
|
7579
|
+
* once when one already is), or `timeoutMs` elapses. Matched messages are
|
|
7580
|
+
* consumed: stamped `delivered.via:"wait"`, removed from the prompt queue
|
|
7581
|
+
* (so they're never also injected as a turn), and — when `ack` (default)
|
|
7582
|
+
* — removed from the inbox. Sets `blockedOn:"inbox"` while parked. */
|
|
7583
|
+
waitForMessages(id: string, filter: MessageFilter, opts: {
|
|
7584
|
+
timeoutMs: number;
|
|
7585
|
+
ack?: boolean;
|
|
7586
|
+
signal?: AbortSignal;
|
|
7587
|
+
}): Promise<WaitForMessagesResult>;
|
|
7588
|
+
/** Read `id`'s inbox (un-consumed messages), newest last. */
|
|
7589
|
+
listInbox(id: string, filter?: MessageFilter & {
|
|
7590
|
+
limit?: number;
|
|
7591
|
+
}): SessionMessage[] | null;
|
|
7592
|
+
/** Find a message `id` RECEIVED (still in its inbox, or already consumed
|
|
7593
|
+
* and only in its transcript) — how `message_reply` routes to the
|
|
7594
|
+
* original sender. `undefined` when `id` never received `messageId`. */
|
|
7595
|
+
findReceivedMessage(id: string, messageId: string): SessionMessage | undefined;
|
|
7596
|
+
/** Ack (remove) messages from `id`'s inbox — and from its prompt queue, so
|
|
7597
|
+
* an acked-but-still-queued message is never delivered afterwards. */
|
|
7598
|
+
ackInbox(id: string, ids: readonly string[] | "all"): {
|
|
7599
|
+
acked: string[];
|
|
7600
|
+
};
|
|
6109
7601
|
/** Snapshot a session's prompt queue for inspection — the after-the-fact
|
|
6110
7602
|
* view of what's sitting in `SessionDescriptor.promptQueue` right now.
|
|
6111
7603
|
* Runs the shared preview + origin-label derivation so every consumer
|
|
@@ -6134,7 +7626,8 @@ interface SessionsRegistry {
|
|
|
6134
7626
|
*
|
|
6135
7627
|
* Implemented as promote-to-front + interrupt: the cancelled turn's
|
|
6136
7628
|
* own `dispatchQueuedPrompt` (in its finally) then drains the promoted
|
|
6137
|
-
* item
|
|
7629
|
+
* item — and only that item; the rest wait for a natural turn-end —
|
|
7630
|
+
* into a fresh turn. On an idle session (nothing to interrupt) the
|
|
6138
7631
|
* promoted item is dispatched directly. Returns:
|
|
6139
7632
|
* `{ delivered: false, reason }` — `"no-session"` / `"not-in-queue"`;
|
|
6140
7633
|
* `{ delivered: true, interrupted: boolean }` otherwise. */
|
|
@@ -6390,6 +7883,15 @@ interface SessionsRegistry {
|
|
|
6390
7883
|
* Initial backfill: synchronously invokes `onLine` once for each
|
|
6391
7884
|
* line currently in the ring buffer so attaches show context. */
|
|
6392
7885
|
attach(id: string, onLine: (line: string, stream: "stdout" | "stderr") => void): (() => void) | null;
|
|
7886
|
+
/** Append a `kind: "mcp_app_tool_call"` record (an MCP App iframe's
|
|
7887
|
+
* `tools/call`, proxied by `mcp_app_tool_call`) to the session's
|
|
7888
|
+
* events.jsonl through the same seq-numbered writer the session's own
|
|
7889
|
+
* events use. No-op-safe for an unknown id (the writer creates the dir). */
|
|
7890
|
+
recordMcpAppToolCall(sessionId: string, record: McpAppToolCallRecord): void;
|
|
7891
|
+
/** Tool name the transcript recorded for `toolCallId` (the latest
|
|
7892
|
+
* non-empty `toolName` across its `tool-call` records), or undefined
|
|
7893
|
+
* when the id isn't in the session's events.jsonl. */
|
|
7894
|
+
findToolCallName(sessionId: string, toolCallId: string): Promise<string | undefined>;
|
|
6393
7895
|
/** Subscribe to a session's structured events.jsonl records as they're
|
|
6394
7896
|
* written — the live-push half of `GET /sessions/:id/events/stream`'s
|
|
6395
7897
|
* replay-then-subscribe handoff. Thin passthrough to the transcript
|
|
@@ -6433,7 +7935,26 @@ interface SessionsRegistry {
|
|
|
6433
7935
|
* bytes at the end; `lastBytes` caps the returned size from the
|
|
6434
7936
|
* tail. Returns null when the session is missing or not a PTY. */
|
|
6435
7937
|
readTerminalOutput(id: string, lastBytes?: number): Buffer | null;
|
|
6436
|
-
|
|
7938
|
+
/** SIGTERM the underlying child + close the agent protocol session.
|
|
7939
|
+
* `reason`, when given, is stamped onto `SessionDescriptor.endedReason`
|
|
7940
|
+
* (see {@link SessionEndReason}) — pass it from every call site that
|
|
7941
|
+
* knows WHY it's killing this session (an operator's explicit stop, a
|
|
7942
|
+
* supervisor tearing down its own judge session, …) rather than leaving
|
|
7943
|
+
* the row's cause of death unlabeled. Omitted preserves today's
|
|
7944
|
+
* behaviour: no `endedReason` is stamped by this call (the row may
|
|
7945
|
+
* already carry one from elsewhere, e.g. a prior `reapIdle`/`markCrashed`
|
|
7946
|
+
* — moot in practice since both already refuse a non-"running" row before
|
|
7947
|
+
* `kill()` would ever run on it).
|
|
7948
|
+
*
|
|
7949
|
+
* A row that's ALREADY terminal (exited/killed/error) normally makes this
|
|
7950
|
+
* a no-op refusal (`false`) — EXCEPT `reason: "operator-completed"`,
|
|
7951
|
+
* which is instead treated as "mark as completed": the persisted
|
|
7952
|
+
* outcome's `termination.reason` is idempotently relabeled to
|
|
7953
|
+
* `"operator-completed"` (the true original mechanism preserved in
|
|
7954
|
+
* `termination.previousReason`) and this returns `true`. Every other
|
|
7955
|
+
* reason (including `"operator-stopped"` or none) on a terminal row
|
|
7956
|
+
* stays the plain no-op. */
|
|
7957
|
+
kill(id: string, signal?: NodeJS.Signals, reason?: SessionEndReason): boolean;
|
|
6437
7958
|
/** Retire a long-idle agent-cli session to free its adapter process — the
|
|
6438
7959
|
* primitive the idle-session reaper (`runIdleReapPass`, PR-6) drives on a
|
|
6439
7960
|
* periodic sweep. Terminates the underlying adapter/child the SAME graceful
|
|
@@ -6541,17 +8062,6 @@ interface SessionsRegistry {
|
|
|
6541
8062
|
* window keeps aging out naturally rather than being wiped by the
|
|
6542
8063
|
* give-up itself. Returns false (no-op) for an unknown id. */
|
|
6543
8064
|
giveUpRestart(id: string, message: string): boolean;
|
|
6544
|
-
/** Queue a `[child-crashed] …` notice on a BUSY parent's descriptor
|
|
6545
|
-
* (`SessionDescriptor.pendingChildCrashNotices`) for delivery at its next
|
|
6546
|
-
* turn (`runAgentTurn`'s flush) — the never-interrupt path
|
|
6547
|
-
* `supervisor-notify.ts` takes when the parent can't be prompted
|
|
6548
|
-
* directly right now (it's mid-turn). Idempotent: the exact same notice
|
|
6549
|
-
* string is never queued twice, so a duplicate event for the same crash
|
|
6550
|
-
* can't double-deliver. No-op (returns false) on an unknown id, a
|
|
6551
|
-
* non-agent-cli row, or a row that isn't alive (`running`/`starting`) —
|
|
6552
|
-
* nothing to flush a notice INTO. Returns true iff the notice was newly
|
|
6553
|
-
* queued. */
|
|
6554
|
-
stampPendingChildCrashNotice(id: string, notice: string): boolean;
|
|
6555
8065
|
/** List permission requests currently parked in the pending-permissions
|
|
6556
8066
|
* inbox across all permission-hold sessions, newest last. Optionally
|
|
6557
8067
|
* filtered to one session. */
|
|
@@ -6563,8 +8073,9 @@ interface SessionsRegistry {
|
|
|
6563
8073
|
* clears the session's awaiting-permission state, and emits
|
|
6564
8074
|
* `session:permission-resolved`. */
|
|
6565
8075
|
respondPermission(id: string, input: PermissionRespondInput): Promise<PermissionRespondResult>;
|
|
6566
|
-
/** Stop tracking a session
|
|
6567
|
-
*
|
|
8076
|
+
/** Stop tracking a session. A still-live session is torn down through
|
|
8077
|
+
* `kill` first (same teardown as `agent_kill`), so forgetting never
|
|
8078
|
+
* orphans a running process tree. */
|
|
6568
8079
|
forget(id: string): boolean;
|
|
6569
8080
|
/** Await every best-effort fire-and-forget per-session write currently in
|
|
6570
8081
|
* flight — today the `CommandLogEntry` → `ToolCallRecord` chain
|
|
@@ -6770,6 +8281,9 @@ interface SpawnAgentInput {
|
|
|
6770
8281
|
/** What session close does to the box, when `remote` is true — see
|
|
6771
8282
|
* `SessionDescriptor.sandboxTeardown`. */
|
|
6772
8283
|
sandboxTeardown?: "kill" | "pause";
|
|
8284
|
+
/** Effective adapter confinement, resolved by the caller — see
|
|
8285
|
+
* `SessionDescriptor.commandSandbox`. */
|
|
8286
|
+
commandSandbox?: "off" | "workspace" | "strict";
|
|
6773
8287
|
/** Port-to-URL map from the booted sandbox — see
|
|
6774
8288
|
* `SessionDescriptor.sandboxPorts`. */
|
|
6775
8289
|
sandboxPorts?: Record<number, string>;
|
|
@@ -7118,7 +8632,7 @@ declare function runEagerResumePass(opts: {
|
|
|
7118
8632
|
|
|
7119
8633
|
/** A minimal `gh` runner — resolves with the captured exit code + stdout.
|
|
7120
8634
|
* Injected so tests drive stamping without spawning a real `gh`. */
|
|
7121
|
-
type GhRunner = (args: readonly string[], cwd: string) => Promise<{
|
|
8635
|
+
type GhRunner$1 = (args: readonly string[], cwd: string) => Promise<{
|
|
7122
8636
|
exitCode: number;
|
|
7123
8637
|
stdout: string;
|
|
7124
8638
|
}>;
|
|
@@ -7206,7 +8720,7 @@ declare function createPrProvenanceReconciler(opts: {
|
|
|
7206
8720
|
* Defaults to reading the session's own events.jsonl via
|
|
7207
8721
|
* {@link readToolCallRecords}; injectable for tests. */
|
|
7208
8722
|
listToolCalls?: (sessionId: string) => Promise<ToolCallRecord[]>;
|
|
7209
|
-
run?: GhRunner;
|
|
8723
|
+
run?: GhRunner$1;
|
|
7210
8724
|
host?: string;
|
|
7211
8725
|
}): PrProvenanceReconciler;
|
|
7212
8726
|
|
|
@@ -7297,6 +8811,79 @@ interface InboundWatcher {
|
|
|
7297
8811
|
shutdown(): void;
|
|
7298
8812
|
}
|
|
7299
8813
|
|
|
8814
|
+
/**
|
|
8815
|
+
* Dynamic MCP-app panels for installed `@agentproto/app-kit` apps that ship
|
|
8816
|
+
* a `ui` block (`defineApp({ ui: { html, title?, tools?, csp? } })`,
|
|
8817
|
+
* `app-tools.ts`'s `performInstall`). Bridges `AppRegistry` → `AgnoMcpApp[]`
|
|
8818
|
+
* so `registerMcpApps` (mcp-apps-adapter.ts) can mount them next to the
|
|
8819
|
+
* built-in panels (agentproto_sessions, agents_overview, ...).
|
|
8820
|
+
*
|
|
8821
|
+
* `mcpServerFactory` (index.ts) rebuilds a fresh McpServer per `/mcp`
|
|
8822
|
+
* request, so this module never throws — a bad app record must not take
|
|
8823
|
+
* down every other request. Failures (a collided tool id, an unreadable
|
|
8824
|
+
* `ui.path`) are skipped with a `console.warn`, not surfaced to the caller.
|
|
8825
|
+
*/
|
|
8826
|
+
|
|
8827
|
+
/**
|
|
8828
|
+
* The MCP Apps wire (spec `2026-01-26`) over `postMessage` JSON-RPC, exposed
|
|
8829
|
+
* as `window.McpApp.connect() -> Promise<{ callTool, sendMessage,
|
|
8830
|
+
* updateModelContext, openLink, onTeardown }>`. No host in this stack injects
|
|
8831
|
+
* an SDK global into the app iframe, so every UI panel that talks through
|
|
8832
|
+
* `window.McpApp` (all of them — see each app's `ui.ts` under
|
|
8833
|
+
* `packages/apps/src`) would otherwise throw `Cannot read properties of
|
|
8834
|
+
* undefined (reading 'connect')` at boot. Injected here, at serve time, so
|
|
8835
|
+
* every installed app's panel is covered without each app shipping its own
|
|
8836
|
+
* copy of the bridge.
|
|
8837
|
+
*
|
|
8838
|
+
* Bridge surface:
|
|
8839
|
+
* - `callTool(name, args)` — JSON-RPC `tools/call`
|
|
8840
|
+
* - `sendMessage(content)` — JSON-RPC `ui/message`
|
|
8841
|
+
* - `updateModelContext({content?, structuredContent?})` — JSON-RPC
|
|
8842
|
+
* `ui/update-model-context`; each call replaces the previous context.
|
|
8843
|
+
* - `openLink(url)` — JSON-RPC `ui/open-link` {url}
|
|
8844
|
+
* - `onTeardown(cb)` — register a cleanup callback invoked on
|
|
8845
|
+
* `ui/resource-teardown` from the host, at which point the bridge also
|
|
8846
|
+
* replies `{result:{}}` automatically.
|
|
8847
|
+
* - `getHostContext()` / `onHostContext(cb)` — the host context captured
|
|
8848
|
+
* from the `ui/initialize` result and merged on every
|
|
8849
|
+
* `ui/notifications/host-context-changed` (the notification carries only
|
|
8850
|
+
* the changed keys, per the ext-apps spec).
|
|
8851
|
+
* - `getToolInput()` / `onToolInput(cb)` — the arguments the panel's own tool
|
|
8852
|
+
* (`app_ui_<slug>`) was invoked with, from `ui/notifications/tool-input`,
|
|
8853
|
+
* falling back to the tool's own result (`ui/notifications/tool-result`,
|
|
8854
|
+
* which `registerMcpApps` fills with `execute()`'s return value) for a host
|
|
8855
|
+
* that forwards results but not inputs. A late subscriber is replayed the
|
|
8856
|
+
* last value, same as `onHostContext`. Lets an MCP-hosted panel resolve a
|
|
8857
|
+
* deep link (e.g. `{view: "wallets/my-profile"}`) the way the browser-served
|
|
8858
|
+
* panel resolves `location.hash`.
|
|
8859
|
+
* - `displayMode` — `{get, available, request, onChange, mountToggle}`, the
|
|
8860
|
+
* shared controller from `@agentproto/app-client/display-mode` (also
|
|
8861
|
+
* published as `window.McpApp.displayMode` once connected). It is what
|
|
8862
|
+
* mounts the floating ⤢ toggle; an app that wants the control in its own
|
|
8863
|
+
* header opts the floating one out (`<meta name="agentproto-display-toggle"
|
|
8864
|
+
* content="none">`, or `connect({displayToggle: "none"})`) and calls
|
|
8865
|
+
* `displayMode.mountToggle(el)` instead.
|
|
8866
|
+
*/
|
|
8867
|
+
declare const MCP_APP_BRIDGE_SCRIPT = "<script>\n(function () {\n window.__AGENTPROTO_UI_TRANSPORT__ = \"mcp\";\n if (window.McpApp) return;\n var nextId = 1, pending = {}, teardownCbs = [];\n var hostContext = null, hostContextCbs = [];\n var toolInput = null, toolInputCbs = [];\n function post(m) { window.parent.postMessage(m, \"*\"); }\n function getHostContext() { return hostContext; }\n function onHostContext(cb) {\n hostContextCbs.push(cb);\n // Replay the last context so a late subscriber isn't stuck blind.\n if (hostContext) { try { cb(hostContext); } catch (_) {} }\n }\n function setHostContext(ctx) {\n if (!ctx || typeof ctx !== \"object\") return;\n // host-context-changed carries only the changed keys \u2014 merge, matching\n // the official ext-apps App behaviour.\n hostContext = Object.assign({}, hostContext || {}, ctx);\n for (var i = 0; i < hostContextCbs.length; i++) {\n try { hostContextCbs[i](hostContext); } catch (_) {}\n }\n }\n function getToolInput() { return toolInput; }\n function onToolInput(cb) {\n toolInputCbs.push(cb);\n // Replay the last known input so a late subscriber isn't stuck blind \u2014\n // same convention as onHostContext.\n if (toolInput) { try { cb(toolInput); } catch (_) {} }\n }\n function setToolInput(input) {\n if (!input || typeof input !== \"object\") return;\n toolInput = input;\n for (var i = 0; i < toolInputCbs.length; i++) {\n try { toolInputCbs[i](toolInput); } catch (_) {}\n }\n }\n // A ui/notifications/tool-result carries the full CallToolResult of the\n // tool call that opened this view (spec 2026-01-26) \u2014 the same envelope\n // registerMcpApps wraps execute()'s return value in (JSON text content, or\n // structuredContent). Read as a fallback source of the tool's arguments\n // for a host that forwards results but not tool-input.\n function extractToolResultInput(result) {\n try {\n if (result && result.structuredContent && typeof result.structuredContent === \"object\") {\n return result.structuredContent;\n }\n var c = result && Array.isArray(result.content) ? result.content[0] : null;\n if (c && c.type === \"text\" && typeof c.text === \"string\") return JSON.parse(c.text);\n } catch (_) {}\n return null;\n }\n window.addEventListener(\"message\", function (e) {\n var m = e.data;\n if (typeof m === \"string\") { try { m = JSON.parse(m); } catch (_) { return; } }\n if (!m || m.jsonrpc !== \"2.0\") return;\n if (m.method === \"ui/resource-teardown\") {\n for (var i = 0; i < teardownCbs.length; i++) teardownCbs[i]();\n post({ jsonrpc: \"2.0\", id: m.id, result: {} });\n return;\n }\n if (m.method === \"ui/notifications/host-context-changed\") { setHostContext(m.params || {}); return; }\n if (m.method === \"ui/notifications/tool-input\") { setToolInput((m.params || {}).arguments); return; }\n if (m.method === \"ui/notifications/tool-result\") { setToolInput(extractToolResultInput(m.params)); return; }\n if (m.id != null && pending[m.id]) { var cb = pending[m.id]; delete pending[m.id]; cb(m.result, m.error); }\n });\n function request(method, params) {\n return new Promise(function (resolve, reject) {\n var id = nextId++;\n pending[id] = function (r, err) { if (err) reject(new Error((err && err.message) || String(err))); else resolve(r); };\n post({ jsonrpc: \"2.0\", id: id, method: method, params: params });\n });\n }\n function requestDisplayMode(mode) { return request(\"ui/request-display-mode\", { mode: mode }); }\n // The shared toggle (@agentproto/app-client/display-mode), injected right\n // after this script. Absent only when the app ships its own\n // window.AgentprotoUI namespace, which suppresses that injection \u2014 the\n // fallback keeps window.McpApp.displayMode callable either way.\n function installDisplayMode(opts) {\n var api = { getHostContext: getHostContext, onHostContext: onHostContext, requestDisplayMode: requestDisplayMode };\n if (window.AgentprotoUI && window.AgentprotoUI.installDisplayMode) {\n return window.AgentprotoUI.installDisplayMode(api, opts);\n }\n return {\n get: function () { return (hostContext && hostContext.displayMode) || \"inline\"; },\n available: function () { return (hostContext && hostContext.availableDisplayModes) || []; },\n request: requestDisplayMode,\n onChange: function (cb) { onHostContext(function (c) { cb((c && c.displayMode) || \"inline\", c); }); return function () {}; },\n mountToggle: function () { return null; }\n };\n }\n window.McpApp = {\n connect: function (opts) {\n if (window.parent === window) return Promise.reject(new Error(\"no host (standalone)\"));\n return request(\"ui/initialize\", {\n appInfo: { name: \"agentproto-app\", version: \"1.0\" },\n appCapabilities: { availableDisplayModes: [\"inline\", \"fullscreen\"] },\n protocolVersion: \"2026-01-26\"\n }).then(function (result) {\n // The initialize result carries the initial hostContext (displayMode,\n // availableDisplayModes, theme, safeAreaInsets) \u2014 capture it before\n // notifying the host, so the toggle renders in the right place on\n // its first paint rather than after a host-context-changed.\n if (result && result.hostContext) setHostContext(result.hostContext);\n post({ jsonrpc: \"2.0\", method: \"ui/notifications/initialized\", params: {} });\n var displayMode = installDisplayMode((opts && opts.displayToggle) ? { toggle: opts.displayToggle } : null);\n window.McpApp.displayMode = displayMode;\n return {\n callTool: function (name, args) { return request(\"tools/call\", { name: name, arguments: args || {} }); },\n sendMessage: function (p) {\n var params = typeof p === \"string\" ? { content: p } : (p || {});\n var content = typeof params.content === \"string\" ? [{ type: \"text\", text: params.content }] : (params.content || []);\n return request(\"ui/message\", { role: \"user\", content: content });\n },\n updateModelContext: function (p) { return request(\"ui/update-model-context\", p || {}); },\n openLink: function (url) { return request(\"ui/open-link\", { url: url }); },\n onTeardown: function (cb) { teardownCbs.push(cb); },\n getHostContext: getHostContext,\n onHostContext: onHostContext,\n getToolInput: getToolInput,\n onToolInput: onToolInput,\n displayMode: displayMode\n };\n });\n }\n };\n})();\n</script>\n";
|
|
8868
|
+
/** Inject `MCP_APP_BRIDGE_SCRIPT` followed by the two
|
|
8869
|
+
* `window.AgentprotoUI` scripts (`DISPLAY_MODE_SCRIPT`, then
|
|
8870
|
+
* `RUNNER_SELECT_SCRIPT`) — every installed app UI gets the shared
|
|
8871
|
+
* display-mode toggle and `mountRunnerSelect` for free, same as it gets
|
|
8872
|
+
* `window.McpApp` (see `injectAfterStructuralTag` for the placement rule).
|
|
8873
|
+
* The halves are independently idempotent, so a single
|
|
8874
|
+
* `injectAfterStructuralTag` call inserts only whichever ones the document
|
|
8875
|
+
* doesn't already define — inserting them one call each would place the
|
|
8876
|
+
* second BEFORE the first (all target "right after the same structural
|
|
8877
|
+
* tag"), which is why they're concatenated first instead. `window.
|
|
8878
|
+
* AgentprotoUI` gates BOTH of its scripts as one unit: a document that
|
|
8879
|
+
* already defines that namespace brings its own, and the bridge's
|
|
8880
|
+
* `installDisplayMode` falls back to a controller with no button rather
|
|
8881
|
+
* than fighting it. The bridge guard matches an assignment only — every
|
|
8882
|
+
* app panel CONSUMES `window.McpApp.connect()`, so matching any mention
|
|
8883
|
+
* would skip injection for exactly the documents that need it, leaving
|
|
8884
|
+
* `window.McpApp` undefined in the host iframe. */
|
|
8885
|
+
declare function injectMcpAppBridge(html: string): string;
|
|
8886
|
+
|
|
7300
8887
|
/**
|
|
7301
8888
|
* MCP tools that expose the per-workspace brain to agents.
|
|
7302
8889
|
*
|
|
@@ -7420,6 +9007,326 @@ interface WorkspaceBrainSubscriber {
|
|
|
7420
9007
|
}
|
|
7421
9008
|
declare function createWorkspaceBrainSubscriber(opts: WorkspaceBrainSubscriberOptions): WorkspaceBrainSubscriber;
|
|
7422
9009
|
|
|
9010
|
+
/**
|
|
9011
|
+
* Review ledger — the daemon-side record of every review attestation.
|
|
9012
|
+
*
|
|
9013
|
+
* Lives under the daemon state dir, NEVER in the reviewed repo's working
|
|
9014
|
+
* tree: `~/.agentproto/reviews/<repo-slug>/<manifestSha>/<binding>/<rangeSha>.json`
|
|
9015
|
+
* — the path IS the ledger key `(repoRemote, manifestSha, binding, rangeSha)`
|
|
9016
|
+
* (the repo slug is a filesystem-safe form of the normalized remote). One
|
|
9017
|
+
* file per key; a re-run of the same key overwrites it with the newer
|
|
9018
|
+
* attestation.
|
|
9019
|
+
*
|
|
9020
|
+
* Every attestation is recorded — including `incomplete` and dirty-tree ones,
|
|
9021
|
+
* so `review_ledger` shows the history honestly — but only a clean `pass` /
|
|
9022
|
+
* `block` is ever served back as a cache hit (see `lookupCached`).
|
|
9023
|
+
*
|
|
9024
|
+
* Each file is an {@link LedgerEntry}: the self-contained attestation (what
|
|
9025
|
+
* `review_export` writes out) plus host-local metadata that is NOT part of
|
|
9026
|
+
* what gets attested (the checkout path, the manifest path, the manifest's
|
|
9027
|
+
* `verdict.exportDir`).
|
|
9028
|
+
*
|
|
9029
|
+
* Beside each entry sits an optional `<rangeSha>.annotations.json`
|
|
9030
|
+
* ({@link LedgerAnnotations}): the MUTABLE follow-up layer — a PR link found
|
|
9031
|
+
* after the fact, and `review_pr` status snapshots appended over time. It is
|
|
9032
|
+
* never hashed into (or exported with) the attestation, so annotating an
|
|
9033
|
+
* entry can't disturb a signature over it.
|
|
9034
|
+
*
|
|
9035
|
+
* Same persistence primitives as the sibling JSON stores (`node:fs/promises`,
|
|
9036
|
+
* write-tmp + rename). The root is injectable so tests never touch
|
|
9037
|
+
* `~/.agentproto`.
|
|
9038
|
+
*/
|
|
9039
|
+
|
|
9040
|
+
/** Host-local metadata stored beside an attestation (never exported). */
|
|
9041
|
+
interface LedgerHostMeta {
|
|
9042
|
+
/** Absolute path of the checkout the review ran in. */
|
|
9043
|
+
repoRoot: string;
|
|
9044
|
+
/** Absolute path of the REVIEW.md that was used. */
|
|
9045
|
+
manifestPath: string;
|
|
9046
|
+
/** The manifest's `verdict.exportDir`, resolved against `repoRoot`. */
|
|
9047
|
+
exportDir?: string;
|
|
9048
|
+
}
|
|
9049
|
+
interface LedgerEntry {
|
|
9050
|
+
attestation: Attestation;
|
|
9051
|
+
host: LedgerHostMeta;
|
|
9052
|
+
}
|
|
9053
|
+
/** One `review_pr` status fetch. */
|
|
9054
|
+
interface PrStatusSnapshot {
|
|
9055
|
+
/** ISO timestamp of the fetch. */
|
|
9056
|
+
fetchedAt: string;
|
|
9057
|
+
state: "open" | "merged" | "closed";
|
|
9058
|
+
reviews: Array<{
|
|
9059
|
+
login: string;
|
|
9060
|
+
state: string;
|
|
9061
|
+
submittedAt: string;
|
|
9062
|
+
}>;
|
|
9063
|
+
checks?: Array<{
|
|
9064
|
+
name: string;
|
|
9065
|
+
conclusion: string | null;
|
|
9066
|
+
}>;
|
|
9067
|
+
}
|
|
9068
|
+
/** The mutable annotations sidecar of a ledger entry. */
|
|
9069
|
+
interface LedgerAnnotations {
|
|
9070
|
+
pr?: ReviewPrRef;
|
|
9071
|
+
/** Oldest first — each `review_pr` call appends one. */
|
|
9072
|
+
prStatus?: PrStatusSnapshot[];
|
|
9073
|
+
}
|
|
9074
|
+
interface ReviewLedgerFilter {
|
|
9075
|
+
repoRemote?: string;
|
|
9076
|
+
rangeSha?: string;
|
|
9077
|
+
binding?: string;
|
|
9078
|
+
manifestSha?: string;
|
|
9079
|
+
}
|
|
9080
|
+
interface ReviewLedger {
|
|
9081
|
+
/** Absolute root directory of the ledger. */
|
|
9082
|
+
readonly root: string;
|
|
9083
|
+
put(entry: LedgerEntry): Promise<string>;
|
|
9084
|
+
get(key: LedgerKey): Promise<LedgerEntry | undefined>;
|
|
9085
|
+
/** A reusable verdict for `key`: a clean (not dirty) `pass`/`block` whose
|
|
9086
|
+
* rubric digests still match. `incomplete` is never reused. */
|
|
9087
|
+
lookupCached(key: LedgerKey, rubrics: readonly RubricDigest[]): Promise<LedgerEntry | undefined>;
|
|
9088
|
+
findByRunId(runId: string): Promise<LedgerEntry | undefined>;
|
|
9089
|
+
/** Entries matching `filter`, newest first. */
|
|
9090
|
+
list(filter?: ReviewLedgerFilter): Promise<LedgerEntry[]>;
|
|
9091
|
+
/** The annotations sidecar of `key` (`{}` when there is none). */
|
|
9092
|
+
getAnnotations(key: LedgerKey): Promise<LedgerAnnotations>;
|
|
9093
|
+
/** Read-modify-write the annotations sidecar of `key`; returns the result. */
|
|
9094
|
+
updateAnnotations(key: LedgerKey, update: (current: LedgerAnnotations) => LedgerAnnotations): Promise<LedgerAnnotations>;
|
|
9095
|
+
}
|
|
9096
|
+
/** Record `pr` as the entry's PR link (replacing any previous link). */
|
|
9097
|
+
declare const withPr: (pr: ReviewPrRef) => (a: LedgerAnnotations) => LedgerAnnotations;
|
|
9098
|
+
/** Append one status snapshot. */
|
|
9099
|
+
declare const withPrStatus: (snapshot: PrStatusSnapshot) => (a: LedgerAnnotations) => LedgerAnnotations;
|
|
9100
|
+
declare const defaultReviewLedgerRoot: () => string;
|
|
9101
|
+
/** Filesystem-safe slug of a normalized repo remote
|
|
9102
|
+
* (`github.com/agentproto/ts` → `github.com_agentproto_ts`). */
|
|
9103
|
+
declare function repoSlug(repoRemote: string): string;
|
|
9104
|
+
declare function createReviewLedger(opts?: {
|
|
9105
|
+
root?: string;
|
|
9106
|
+
}): ReviewLedger;
|
|
9107
|
+
|
|
9108
|
+
/**
|
|
9109
|
+
* Review runner — the daemon host for `@agentproto/review`.
|
|
9110
|
+
*
|
|
9111
|
+
* The pure package parses REVIEW.md and compiles a binding into an ordinary
|
|
9112
|
+
* AIP-15 workflow; this module supplies everything that touches the world:
|
|
9113
|
+
*
|
|
9114
|
+
* 1. resolve the repo + range — `merge-base(<target.base>, HEAD)..HEAD`
|
|
9115
|
+
* unless the caller pins `base`/`head`;
|
|
9116
|
+
* 2. ledger pre-check — a clean `pass`/`block` already recorded for the
|
|
9117
|
+
* same `(repoRemote, manifestSha, binding, rangeSha)` (and the same
|
|
9118
|
+
* rubric digests) is returned with `cached: true`, nothing runs;
|
|
9119
|
+
* 3. execute the compiled workflow through `@agentproto/workflow-runtime`'s
|
|
9120
|
+
* `compileWorkflow` + `runWorkflow` — prepare steps (the engine's own
|
|
9121
|
+
* gate runner), then the FREEZE (head resolved after prepare), then the
|
|
9122
|
+
* lanes in parallel through {@link createReviewLaneExecutor}, then the
|
|
9123
|
+
* fan-in verdict;
|
|
9124
|
+
* 4. build the attestation and write it to the ledger. A CANCELLED run
|
|
9125
|
+
* (`cancel()`, or superseded by a newer head — see `supersede`) writes
|
|
9126
|
+
* nothing: nobody asked for its verdict any more.
|
|
9127
|
+
*
|
|
9128
|
+
* Lanes: command lanes run `sh -c <run>` in their own process group with a
|
|
9129
|
+
* hard timeout; agent lanes spawn a CHILD REVIEWER SESSION through
|
|
9130
|
+
* {@link ReviewerSessionHost} — in the daemon, {@link createDaemonReviewerHost},
|
|
9131
|
+
* which uses the same `spawnAgentSession` core `agent_start` uses and kills
|
|
9132
|
+
* the session through the registry on timeout/cancel (a child session, never
|
|
9133
|
+
* an orphan pid). The reviewer gets a pointer-style prompt (range + rubric
|
|
9134
|
+
* path) and writes a structured verdict file under the ledger's run dir —
|
|
9135
|
+
* outside the reviewed tree.
|
|
9136
|
+
*
|
|
9137
|
+
* Async pattern mirrors `WorkflowRunner`: `start()` returns a run record
|
|
9138
|
+
* immediately and executes in the background; `status()` polls; `wait()`
|
|
9139
|
+
* blocks. Runs live in memory for the daemon's lifetime; the ATTESTATION is
|
|
9140
|
+
* what persists (the ledger), and `status()` falls back to it for a run that
|
|
9141
|
+
* finished before a daemon restart.
|
|
9142
|
+
*/
|
|
9143
|
+
|
|
9144
|
+
/**
|
|
9145
|
+
* Normalize a git remote URL so SSH and HTTPS clones of the same repo agree:
|
|
9146
|
+
* `git@github.com:agentproto/ts.git` and `https://user@github.com/agentproto/ts`
|
|
9147
|
+
* both become `github.com/agentproto/ts`. Credentials are always stripped.
|
|
9148
|
+
*/
|
|
9149
|
+
declare function normalizeRemote(url: string): string;
|
|
9150
|
+
/** Run one command lane: `sh -c <command>` in its own process group, output
|
|
9151
|
+
* captured (tail-bounded), hard-killed on timeout or cancel. */
|
|
9152
|
+
declare function runShellLane(input: {
|
|
9153
|
+
command: string;
|
|
9154
|
+
cwd: string;
|
|
9155
|
+
timeoutMs: number;
|
|
9156
|
+
signal?: AbortSignal;
|
|
9157
|
+
}): Promise<LaneOutcome>;
|
|
9158
|
+
/** Outcome of one reviewer session's run. */
|
|
9159
|
+
type ReviewerRunResult = {
|
|
9160
|
+
status: "ended";
|
|
9161
|
+
sessionId: string;
|
|
9162
|
+
preset: string;
|
|
9163
|
+
model?: string;
|
|
9164
|
+
} | {
|
|
9165
|
+
status: "timeout";
|
|
9166
|
+
sessionId: string;
|
|
9167
|
+
preset: string;
|
|
9168
|
+
model?: string;
|
|
9169
|
+
} | {
|
|
9170
|
+
status: "failed";
|
|
9171
|
+
error: string;
|
|
9172
|
+
sessionId?: string;
|
|
9173
|
+
preset?: string;
|
|
9174
|
+
model?: string;
|
|
9175
|
+
};
|
|
9176
|
+
/**
|
|
9177
|
+
* The agent-lane executor seam: spawn a reviewer session under a harness
|
|
9178
|
+
* preset, run ONE turn with `prompt`, and stop it — killing it through the
|
|
9179
|
+
* session lifecycle on timeout or cancel. The daemon wires
|
|
9180
|
+
* {@link createDaemonReviewerHost}; tests wire a fake.
|
|
9181
|
+
*/
|
|
9182
|
+
interface ReviewerSessionHost {
|
|
9183
|
+
run(input: {
|
|
9184
|
+
preset: string;
|
|
9185
|
+
cwd: string;
|
|
9186
|
+
prompt: string;
|
|
9187
|
+
label: string;
|
|
9188
|
+
timeoutMs: number;
|
|
9189
|
+
parentSessionId?: string;
|
|
9190
|
+
signal?: AbortSignal;
|
|
9191
|
+
}): Promise<ReviewerRunResult>;
|
|
9192
|
+
}
|
|
9193
|
+
interface ReviewLaneExecutorContext {
|
|
9194
|
+
runId: string;
|
|
9195
|
+
reviewId: string;
|
|
9196
|
+
repoRoot: string;
|
|
9197
|
+
manifestPath: string;
|
|
9198
|
+
/** Directory the agent lanes' verdict files are written under. */
|
|
9199
|
+
runDir: string;
|
|
9200
|
+
reviewers?: ReviewerSessionHost;
|
|
9201
|
+
parentSessionId?: string;
|
|
9202
|
+
}
|
|
9203
|
+
/** The daemon's {@link ReviewLaneExecutor}: subprocess command lanes, child
|
|
9204
|
+
* reviewer sessions for agent lanes. */
|
|
9205
|
+
declare function createReviewLaneExecutor(ctx: ReviewLaneExecutorContext): ReviewLaneExecutor;
|
|
9206
|
+
interface ReviewRunInput {
|
|
9207
|
+
/** Any directory inside the repo to review. */
|
|
9208
|
+
cwd: string;
|
|
9209
|
+
/** REVIEW.md path — absolute, or relative to `cwd`. Default: `<repo root>/REVIEW.md`. */
|
|
9210
|
+
manifestPath?: string;
|
|
9211
|
+
/** Binding name. Default: the sole binding, or `default`. */
|
|
9212
|
+
binding?: string;
|
|
9213
|
+
/** Range base (ref or sha). Default: `merge-base(<target.base>, HEAD)`. */
|
|
9214
|
+
base?: string;
|
|
9215
|
+
/** Range head (ref or sha). Default: `HEAD`, resolved AFTER prepare. */
|
|
9216
|
+
head?: string;
|
|
9217
|
+
/** Ignore a cached ledger verdict and re-run. */
|
|
9218
|
+
nocache?: boolean;
|
|
9219
|
+
/** Session the agent lanes' reviewer sessions nest under. */
|
|
9220
|
+
parentSessionId?: string;
|
|
9221
|
+
/** Session that requested the review — recorded as
|
|
9222
|
+
* `attestation.requester.sessionId`. Default: `parentSessionId`. */
|
|
9223
|
+
requesterSessionId?: string;
|
|
9224
|
+
/** The PR the range is being reviewed for, when the caller knows it —
|
|
9225
|
+
* recorded as `attestation.pr` and as the entry's annotation link. */
|
|
9226
|
+
pr?: ReviewPrRef;
|
|
9227
|
+
/** Before running, cancel in-flight runs for the same repo + binding + base
|
|
9228
|
+
* whose head DIFFERS (an older push nobody will read the verdict of) — as
|
|
9229
|
+
* long as that run is the same line of work: the same checkout, or a head
|
|
9230
|
+
* that is an ancestor of this one. A sibling branch reviewed from another
|
|
9231
|
+
* worktree off the same base is never cancelled. Gates should pass
|
|
9232
|
+
* `true`; the default is `false`. */
|
|
9233
|
+
supersede?: boolean;
|
|
9234
|
+
}
|
|
9235
|
+
type ReviewRunStatus = "running" | "done" | "failed" | "cancelled";
|
|
9236
|
+
interface ReviewRun {
|
|
9237
|
+
runId: string;
|
|
9238
|
+
status: ReviewRunStatus;
|
|
9239
|
+
startedAt: string;
|
|
9240
|
+
endedAt?: string;
|
|
9241
|
+
reviewId?: string;
|
|
9242
|
+
binding?: string;
|
|
9243
|
+
repoRemote?: string;
|
|
9244
|
+
/** The resolved range base, once known. */
|
|
9245
|
+
baseSha?: string;
|
|
9246
|
+
/** The range head: the pre-prepare head once resolved, then the frozen head. */
|
|
9247
|
+
headSha?: string;
|
|
9248
|
+
/** The checkout the run reviews, once resolved. */
|
|
9249
|
+
repoRoot?: string;
|
|
9250
|
+
/** Set on a run cancelled because a newer head superseded it. */
|
|
9251
|
+
supersededBy?: string;
|
|
9252
|
+
/** Lanes settled so far (live progress while `running`). */
|
|
9253
|
+
lanes: LaneResult[];
|
|
9254
|
+
/** Set once `done`. */
|
|
9255
|
+
attestation?: Attestation;
|
|
9256
|
+
/** True when `attestation` was served from the ledger — nothing ran. */
|
|
9257
|
+
cached?: boolean;
|
|
9258
|
+
/** Where the attestation was written in the ledger. */
|
|
9259
|
+
ledgerPath?: string;
|
|
9260
|
+
error?: string;
|
|
9261
|
+
}
|
|
9262
|
+
interface ReviewRunner {
|
|
9263
|
+
start(input: ReviewRunInput): ReviewRun;
|
|
9264
|
+
status(runId: string): Promise<ReviewRun | undefined>;
|
|
9265
|
+
wait(runId: string): Promise<ReviewRun | undefined>;
|
|
9266
|
+
cancel(runId: string): boolean;
|
|
9267
|
+
readonly ledger: ReviewLedger;
|
|
9268
|
+
}
|
|
9269
|
+
interface CreateReviewRunnerOptions {
|
|
9270
|
+
ledger: ReviewLedger;
|
|
9271
|
+
/** Agent-lane executor. Omitted ⇒ agent lanes are `skipped` (and the
|
|
9272
|
+
* verdict therefore `incomplete`), never silently passed. */
|
|
9273
|
+
reviewers?: ReviewerSessionHost;
|
|
9274
|
+
/** Attestor identity. Default: `agentproto-runtime@<hostname>`. */
|
|
9275
|
+
daemonId?: string;
|
|
9276
|
+
}
|
|
9277
|
+
/** Placeholder values the daemon binds for every review. `{changed}` is a
|
|
9278
|
+
* shell-quoted turbo filter for the packages changed since the range base
|
|
9279
|
+
* (compose dependents with `...{changed}`). */
|
|
9280
|
+
declare function hostPlaceholders(baseSha: string): Record<string, string>;
|
|
9281
|
+
declare function createReviewRunner(opts: CreateReviewRunnerOptions): ReviewRunner;
|
|
9282
|
+
|
|
9283
|
+
/**
|
|
9284
|
+
* PR follow-up for review attestations — the host side of `review_pr`.
|
|
9285
|
+
*
|
|
9286
|
+
* A review attests a git range; whether that range became a PR, and what
|
|
9287
|
+
* happened to the PR afterwards, is only knowable later. This module asks
|
|
9288
|
+
* GitHub through the daemon host's authed `gh` CLI (shelled out — no HTTP
|
|
9289
|
+
* client, no token handling of our own):
|
|
9290
|
+
*
|
|
9291
|
+
* - {@link findPrForCommit}: `headSha → PR` via
|
|
9292
|
+
* `gh api repos/{owner}/{repo}/commits/{sha}/pulls`;
|
|
9293
|
+
* - {@link fetchPrStatus}: the PR's state + reviews (+ check runs on the
|
|
9294
|
+
* PR head, best-effort) as one {@link PrStatusSnapshot}.
|
|
9295
|
+
*
|
|
9296
|
+
* Every failure is a {@link PrLookupError} with a stable `code` — `gh`
|
|
9297
|
+
* missing, `gh` failing (auth, network, 404), a non-GitHub remote, no PR for
|
|
9298
|
+
* the commit — so the tool can return it as structured data instead of
|
|
9299
|
+
* throwing.
|
|
9300
|
+
*/
|
|
9301
|
+
|
|
9302
|
+
type PrLookupErrorCode = "gh_unavailable" | "gh_failed" | "unsupported_remote" | "no_pr";
|
|
9303
|
+
declare class PrLookupError extends Error {
|
|
9304
|
+
readonly code: PrLookupErrorCode;
|
|
9305
|
+
constructor(code: PrLookupErrorCode, message: string);
|
|
9306
|
+
}
|
|
9307
|
+
/** Runs `gh <args>` and resolves its stdout. */
|
|
9308
|
+
type GhRunner = (args: readonly string[]) => Promise<string>;
|
|
9309
|
+
/** The real runner: `gh` from the daemon's PATH. A missing binary is
|
|
9310
|
+
* `gh_unavailable`; any non-zero exit is `gh_failed` with gh's stderr. */
|
|
9311
|
+
declare const execGh: GhRunner;
|
|
9312
|
+
/** `github.com/owner/name` → `owner/name`; `undefined` for any other host.
|
|
9313
|
+
* Also accepts the multi-account SSH host-alias convention
|
|
9314
|
+
* (`git@github.com-work:owner/name` normalizes to `github.com-work/owner/name`). */
|
|
9315
|
+
declare function githubRepoOf(repoRemote: string): string | undefined;
|
|
9316
|
+
/** Parse `https://github.com/owner/name/pull/42` (trailing path/query ok). */
|
|
9317
|
+
declare function parsePrUrl(url: string): {
|
|
9318
|
+
repo: string;
|
|
9319
|
+
number: number;
|
|
9320
|
+
} | undefined;
|
|
9321
|
+
/** The PR `headSha` belongs to, or `undefined` when GitHub knows none.
|
|
9322
|
+
* Prefers a PR whose head IS `headSha`, then an open one, then the first. */
|
|
9323
|
+
declare function findPrForCommit(gh: GhRunner, repo: string, headSha: string): Promise<ReviewPrRef | undefined>;
|
|
9324
|
+
/** The PR's head sha (for matching a `prUrl` to ledger entries). */
|
|
9325
|
+
declare function prHeadSha(gh: GhRunner, repo: string, number: number): Promise<string | undefined>;
|
|
9326
|
+
/** One status snapshot of `pr`: state, reviews, and (best-effort — omitted
|
|
9327
|
+
* when that call fails) the check runs on the PR's current head. */
|
|
9328
|
+
declare function fetchPrStatus(gh: GhRunner, pr: ReviewPrRef, now?: () => Date): Promise<PrStatusSnapshot>;
|
|
9329
|
+
|
|
7423
9330
|
/**
|
|
7424
9331
|
* `~/.agentproto/harness-presets.json` — the persisted harness→profile binding
|
|
7425
9332
|
* (mode 0600). A {@link HarnessPreset} names, per adapter harness, WHICH auth
|
|
@@ -7527,6 +9434,77 @@ declare function removeHarnessPreset(id: string): Promise<boolean>;
|
|
|
7527
9434
|
*/
|
|
7528
9435
|
declare function setDefaultPreset(harnessSlug: string, presetId: string): Promise<HarnessPreset>;
|
|
7529
9436
|
|
|
9437
|
+
/**
|
|
9438
|
+
* The daemon's {@link ReviewerSessionHost}: agent review lanes as CHILD
|
|
9439
|
+
* SESSIONS, spawned through the same `spawnAgentSession` core `agent_start`
|
|
9440
|
+
* uses, waited on with the same `monitorSessionWait` core `session_monitor` /
|
|
9441
|
+
* `sessions wait` use, and stopped through `registry.kill` — the normal
|
|
9442
|
+
* session lifecycle, so a timed-out or cancelled reviewer is a killed session
|
|
9443
|
+
* in `session_list`, never an orphan pid.
|
|
9444
|
+
*
|
|
9445
|
+
* A lane's `preset` names the daemon's existing preset surface — no parallel
|
|
9446
|
+
* model/auth config: first a harness preset (`harness-presets.json`: adapter
|
|
9447
|
+
* harness + auth profile + default model), then a user preset
|
|
9448
|
+
* (`presets.json`, handed to `spawnAgentSession` as-is so it expands the
|
|
9449
|
+
* preset exactly like `agent_start.presetId` does).
|
|
9450
|
+
*
|
|
9451
|
+
* Reviewers spawn with role `executor` (no re-delegation), `worktree: false`
|
|
9452
|
+
* (they read the reviewed checkout's history; they never edit), and
|
|
9453
|
+
* `dedupe: false` (two lanes/runs with the same label are distinct
|
|
9454
|
+
* reviewers, never merged).
|
|
9455
|
+
*/
|
|
9456
|
+
|
|
9457
|
+
interface DaemonReviewerHostDeps {
|
|
9458
|
+
registry: SessionsRegistry;
|
|
9459
|
+
sessionEvents: SessionEventBus;
|
|
9460
|
+
eventRing: EventRing;
|
|
9461
|
+
resolveAgentAdapter: AgentAdapterResolver;
|
|
9462
|
+
/** Extra spawn deps forwarded to `spawnAgentSession` (sandbox resolver,
|
|
9463
|
+
* catalog models, …). `registry`/`resolveAgentAdapter` always win. */
|
|
9464
|
+
spawnDeps?: Partial<SpawnAgentSessionDeps>;
|
|
9465
|
+
/** Preset lookups — injectable for tests; default to the real stores. */
|
|
9466
|
+
getHarnessPreset?: (id: string) => Promise<HarnessPreset | undefined>;
|
|
9467
|
+
getUserPreset?: (id: string) => Promise<UserPreset | undefined>;
|
|
9468
|
+
}
|
|
9469
|
+
/** Resolve a lane's `preset` to spawn fields — harness preset first, then a
|
|
9470
|
+
* user preset. `undefined` when neither store knows the id. */
|
|
9471
|
+
declare function resolveReviewerPreset(preset: string, lookups?: Pick<DaemonReviewerHostDeps, "getHarnessPreset" | "getUserPreset">): Promise<Pick<SpawnAgentSessionInput, "adapter" | "model" | "access" | "preset"> | undefined>;
|
|
9472
|
+
declare function createDaemonReviewerHost(deps: DaemonReviewerHostDeps): ReviewerSessionHost;
|
|
9473
|
+
|
|
9474
|
+
/**
|
|
9475
|
+
* MCP tools for the review primitive (`@agentproto/review`):
|
|
9476
|
+
*
|
|
9477
|
+
* review_run run a REVIEW.md binding over a git range → attestation
|
|
9478
|
+
* (ledger hit ⇒ the cached verdict, `cached: true`)
|
|
9479
|
+
* review_status poll a run started with `wait: false`
|
|
9480
|
+
* review_cancel cancel a running review (lane sessions are killed)
|
|
9481
|
+
* review_ledger list recorded attestations
|
|
9482
|
+
* review_export write one attestation out as a standalone JSON file
|
|
9483
|
+
* review_pr follow a recorded review to its GitHub PR (via `gh`):
|
|
9484
|
+
* link it, snapshot the PR's state/reviews/checks into the
|
|
9485
|
+
* entry's annotations, return the combined view
|
|
9486
|
+
*
|
|
9487
|
+
* Async pattern mirrors `workflow_start`/`workflow_status`: `review_run`
|
|
9488
|
+
* blocks by default (`wait: true`) — pass `wait: false` for long reviews and
|
|
9489
|
+
* poll `review_status` with the returned `runId`.
|
|
9490
|
+
*
|
|
9491
|
+
* Trust note: `review_run` executes the command checks the repo's own
|
|
9492
|
+
* REVIEW.md declares (`sh -c`), the same trust `workflow_run_file` extends to
|
|
9493
|
+
* a WORKFLOW.md's gate steps — not the `command_execute` allowlist, which
|
|
9494
|
+
* governs ad-hoc commands a remote caller composes.
|
|
9495
|
+
*/
|
|
9496
|
+
|
|
9497
|
+
interface RegisterReviewToolsOptions {
|
|
9498
|
+
runner: ReviewRunner;
|
|
9499
|
+
/** The calling session (from `?callerSessionId=`) — agent-lane reviewer
|
|
9500
|
+
* sessions nest under it, and it is the default requester. */
|
|
9501
|
+
callerSessionId?: string;
|
|
9502
|
+
/** `gh` runner for `review_pr` — injectable for tests. Default: the real
|
|
9503
|
+
* `gh` on the daemon's PATH. */
|
|
9504
|
+
gh?: GhRunner;
|
|
9505
|
+
}
|
|
9506
|
+
declare function registerReviewTools(server: McpServer, opts: RegisterReviewToolsOptions): void;
|
|
9507
|
+
|
|
7530
9508
|
/**
|
|
7531
9509
|
* Built-in custom-route registration (PR-5).
|
|
7532
9510
|
*
|
|
@@ -7987,6 +9965,76 @@ declare function reapGcEntry(entry: SandboxLedgerEntry, opts: {
|
|
|
7987
9965
|
/** States that still name a box the gc might act on. */
|
|
7988
9966
|
declare const GC_REAPABLE_STATES: readonly SandboxLedgerState[];
|
|
7989
9967
|
|
|
9968
|
+
/**
|
|
9969
|
+
* Sandbox ledger reconcile — closes the gap between what
|
|
9970
|
+
* `~/.agentproto/sandboxes.json` believes is still booted/paused/connected
|
|
9971
|
+
* and what the PROVIDER actually still has running. A failed teardown, a
|
|
9972
|
+
* daemon that crashed mid-close, or a provider-side idle-reap the daemon
|
|
9973
|
+
* never heard about all leave a ledger row claiming a box is alive long
|
|
9974
|
+
* after the provider reaped it — real-world evidence: one daemon's ledger
|
|
9975
|
+
* carried ~50 rows in "paused" while the provider had far fewer boxes left.
|
|
9976
|
+
*
|
|
9977
|
+
* This is read-only against the PROVIDER (`SandboxProvider.probe`, the same
|
|
9978
|
+
* primitive `GET /sandboxes/:id/alive` and `agentproto sandbox list` already
|
|
9979
|
+
* use per-row) and never tears a box down — it only ever flips a ledger
|
|
9980
|
+
* row's `state` to `"gone"` via `recordSandboxLiveness` when the provider
|
|
9981
|
+
* confirms the box no longer exists. A box a caller still wants stays
|
|
9982
|
+
* completely untouched; this module has no `stop()`/`pause()`/`connect()`
|
|
9983
|
+
* call anywhere in it.
|
|
9984
|
+
*/
|
|
9985
|
+
|
|
9986
|
+
/** The slice of `SandboxProviderHandle` reconcile needs — just the liveness
|
|
9987
|
+
* probe, so tests (and the `local` provider, which has none) can hand back
|
|
9988
|
+
* a handle without a `probe` at all. */
|
|
9989
|
+
interface SandboxReconcileProviderHandle {
|
|
9990
|
+
provider: {
|
|
9991
|
+
probe?(sandboxId: string): Promise<{
|
|
9992
|
+
alive: boolean;
|
|
9993
|
+
state?: string;
|
|
9994
|
+
}>;
|
|
9995
|
+
};
|
|
9996
|
+
}
|
|
9997
|
+
interface SandboxReconcileDeps {
|
|
9998
|
+
/** Resolve a ledger row's provider slug to a handle. Mirrors
|
|
9999
|
+
* `SandboxGcReapDeps.resolveProvider` (`sandbox-gc.ts`) — same DI shape,
|
|
10000
|
+
* narrower need (probe only, never connect/boot). */
|
|
10001
|
+
resolveProvider: (slug: string) => Promise<SandboxReconcileProviderHandle | null>;
|
|
10002
|
+
/** Defaults to `readSandboxLedger` — injectable so callers that already
|
|
10003
|
+
* hold a mocked/scoped ledger reader (tests, a scoped CLI mock) can reuse
|
|
10004
|
+
* it instead of this module reaching for the real `~/.agentproto/
|
|
10005
|
+
* sandboxes.json` on disk. */
|
|
10006
|
+
readLedger?: (path?: string) => SandboxLedgerEntry[];
|
|
10007
|
+
/** Defaults to `recordSandboxLiveness` — same injectability reasoning. */
|
|
10008
|
+
recordLiveness?: (sandboxId: string, alive: boolean, path?: string) => void;
|
|
10009
|
+
ledgerPath?: string;
|
|
10010
|
+
}
|
|
10011
|
+
/** Verdict for one reconciled row. `"skipped"` means the provider has no
|
|
10012
|
+
* `probe()` (e.g. Box today) — never treated as evidence of death. */
|
|
10013
|
+
type SandboxReconcileVerdict = "alive" | "gone" | "unknown" | "skipped";
|
|
10014
|
+
interface SandboxReconcileRow {
|
|
10015
|
+
sandboxId: string;
|
|
10016
|
+
provider: string;
|
|
10017
|
+
verdict: SandboxReconcileVerdict;
|
|
10018
|
+
/** Present when `verdict` is "unknown" — the resolve/probe failure message. */
|
|
10019
|
+
error?: string;
|
|
10020
|
+
}
|
|
10021
|
+
interface SandboxReconcileResult {
|
|
10022
|
+
checked: number;
|
|
10023
|
+
alive: number;
|
|
10024
|
+
gone: number;
|
|
10025
|
+
unknown: number;
|
|
10026
|
+
skipped: number;
|
|
10027
|
+
rows: SandboxReconcileRow[];
|
|
10028
|
+
}
|
|
10029
|
+
/**
|
|
10030
|
+
* Probe every ledger row still claiming to be alive against its provider,
|
|
10031
|
+
* and stamp the verdict back into the ledger (`recordSandboxLiveness` flips
|
|
10032
|
+
* a dead row to `"gone"`; a live or unprobeable row is left as-is). One
|
|
10033
|
+
* broken row's provider resolution or probe call never aborts the pass for
|
|
10034
|
+
* the rest — each row's outcome is independent and best-effort.
|
|
10035
|
+
*/
|
|
10036
|
+
declare function reconcileSandboxLedger(deps: SandboxReconcileDeps): Promise<SandboxReconcileResult>;
|
|
10037
|
+
|
|
7990
10038
|
/**
|
|
7991
10039
|
* Idle agent-session reaper (PR-6).
|
|
7992
10040
|
*
|
|
@@ -9558,6 +11606,16 @@ interface CreateGatewayOptions {
|
|
|
9558
11606
|
* `worktree_gc` returns a clear "not enabled" error.
|
|
9559
11607
|
*/
|
|
9560
11608
|
runWorktreeGc?: WorktreeGcRunner;
|
|
11609
|
+
/**
|
|
11610
|
+
* Optional branch-`gc` runner powering `branch_gc` (+ `POST /branches/gc`).
|
|
11611
|
+
* Injected for the same reason as `runWorktreeGc`. Omitted → `branch_gc`
|
|
11612
|
+
* returns a clear "not enabled" error.
|
|
11613
|
+
*/
|
|
11614
|
+
runBranchGc?: BranchGcRunner;
|
|
11615
|
+
/** Optional verdict recorder powering `branch_gc_verdict` (+ `POST /branches/gc/verdict`). */
|
|
11616
|
+
recordBranchGcVerdict?: BranchGcVerdictRecorder;
|
|
11617
|
+
/** Optional verdict reader powering `branch_gc_verdict_get`. */
|
|
11618
|
+
readBranchGcVerdict?: BranchGcVerdictReader;
|
|
9561
11619
|
/**
|
|
9562
11620
|
* Optional best-effort exit-time reclaim of ONE policy-provisioned
|
|
9563
11621
|
* (implicit) session's own worktree — powers `SessionDescriptor.
|
|
@@ -9607,6 +11665,24 @@ interface CreateGatewayOptions {
|
|
|
9607
11665
|
* registered and the `llm_endpoint_*` MCP tools are not exposed. */
|
|
9608
11666
|
llmEndpoint?: boolean;
|
|
9609
11667
|
}
|
|
11668
|
+
/**
|
|
11669
|
+
* Default always-on set when `deferredTools` is enabled without an
|
|
11670
|
+
* explicit `alwaysOn` override: the core spawn/drive/observe/report loop
|
|
11671
|
+
* most sessions need immediately — including an EXECUTOR (the role
|
|
11672
|
+
* `deferredTools` defaults on for, see `role.ts`), which cannot spawn
|
|
11673
|
+
* (`agent_start`/`agent_prompt` are stripped for it anyway by
|
|
11674
|
+
* `toolPolicy.delegation: "deny"`, so those two names are simply absent
|
|
11675
|
+
* from a deny-role's registry and cost nothing) but still needs to report
|
|
11676
|
+
* back to its parent (`message_parent`), coordinate over the task ledger
|
|
11677
|
+
* (`task_*`), and observe its own session/turn state
|
|
11678
|
+
* (`session_context_status` alongside the pre-existing `session_list` /
|
|
11679
|
+
* `session_monitor` / `session_events_poll`). Everything else (fs_*,
|
|
11680
|
+
* directory_*, command_*, remote_*, browser_*, terminal_*, mcp_*,
|
|
11681
|
+
* routine_*, workflow_*, policy_*, inbound_watcher_*, session_tree,
|
|
11682
|
+
* agent_export, adapter_list, every `app_ui_*` panel tool, ...) starts
|
|
11683
|
+
* deferred — reachable via `tool_search`, never removed from `tools/call`.
|
|
11684
|
+
*/
|
|
11685
|
+
declare const DEFAULT_ALWAYS_ON_TOOLS: readonly string[];
|
|
9610
11686
|
interface GatewayHandle {
|
|
9611
11687
|
url: string;
|
|
9612
11688
|
workspace: string;
|
|
@@ -9664,4 +11740,4 @@ interface GatewayHandle {
|
|
|
9664
11740
|
*/
|
|
9665
11741
|
declare function createGateway(opts: CreateGatewayOptions): Promise<GatewayHandle>;
|
|
9666
11742
|
|
|
9667
|
-
export { type ActivityKind, type ActivityListFilter, type ActivityPolicyLister, type ActivityProjector, type ActivityProjectorRegistry, type ActivityProjectorSession, type ActivityRecord, type ActivitySource, type ActivityState, type ActivityWaitingOn, type ActivityWorkflowLister, AdapterAuthDescriptor, type AdapterCapabilitiesLister, type AdapterInstallResult, type AdapterListEntry, type AgentAdapterInstaller, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AnthropicReaderConfig, AnthropicRemainingQuotaReader, type AttachPolicyInput, type AttachSandboxOpts, type AttachSandboxResult, AuthMethod, BUCKETS_ROOT, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, CanonicalPosture, type CatalogModelsLister, CatalogModelsQuery, CatalogModelsResponse, type CatalogProviderModel, type CatalogProviderModelsQuery, type CatalogProviderModelsResponse, type CatalogProviderPricing, type ClaudeNativeRef, type CommitSpec, type CompletionPolicySupervisor, ContextProfile, type ConversationIndexRecord, type ConversationNativeRef, type CostBudgetDecision, type CrashDetectSummary, type CrashReaperRegistry, type CreateGatewayOptions, type CreateOfferInput, type CreatedOffer, DEAD_SESSION_STATUSES, DEFAULT_BUCKET, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_WORKTREE_ISOLATION, DeclaredAdapterOption, type DeclaredAdapterPreset, type EagerResumeFailReason, type EagerResumeOutcome, type EagerResumeSkipReason, type EagerResumeSummary, EffortLevel, GC_REAPABLE_STATES, type GateSpec, type GatewayHandle, type HarnessPreset, type HarnessPresetValidationDeps, HarnessPresetValidationError, type HarnessPresetsFile, type HermesNativeRef, INBOUND_PROVIDERS, type IdleReapSummary, type IdleReaperRegistry, type InboundEndpoint, type InboundEndpointStore, type InboundEndpointStoreOptions, type InboundEnqueuePrompt, type InboundIsSessionAlive, type InboundMessage, type InboundProvider, type InboundRestartSession, type InboundRouteMode, type InboundRouterDeps, type InboundRouterLog, type InboundSpawnForContact, type InboundWatcher, type JudgeGateSpec, LEGACY_SESSIONS_FILE, type LocatedConversation, type LocatedConversationByPath, type McpCredentialDeps, type MigrationMarker, type NormalizeInboundResult, type OnFailSpec, type OpenPrResolver, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type OrphanReaperRegistry, PAIRINGS_VERSION, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, type PairingChannelContext, type PairingChannelHandle, type PairingChannelMode, type PairingRecord, type PairingRegistry, type PairingRegistryDeps, type PendingPermission, type PermissionRespondInput, type PermissionRespondResult, type PolicyRunState, type PolicyRunStatus, Posture, type PostureResolution, type PrResolvedState, type PrStateResolver, type PresetInfo, type PricingResolver, type QuotaReadableProfile, type QuotaStoreFile, type QuotaStoreOptions, type ReconnectLogGate, type RegisterBrainToolsOptions, type RegisterBrowserInput, type RegisterPairingToolsOptions, type RegisterSessionInput, type RegisterWebSearchToolsOptions, type RemainingQuota, type RemainingQuotaReader, type ResolveNativeLinkInput, ResolvedAuthSpec, ResumeDisabledError, type ReuseResolution, type RouteAwareLaunchConfig, type RouteAwareLaunchConfigInput, RouteSpec, type RuntimeMeta, SESSION_ID_ENV, type SandboxAdapterInfo, type SandboxConnectionDescriptor, type SandboxGcCandidate, type SandboxGcProviderHandle, type SandboxGcReapDeps, type SandboxGcReapResult, type SandboxLedgerEntry, type SandboxLedgerState, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type ScopeTokenRegistry, SessionConfig, type SessionCurrentPhase, type SessionDescriptor, type SessionKind, type SessionObserver, type SessionSnapshots, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, type SpawnSessionInput, type StallWatchdogRegistry, type StallWatchdogSummary, type StoredProfileQuota, TASK_STATUSES, type TaskCaller, type TaskChangedEvent, type TaskClaimInput, type TaskCreateInput, type TaskGateOutcome, type TaskGateRunner, type TaskLedger, type TaskLedgerRegistry, type TaskLedgerSessionSlice, type TaskListFilter, type TaskRecord, type TaskStatus, type TaskUpdateInput, type TaskVerification, type TaskVerifySupervisor, type TaskWriteResult, type TokenPricing, type TransmitterBinding, type TransmitterBindingStore, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageBucket, type UsageComputeInput, type UsageRollup, type UsageSnapshotRecord, type UsageSource, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, type WatcherDescriptor, type WatcherStartInput, type WebSearchInput, type WebSearchOutput, type WebSearchResult, type WorkspaceBrainSubscriber, type WorkspaceBrainSubscriberOptions, type WorkspaceBrains, WorkspaceFs, type WorktreeAutoReclaimer, type WorktreeDecision, type WorktreeField, type WorktreeGcClass, type WorktreeGcOutcomeView, type WorktreeGcPlanEntryView, type WorktreeGcReclaimReason, type WorktreeGcResult, type WorktreeGcRunInput, type WorktreeGcRunner, WorktreeIsolationMode, type WorktreeProvisionOutcome, type WorktreeProvisionRequest, type WorktreeProvisioner, type WorktreeRequest, type WorktreeStatusLister, type WorktreeStatusView, activityCounts, addHarnessPreset, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogProviderModels, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, claudeProjectSlug, collectGcCandidates, composeSessionObservers, conversationIndexPath, createActivityProjector, createFileStepCache, createGateway, createInboundEndpointStore, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createPrProvenanceReconciler, createReconnectLogGate, createScopeTokenRegistry, createSupervisorTaskGateRunner, createTaskLedger, createWorkspaceBrainSubscriber, createWorkspaceBrains, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, defineBraveSearchHttpDriver, defineSerperHttpDriver, deriveSessionUsage, enrichRollupWithProviderQuota, enrichWithRemainingQuota, evaluateCostBudget, filterActivities, findConversationRecord, findNativeMode, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getMcpCredentialDeps, harnessPresetsPath, isAgentCliAuthConfigured, isClosedTaskStatus, isSafeBucketSlug, isTerminalActivityState, listBuckets, listHarnessPresets, listPresets, loadHarnessPresets, loadQuotaStore, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeSandboxCredsStore, makeSandboxResolver, migrateLegacySessionsFile, migrationMarkerPath, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeInbound, normalizeModeId, normalizeWorktreeField, parseAnthropicRateLimitHeaders, parseTaskStatus, parseWindow, parseWorktreeIsolationMode, policyToActivities, policyWatchesSession, prToActivities, projectSessionUsage, readConversationIndex, readDaemonRegistry, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, readUsageSnapshots, reapGcEntry, reapOrphanedDescendants, recordProfileQuota, recordSandboxBoot, recordSandboxLiveness, recordSandboxOrigin, recordSandboxState, registerBrainTools, registerBuiltinRoutes, registerPairingTools, registerSandboxAttachTool, registerWebSearchTools, removeHarnessPreset, removeSandboxLedgerEntry, resolveBucketSlug, resolveNativeLink, resolvePosture, resolveReuseFromLedger, rollupUsage, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runStallWatchdogPass, sandboxLedgerPath, setDefaultPreset, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, toWorktreeStatusView, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, updateHarnessPreset, upsertSandboxLedger, verifyInboundSignature, webSearchTool, workflowToActivities, writeDaemonRegistryEntry };
|
|
11743
|
+
export { type ActivityKind, type ActivityListFilter, type ActivityPolicyLister, type ActivityProjector, type ActivityProjectorRegistry, type ActivityProjectorSession, type ActivityRecord, type ActivitySource, type ActivityState, type ActivityWaitingOn, type ActivityWorkflowLister, AdapterAuthDescriptor, type AdapterCapabilitiesLister, type AdapterInstallResult, type AdapterListEntry, type AgentAdapterInstaller, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AnthropicReaderConfig, AnthropicRemainingQuotaReader, type AttachPolicyInput, type AttachSandboxOpts, type AttachSandboxResult, AuthMethod, BUCKETS_ROOT, type BranchGcClass, type BranchGcCoverageView, type BranchGcHoldReason, type BranchGcKind, type BranchGcOutcomeView, type BranchGcPlanEntryView, type BranchGcPlanView, type BranchGcReclaimReason, type BranchGcResult, type BranchGcRunInput, type BranchGcRunner, type BranchGcStatus, type BranchGcSummaryView, type BranchGcTriageVerdict, type BranchGcVerdictInput, type BranchGcVerdictLookupInput, type BranchGcVerdictReader, type BranchGcVerdictRecordView, type BranchGcVerdictRecorder, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, CanonicalPosture, type CatalogModelsLister, CatalogModelsQuery, CatalogModelsResponse, type CatalogProviderModel, type CatalogProviderModelsQuery, type CatalogProviderModelsResponse, type CatalogProviderPricing, type ClaudeNativeRef, type CommitSpec, type CompletionPolicySupervisor, ContextProfile, type ConversationIndexRecord, type ConversationNativeRef, type CostBudgetDecision, type CrashDetectSummary, type CrashReaperRegistry, type CreateGatewayOptions, type CreateOfferInput, type CreateReviewRunnerOptions, type CreatedOffer, DEAD_SESSION_STATUSES, DEFAULT_ALWAYS_ON_TOOLS, DEFAULT_BUCKET, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_WORKTREE_ISOLATION, type DaemonReviewerHostDeps, DeclaredAdapterOption, type DeclaredAdapterPreset, DefaultsAdapterAuthConfig, type EagerResumeFailReason, type EagerResumeOutcome, type EagerResumeSkipReason, type EagerResumeSummary, EffortLevel, type EnableInput, type EnableResult, GC_REAPABLE_STATES, type GateSpec, type GatewayHandle, type GhRunner, type HarnessPreset, type HarnessPresetValidationDeps, HarnessPresetValidationError, type HarnessPresetsFile, type HermesNativeRef, INBOUND_PROVIDERS, type IdleReapSummary, type IdleReaperRegistry, type InboundEndpoint, type InboundEndpointStore, type InboundEndpointStoreOptions, type InboundEnqueuePrompt, type InboundIsSessionAlive, type InboundMessage, type InboundProvider, type InboundRestartSession, type InboundRouteMode, type InboundRouterDeps, type InboundRouterLog, type InboundSpawnForContact, type InboundWatcher, type JudgeGateSpec, LEGACY_SESSIONS_FILE, type LedgerAnnotations, type LedgerEntry, type LedgerHostMeta, type LocatedConversation, type LocatedConversationByPath, MAX_MESSAGE_DATA_BYTES, MCP_APP_BRIDGE_SCRIPT, MESSAGE_KINDS, MESSAGE_PREAMBLE, MESSAGE_TAG, MESSAGE_URGENCIES, type McpCredentialDeps, type MessageDeliveryVia, type MessageFilter, type MessageKind, type MessageRelation, type MessageTreeNode, type MessageUrgency, type MigrationMarker, type NormalizeInboundResult, type OnFailSpec, type OpenPrResolver, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type OrphanReaperRegistry, PAIRINGS_VERSION, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, type PairingChannelContext, type PairingChannelHandle, type PairingChannelMode, type PairingRecord, type PairingRegistry, type PairingRegistryDeps, type PendingPermission, type PermissionRespondInput, type PermissionRespondResult, type PolicyRunState, type PolicyRunStatus, Posture, type PostureResolution, PrLookupError, type PrLookupErrorCode, type PrResolvedState, type PrStateResolver, type PrStatusSnapshot, type PresetInfo, type PricingResolver, type QuotaReadableProfile, type QuotaStoreFile, type QuotaStoreOptions, type ReconnectLogGate, type RegisterBrainToolsOptions, type RegisterBrowserInput, type RegisterPairingToolsOptions, type RegisterReviewToolsOptions, type RegisterSessionInput, type RegisterWebSearchToolsOptions, type RemainingQuota, type RemainingQuotaReader, type RemoteStatus, type ResolveNativeLinkInput, ResolvedAuthSpec, ResumeDisabledError, type ReuseResolution, type ReviewLedger, type ReviewLedgerFilter, type ReviewRun, type ReviewRunInput, type ReviewRunStatus, type ReviewRunner, type ReviewerRunResult, type ReviewerSessionHost, type RouteAwareLaunchConfig, type RouteAwareLaunchConfigInput, RouteSpec, type RuntimeMeta, SESSION_END_REASONS, SESSION_ID_ENV, type SandboxAdapterInfo, type SandboxConnectionDescriptor, type SandboxGcCandidate, type SandboxGcProviderHandle, type SandboxGcReapDeps, type SandboxGcReapResult, type SandboxLedgerEntry, type SandboxLedgerState, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type SandboxReconcileDeps, type SandboxReconcileProviderHandle, type SandboxReconcileResult, type SandboxReconcileRow, type SandboxReconcileVerdict, type ScopeTokenRegistry, SessionConfig, type SessionCurrentPhase, type SessionDescriptor, type SessionEndReason, type SessionKind, type SessionMessage, type SessionMessageFrom, type SessionMessageSentRecord, type SessionObserver, type SessionOutcome, type SessionOutcomeArtifact, type SessionOutcomeCompact, type SessionOutcomeLink, type SessionSnapshots, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, SpawnDefaultsConfig, type SpawnSessionInput, type StallWatchdogRegistry, type StallWatchdogSummary, type StoredProfileQuota, TASK_STATUSES, type TaskCaller, type TaskChangedEvent, type TaskClaimInput, type TaskCreateInput, type TaskGateOutcome, type TaskGateRunner, type TaskLedger, type TaskLedgerRegistry, type TaskLedgerSessionSlice, type TaskListFilter, type TaskRecord, type TaskStatus, type TaskUpdateInput, type TaskVerification, type TaskVerifySupervisor, type TaskWriteResult, type TokenPricing, type TransmitterBinding, type TransmitterBindingStore, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageBucket, type UsageComputeInput, type UsageRollup, type UsageSnapshotRecord, type UsageSource, UserPreset, WORKSPACE_SLUG_ENV, WORKTREE_ISOLATION_ENV, type WatcherDescriptor, type WatcherStartInput, type WebSearchInput, type WebSearchOutput, type WebSearchResult, type WorkspaceBrainSubscriber, type WorkspaceBrainSubscriberOptions, type WorkspaceBrains, WorkspaceFs, type WorktreeAutoReclaimer, type WorktreeDecision, type WorktreeField, type WorktreeGcClass, type WorktreeGcOutcomeView, type WorktreeGcPlanEntryView, type WorktreeGcReclaimReason, type WorktreeGcResult, type WorktreeGcRunInput, type WorktreeGcRunner, WorktreeIsolationMode, type WorktreeProvisionOutcome, type WorktreeProvisionRequest, type WorktreeProvisioner, type WorktreeRequest, type WorktreeStatusLister, type WorktreeStatusView, activityCounts, addHarnessPreset, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogProviderModels, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, claudeProjectSlug, collectGcCandidates, compactOutcome, composeSessionObservers, conversationIndexPath, createActivityProjector, createDaemonReviewerHost, createFileStepCache, createGateway, createInboundEndpointStore, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createPrProvenanceReconciler, createReconnectLogGate, createReviewLaneExecutor, createReviewLedger, createReviewRunner, createScopeTokenRegistry, createSessionMessage, createSupervisorTaskGateRunner, createTaskLedger, createWorkspaceBrainSubscriber, createWorkspaceBrains, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, defaultReviewLedgerRoot, defineBraveSearchHttpDriver, defineSerperHttpDriver, deriveSessionOutcome, deriveSessionUsage, enrichRollupWithProviderQuota, enrichWithRemainingQuota, escapeHumanPrompt, escapeMessageBody, evaluateCostBudget, execGh, fetchPrStatus, filterActivities, findConversationRecord, findNativeMode, findPrForCommit, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getMcpCredentialDeps, githubRepoOf, harnessPresetsPath, hostPlaceholders, injectMcpAppBridge, isAgentCliAuthConfigured, isClosedTaskStatus, isKnownSessionEndReason, isMessageAllowed, isProviderLimitError, isSafeBucketSlug, isTerminalActivityState, listBuckets, listHarnessPresets, listPresets, loadHarnessPresets, loadQuotaStore, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeSandboxCredsStore, makeSandboxResolver, matchesMessageFilter, messageFrom, migrateLegacySessionsFile, migrationMarkerPath, mintMessageId, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeInbound, normalizeModeId, normalizeRemote, normalizeWorktreeField, parseAnthropicRateLimitHeaders, parsePrUrl, parseTaskStatus, parseWindow, parseWorktreeIsolationMode, policyToActivities, policyWatchesSession, prHeadSha, prToActivities, projectSessionUsage, readConversationIndex, readDaemonRegistry, readProfileQuota, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, readUsageSnapshots, reapGcEntry, reapOrphanedDescendants, reconcileSandboxLedger, recordProfileQuota, recordSandboxBoot, recordSandboxLiveness, recordSandboxOrigin, recordSandboxState, registerBrainTools, registerBuiltinRoutes, registerPairingTools, registerReviewTools, registerSandboxAttachTool, registerWebSearchTools, removeHarnessPreset, removeSandboxLedgerEntry, renderInboxDigest, renderSessionMessage, renderSessionMessages, repoSlug, resolveBucketSlug, resolveNativeLink, resolvePosture, resolveRelation, resolveReuseFromLedger, resolveReviewerPreset, rollupUsage, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runShellLane, runStallWatchdogPass, sandboxLedgerPath, sanitizeLabel, setDefaultPreset, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, toWorktreeStatusView, turnToActivities, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, updateHarnessPreset, upsertSandboxLedger, verifyInboundSignature, webSearchTool, withPr, withPrStatus, workflowToActivities, writeDaemonRegistryEntry };
|