@agentproto/runtime 5.2.1 → 5.3.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/dist/index.d.ts CHANGED
@@ -1,15 +1,17 @@
1
1
  import { DoctypeSpec } from '@agentproto/manifest';
2
+ import { h as WorktreeIsolationMode, i as SpawnAttachMode, j as SpawnDedupeMode, R as ResolvedModelRole } from './config-DcESQDmZ.js';
3
+ export { k as DEFAULT_MODEL_ROLES, M as MODEL_ROLE_REF_PREFIX, l as ModelRoleContext, m as ModelRoleEntry, n as ModelRoleSource, o as ModelRoleValue, p as ModelRolesConfig, q as listModelRoles, r as parseModelRoleRef, s as resolveModelRole } from './config-DcESQDmZ.js';
2
4
  import { B as BuildHeartbeatAgent } from './heartbeat-BJtxbDb9.js';
3
5
  export { H as HeartbeatAgent, a as HeartbeatRunner, R as RuntimeEvent, b as RuntimeEvents, p as parseDuration } from './heartbeat-BJtxbDb9.js';
4
- import { M as MessageUrgency, S as SessionEvent, a as SessionEventType, b as SessionEventBus, c as SessionsRegistry, C as CompletionPolicySupervisor, T as TaskLedger, d as SessionDescriptor, e as SessionEndReason, A as ActivityPolicySlice, f as ActivityListFilter, g as ActivityRecord, h as ActivityTurnSession, i as ActivityPrSession, j as ActivityWorkflowRunSlice, P as PrResolvedState, k as ActivityTaskSlice, l as AgentsMdResolution, U as UserPreset, R as RestartPolicy, m as SandboxAppServeSpec, n as AgentSessionLike, o as UsageReadContext, p as UsageReadResult, q as MessageKind, r as SessionMessage, s as AgentStreamEvent, t as SessionUsage, u as ToolCallRecord, v as UsageRollup, w as RemainingQuotaReader, Q as QuotaReadableProfile, x as UsageSnapshotRecord, y as SessionAwaitingQuestion, z as PolicyRunState, B as PtyFactory } from './sessions-g4fw_zKx.js';
5
- export { D as ActivityKind, E as ActivitySource, F as ActivityState, G as ActivityWaitingOn, H as AnthropicReaderConfig, I as AnthropicRemainingQuotaReader, J as AttachPolicyInput, K as CommitSpec, L as EagerResumeFailReason, N as EagerResumeOutcome, O as EagerResumeSkipReason, V as GateSpec, W as JudgeGateSpec, X as MAX_MESSAGE_DATA_BYTES, Y as MESSAGE_KINDS, Z as MESSAGE_PREAMBLE, _ as MESSAGE_TAG, $ as MESSAGE_URGENCIES, a0 as MessageDeliveryVia, a1 as MessageFilter, a2 as MessageRelation, a3 as MessageTreeNode, a4 as OnFailSpec, a5 as PendingPermission, a6 as PermissionRespondInput, a7 as PermissionRespondResult, a8 as PolicyRunStatus, a9 as PricingResolver, aa as QuotaStoreFile, ab as QuotaStoreOptions, ac as RegisterBrowserInput, ad as RegisterSessionInput, ae as RemainingQuota, af as ResumeDisabledError, ag as SESSION_END_REASONS, ah as SESSION_ID_ENV, ai as SessionCurrentPhase, aj as SessionKind, ak as SessionMessageFrom, al as SessionOutcome, am as SessionOutcomeArtifact, an as SessionOutcomeCompact, ao as SessionOutcomeLink, ap as SessionSnapshots, aq as SessionStatus, ar as ShellGateSpec, as as SpawnAgentInput, at as SpawnSessionInput, au as StoredProfileQuota, av as TASK_STATUSES, aw as TaskCaller, ax as TaskChangedEvent, ay as TaskClaimInput, az as TaskCreateInput, aA as TaskGateOutcome, aB as TaskGateRunner, aC as TaskLedgerRegistry, aD as TaskLedgerSessionSlice, aE as TaskListFilter, aF as TaskRecord, aG as TaskStatus, aH as TaskUpdateInput, aI as TaskVerification, aJ as TaskVerifySupervisor, aK as TaskWriteResult, aL as TokenPricing, aM as UsageBucket, aN as UsageComputeInput, aO as UsageDetail, aP as UsageSource, aQ as UserPresetsFile, aR as WORKSPACE_SLUG_ENV, aS as activityCounts, aT as compactOutcome, aU as createSessionMessage, aV as createSupervisorTaskGateRunner, aW as createTaskLedger, aX as deleteUserPreset, aY as deriveSessionOutcome, aZ as deriveSessionUsage, a_ as escapeHumanPrompt, a$ as escapeMessageBody, b0 as filterActivities, b1 as getUserPreset, b2 as isClosedTaskStatus, b3 as isKnownSessionEndReason, b4 as isMessageAllowed, b5 as isProviderLimitError, b6 as isTerminalActivityState, b7 as listUserPresets, b8 as loadQuotaStore, b9 as loadUserPresets, ba as matchesMessageFilter, bb as messageFrom, bc as mintMessageId, bd as parseAnthropicRateLimitHeaders, be as parseTaskStatus, bf as parseWindow, bg as pickUsageDetail, bh as policyToActivities, bi as policyWatchesSession, bj as prToActivities, bk as projectSessionUsage, bl as readProfileQuota, bm as recordProfileQuota, bn as renderInboxDigest, bo as renderSessionMessage, bp as renderSessionMessages, bq as resolveRelation, br as rollupUsage, bs as sanitizeLabel, bt as saveUserPreset, bu as turnToActivities, bv as userPresetsPath, bw as workflowToActivities } from './sessions-g4fw_zKx.js';
6
- import { R as RouteSpec, P as Posture, C as ContextProfile, a as CanonicalPosture } from './session-config-RyRL2AbD.js';
7
- export { A as AuthMethod, D as DeclaredAdapterMode, E as EffortLevel, S as SessionConfig, c as composeMode, d as decomposeMode } from './session-config-RyRL2AbD.js';
6
+ import { M as MessageUrgency, S as SessionEvent, a as SessionEventType, b as SessionEventBus, c as SessionsRegistry, C as CompletionPolicySupervisor, T as TaskLedger, d as SessionDescriptor, e as SessionEndReason, A as ActivityPolicySlice, f as ActivityListFilter, g as ActivityRecord, h as ActivityTurnSession, i as ActivityPrSession, j as ActivityWorkflowRunSlice, P as PrResolvedState, k as ActivityTaskSlice, W as WorktreeProvisioner, l as AgentsMdResolution, U as UserPreset, R as RestartPolicy, m as SandboxAppServeSpec, n as WorktreeField, o as AgentSessionLike, p as UsageReadContext, q as UsageReadResult, r as MessageKind, s as SessionMessage, t as AgentStreamEvent, u as SessionUsage, v as ToolCallRecord, w as StatsSessionDescriptor, x as ProcRow, y as ProvisionInFlight, z as ProvisionTracker, B as UsageRollup, D as RemainingQuotaReader, Q as QuotaReadableProfile, E as UsageSnapshotRecord, F as SessionAwaitingQuestion, G as PolicyRunState, H as PtyFactory, I as WorktreeAutoReclaimer } from './sessions-DKm6Wqro.js';
7
+ export { J as ActivityKind, K as ActivitySource, L as ActivityState, N as ActivityWaitingOn, O as AnthropicReaderConfig, V as AnthropicRemainingQuotaReader, X as AttachPolicyInput, Y as CommandGroupStats, Z as CommitSpec, _ as DEFAULT_WORKTREE_ISOLATION, $ as DEFAULT_WORKTREE_PROVISION_CONCURRENCY, a0 as EagerResumeFailReason, a1 as EagerResumeOutcome, a2 as EagerResumeSkipReason, a3 as GateSpec, a4 as HostInfo, a5 as JudgeGateSpec, a6 as LabeledProcessStatsReport, a7 as LabeledSessionStats, a8 as MAX_MESSAGE_DATA_BYTES, a9 as MESSAGE_KINDS, aa as MESSAGE_PREAMBLE, ab as MESSAGE_TAG, ac as MESSAGE_URGENCIES, ad as MessageDeliveryVia, ae as MessageFilter, af as MessageRelation, ag as MessageTreeNode, ah as OnFailSpec, ai as OrphanGroup, aj as PendingPermission, ak as PermissionRespondInput, al as PermissionRespondResult, am as PolicyRunStatus, an as PricingResolver, ao as ProcessDetail, ap as ProcessStatsReport, aq as ProcessStatsService, ar as QuotaStoreFile, as as QuotaStoreOptions, at as RegisterBrowserInput, au as RegisterSessionInput, av as RemainingQuota, aw as ResourceStats, ax as ResumeDisabledError, ay as SESSION_END_REASONS, az as SESSION_ID_ENV, aA as SessionCurrentPhase, aB as SessionKind, aC as SessionMessageFrom, aD as SessionOutcome, aE as SessionOutcomeArtifact, aF as SessionOutcomeCompact, aG as SessionOutcomeLink, aH as SessionResourceStats, aI as SessionSnapshots, aJ as SessionStatus, aK as ShellGateSpec, aL as SpawnAgentInput, aM as SpawnSessionInput, aN as StatsDetail, aO as StoredProfileQuota, aP as TASK_STATUSES, aQ as TaskCaller, aR as TaskChangedEvent, aS as TaskClaimInput, aT as TaskCreateInput, aU as TaskGateOutcome, aV as TaskGateRunner, aW as TaskLedgerRegistry, aX as TaskLedgerSessionSlice, aY as TaskListFilter, aZ as TaskRecord, a_ as TaskStatus, a$ as TaskUpdateInput, b0 as TaskVerification, b1 as TaskVerifySupervisor, b2 as TaskWriteResult, b3 as TokenPricing, b4 as UsageBucket, b5 as UsageComputeInput, b6 as UsageDetail, b7 as UsageSource, b8 as UserPresetsFile, b9 as WORKSPACE_SLUG_ENV, ba as WORKTREE_ISOLATION_ENV, bb as WORKTREE_PROVISION_CONCURRENCY_ENV, bc as WorktreeDecision, bd as WorktreeProvisionOutcome, be as WorktreeProvisionPhase, bf as WorktreeProvisionProgress, bg as WorktreeProvisionRequest, bh as WorktreeRequest, bi as activityCounts, bj as compactOutcome, bk as createProcessStatsService, bl as createSessionMessage, bm as createSupervisorTaskGateRunner, bn as createTaskLedger, bo as decideWorktreeIsolation, bp as deleteUserPreset, bq as deriveSessionOutcome, br as deriveSessionUsage, bs as escapeHumanPrompt, bt as escapeMessageBody, bu as filterActivities, bv as getProcessStatsService, bw as getUserPreset, bx as isClosedTaskStatus, by as isKnownSessionEndReason, bz as isMessageAllowed, bA as isProviderLimitError, bB as isTerminalActivityState, bC as listUserPresets, bD as loadQuotaStore, bE as loadUserPresets, bF as loadWorktreeIsolation, bG as matchesMessageFilter, bH as messageFrom, bI as mintMessageId, bJ as normalizeCommand, bK as normalizeWorktreeField, bL as parseAnthropicRateLimitHeaders, bM as parseTaskStatus, bN as parseWindow, bO as parseWorktreeIsolationMode, bP as pickUsageDetail, bQ as policyToActivities, bR as policyWatchesSession, bS as prToActivities, bT as projectSessionUsage, bU as readProfileQuota, bV as recordProfileQuota, bW as renderInboxDigest, bX as renderSessionMessage, bY as renderSessionMessages, bZ as resolveRelation, b_ as rollupUsage, b$ as sanitizeLabel, c0 as saveUserPreset, c1 as trackWorktreeProvision, c2 as turnToActivities, c3 as userPresetsPath, c4 as workflowToActivities } from './sessions-DKm6Wqro.js';
8
+ import { R as RouteSpec, P as Posture, C as ContextProfile, a as CanonicalPosture } from './session-config-DxIIuJFY.js';
9
+ export { A as AuthMethod, D as DeclaredAdapterMode, E as EffortLevel, S as SessionConfig, c as composeMode, d as decomposeMode } from './session-config-DxIIuJFY.js';
8
10
  import { AcpMcpServer } from '@agentproto/acp';
9
11
  import { SandboxMode } from '@agentproto/command-sandbox';
10
12
  import { AdapterHandle, SetupField, AdapterResolver, AdapterLister, CredsStore, HarnessCapabilities, AdapterEntry } from '@agentproto/provider-kit';
11
- import { S as SpawnDefaultsConfig, D as DefaultsAdapterAuthConfig, R as ResolvedAuthSpec, a as DeclaredAdapterOption, A as AdapterAuthDescriptor } from './spawn-defaults-CHvz85DD.js';
12
- 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-CHvz85DD.js';
13
+ import { a as SpawnBrowserMode, S as SpawnDefaultsConfig, b as ResolveHeadlessBrowser, D as DefaultsAdapterAuthConfig, C as ContextContinuityPolicy, c as ResolvedAuthSpec, d as DeclaredAdapterOption, A as AdapterAuthDescriptor } from './spawn-defaults-Cp9SGZex.js';
14
+ export { e as AuthEcho, f as AuthResolutionError, g as CLAUDE_CODE_OAUTH_SOURCE, h as CredentialSource, i as DefaultsAdapterConfig, j as DeferredToolsConfig, k as ResolveSubscriptionCredentialInput, l as ResolvedSpawnAuthMaterial, m as ResolvedSpawnDefaults, n as SubscriptionCredentialResolution, o as SubscriptionSourceError, p as credentialFingerprint, q as normalizeSkillsOption, r as resolveAuthSpec, s as resolveDeferredToolsGatewayOption, t as resolveSpawnDefaults, u as resolveSubscriptionCredential } from './spawn-defaults-Cp9SGZex.js';
13
15
  import { CatalogModelsQuery, CatalogModelsResponse } from './catalog-models.js';
14
16
  export { CatalogAdapterInput, CatalogAdapterModelInput, CatalogPricing, CatalogProduct, CatalogRoute, CatalogRouteSummary, CatalogVendor, buildCatalogModels } from './catalog-models.js';
15
17
  import { FooterSession } from './pr-provenance.js';
@@ -22,13 +24,15 @@ import { ToolContext } from '@agentproto/tool';
22
24
  import { z } from 'zod';
23
25
  import { DriverHandle } from '@agentproto/driver';
24
26
  import { Attestation, LedgerKey, RubricDigest, PackDigest, ReviewPrRef, LaneResult, ReviewLaneExecutor, LaneOutcome, Attestor, PackLoader } from '@agentproto/review';
27
+ import { BundlesFile } from './bundles.js';
25
28
  import { ImportedMcpsConfig } from './mcp-imports.js';
26
29
  import { CostBudget, AuthProfile, CostBudgetScope } from '@agentproto/auth';
27
30
  export { CostBudget, CostBudgetScope } from '@agentproto/auth';
28
- import { S as SpawnBrowserMode, a as ResolveHeadlessBrowser, C as ContextContinuityPolicy } from './context-continuity-BfNVbX5W.js';
29
- import { WorktreeIsolationMode, SpawnAttachMode, SpawnDedupeMode } from './config.js';
30
31
  import { ResolvedModel } from '@agentproto/model-catalog';
31
- import { FrameSink, E2eFrameSink } from '@agentproto/acp/tunnel';
32
+ import { BrowserProvider, BrowserCapabilities, BrowserAttachOptions, BrowserInstance } from '@agentproto/driver-browser';
33
+ import { PairingRegistry } from '@agentproto/pairing-host';
34
+ export { CreateOfferInput, CreatedOffer, PAIRINGS_VERSION, PairingChannelContext, PairingChannelHandle, PairingChannelMode, PairingRecord, PairingRegistry, PairingRegistryDeps, ReconnectLogGate, createPairingRegistry, createReconnectLogGate, readPairingsSnapshot } from '@agentproto/pairing-host';
35
+ import { FrameSink } from '@agentproto/acp/tunnel';
32
36
  import { DaemonIdentity } from '@agentproto/secrets/identity';
33
37
  import { WorkspaceFs } from './workspace-fs.js';
34
38
  export { createWorkspaceFs } from './workspace-fs.js';
@@ -40,6 +44,39 @@ import { StepCache } from '@agentproto/workflow-runtime';
40
44
  export { PROVIDER_ENV_VARS, ProviderEntry, ProvidersFile, getProviderKey, injectProviderKeysIntoEnv, loadProviders, providerEnvVar, providersPath, removeProviderKey, setProviderKey } from '@agentproto/providers-store';
41
45
  import 'node:child_process';
42
46
 
47
+ /**
48
+ * App boundary — filesystem zones for sessions an app (or an app workflow)
49
+ * spawns.
50
+ *
51
+ * readOnly the installed app source (dir, `.agentproto/`, `scripts/`, …)
52
+ * writable the workflow run workspace (`~/.agentproto/runs/<runId>/`,
53
+ * `$run.workspace`) and the app `data/` dir
54
+ * hidden host trees that must not be readable even though the OS
55
+ * sandbox alone would allow them (the daemon workspace, the host
56
+ * monorepo the app happens to be installed inside)
57
+ * else denied
58
+ *
59
+ * One `AppBoundary` value drives every enforcement surface:
60
+ * - daemon file tools (`fs-tools.ts`) and `command_execute`
61
+ * (`command-tools.ts`) resolve paths through {@link resolveBoundaryPath};
62
+ * - the harness's native tools are confined by the OS sandbox
63
+ * (`@agentproto/command-sandbox`) built from {@link boundaryToSandboxZones};
64
+ * - the boundary rides on the session descriptor (`meta.appBoundary`) so the
65
+ * daemon gateway can recover a caller's boundary from its trusted
66
+ * `callerSessionId`, and children/restarts inherit it.
67
+ */
68
+
69
+ type AppBoundaryEnforce = "required" | "best-effort";
70
+ interface AppBoundary {
71
+ readonly appId: string;
72
+ /** Base for relative paths in the daemon file tools — the app dir. */
73
+ readonly root: string;
74
+ readonly readOnly: readonly string[];
75
+ readonly writable: readonly string[];
76
+ readonly hidden: readonly string[];
77
+ readonly enforce: AppBoundaryEnforce;
78
+ }
79
+
43
80
  /**
44
81
  * Runtime-side glue for the per-workspace brain: a shared registry of
45
82
  * {@link BrainManager}s (one per workspace bucket) plus the two bridges that
@@ -581,229 +618,6 @@ interface RemoteStatus {
581
618
  lastError?: string;
582
619
  }
583
620
 
584
- /**
585
- * Daemon-side pairing registry (design: DESIGN §3/§4, PLAN deliverable 2).
586
- *
587
- * Owns everything the daemon needs to be *paired with* over an untrusted
588
- * rendezvous:
589
- *
590
- * - **Offer store** — in-memory, single-use, expiry-checked one-time offer
591
- * secrets minted by `pair offer`. A daemon restart voids outstanding offers
592
- * (acceptable + documented). The daemon parks on the offer's ROUTE token and
593
- * the handshake's `verifyAuthToken` predicate checks the sealed AUTH token,
594
- * SPENDING the offer on the first successful handshake (a wrong token spends
595
- * nothing).
596
- * - **Pairings store** — `~/.agentproto/pairings.json` (0600, atomic write),
597
- * one record per paired client: `{clientPub, name, fingerprint, createdAt,
598
- * lastSeen, pairRoot, rendezvousUrl}`. `pairRoot` is the long-term shared
599
- * secret (`derivePairRoot`) from which reconnect routing tokens derive.
600
- * - **Rendezvous connections** — for a fresh offer, and for every persisted
601
- * pairing on boot (autoconnect), the daemon dials the rendezvous *outbound*
602
- * (`side=daemon&t=<route>`), runs `daemonHandshakeOverSink` with the P1
603
- * crypto, and — on success — serves the spliced, E2E-wrapped channel exactly
604
- * like `serve --connect` serves a tunnel host. The serving path itself is
605
- * injected (`serve`) so this module stays free of pty/adapter concerns and
606
- * the CLI can reuse its `createTunnelServer` config verbatim.
607
- * - **Reconnect epochs** — a persisted pairing's standing connection parks on
608
- * the pairing-derived route `HKDF(pairRoot, "rv-route"‖epoch)`, rotated per
609
- * UTC day. The daemon parks on BOTH the current and previous
610
- * epoch tokens so a client whose clock straddles midnight still finds it;
611
- * reconnect-with-backoff keeps the standing connection alive.
612
- * - **Revocation** — removing a pairing drops its rendezvous connections, so
613
- * it can no longer be served. For a grace period (`revokedGraceMs`, default
614
- * 14 days) the daemon keeps a *tombstone*: it still parks on the pairing's
615
- * epoch ROUTES, completes the (daemon-signed) handshake only for a hello
616
- * carrying that epoch's AUTH token, and answers with a single E2E-encrypted
617
- * `error{code:"pairing_revoked"}` frame before closing — never serving the
618
- * channel. That is what lets a client tell "unpaired" from "daemon
619
- * offline" (which both otherwise look like a park timeout at the broker)
620
- * and stop retrying. The signal is authenticated like every tunnel frame:
621
- * it arrives inside the AEAD channel of a handshake whose transcript the
622
- * client verified against the pinned daemon key, so the broker can't forge
623
- * it; and the broker, which knows the routes, can't elicit it either (no
624
- * auth token). A tombstone keeps only the per-epoch route + auth tokens for
625
- * its window — the pair root is dropped at revoke.
626
- *
627
- * ## Reconnect authentication (why no stable client key)
628
- *
629
- * The handshake carries only a client *ephemeral* key (regenerated per
630
- * handshake) — there is no persistent client identity key. So a reconnect
631
- * authenticates the client by **possession of the epoch AUTH token**
632
- * `HKDF(pairRoot, "rv-auth"‖epoch)`, which derives from `pairRoot` — a secret
633
- * only the paired client and daemon share (it fell out of the original ECDH).
634
- * The daemon parks on the pairing's epoch ROUTE, and on that connection the
635
- * `verifyAuthToken` predicate accepts a hello whose sealed auth equals the same
636
- * epoch's auth token (constant-time). The route and auth are separate one-way
637
- * HKDF outputs: the broker sees every route and can't compute an auth from it.
638
- * (pair/v1 used ONE value for both, so a broker could replay a logged route as
639
- * the proof and be served.) The stored `fingerprint` (of the first handshake's
640
- * ephemeral key) is a stable display/revocation handle, not an auth input.
641
- *
642
- * ## Legacy (pair/v1) pairings
643
- *
644
- * A v1 `pairings.json` is loaded with every record flagged `legacy`: listed and
645
- * revocable, never served. The daemon still parks on a legacy pairing's routes
646
- * (the epoch route is unchanged from v1) so that pairing's not-yet-upgraded
647
- * client reaches it and is told to re-pair — see `respondToLegacyHandshake` —
648
- * rather than timing out. v1 records are not upgraded in place: v1 let the
649
- * broker pair as a client, so any v1 record may be the broker's own.
650
- */
651
-
652
- /** `pairings.json` format. v2 = pairings made under pair/v2 (route/auth
653
- * split). A v1 file still loads, every record flagged `legacy`. */
654
- declare const PAIRINGS_VERSION: 2;
655
- /** One persisted pairing. Written verbatim to `pairings.json`. */
656
- interface PairingRecord {
657
- /** The client ephemeral public key from the FIRST handshake (a snapshot —
658
- * reconnects use fresh ephemerals; this is not an auth input). */
659
- clientPub: string;
660
- /** Human-facing label the client chose on `pair accept`. */
661
- name: string;
662
- /** `identityFingerprint(clientPub)` from the first handshake — the stable
663
- * display + revocation handle. */
664
- fingerprint: string;
665
- /** ISO-8601 first-pair timestamp. */
666
- createdAt: string;
667
- /** ISO-8601 of the most recent successful (re)connect. */
668
- lastSeen: string;
669
- /** Long-term shared secret (base64), from which epoch routing tokens derive. */
670
- pairRoot: string;
671
- /** Rendezvous endpoint to reconnect through. */
672
- rendezvousUrl: string;
673
- /** Set on a pairing made under the retired pair/v1 protocol: listed and
674
- * revocable, never served — its client is told to re-pair. */
675
- legacy?: true;
676
- /** Set when this pairing was made under an offer minted with
677
- * `agentproto pair offer --host` (PR-C) — i.e. the offering daemon's own
678
- * intent, recorded server-side at handshake time from the OfferEntry it
679
- * itself created, never from the (unauthenticated) `scope` param a client
680
- * presented in the offer URL. Absent for an ordinary remote-control
681
- * pairing. Purely informational here — it does not change how this
682
- * pairing is served. */
683
- scope?: "host";
684
- }
685
- /** Mode of a served channel — first-contact offer vs. an established reconnect. */
686
- type PairingChannelMode = "offer" | "reconnect";
687
- /** Context handed to the injected `serve` when a channel comes up. */
688
- interface PairingChannelContext {
689
- mode: PairingChannelMode;
690
- /** Stable pairing fingerprint (present for reconnect; for an offer it's the
691
- * freshly-derived one). */
692
- fingerprint: string;
693
- /** Client label. */
694
- name: string;
695
- /** This pairing's OWN recorded scope (mirrors `PairingRecord.scope`) —
696
- * `"host"` when the offer that produced it was minted with
697
- * `agentproto pair offer --host`, absent for an ordinary remote-control
698
- * pairing. Present on BOTH the offer and every reconnect context, so
699
- * `serve` can gate scope-restricted routes (e.g. device-inference
700
- * proxying) the same way on first contact and on every later reconnect. */
701
- scope?: "host";
702
- }
703
- /** Handle to a live served channel — the registry closes it on teardown. */
704
- interface PairingChannelHandle {
705
- close(): Promise<void>;
706
- }
707
- interface CreatedOffer {
708
- /** The one-time offer secret (base64url) — the URL's `s`. Never on the wire:
709
- * the broker only ever sees its derived route. */
710
- secret: string;
711
- /** Offer expiry, unix seconds. */
712
- exp: number;
713
- /** The full `agentproto://pair?…` offer URL. */
714
- url: string;
715
- /** The daemon's identity fingerprint (shown to the human at accept time). */
716
- fingerprint: string;
717
- /** The rendezvous the offer routes through. */
718
- rendezvousUrl: string;
719
- /** True when `rendezvousUrl` is the hosted default — i.e. neither an explicit
720
- * `--rendezvous` nor a configured `pairing.rendezvous` applied, so the offer
721
- * falls back to `HOSTED_RENDEZVOUS_URL`. Surfaced so `pair offer` can flag,
722
- * never silently, that the daemon is relaying through our infrastructure. */
723
- rendezvousIsHostedDefault: boolean;
724
- /** Echoes `CreateOfferInput.scope`. `"host"` when minted with `--host`;
725
- * absent for a plain offer. */
726
- scope?: "host";
727
- }
728
- interface CreateOfferInput {
729
- /** Time-to-live in ms. Default 10 minutes. */
730
- ttlMs?: number;
731
- /** Rendezvous URL override; falls back to the configured default. */
732
- rendezvousUrl?: string;
733
- /** Mint a HOST-scoped offer (PR-C): the accepting side may register this
734
- * daemon as a driveable host (`devices add`), not just remote-control it.
735
- * Recorded on the resulting `OfferEntry`/`PairingRecord` server-side — this
736
- * is the authoritative record of what was granted, independent of the
737
- * `scope` param an accepting client's offer URL happens to carry. */
738
- scope?: "host";
739
- }
740
- interface PairingRegistryDeps {
741
- /** Lazily load (create on first use) the daemon identity. Kept lazy so a
742
- * daemon that never pairs never writes an identity file. */
743
- loadIdentity: () => Promise<DaemonIdentity>;
744
- /** Path to `pairings.json`. Defaults to `~/.agentproto/pairings.json`. */
745
- pairingsPath?: string;
746
- /** Configured rendezvous URL (from `config.pairing.rendezvous`). Three states:
747
- * - `undefined` (key absent) → `createOffer` falls back to the hosted default
748
- * (`HOSTED_RENDEZVOUS_URL`).
749
- * - a non-empty URL → that endpoint is the default for offers.
750
- * - `""` (explicitly empty) → an explicit opt-out: no default applies, so an
751
- * offer without `--rendezvous` fails closed. Wire it through verbatim (do
752
- * not coerce `""` to `undefined`) or the opt-out silently reverts to the
753
- * hosted default. */
754
- defaultRendezvousUrl?: string;
755
- /** Dial a rendezvous WS and adapt it to a FrameSink. Injected by the CLI
756
- * (uses `ws` + `wrapWebSocket`). Rejects if the dial fails. The `signal`
757
- * aborts on registry shutdown. */
758
- dial: (wsUrl: string, signal: AbortSignal) => Promise<FrameSink>;
759
- /** Serve the E2E-wrapped channel (the CLI builds `createTunnelServer` over
760
- * it with the same config `serve --connect` uses). */
761
- serve: (sink: E2eFrameSink, ctx: PairingChannelContext) => PairingChannelHandle;
762
- /** Injectable clock (ms). Defaults to Date.now. */
763
- now?: () => number;
764
- /** Diagnostic log sink. */
765
- log?: (line: string) => void;
766
- /** Reconnect backoff floor / ceiling (ms). Defaults 1s / 30s. */
767
- reconnectMinMs?: number;
768
- reconnectMaxMs?: number;
769
- /** How long a parked daemon socket waits for a client hello before recycling
770
- * the connection. Kept just under the broker's park timeout. Default 110s. */
771
- handshakeTimeoutMs?: number;
772
- /** How long a revoked pairing is still answered with `pairing_revoked` (see
773
- * "Revocation" above). Default 14 days; `0` disables tombstones, so a
774
- * revoked client just stops finding the daemon. */
775
- revokedGraceMs?: number;
776
- }
777
- interface PairingRegistry {
778
- /** Mint a one-time offer + start dialing the rendezvous for it. */
779
- createOffer(input?: CreateOfferInput): Promise<CreatedOffer>;
780
- /** All persisted pairings (copies). Loads `pairings.json` on first call. */
781
- list(): Promise<PairingRecord[]>;
782
- /** Rename a pairing by fingerprint or name (cosmetic only — no effect on
783
- * auth or routing). Returns false when nothing matched; throws on an
784
- * empty `newName`. */
785
- rename(idOrName: string, newName: string): Promise<boolean>;
786
- /** Drop a pairing by fingerprint or name; stops its rendezvous connections.
787
- * Returns false when nothing matched. */
788
- revoke(idOrName: string): Promise<boolean>;
789
- /** Is a channel (offer or reconnect) currently served for this fingerprint? */
790
- isOnline(fingerprint: string): boolean;
791
- /** Start standing reconnect connections for every persisted pairing. Call
792
- * after the gateway is up (so the injected `serve` can reach it). */
793
- startAutoconnect(): Promise<void>;
794
- /** Tear down every offer + reconnect connection and served channel. */
795
- shutdown(): Promise<void>;
796
- }
797
- /**
798
- * Read-only snapshot of `pairings.json` for callers that just want the
799
- * persisted records — no `dial`/`serve`/`loadIdentity` deps, no rendezvous
800
- * connections started (e.g. `agentproto doctor`'s devices check). Mirrors
801
- * `ensureLoaded`'s parse + v1-legacy flagging; never throws — a missing or
802
- * malformed file just yields `[]`.
803
- */
804
- declare function readPairingsSnapshot(path?: string): Promise<PairingRecord[]>;
805
- declare function createPairingRegistry(deps: PairingRegistryDeps): PairingRegistry;
806
-
807
621
  /**
808
622
  * Daemon-side HOST registry (DEVICES-PLAN PR-C) — the "client" half of
809
623
  * pair/v2, living on the daemon so it's reachable over both an HTTP route
@@ -843,16 +657,40 @@ declare function createPairingRegistry(deps: PairingRegistryDeps): PairingRegist
843
657
  *
844
658
  * ## Online tracking
845
659
  *
846
- * `isOnline(fingerprint)` mirrors `PairingRegistry.isOnline`: it's true only
847
- * while a `forwardHttp()` call for that fingerprint is in flight (a
848
- * reference count, incremented on dial and decremented in a `finally`).
849
- * There is no live probe backing `list()` — that would make `devices list`
850
- * slow/flaky over N hosts — so `list()`'s `online` is only ever true
851
- * immediately after (or during) an actual `forwardHttp`/`devices status`
852
- * call, never a background heartbeat. That's enough to make `devices list`
853
- * show the right thing right after `devices status`/`exec`, which is what
854
- * matters for this PR; a standing/autoconnect host connection with a real
855
- * liveness signal is PR-D's to build.
660
+ * `isOnline(fingerprint)` is true while a `forwardHttp()` call for that
661
+ * fingerprint is in flight (a reference count, incremented on dial and
662
+ * decremented in a `finally`), OR within `onlineGraceMs` of the last time a
663
+ * dial to it actually succeeded (an `add()` handshake, a `forwardHttp`, or a
664
+ * background snapshot poll). There is no live probe backing `list()` — that
665
+ * would make `devices list` slow/flaky over N hosts — so a host answering
666
+ * every ~15s snapshot poll stays online, and one that stops answering
667
+ * decays to offline after the grace window. Every contact attempt stamps
668
+ * `lastProbeAt`; a failed one records `lastError` (cleared by the next success).
669
+ *
670
+ * ## Proactive session snapshots
671
+ *
672
+ * A join-token-added host (an ephemeral CI runner) lives ~3 minutes, far
673
+ * shorter than anyone watches it. So from the moment such a host joins, this
674
+ * registry polls it (`snapshotIntervalMs`, faster while one of its sessions
675
+ * is running) for its session list plus a capped output tail per session and
676
+ * keeps the result in memory. Once the host is offline, `getSessionsSnapshot`
677
+ * serves that — `stale: true` with the capture time. After
678
+ * `snapshotMaxFailures` consecutive unreachable polls the loop backs off
679
+ * exponentially (up to `probeBackoffMaxMs`) and keeps the last good capture;
680
+ * `start()` resumes the loop for every join-added host after a daemon
681
+ * restart, and background probes share a `probeConcurrency` cap.
682
+ * `snapshotNow()` lets a departing host trigger one last
683
+ * capture (see `join-token-registry.ts`'s goodbye hello).
684
+ *
685
+ * ## Ended hosts
686
+ *
687
+ * A join-added host is an ephemeral CI box, so it is marked `ended` when its
688
+ * goodbye arrives (`markEnded`) or when it has been unreachable for
689
+ * `endedTtlMs` (2 h), and deleted `endedRetentionMs` (7 d) after that.
690
+ * `sweep()` runs that pass (the daemon calls it on a timer; `list()` runs it
691
+ * too). Ended hosts are still returned by `list()` — hiding them from the
692
+ * default `device_list` is `device-registry.ts`'s job. A manually added host
693
+ * is never ended or deleted; `list()` only flags it `stale`.
856
694
  */
857
695
 
858
696
  /** `hosts.json` format. */
@@ -876,8 +714,26 @@ interface HostRecord {
876
714
  pairRoot: string;
877
715
  /** ISO-8601 first-add timestamp. */
878
716
  createdAt: string;
879
- /** ISO-8601 of the most recent successful `forwardHttp`. */
717
+ /** ISO-8601 of the most recent successful contact (join, dial, background poll). */
880
718
  lastSeen: string;
719
+ /** ISO-8601 of the most recent contact attempt, successful or not. Not
720
+ * persisted on every attempt — it rides along with the next write. */
721
+ lastProbeAt?: string;
722
+ /** Why the most recent contact attempt failed; cleared by the next success. */
723
+ lastError?: string;
724
+ /** A join-added host that is gone: it said goodbye, or was unreachable for
725
+ * longer than `endedTtlMs`. Ended hosts are no longer polled, read offline,
726
+ * and are deleted `endedRetentionMs` after `endedAt`. Never set on a
727
+ * manually added host. */
728
+ ended?: true;
729
+ /** ISO-8601 of when the host ended (for a TTL end: when the TTL lapsed, not
730
+ * when the sweep noticed). */
731
+ endedAt?: string;
732
+ endReason?: "goodbye" | "ttl";
733
+ /** Computed by `list()`, never persisted: a manually added host that has
734
+ * been unreachable for longer than `endedTtlMs`. Stale hosts stay listed
735
+ * and are never deleted — only join-added hosts are. */
736
+ stale?: true;
881
737
  /** Set on a host added under the retired pair/v1 protocol. Present for
882
738
  * parity with `PairingRecord`/`ClientPairing`; pair/v1 offers are refused
883
739
  * by `parseOfferUrl` before `add()` ever sees them, so this is currently
@@ -896,9 +752,9 @@ interface HostRecord {
896
752
  * `"manual"` for the human `pair offer --host` + `devices add` ceremony.
897
753
  * Absent on a record persisted before this field existed; treated as
898
754
  * `"manual"` (never auto-pruned) rather than assumed ephemeral. Only
899
- * `"join"` hosts are eligible for the `joinedHostTtlMs` sweep in `list()`
900
- * — a human's own paired machine must never silently disappear just
901
- * because it hasn't been dialed in a week.
755
+ * `"join"` hosts are eligible for the ended/retention sweep — a human's
756
+ * own paired machine must never silently disappear just because it hasn't
757
+ * been dialed in a week.
902
758
  */
903
759
  addedVia?: "join" | "manual";
904
760
  }
@@ -929,16 +785,32 @@ interface HostRegistryDeps {
929
785
  /** Handshake ceiling per attempt. Default 15s. */
930
786
  handshakeTimeoutMs?: number;
931
787
  /**
932
- * TTL (ms) for a join-token-added host (`HostRecord.addedVia === "join"`)
933
- * that hasn't been seen since — swept opportunistically at the top of
934
- * every `list()` call rather than on its own timer, since staleness here
935
- * is an observability concern (an ephemeral CI box's `hosts.json` entry
936
- * outliving it by weeks), not something anything blocks on. Default 7
937
- * days. `0` disables pruning entirely. A manually-added host
938
- * (`addedVia !== "join"`, including every record persisted before this
939
- * field existed) is NEVER pruned, regardless of this setting.
788
+ * A join-added host (`HostRecord.addedVia === "join"`) unreachable for this
789
+ * long (ms since `lastSeen`) is marked `ended`. Default 2 h; `0` disables.
790
+ * Manually added hosts are never ended — `list()` only flags them `stale`.
940
791
  */
941
- joinedHostTtlMs?: number;
792
+ endedTtlMs?: number;
793
+ /**
794
+ * An ended host is deleted this long (ms) after `endedAt`. Default 7 days;
795
+ * `0` keeps ended hosts forever. Only join-added hosts are ever deleted.
796
+ */
797
+ endedRetentionMs?: number;
798
+ /** Cadence (ms) of the proactive session snapshot poll for a join-added
799
+ * host. Default 15s; `0` disables the poll (and `snapshotNow` becomes a
800
+ * no-op that returns false). */
801
+ snapshotIntervalMs?: number;
802
+ /** Faster cadence used while a snapshotted session is running. Default 5s. */
803
+ snapshotActiveIntervalMs?: number;
804
+ /** Consecutive unreachable polls before the poll starts backing off. Default 3. */
805
+ snapshotMaxFailures?: number;
806
+ /** A host stays `online` for this long after a successful dial. Default 2 min. */
807
+ onlineGraceMs?: number;
808
+ /** Consecutive-failure poll backoff ceiling (ms). Default 5 min. */
809
+ probeBackoffMaxMs?: number;
810
+ /** Max background probes in flight across all hosts. Default 4. */
811
+ probeConcurrency?: number;
812
+ /** Min gap between disk writes for a `lastSeen`-only change. Default 30s. */
813
+ lastSeenPersistIntervalMs?: number;
942
814
  }
943
815
  interface ForwardHttpRequest {
944
816
  method: string;
@@ -1023,6 +895,31 @@ interface HostRegistry {
1023
895
  * why that's an acceptable trade here.
1024
896
  */
1025
897
  getSessionsSnapshot(idOrName: string, path: string): ForwardHttpResponse | undefined;
898
+ /**
899
+ * Capture this host's session list + output tails right now (the same
900
+ * capture the background poll takes). Resolves true when the host was
901
+ * reached. Never throws; false for an unknown host, an unreachable one, or
902
+ * when snapshots are disabled.
903
+ */
904
+ snapshotNow(idOrName: string): Promise<boolean>;
905
+ /**
906
+ * Mark a join-added host ended right now (its CI job said goodbye). Stops
907
+ * its poll. Returns false for an unknown host or a manually added one,
908
+ * which is never ended. Idempotent.
909
+ */
910
+ markEnded(idOrName: string, reason?: "goodbye" | "ttl"): Promise<boolean>;
911
+ /**
912
+ * Run the lifecycle sweep now: mark join-added hosts ended past `endedTtlMs`,
913
+ * delete those ended past `endedRetentionMs`, persist if anything changed.
914
+ * Cheap (one pass over the in-memory map); `list()` runs the same pass.
915
+ */
916
+ sweep(): Promise<void>;
917
+ /**
918
+ * Load `hosts.json` and resume the background poll for every join-added
919
+ * host, so a daemon restart doesn't leave still-running CI boxes frozen at
920
+ * their join-time `lastSeen`. Idempotent; call once at boot.
921
+ */
922
+ start(): Promise<void>;
1026
923
  }
1027
924
  declare function createHostRegistry(deps: HostRegistryDeps): HostRegistry;
1028
925
 
@@ -1170,6 +1067,17 @@ interface JoinTokenRegistryDeps {
1170
1067
  * are logged and swallowed: a bad/unreachable offer from one join must not
1171
1068
  * crash the standing accept loop. */
1172
1069
  addHost: (offerUrl: string, name?: string, meta?: HostJoinMeta) => Promise<unknown>;
1070
+ /** Called when a joined box says goodbye just before it exits (see
1071
+ * `JoinHello.goodbye`), with its daemon fingerprint — normally
1072
+ * `hostRegistry.snapshotNow`, so the box's final session output is captured
1073
+ * while it can still answer. The box waits for this to settle (bounded on
1074
+ * its side), so it should not hang. Errors are logged and swallowed. */
1075
+ flushHost?: (fingerprint: string) => Promise<unknown>;
1076
+ /** Called after the goodbye's final capture (even if it failed), with the
1077
+ * same fingerprint — normally `hostRegistry.markEnded`, so a departed CI
1078
+ * box stops reading as a live host immediately. Errors are logged and
1079
+ * swallowed. */
1080
+ endHost?: (fingerprint: string) => Promise<unknown>;
1173
1081
  /** Injectable clock (ms). Defaults to Date.now. */
1174
1082
  now?: () => number;
1175
1083
  /** Diagnostic log sink. */
@@ -1471,7 +1379,12 @@ interface InboundRouterDeps {
1471
1379
  * Supports the dialects documented in packages/runtime/docs/TRANSMITTER.md.
1472
1380
  */
1473
1381
 
1474
- type InboundProvider = "agentpush" | "telegram" | "whatsapp" | "slack" | "generic" | "native";
1382
+ type InboundProvider = "agentpush" | "telegram" | "whatsapp" | "slack" | "generic" | "native"
1383
+ /** GitHub repo webhooks feeding the `webhook` sentinel provider (AIP-60).
1384
+ * Not a user-registrable endpoint dialect: `handleProviderInbound` routes
1385
+ * `/inbound/sentinel-<hookKey>` straight into the sentinel runtime, and the
1386
+ * provider verifies with this dialect's `X-Hub-Signature-256` check. */
1387
+ | "sentinel";
1475
1388
  declare const INBOUND_PROVIDERS: readonly InboundProvider[];
1476
1389
  type NormalizeInboundResult = {
1477
1390
  ok: true;
@@ -2022,29 +1935,6 @@ declare function createActivityProjector(opts: {
2022
1935
  resolvePrState?: PrStateResolver;
2023
1936
  }): ActivityProjector;
2024
1937
 
2025
- /**
2026
- * `~/.agentproto/bundles.json` — named sets of imported MCPs + skills (+
2027
- * optionally the daemon's own `/mcp`), attachable to any harness in one
2028
- * `agent_start({bundles:["research"]})` call.
2029
- *
2030
- * Same load/save/atomic-write pattern as `user-presets.ts`; validation
2031
- * against the live imported-MCP set is the single boundary every writer
2032
- * (MCP tools, HTTP routes) goes through (`saveBundle`).
2033
- */
2034
-
2035
- declare const bundlesFileSchema: z.ZodObject<{
2036
- version: z.ZodLiteral<1>;
2037
- bundles: z.ZodArray<z.ZodObject<{
2038
- id: z.ZodString;
2039
- label: z.ZodString;
2040
- description: z.ZodOptional<z.ZodString>;
2041
- mcpImports: z.ZodArray<z.ZodString>;
2042
- includeDaemon: z.ZodOptional<z.ZodBoolean>;
2043
- skills: z.ZodArray<z.ZodString>;
2044
- }, z.core.$strip>>;
2045
- }, z.core.$strip>;
2046
- type BundlesFile = z.infer<typeof bundlesFileSchema>;
2047
-
2048
1938
  /**
2049
1939
  * Spawn-time role profiles — the primitive that decides whether a
2050
1940
  * spawned agent may itself delegate (spawn further children).
@@ -2177,225 +2067,6 @@ type DeviceProbeResult = {
2177
2067
  message: string;
2178
2068
  };
2179
2069
 
2180
- /**
2181
- * Policy layer for `agent_start.worktree` — the config-driven decision of
2182
- * WHETHER to isolate a spawn into its own git worktree, kept deliberately
2183
- * separate from HOW one is provisioned.
2184
- *
2185
- * This module holds no dependency on `@agentproto/worktree`. Same reasoning
2186
- * as `worktree-identity.ts`'s docblock, only stronger: provisioning runs the
2187
- * `worktree.provision` TOOL (git + the base tree's `agentproto.json` setup
2188
- * hooks), which would drag the driver/harness/provider graph into
2189
- * `@agentproto/runtime` for a capability the runtime only ever *triggers*.
2190
- * So the concrete provisioner is an INJECTED PORT ({@link WorktreeProvisioner})
2191
- * wired at the composition root by a host that already depends on the
2192
- * worktree package (the CLI). The runtime owns only the pure decision
2193
- * ({@link decideWorktreeIsolation}) and the config/env resolution
2194
- * ({@link loadWorktreeIsolation}) — both trivially unit-testable without git.
2195
- *
2196
- * Mirrors `agent_start.sandbox`'s `resolveSandboxProvider` injection shape,
2197
- * except sandbox can default its resolver inside the runtime (the runtime
2198
- * depends on `@agentproto/sandbox`); worktree cannot, so an unwired daemon
2199
- * simply has no provisioner and a spawn that would need one fails loud rather
2200
- * than silently spawning unisolated.
2201
- */
2202
-
2203
- /** Env override for the isolation policy. Highest-priority source, ahead of
2204
- * the `worktrees.isolation` config field — see `loadWorktreeIsolation`. */
2205
- declare const WORKTREE_ISOLATION_ENV = "AGENTPROTO_WORKTREES_ISOLATION";
2206
- /** The default when nothing is configured. Back-compat-preserving: a caller
2207
- * that passes no `worktree` field spawns exactly where it asked. */
2208
- declare const DEFAULT_WORKTREE_ISOLATION: WorktreeIsolationMode;
2209
- /**
2210
- * The `agent_start.worktree` field. `true` isolates with an auto-minted slug;
2211
- * an object additionally pins the slug and/or base ref, and can opt into
2212
- * async provisioning (`async: true` — see `WorktreeRequest.async`); `false`
2213
- * (or omitted) is "no explicit request" — the policy mode decides.
2214
- */
2215
- type WorktreeField = boolean | {
2216
- slug?: string;
2217
- base?: string;
2218
- async?: boolean;
2219
- };
2220
- /** The caller's explicit request, normalized — `undefined` when the field is
2221
- * absent or `false`, otherwise the (possibly empty) slug/base overrides. */
2222
- interface WorktreeRequest {
2223
- slug?: string;
2224
- base?: string;
2225
- /** Return a real, registered session as soon as it's minted, provisioning
2226
- * the worktree in the BACKGROUND instead of blocking `agent_start`'s
2227
- * response on `git worktree add` + the repo's setup hooks (which can run
2228
- * minutes — see `session-spawn.ts`'s async-provision branch).
2229
- *
2230
- * DEFAULTS TO TRUE for any spawn that provisions a worktree, UNLESS this
2231
- * spawn also carries `wait` (which needs a first turn to block on — see
2232
- * `worktree_async_wait_conflict` — so the presence of `wait` alone falls
2233
- * back to the synchronous path rather than conflicting by default). That
2234
- * default is applied by `session-spawn.ts` itself (WP-H), not by this
2235
- * field or `normalizeWorktreeField` — the normalizer leaves `async`
2236
- * exactly as the caller sent it (`undefined` when omitted; see its own
2237
- * test), so a caller inspecting the normalized request never sees a
2238
- * value it didn't write. WP-H incident: the synchronous contract this
2239
- * field opts OUT of — hold the RPC open for however long setup hooks
2240
- * take, routinely minutes — is exactly what let a client's own request
2241
- * timeout retry into a second live agent sharing the first one's
2242
- * worktree (closed on the other side too — see `session-spawn.ts`'s
2243
- * `findWorktreeLabelCwdCollision`, which now refuses that retry outright
2244
- * rather than merely warning). Pass `false` explicitly to keep the old
2245
- * blocking ok/fail contract (this package's own `worktree_provision_failed`
2246
- * test coverage exercises it deliberately synchronous). */
2247
- async?: boolean;
2248
- }
2249
- /** What the runtime hands the provisioner. `cwd` is where the session would
2250
- * otherwise spawn; the provisioner resolves the owning repo from it. */
2251
- interface WorktreeProvisionRequest {
2252
- cwd: string;
2253
- /** Explicit slug from the caller; omitted ⇒ the provisioner mints a
2254
- * collision-free one (see the host implementation). */
2255
- slug?: string;
2256
- /** Base ref the worktree branch is cut from; omitted ⇒ the provisioner's
2257
- * default (`origin/main`). */
2258
- base?: string;
2259
- /** Free-text label (the session's `label`) the provisioner may fold into a
2260
- * minted slug for human readability. Never load-bearing for correctness. */
2261
- labelHint?: string;
2262
- /** Absolute path the provisioner should append the setup hooks' FULL
2263
- * stdout+stderr to (see `worktree.provision`'s `setupLogPath` input and
2264
- * `@agentproto/worktree`'s `runSetup`). `session-spawn.ts` passes the
2265
- * spawning session's own transcript dir here, so a failing setup hook's
2266
- * full output survives even after a subsequently-reclaimed worktree is
2267
- * gone — the short `HookError` message alone only carries a filtered
2268
- * tail. Omitted callers (e.g. `agentproto worktree new`, no session to
2269
- * log into) simply get no persisted log. */
2270
- setupLogPath?: string;
2271
- /** Re-run a failing `worktree.setup` command exactly once before giving
2272
- * up — see `worktree.provision`'s `retrySetupOnFailure` input and
2273
- * `runSetup`'s doc for why this is a bounded complement, not a
2274
- * substitute, and why the daemon opts in while `agentproto worktree new`
2275
- * doesn't. */
2276
- retrySetupOnFailure?: boolean;
2277
- }
2278
- /** The provisioner's outcome. `isolated: false` is NOT a failure — it means
2279
- * there was nothing to isolate (`cwd` sits in no git repo), and the caller
2280
- * should spawn plain at the original cwd. A genuine failure throws. */
2281
- type WorktreeProvisionOutcome = {
2282
- isolated: true;
2283
- cwd: string;
2284
- branch: string;
2285
- } | {
2286
- isolated: false;
2287
- reason: "not-a-git-repo";
2288
- };
2289
- /**
2290
- * Injected port: provision a git worktree for `req.cwd` and return the
2291
- * worktree's own cwd for the spawn to land in. Wired at the composition root
2292
- * by the CLI (over `@agentproto/worktree`); absent on a bare runtime.
2293
- */
2294
- type WorktreeProvisioner = (req: WorktreeProvisionRequest) => Promise<WorktreeProvisionOutcome>;
2295
- /**
2296
- * Injected port: best-effort attempt to reclaim ONE worktree by path, called
2297
- * when its session reaches a terminal state (see
2298
- * `SessionDescriptor.worktreeAutoProvisioned` and `createSessionsRegistry`'s
2299
- * `runWorktreeAutoReclaim` option in `sessions.ts`). Deliberately scoped to
2300
- * exactly the one path a session's own exit is allowed to touch — never a
2301
- * repo-wide sweep. The implementation (wired by the CLI over
2302
- * `@agentproto/worktree`'s `reclaimOneWorktree`) re-classifies fresh and only
2303
- * ever removes the worktree when that comes back `reclaim` (merged-or-fresh,
2304
- * clean, idle) — a dirty or held worktree is simply left alone. Must never
2305
- * reject in a way the caller can't safely ignore; `sessions.ts` treats any
2306
- * rejection as "couldn't reclaim this time, leave it for a manual or
2307
- * scheduled `gc` sweep" and logs rather than lets it interrupt session
2308
- * teardown. Absent on a bare runtime — auto-reclaim is simply skipped, and a
2309
- * caller-explicit worktree request is never routed through this port at all
2310
- * (see `WorktreeDecision.provision.implicit`).
2311
- */
2312
- type WorktreeAutoReclaimer = (worktreePath: string) => Promise<void>;
2313
- /** The pure decision's three outcomes. `spawn-in-place` may carry a `warn`:
2314
- * a non-fatal notice the caller should surface (the child is about to run in
2315
- * a shared, dirty checkout it doesn't own). A `warn` never blocks the spawn —
2316
- * it's the loud-but-legitimate middle ground between silently spawning into a
2317
- * shared tree and hard-rejecting an in-place spawn that's normal at depth.
2318
- * `provision.implicit` is `true` exactly when the caller made no explicit
2319
- * `worktree` request and the `"always"` policy provisioned one anyway (the
2320
- * worktree the caller never asked to keep) — `false` whenever the request
2321
- * came from the caller itself (`on-request`'s only path here, or `"always"`
2322
- * with an explicit field). This is the signal `session-spawn.ts` threads
2323
- * onto the session descriptor so exit-time auto-reclaim (`sessions.ts`)
2324
- * only ever touches a worktree the daemon minted on its own — a worktree a
2325
- * caller explicitly asked to keep is never auto-removed. */
2326
- type WorktreeDecision = {
2327
- action: "spawn-in-place";
2328
- warn?: string;
2329
- } | {
2330
- action: "provision";
2331
- request: WorktreeRequest;
2332
- implicit: boolean;
2333
- } | {
2334
- action: "reject";
2335
- message: string;
2336
- };
2337
- /**
2338
- * Normalize the raw field into an explicit request, or `undefined` when the
2339
- * caller made no request (`false` / omitted). An object with no overrides
2340
- * still counts as a request (`{}`) — the caller opted in, just without pins.
2341
- */
2342
- declare function normalizeWorktreeField(field: WorktreeField | undefined): WorktreeRequest | undefined;
2343
- /**
2344
- * The resolution matrix — mode × explicit-request × depth — with no side
2345
- * effects. Every branch is exercised in `worktree-isolation.test.ts`.
2346
- *
2347
- * Depth-0 gate: a nested spawn (`depth > 0`, i.e. made through the scoped
2348
- * orchestrator sub-gateway) NEVER provisions a worktree of its own — it
2349
- * inherits its parent's ground, per AIP-46 §Delegation. This bites before
2350
- * the mode is even consulted, so `always` too provisions only at the root.
2351
- * But "never provisions" is NOT "silently ignore an explicit request": a
2352
- * nested caller that passes an EXPLICIT `worktree` (`true` / `{slug}`) asked
2353
- * for isolation and would silently get none — the spawn quietly runs in the
2354
- * shared checkout, exactly the footgun that nearly clobbered a shared tree.
2355
- * So an explicit request at depth > 0 is REJECTED loudly (same shape as the
2356
- * `never`-policy reject below), pointing the caller at sandbox isolation —
2357
- * child isolation is the sandbox, not a second worktree. Only the IMPLICIT/
2358
- * absent case (`undefined` / `false`) stays an in-place spawn: the child is
2359
- * meant to share the parent's tree and made no request to the contrary.
2360
- *
2361
- * That implicit case still has a footgun, though: the inherited cwd may be a
2362
- * LIVE, DIRTY, shared checkout (the real repo, not a daemon-provisioned
2363
- * worktree) — spawning in place there lets a nested child edit a tree someone
2364
- * else is actively working in. We don't hard-reject it (implicit in-place is
2365
- * legitimate and common), but we DON'T stay silent either: when the caller
2366
- * hands us `sharedDirtyCwd` (an impure signal it computed — see
2367
- * `session-spawn.ts`), the in-place spawn carries a `warn`. A caller that
2368
- * genuinely intends it passes `allowSharedCwd` to acknowledge and silence the
2369
- * warning. The signal is only consulted for the implicit nested case; every
2370
- * other branch ignores it, keeping the root matrix unchanged.
2371
- */
2372
- declare function decideWorktreeIsolation(input: {
2373
- mode: WorktreeIsolationMode;
2374
- field: WorktreeField | undefined;
2375
- depth: number;
2376
- /** Impure signal, computed by the caller (never inside this pure fn): the
2377
- * inherited cwd is a git work tree that is DIRTY and NOT a daemon-
2378
- * provisioned worktree — i.e. a shared checkout the child would edit in
2379
- * place. Only consulted for an implicit nested spawn. */
2380
- sharedDirtyCwd?: boolean;
2381
- /** Caller's explicit acknowledgement that spawning into a shared dirty cwd
2382
- * is intended — silences the `sharedDirtyCwd` warning. */
2383
- allowSharedCwd?: boolean;
2384
- }): WorktreeDecision;
2385
- /** Parse a raw string into a valid mode, or `undefined` when it isn't one. */
2386
- declare function parseWorktreeIsolationMode(raw: string | undefined): WorktreeIsolationMode | undefined;
2387
- /**
2388
- * Resolve the effective isolation mode: env > config field > default. Mirrors
2389
- * `resolveWorktreesRoot`'s precedence (there's no flag layer — this is read
2390
- * daemon-side at spawn, not from an invocation). Never throws: an unreadable
2391
- * config falls through to the default.
2392
- */
2393
- declare function loadWorktreeIsolation(loadCfg?: () => Promise<{
2394
- worktrees?: {
2395
- isolation?: WorktreeIsolationMode;
2396
- };
2397
- }>): Promise<WorktreeIsolationMode>;
2398
-
2399
2070
  /**
2400
2071
  * Policy layer for `agent_start.attach` — the config-driven decision of WHO a
2401
2072
  * spawn nests under, kept deliberately separate (and pure) from the spawn
@@ -2548,7 +2219,9 @@ interface SpawnAgentSessionDeps {
2548
2219
  * line. Defaults to the real resolver over `loadAgentsMdInlineMaxKb`'s
2549
2220
  * config-derived threshold when omitted; tests inject a stub to avoid
2550
2221
  * touching the filesystem, git, and the real config on every spawn. */
2551
- resolveAgentsMd?: (cwd: string, inlineMaxKb?: number) => Promise<AgentsMdResolution>;
2222
+ resolveAgentsMd?: (cwd: string, inlineMaxKb?: number, opts?: {
2223
+ stopAt?: string;
2224
+ }) => Promise<AgentsMdResolution>;
2552
2225
  /** Resolves + shapes the per-workspace RULES.md for a spawn (see
2553
2226
  * `workspace-rules.ts`): the path of the workspace's `RULES.md`, inlined
2554
2227
  * in full when present, absent otherwise. Injected into EVERY spawn in
@@ -2639,6 +2312,18 @@ interface SpawnAgentSessionInput {
2639
2312
  * the model driving the session has no way to know its own appId unless
2640
2313
  * told. Absent on a spawn made outside `app_run`. */
2641
2314
  appId?: string;
2315
+ /**
2316
+ * Filesystem boundary for this spawn (see `app-boundary.ts`): app source
2317
+ * read-only, run workspace + data dir writable, the rest denied. Set by
2318
+ * `app_run` and by app-workflow agent steps; a child spawned by an
2319
+ * already-boundaried session inherits its parent's boundary instead (this
2320
+ * field cannot widen it). Makes the spawn: refuse `worktree`, resolve
2321
+ * AGENTS.md no higher than the boundary root, isolate host CLAUDE.md, and
2322
+ * either confine the harness's native tools through the OS sandbox or
2323
+ * warn / refuse (`boundaries.enforce: "required"`) — never silently
2324
+ * downgrade.
2325
+ */
2326
+ appBoundary?: AppBoundary;
2642
2327
  /** Reattach to a pre-existing adapter-native session (claude-code's
2643
2328
  * conversation id, hermes' chat handle, …) instead of starting
2644
2329
  * blank. Not exposed on the MCP `agent_start` tool today — only the
@@ -3402,7 +3087,30 @@ type AgentAdapterResolver = (slug: string) => Promise<{
3402
3087
  * read-only grant; writes and sibling reads stay denied. Adapters
3403
3088
  * that can't model the grant ignore it. */
3404
3089
  additionalReadPaths?: string[];
3090
+ /** App-boundary filesystem zones (app source read-only, run workspace +
3091
+ * data dir writable, `hidden` denied) for the adapter's OWN process
3092
+ * tree — forwarded to the driver's `runtime.start({ fsZones })`, which
3093
+ * confines it through the OS sandbox (always engaged; refuses
3094
+ * `commandSandbox: "off"`) and, on claude-code, registers the writable
3095
+ * zones as `additionalDirectories`. Only passed to adapters whose
3096
+ * resolver entry sets `supportsFsZones`. */
3097
+ fsZones?: {
3098
+ readOnly: string[];
3099
+ writable: string[];
3100
+ hidden?: string[];
3101
+ };
3102
+ /** Don't load the host repo's CLAUDE.md/AGENTS.md above the session cwd
3103
+ * (claude-code: `claudeMdExcludes`). Only passed to adapters whose
3104
+ * resolver entry sets `supportsHostContextIsolation`. */
3105
+ isolateHostContext?: boolean;
3405
3106
  }): Promise<AgentSessionLike>;
3107
+ /** True when `startSession` honours `fsZones` (native tools confined by the
3108
+ * OS sandbox). Omitted/false ⇒ an app-boundary spawn on this adapter gets
3109
+ * an explicit `session:harness-warning` (or is refused when the app
3110
+ * declares `boundaries.enforce: "required"`). */
3111
+ supportsFsZones?: boolean;
3112
+ /** True when `startSession` honours `isolateHostContext`. */
3113
+ supportsHostContextIsolation?: boolean;
3406
3114
  /** Display label for the descriptor's `command` field. */
3407
3115
  commandPreview?: string;
3408
3116
  /** Best-effort per-session usage reader (adapter-specific, e.g. hermes
@@ -3719,6 +3427,41 @@ interface BrowserAdapterInfo {
3719
3427
  defaultPort: number;
3720
3428
  }
3721
3429
 
3430
+ /**
3431
+ * `model_roles` — read-only MCP tool listing every model role, the model it
3432
+ * resolves to right now, and which layer supplied it. The precedence itself
3433
+ * (input > workspace > daemon > built-in default) is defined once, in
3434
+ * `model-roles.ts`; this file only loads the layers and exposes the result.
3435
+ *
3436
+ * Workflow `tool` steps call it (the daemon's `dispatchTool` reaches every
3437
+ * root-`/mcp` tool) to resolve a role at RUN time — a workflow's own
3438
+ * `reviewModelSmall`-style input is passed as `inputs` so an explicit input
3439
+ * still wins, and the tool reports `source: "input"` for it.
3440
+ *
3441
+ * Registered on the root `/mcp` server only, next to `config_get`.
3442
+ */
3443
+
3444
+ interface ModelRolesInput {
3445
+ /** Narrow to these roles. Omit for every built-in + configured role. */
3446
+ roles?: string[] | undefined;
3447
+ /** Explicit per-role values (layer 1) — e.g. a workflow's own inputs. */
3448
+ inputs?: Record<string, unknown> | undefined;
3449
+ /** Repo whose `agentproto.json` `models` is the workspace layer. */
3450
+ repoRoot?: string | undefined;
3451
+ /** Workspace slug (resolved to its path). The active workspace when both are omitted. */
3452
+ workspaceSlug?: string | undefined;
3453
+ }
3454
+ interface ModelRolesOutput {
3455
+ roles: ResolvedModelRole[];
3456
+ /** role → resolved model id, for a workflow `$steps.<id>.models["review.small"]`-style read. */
3457
+ models: Record<string, string>;
3458
+ /** Directory whose `agentproto.json` supplied the workspace layer, when one was found. */
3459
+ workspaceRoot?: string;
3460
+ precedence: readonly string[];
3461
+ }
3462
+ /** `models` from `<root>/agentproto.json`; undefined when absent/unreadable/malformed. */
3463
+ declare function loadWorkspaceModelRoles(root: string): Promise<Record<string, unknown> | undefined>;
3464
+
3722
3465
  /**
3723
3466
  * Bounded eager resume-on-boot pass (session-survivability plan §5, PR-4).
3724
3467
  *
@@ -4177,6 +3920,12 @@ interface InboundWatcher {
4177
3920
  * adapter's own already-installed package by its `packageName`.
4178
3921
  */
4179
3922
 
3923
+ /** How a harness reaches one imported MCP by default:
3924
+ * - `native` — a default bundle mounts it as a native mcpServers entry;
3925
+ * - `indirect` — only via the daemon's own `/mcp` (`mcp_imported_call`),
3926
+ * which the harness gets by default / config / bundle;
3927
+ * - `none` — no default path (still reachable on request). */
3928
+ type ImportedMcpReach = "native" | "indirect" | "none";
4180
3929
  interface CapabilitiesInventoryImportedMcp {
4181
3930
  id: string;
4182
3931
  alias?: string;
@@ -4188,6 +3937,38 @@ interface CapabilitiesInventoryImportedMcp {
4188
3937
  /** Only present when `status === "connected"` — never connects just to count. */
4189
3938
  toolCount?: number;
4190
3939
  usedBySessions: string[];
3940
+ /** `live` re-reads the source harness config; `snapshot` uses the stored copy. */
3941
+ resolve?: "live" | "snapshot";
3942
+ /** Set when the last resolution fell back (source missing / secret unresolved). */
3943
+ stale?: {
3944
+ reason: string;
3945
+ };
3946
+ /** Header/env KEY names held behind secret refs (never values). */
3947
+ secretRefKeys?: {
3948
+ headers?: string[];
3949
+ env?: string[];
3950
+ };
3951
+ /** Per installed adapter: how it reaches this import with NO per-spawn
3952
+ * arguments (resolved default bundles + daemon self-mount default). */
3953
+ reach: Record<string, ImportedMcpReach>;
3954
+ /** Double-mount report (P3): OTHER discovered harness-config entries that
3955
+ * point at the same upstream as this import, i.e. a harness likely
3956
+ * mounts it natively AND through the daemon. Omitted when none. Identity
3957
+ * fields only — never url/command/args/headers/env.
3958
+ * `sameName` = the slugified alias equals the native name (claude-code
3959
+ * then shadows one with the other: no duplicate tools, but they may
3960
+ * silently be different servers/creds).
3961
+ * Limitation: discovery scans the host configs + registered workspaces
3962
+ * only; a session's own cwd `.mcp.json` outside a registered workspace is
3963
+ * NOT seen here (only `mcp-app-resolve` sees it). Report only — nothing
3964
+ * is rewritten. */
3965
+ alsoNativeIn?: CapabilitiesInventoryAlsoNative[];
3966
+ }
3967
+ interface CapabilitiesInventoryAlsoNative {
3968
+ source: string;
3969
+ scope: string;
3970
+ name: string;
3971
+ sameName: boolean;
4191
3972
  }
4192
3973
  interface CapabilitiesInventoryDiscoveredMcp {
4193
3974
  id: string;
@@ -4923,6 +4704,7 @@ interface FindComposeCandidateInput {
4923
4704
  * (non-pack) check — nothing extra to require. */
4924
4705
  packDigest?: {
4925
4706
  id: string;
4707
+ alg: string;
4926
4708
  sha256: string;
4927
4709
  };
4928
4710
  baseSha: string;
@@ -5391,6 +5173,80 @@ declare function makeBrowserAdapterLister(opts: {
5391
5173
  listBrowserAdapters: BrowserAdapterLister;
5392
5174
  resolveBrowserAdapter?: BrowserAdapterResolver;
5393
5175
  }): AdapterLister<BrowserAdapterInfo>;
5176
+ /**
5177
+ * The one built-in adapter table the daemon, the HTTP route and the CLI share:
5178
+ * the `@agentproto/adapter-browser` facade (kit providers camofox, bureau,
5179
+ * chromium behind the legacy handle shape). Hosts that want a different set
5180
+ * still inject their own `resolveBrowserAdapter` / `listBrowserAdapters`.
5181
+ */
5182
+ declare function defaultBrowserAdapterResolution(): {
5183
+ resolveBrowserAdapter: BrowserAdapterResolver;
5184
+ listBrowserAdapters: BrowserAdapterLister;
5185
+ };
5186
+ /** Ids of the built-in adapters, for "not found, available: ..." messages. */
5187
+ declare function defaultBrowserAdapterIds(): string[];
5188
+
5189
+ /**
5190
+ * `projectBrowserTools`: project a kit `BrowserInstance` (from
5191
+ * `@agentproto/driver-browser`) onto the page-level `browser_*` MCP tools.
5192
+ *
5193
+ * MCP only. The SDK stays the existing typed client. The lifecycle tools
5194
+ * (`start_browser`, `browser_status`, ...) live in `browser-tools.ts` and are
5195
+ * untouched; this module adds the page-control set on top of an instance:
5196
+ *
5197
+ * browser_navigate, browser_evaluate, browser_click, browser_fill,
5198
+ * browser_screenshot, browser_get_dom, browser_list_requests,
5199
+ * browser_get_request_body, browser_cdp_send
5200
+ *
5201
+ * Capability gating is declarative (`BROWSER_TOOL_GATES` in the kit, AIP-14
5202
+ * capability gate): a tool whose capability the provider lacks answers with a
5203
+ * typed `browser:unsupported` error result naming the capability, before any
5204
+ * driver is attached. It is never a crash and never an empty success.
5205
+ */
5206
+
5207
+ /** What the projection needs to know about the provider that owns the instance. */
5208
+ type ProjectedProvider = Pick<BrowserProvider, "id"> & {
5209
+ capabilities: Partial<BrowserCapabilities>;
5210
+ };
5211
+ /** Result of one projected tool call, MCP `CallToolResult` compatible. */
5212
+ interface ProjectedToolResult {
5213
+ content: {
5214
+ type: "text";
5215
+ text: string;
5216
+ }[];
5217
+ structuredContent: Record<string, unknown>;
5218
+ isError?: true;
5219
+ [key: string]: unknown;
5220
+ }
5221
+ interface ProjectedBrowserTool {
5222
+ /** MCP tool name, e.g. `browser_list_requests`. */
5223
+ name: string;
5224
+ description: string;
5225
+ /** Kit tool id used for the capability gate, e.g. `browser.list_requests`. */
5226
+ gateId: string;
5227
+ inputSchema: z.ZodObject<z.ZodRawShape>;
5228
+ call(input: unknown): Promise<ProjectedToolResult>;
5229
+ }
5230
+ interface ProjectBrowserToolsOptions {
5231
+ /** The provider that launched `instance` (its manifest capabilities gate the tools). */
5232
+ provider: ProjectedProvider;
5233
+ /** Passed to `instance.attach()` on the first tool call. */
5234
+ attach?: BrowserAttachOptions;
5235
+ /**
5236
+ * Writes bytes to a path on the host and returns the resolved path. Needed
5237
+ * only for `path` on `browser_screenshot` and `browser_get_dom`; without it
5238
+ * those calls fail with a clear message instead of writing anywhere.
5239
+ */
5240
+ writeArtifact?: (path: string, bytes: Buffer) => string;
5241
+ }
5242
+ interface ProjectedBrowserTools {
5243
+ tools: readonly ProjectedBrowserTool[];
5244
+ /** Register every projected tool on an MCP server. */
5245
+ register(server: McpServer): void;
5246
+ /** Close the lazily attached driver, if any. Safe to call twice. */
5247
+ close(): Promise<void>;
5248
+ }
5249
+ declare function projectBrowserTools(instance: BrowserInstance, opts: ProjectBrowserToolsOptions): ProjectedBrowserTools;
5394
5250
 
5395
5251
  /**
5396
5252
  * AIP-36 `sandbox attach` — Phase 1: CONNECT to an already-existing sandbox
@@ -5759,6 +5615,288 @@ interface SandboxReconcileResult {
5759
5615
  */
5760
5616
  declare function reconcileSandboxLedger(deps: SandboxReconcileDeps): Promise<SandboxReconcileResult>;
5761
5617
 
5618
+ /**
5619
+ * Host-level load report - answers "why is this machine on its knees" without
5620
+ * a hand-run `top` / `vm_stat` / `iostat` / `ps` / `lsof` session.
5621
+ *
5622
+ * One collector (`createHostLoadService`) gathers, in parallel and each under
5623
+ * a hard timeout so the whole call stays inside a small budget even at load
5624
+ * 500:
5625
+ *
5626
+ * - load average vs core count, CPU user/sys/idle
5627
+ * - RAM used / wired / compressor / cached / free, swap used
5628
+ * - per-disk transfers/s and MB/s
5629
+ * - the process table, attributed to sessions with the same rules as
5630
+ * `session_stats` (`process-stats.ts`), plus per-process memory footprint
5631
+ * including compressed pages where the OS exposes it
5632
+ * - listening TCP ports and (for a handful of suspects) the cwd, to spot
5633
+ * deleted-cwd loops and duplicate dev servers
5634
+ *
5635
+ * and turns them into WARNINGS: swap pressure, reparented (ppid 1) leftovers
5636
+ * that are old and busy or serving, deleted-cwd processes, filesystem-wide
5637
+ * scans, several servers on one port, load far above the core count.
5638
+ *
5639
+ * macOS shells out to `vm_stat`, `sysctl vm.swapusage`, `iostat`, `top`, `ps`,
5640
+ * `lsof`; Linux reads `/proc` (+ `ps`, `ss`). Nothing needs sudo. A probe that
5641
+ * is missing, denied or too slow is skipped and named in `partial` - the rest
5642
+ * of the report still ships. The collector is exported (`getHostLoadService`,
5643
+ * `createHostLoadService`) so a scheduler can gate heavy jobs on it.
5644
+ */
5645
+
5646
+ type HostLoadDetail = "summary" | "full";
5647
+ interface HostLoadCpu {
5648
+ userPercent: number;
5649
+ sysPercent: number;
5650
+ idlePercent: number;
5651
+ source: "iostat" | "top" | "proc-stat";
5652
+ }
5653
+ interface HostLoadMemory {
5654
+ totalBytes: number;
5655
+ /** App + wired + compressed (Activity Monitor's "Memory Used"). Absent when
5656
+ * the platform gives no such split. */
5657
+ usedBytes?: number;
5658
+ wiredBytes?: number;
5659
+ /** Bytes physically occupied by the compressor (macOS). */
5660
+ compressorBytes?: number;
5661
+ /** File cache + purgeable pages. */
5662
+ cachedBytes?: number;
5663
+ /** Never-touched pages only. */
5664
+ freeBytes: number;
5665
+ /** Free + reclaimable: what a new job can actually get without swapping. */
5666
+ availableBytes: number;
5667
+ }
5668
+ interface HostLoadSwap {
5669
+ totalBytes: number;
5670
+ usedBytes: number;
5671
+ freeBytes: number;
5672
+ percent: number;
5673
+ }
5674
+ interface DiskLoad {
5675
+ name: string;
5676
+ /** Transfers per second over the sampling interval. */
5677
+ tps: number;
5678
+ mbPerSec: number;
5679
+ /** Average KB per transfer, when the OS reports it. */
5680
+ kbPerTransfer?: number;
5681
+ }
5682
+ type HostProcessOwner = {
5683
+ kind: "session";
5684
+ sessionId: string;
5685
+ label?: string;
5686
+ detached?: boolean;
5687
+ } | {
5688
+ kind: "daemon";
5689
+ } | {
5690
+ kind: "provisioning";
5691
+ }
5692
+ /** Reparented to init by a session that is gone (or never was one). */
5693
+ | {
5694
+ kind: "orphan";
5695
+ sessionHint?: string;
5696
+ }
5697
+ /** OS services and installed apps. */
5698
+ | {
5699
+ kind: "system";
5700
+ }
5701
+ /** Anything else: the operator's own shells, editors, other users. */
5702
+ | {
5703
+ kind: "other";
5704
+ };
5705
+ interface HostProcess {
5706
+ pid: number;
5707
+ ppid: number;
5708
+ uid: number;
5709
+ /** Normalized name (`pnpm install`, `vitest`, `node`, ...). */
5710
+ command: string;
5711
+ /** Raw command line, truncated. */
5712
+ args: string;
5713
+ rssBytes: number;
5714
+ /** Footprint including compressed pages when measured, else RSS. */
5715
+ memoryBytes: number;
5716
+ memorySource: "footprint" | "rss";
5717
+ /** Bytes of this process the OS has compressed / swapped out. */
5718
+ compressedBytes?: number;
5719
+ cpuPercent: number;
5720
+ elapsedSec: number;
5721
+ owner: HostProcessOwner;
5722
+ /** TCP ports it listens on. */
5723
+ listening?: number[];
5724
+ /** Its cwd was deleted out from under it. */
5725
+ cwdDeleted?: boolean;
5726
+ }
5727
+ type HostWarningKind = "swap" | "load" | "orphan" | "deleted-cwd" | "fs-scan" | "duplicate-port";
5728
+ interface HostWarning {
5729
+ kind: HostWarningKind;
5730
+ severity: "warn" | "critical";
5731
+ message: string;
5732
+ pids?: number[];
5733
+ }
5734
+ interface HostSessionRollup {
5735
+ sessionId: string;
5736
+ label?: string;
5737
+ rssBytes: number;
5738
+ memoryBytes: number;
5739
+ cpuPercent: number;
5740
+ procCount: number;
5741
+ }
5742
+ interface HostLoadReport {
5743
+ sampledAt: string;
5744
+ detail: HostLoadDetail;
5745
+ /** Wall time the collection took. */
5746
+ elapsedMs: number;
5747
+ /** Probes that failed, timed out or were skipped; the rest is still valid. */
5748
+ partial: string[];
5749
+ platform: NodeJS.Platform;
5750
+ loadAvg: [number, number, number];
5751
+ cpuCount: number;
5752
+ /** 1-minute load divided by core count. */
5753
+ loadPerCore: number;
5754
+ cpu?: HostLoadCpu;
5755
+ memory: HostLoadMemory;
5756
+ swap?: HostLoadSwap;
5757
+ disks: DiskLoad[];
5758
+ topByCpu: HostProcess[];
5759
+ topByMemory: HostProcess[];
5760
+ warnings: HostWarning[];
5761
+ /** `detail: "full"` only. */
5762
+ sessions?: HostSessionRollup[];
5763
+ /** `detail: "full"` only: every process, largest memory first. */
5764
+ processes?: HostProcess[];
5765
+ /** Subtree-scoped caller: only its own sessions' processes are listed. */
5766
+ scoped?: true;
5767
+ }
5768
+ /** Per-process memory from `top -l 1 -stats pid,mem,cmprs`: `mem` is the
5769
+ * resident part, `cmprs` the compressed part; footprint is their sum. */
5770
+ interface Footprint {
5771
+ memoryBytes: number;
5772
+ compressedBytes: number;
5773
+ }
5774
+ interface HostLoadThresholds {
5775
+ swapWarnPercent: number;
5776
+ swapCriticalPercent: number;
5777
+ /** Reparented processes younger than this are not flagged. */
5778
+ orphanMinAgeSec: number;
5779
+ orphanCpuPercent: number;
5780
+ /** 1-minute load / cores above which the host is flagged. */
5781
+ loadPerCoreLimit: number;
5782
+ }
5783
+ declare const DEFAULT_HOST_LOAD_THRESHOLDS: HostLoadThresholds;
5784
+ declare function describeOwner(o: HostProcessOwner): string;
5785
+ interface HostWarningInput {
5786
+ loadAvg: readonly [number, number, number];
5787
+ cpuCount: number;
5788
+ swap?: HostLoadSwap;
5789
+ processes: readonly HostProcess[];
5790
+ homeDir: string;
5791
+ thresholds?: Partial<HostLoadThresholds>;
5792
+ }
5793
+ declare function computeHostWarnings(input: HostWarningInput): HostWarning[];
5794
+ /** Raw inputs of a Linux CPU/disk sample: two reads of `/proc/stat` and
5795
+ * `/proc/diskstats`. */
5796
+ interface LinuxCpuDiskSample {
5797
+ statBefore: string;
5798
+ statAfter: string;
5799
+ diskBefore: string;
5800
+ diskAfter: string;
5801
+ intervalSec: number;
5802
+ }
5803
+ interface CwdInfo {
5804
+ path: string;
5805
+ deleted: boolean;
5806
+ }
5807
+ /** Every external read the collector performs. Each takes the time (ms) it may
5808
+ * spend; a probe that is not applicable on the platform is left undefined. */
5809
+ interface HostProbes {
5810
+ platform: NodeJS.Platform;
5811
+ table: (timeoutMs: number) => Promise<ProcRow[]>;
5812
+ vmStat?: (timeoutMs: number) => Promise<string>;
5813
+ swapUsage?: (timeoutMs: number) => Promise<string>;
5814
+ iostat?: (timeoutMs: number) => Promise<string>;
5815
+ top?: (timeoutMs: number) => Promise<string>;
5816
+ meminfo?: (timeoutMs: number) => Promise<string>;
5817
+ cpuDisk?: (timeoutMs: number) => Promise<LinuxCpuDiskSample>;
5818
+ listeners?: (timeoutMs: number) => Promise<string>;
5819
+ cwds?: (pids: readonly number[], timeoutMs: number) => Promise<Map<number, CwdInfo>>;
5820
+ smaps?: (pids: readonly number[], timeoutMs: number) => Promise<Map<number, Footprint>>;
5821
+ envHints?: (pids: readonly number[], timeoutMs: number) => Promise<Map<number, string>>;
5822
+ /** Pids of the child processes the probes themselves spawned, so they are
5823
+ * not billed as host load. */
5824
+ ownPids?: () => ReadonlySet<number>;
5825
+ loadAvg?: () => [number, number, number];
5826
+ cpuCount?: () => number;
5827
+ totalMem?: () => number;
5828
+ }
5829
+ declare function createDefaultHostProbes(): HostProbes;
5830
+ interface HostSample {
5831
+ at: number;
5832
+ budgetMs: number;
5833
+ elapsedMs: number;
5834
+ partial: string[];
5835
+ platform: NodeJS.Platform;
5836
+ loadAvg: [number, number, number];
5837
+ cpuCount: number;
5838
+ cpu?: HostLoadCpu;
5839
+ memory: HostLoadMemory;
5840
+ swap?: HostLoadSwap;
5841
+ disks: DiskLoad[];
5842
+ table: ProcRow[];
5843
+ footprints: Map<number, Footprint>;
5844
+ listeners: Map<number, number[]>;
5845
+ cwds: Map<number, CwdInfo>;
5846
+ envHints: Map<number, string>;
5847
+ }
5848
+ declare const DEFAULT_HOST_LOAD_BUDGET_MS = 1900;
5849
+ /**
5850
+ * Run every probe under the budget and fold the results into one sample. A
5851
+ * failed probe is recorded in `partial` and its section left empty.
5852
+ */
5853
+ declare function collectHostSample(probes: HostProbes, sessions: readonly StatsSessionDescriptor[], opts?: {
5854
+ budgetMs?: number;
5855
+ now?: () => number;
5856
+ uid?: number;
5857
+ daemonPid?: number;
5858
+ }): Promise<HostSample>;
5859
+ interface BuildHostLoadOptions {
5860
+ sessions: readonly StatsSessionDescriptor[];
5861
+ detail?: HostLoadDetail;
5862
+ daemonPid?: number;
5863
+ uid?: number;
5864
+ homeDir?: string;
5865
+ provisions?: readonly ProvisionInFlight[];
5866
+ /** Restrict to these sessions' processes (subtree-scoped MCP caller). */
5867
+ visible?: ReadonlySet<string>;
5868
+ thresholds?: Partial<HostLoadThresholds>;
5869
+ topN?: number;
5870
+ }
5871
+ /** Fold a sample plus the session registry into the report. Pure. */
5872
+ declare function buildHostLoadReport(sample: HostSample, opts: BuildHostLoadOptions): HostLoadReport;
5873
+ interface HostLoadServiceOptions {
5874
+ probes?: HostProbes;
5875
+ tracker?: ProvisionTracker;
5876
+ daemonPid?: number;
5877
+ uid?: number;
5878
+ homeDir?: string;
5879
+ /** How long a sample is reused. Default 2000 ms. */
5880
+ ttlMs?: number;
5881
+ /** Default per-call budget. */
5882
+ budgetMs?: number;
5883
+ now?: () => number;
5884
+ }
5885
+ interface HostLoadService {
5886
+ report(sessions: readonly StatsSessionDescriptor[], opts?: {
5887
+ detail?: HostLoadDetail;
5888
+ fresh?: boolean;
5889
+ budgetMs?: number;
5890
+ visible?: ReadonlySet<string>;
5891
+ thresholds?: Partial<HostLoadThresholds>;
5892
+ }): Promise<HostLoadReport>;
5893
+ }
5894
+ declare function createHostLoadService(opts?: HostLoadServiceOptions): HostLoadService;
5895
+ /** Process-wide collector shared by MCP, HTTP and in-process callers (a job
5896
+ * scheduler gating on `report.loadPerCore` / `report.warnings`), so one probe
5897
+ * round serves them all within the TTL. */
5898
+ declare function getHostLoadService(): HostLoadService;
5899
+
5762
5900
  /**
5763
5901
  * Idle agent-session reaper (PR-6).
5764
5902
  *
@@ -6124,9 +6262,10 @@ declare function rollupSessionSubtree(root: SessionDescriptor, all: readonly Ses
6124
6262
  /**
6125
6263
  * Dependency-injection surface for MCP credential resolution.
6126
6264
  *
6127
- * `packages/runtime` intentionally does NOT depend on `@agentproto/auth`;
6128
- * the daemon bootstrap (e.g. `packages/cli`) can set a broker-backed
6129
- * resolver here, and `session-spawn.ts` will call it when an `mcpServers`
6265
+ * `packages/runtime` does depend on `@agentproto/auth` (e.g. `KeychainStore`
6266
+ * in `session-spawn.ts`), but credential resolution is still injected here
6267
+ * so non-darwin / test stores stay pluggable. The daemon bootstrap (e.g.
6268
+ * `packages/cli`) can set a broker-backed resolver here, and `session-spawn.ts` will call it when an `mcpServers`
6130
6269
  * entry carries `credentialRef`. Errors from the hook are treated as
6131
6270
  * non-fatal by the caller.
6132
6271
  */
@@ -6149,6 +6288,12 @@ interface McpCredentialDeps {
6149
6288
  * bare `process.env` read at the call site. Returns null when the slug
6150
6289
  * can't be resolved (missing/unconfigured). */
6151
6290
  resolveSandboxSecret?: (slug: string) => Promise<string | null>;
6291
+ /** Read an imported-MCP secret by opaque ref
6292
+ * (`agentproto/mcp-import/<importId>#<header|env>:<KEY>`, split on the last
6293
+ * `#` into keychain path + account). Undefined when the ref is missing. */
6294
+ resolveMcpSecret?: (ref: string) => Promise<string | undefined>;
6295
+ /** Persist an imported-MCP secret under `ref`. */
6296
+ storeMcpSecret?: (ref: string, value: string) => Promise<void>;
6152
6297
  }
6153
6298
  declare function setMcpCredentialDeps(d: McpCredentialDeps): void;
6154
6299
  declare function getMcpCredentialDeps(): McpCredentialDeps;
@@ -6233,8 +6378,11 @@ declare function readUsageSnapshots(sessionId: string, baseDir?: string): Promis
6233
6378
  * "trusted `?callerSessionId=`" pattern `message-tools.ts` uses — so a
6234
6379
  * session watching its own PR doesn't need to know its own id.
6235
6380
  *
6236
- * Provider auto-select isn't implemented yet (design §6): `provider`
6237
- * defaults to `local-gh`, the only built-in that ships as of this step.
6381
+ * Provider auto-select (design §5, `sentinel-provider-select.ts`): with no
6382
+ * explicit `provider`, `agentpush` when it is set up, else `webhook` when a
6383
+ * STABLE public URL exists and it is ready, else `local-gh`. An explicit
6384
+ * `provider` is never second-guessed (and never silently falls back — a
6385
+ * not-ready `webhook` fails `create` with its setup error).
6238
6386
  *
6239
6387
  * `createSentinelWatch`/`cancelSentinelWatch`/`sentinelView` are exported so
6240
6388
  * `http-server.ts`'s `POST/GET/DELETE /sentinels` routes (the daemon-HTTP
@@ -6328,9 +6476,9 @@ interface Device {
6328
6476
  createdAt: string;
6329
6477
  lastSeen: string;
6330
6478
  /** A channel (offer or reconnect) is served for this device right now
6331
- * (client) or a `forwardHttp` call is in flight for it right now (host).
6332
- * For a host this is NOT a live heartbeat — see host-registry.ts's
6333
- * "Online tracking" — it only reflects actual recent/current traffic. */
6479
+ * (client), or for a host: a forward/snapshot is in flight or one reached
6480
+ * it within the online grace window (a background poll keeps that fresh
6481
+ * for joined hosts) — see host-registry.ts's "Online tracking". */
6334
6482
  online: boolean;
6335
6483
  /** A pair/v1 pairing: listed and revocable, but can't connect until
6336
6484
  * re-paired — see `PairingRecord.legacy`. */
@@ -6346,10 +6494,26 @@ interface Device {
6346
6494
  provider?: string;
6347
6495
  sandboxId?: string;
6348
6496
  labels?: Record<string, string>;
6497
+ /** Host only: when this daemon last tried to reach it, and why the most
6498
+ * recent attempt failed (absent when the last attempt succeeded). */
6499
+ lastProbeAt?: string;
6500
+ lastError?: string;
6501
+ /** Host only: a join-added (CI) host that is gone — said goodbye or was
6502
+ * unreachable past the TTL. Hidden from `list()` unless `includeEnded`. */
6503
+ ended?: true;
6504
+ endedAt?: string;
6505
+ /** Host only: a manually added host unreachable past the TTL. Still listed,
6506
+ * never auto-deleted. */
6507
+ stale?: true;
6508
+ }
6509
+ interface ListDevicesOptions {
6510
+ /** Include ended (gone) join-added hosts, which `list()` hides by default. */
6511
+ includeEnded?: boolean;
6349
6512
  }
6350
6513
  interface DeviceRegistry {
6351
- /** Every known device. Read-only. */
6352
- list(): Promise<Device[]>;
6514
+ /** Every known device, minus ended join-added hosts unless
6515
+ * `includeEnded`. Read-only. */
6516
+ list(opts?: ListDevicesOptions): Promise<Device[]>;
6353
6517
  /** Rename a device (fingerprint or current name) to a new label. Tries the
6354
6518
  * pairing registry first, then the host registry. Returns false when
6355
6519
  * nothing matched. */
@@ -6411,37 +6575,6 @@ interface RegisterDeviceToolsOptions {
6411
6575
  }
6412
6576
  declare function registerDeviceTools(server: McpServer, opts: RegisterDeviceToolsOptions): void;
6413
6577
 
6414
- /**
6415
- * Rate-limited failure logging for reconnect loops.
6416
- *
6417
- * A standing reconnect loop (the outbound tunnel, a pairing rendezvous) whose
6418
- * peer is permanently gone re-dials on backoff forever. Logging every single
6419
- * failure buries the daemon log — a single dead pairing produced ~85% of one
6420
- * 2.9MB never-rotated `~/.agentproto/daemon.log`, and the tunnel reconnect
6421
- * spam another chunk. This gate logs the FIRST failure per key immediately,
6422
- * then at most one line per `windowMs`, and when it does emit again it carries
6423
- * the count of failures it swallowed in between. A successful connect resets
6424
- * the key so the next outage logs promptly again.
6425
- *
6426
- * Deliberately dependency-free: a per-key `{ lastLoggedAt, suppressed }` map.
6427
- * `now` is injectable so tests can advance the clock without real timers. This
6428
- * only changes logging cadence — reconnect timing/backoff is untouched.
6429
- */
6430
- interface ReconnectLogGate {
6431
- /**
6432
- * Record a failure for `key`. Returns the line to log now — the given
6433
- * `message`, with a `(N failures suppressed)` suffix when repeats were
6434
- * swallowed since the last emit — or `null` to stay quiet this time.
6435
- */
6436
- onFailure(key: string, message: string): string | null;
6437
- /** Reset suppression for `key` after a successful connect. */
6438
- onSuccess(key: string): void;
6439
- }
6440
- declare function createReconnectLogGate(opts?: {
6441
- windowMs?: number;
6442
- now?: () => number;
6443
- }): ReconnectLogGate;
6444
-
6445
6578
  /**
6446
6579
  * Provider-preset family on top of `@agentproto/provider-kit` — the *thin,
6447
6580
  * honest* lister (Option B). Unlike tunnels/sandboxes/eval-reporters, presets
@@ -7798,4 +7931,4 @@ interface GatewayHandle {
7798
7931
  */
7799
7932
  declare function createGateway(opts: CreateGatewayOptions): Promise<GatewayHandle>;
7800
7933
 
7801
- export { ActivityListFilter, type ActivityPolicyLister, type ActivityProjector, type ActivityProjectorRegistry, type ActivityProjectorSession, ActivityRecord, type ActivityWorkflowLister, AdapterAuthDescriptor, type AdapterCapabilitiesLister, type AdapterInstallResult, type AdapterListEntry, type AgentAdapterInstaller, type AgentAdapterLister, type AgentAdapterResolver, AgentSessionLike, AgentStreamEvent, type AttachSandboxOpts, type AttachSandboxResult, 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, CONTINUE_PROMPT_SOURCE, CanonicalPosture, type CapabilitiesInventory, type CapabilitiesInventoryMcp, type CapabilitiesInventorySkills, type CatalogModelsLister, CatalogModelsQuery, CatalogModelsResponse, type CatalogProviderModel, type CatalogProviderModelsQuery, type CatalogProviderModelsResponse, type CatalogProviderPricing, type ClaudeNativeRef, CompletionPolicySupervisor, type ComposeCandidate, ContextProfile, type ContinueInterruptedMode, type ContinueInterruptedOutcome, type ContinueInterruptedResult, type ContinueInterruptedSkipReason, type ContinueOnBootSummary, type ConversationIndexRecord, type ConversationNativeRef, type CostBudgetDecision, type CrashDetectSummary, type CrashReaperRegistry, type CreateGatewayOptions, type CreateJoinTokenInput, type CreateOfferInput, type CreateReviewRunnerOptions, type CreatedJoinToken, type CreatedOffer, DEAD_SESSION_STATUSES, DEFAULT_ALWAYS_ON_TOOLS, DEFAULT_BUCKET, DEFAULT_CONTINUE_PROMPT, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_WORKTREE_ISOLATION, type DaemonReviewerHostDeps, DeclaredAdapterOption, type DeclaredAdapterPreset, DefaultsAdapterAuthConfig, type Device, type DeviceKind, type DeviceRegistry, type DeviceRole, type EagerResumeSummary, type EnableInput, type EnableResult, type FindComposeCandidateInput, type ForwardHttpRequest, type ForwardHttpResponse, GC_REAPABLE_STATES, type GatewayHandle, type GhRunner, HOSTS_VERSION, HOST_SCOPE_HEADER, type HarnessPreset, type HarnessPresetValidationDeps, HarnessPresetValidationError, type HarnessPresetsFile, type HermesNativeRef, type HostJoinMeta, type HostRecord, type HostRegistry, type HostRegistryDeps, 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, JOIN_TOKENS_VERSION, type JoinTokenRecord, type JoinTokenRegistry, type JoinTokenRegistryDeps, LEGACY_SESSIONS_FILE, type LedgerAnnotations, type LedgerEntry, type LedgerHostMeta, type LlmEndpointDescriptor, type LlmEndpointStatus, type LlmEndpointStatusReport, type LocatedConversation, type LocatedConversationByPath, MAX_AUTO_CONTINUE_ATTEMPTS, MCP_APP_BRIDGE_SCRIPT, type McpCredentialDeps, type MeasurableTool, type MeasuredToolEntry, MessageKind, MessageUrgency, type MigrationMarker, type NormalizeInboundResult, 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, PolicyRunState, Posture, type PostureResolution, PrLookupError, type PrLookupErrorCode, PrResolvedState, type PrStateResolver, type PrStatusSnapshot, type PresetInfo, QuotaReadableProfile, type ReconnectLogGate, type RegisterBrainToolsOptions, type RegisterDeviceToolsOptions, type RegisterPairingToolsOptions, type RegisterReviewToolsOptions, type RegisterWebSearchToolsOptions, RemainingQuotaReader, type RemoteStatus, type ResolveNativeLinkInput, ResolvedAuthSpec, type ReuseResolution, type ReviewComposeContext, type ReviewLedger, type ReviewLedgerFilter, type ReviewRun, type ReviewRunInput, type ReviewRunStatus, type ReviewRunner, type ReviewSignature, type ReviewSigningKey, type ReviewerRunResult, type ReviewerSessionHost, type RouteAwareLaunchConfig, type RouteAwareLaunchConfigInput, RouteSpec, type RuntimeMeta, SIGN_NAMESPACE, 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, type SentinelMatchClause, type SentinelSpec, type SentinelStatus, type SentinelTarget, type SentinelUntil, type SentinelView, SessionDescriptor, SessionEndReason, SessionMessage, type SessionMessageSentRecord, type SessionObserver, SessionUsage, type SessionUsageWithSubtree, type SessionWaitEvent, type SessionWaitResult, SessionsRegistry, type SkillPackInventoryEntry, type SkillsByHarnessEntry, SpawnDefaultsConfig, type StallWatchdogRegistry, type StallWatchdogSummary, type SubtreeChildUsage, type SubtreeUsageTotals, TaskLedger, type ToolListMeasurement, type TransmitterBinding, type TransmitterBindingStore, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, UsageReadContext, UsageReadResult, UsageRollup, UsageSnapshotRecord, UserPreset, type VerifySignedAttestationResult, 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, addHarnessPreset, allowedSignersLine, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogProviderModels, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, claudeProjectSlug, collectGcCandidates, composeSessionObservers, composedFromRangeSha, continueInterruptedSessions, continueSkipReason, conversationIndexPath, createActivityProjector, createDaemonReviewerHost, createDeviceRegistry, createFileStepCache, createGateway, createHostRegistry, createInboundEndpointStore, createJoinTokenRegistry, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createPrProvenanceReconciler, createReconnectLogGate, createReviewLaneExecutor, createReviewLedger, createReviewPackLoader, createReviewRunner, createScopeTokenRegistry, createWorkspaceBrainSubscriber, createWorkspaceBrains, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, defaultReviewKeysDir, defaultReviewLedgerRoot, defaultReviewPackCacheDir, defineBraveSearchHttpDriver, defineSerperHttpDriver, enrichRollupWithProviderQuota, enrichWithRemainingQuota, ensureReviewSigningKey, evaluateCostBudget, execGh, extractHelpSection, fetchPrStatus, fileExists, findComposeCandidate, findConversationRecord, findNativeMode, findPrForCommit, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getMcpCredentialDeps, getToolHelp, githubRepoOf, harnessPresetsPath, hostPlaceholders, injectMcpAppBridge, isAgentCliAuthConfigured, isSafeBucketSlug, listBuckets, listHarnessPresets, listPresets, listToolHelpTopics, loadHarnessPresets, loadWorktreeIsolation, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeSandboxCredsStore, makeSandboxResolver, measureTool, measureToolList, migrateLegacySessionsFile, migrationMarkerPath, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeInbound, normalizeModeId, normalizeRemote, normalizeWorktreeField, parsePrUrl, parseWorktreeIsolationMode, prHeadSha, readConversationIndex, readDaemonRegistry, readPairingsSnapshot, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, readUsageSnapshots, reapGcEntry, reapOrphanedDescendants, reconcileSandboxLedger, recordSandboxBoot, recordSandboxLiveness, recordSandboxOrigin, recordSandboxState, registerBrainTools, registerBuiltinRoutes, registerDeviceTools, registerPairingTools, registerReviewTools, registerSandboxAttachTool, registerWebSearchTools, removeHarnessPreset, removeSandboxLedgerEntry, repoSlug, resolveBucketSlug, resolveEffectiveLlmEndpointFlag, resolveNativeLink, resolvePosture, resolvePrincipal, resolveReuseFromLedger, resolveReviewerPreset, rollupSessionSubtree, runContinueOnBootPass, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runShellLane, runStallWatchdogPass, sandboxLedgerPath, setDefaultPreset, setMcpCredentialDeps, signAttestation, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, toWorktreeStatusView, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, updateHarnessPreset, upsertSandboxLedger, verifyInboundSignature, verifySignedAttestation, webSearchTool, withPr, withPrStatus, writeDaemonRegistryEntry };
7934
+ export { ActivityListFilter, type ActivityPolicyLister, type ActivityProjector, type ActivityProjectorRegistry, type ActivityProjectorSession, ActivityRecord, type ActivityWorkflowLister, AdapterAuthDescriptor, type AdapterCapabilitiesLister, type AdapterInstallResult, type AdapterListEntry, type AgentAdapterInstaller, type AgentAdapterLister, type AgentAdapterResolver, AgentSessionLike, AgentStreamEvent, type AttachSandboxOpts, type AttachSandboxResult, 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, CONTINUE_PROMPT_SOURCE, CanonicalPosture, type CapabilitiesInventory, type CapabilitiesInventoryMcp, type CapabilitiesInventorySkills, type CatalogModelsLister, CatalogModelsQuery, CatalogModelsResponse, type CatalogProviderModel, type CatalogProviderModelsQuery, type CatalogProviderModelsResponse, type CatalogProviderPricing, type ClaudeNativeRef, CompletionPolicySupervisor, type ComposeCandidate, ContextProfile, type ContinueInterruptedMode, type ContinueInterruptedOutcome, type ContinueInterruptedResult, type ContinueInterruptedSkipReason, type ContinueOnBootSummary, type ConversationIndexRecord, type ConversationNativeRef, type CostBudgetDecision, type CrashDetectSummary, type CrashReaperRegistry, type CreateGatewayOptions, type CreateJoinTokenInput, type CreateReviewRunnerOptions, type CreatedJoinToken, DEAD_SESSION_STATUSES, DEFAULT_ALWAYS_ON_TOOLS, DEFAULT_BUCKET, DEFAULT_CONTINUE_PROMPT, DEFAULT_HOST_LOAD_BUDGET_MS, DEFAULT_HOST_LOAD_THRESHOLDS, DEFAULT_ORCHESTRATOR_TOOLS, type DaemonReviewerHostDeps, DeclaredAdapterOption, type DeclaredAdapterPreset, DefaultsAdapterAuthConfig, type Device, type DeviceKind, type DeviceRegistry, type DeviceRole, type DiskLoad, type EagerResumeSummary, type EnableInput, type EnableResult, type FindComposeCandidateInput, type ForwardHttpRequest, type ForwardHttpResponse, GC_REAPABLE_STATES, type GatewayHandle, type GhRunner, HOSTS_VERSION, HOST_SCOPE_HEADER, type HarnessPreset, type HarnessPresetValidationDeps, HarnessPresetValidationError, type HarnessPresetsFile, type HermesNativeRef, type HostJoinMeta, type HostLoadCpu, type HostLoadDetail, type HostLoadMemory, type HostLoadReport, type HostLoadService, type HostLoadSwap, type HostLoadThresholds, type HostProbes, type HostProcess, type HostProcessOwner, type HostRecord, type HostRegistry, type HostRegistryDeps, type HostSessionRollup, type HostWarning, type HostWarningKind, 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, JOIN_TOKENS_VERSION, type JoinTokenRecord, type JoinTokenRegistry, type JoinTokenRegistryDeps, LEGACY_SESSIONS_FILE, type LedgerAnnotations, type LedgerEntry, type LedgerHostMeta, type LlmEndpointDescriptor, type LlmEndpointStatus, type LlmEndpointStatusReport, type LocatedConversation, type LocatedConversationByPath, MAX_AUTO_CONTINUE_ATTEMPTS, MCP_APP_BRIDGE_SCRIPT, type McpCredentialDeps, type MeasurableTool, type MeasuredToolEntry, MessageKind, MessageUrgency, type MigrationMarker, type ModelRolesInput, type ModelRolesOutput, type NormalizeInboundResult, type OpenPrResolver, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type OrphanReaperRegistry, POSTURE_NATIVE_ALIASES, POSTURE_PREAMBLES, PolicyRunState, Posture, type PostureResolution, PrLookupError, type PrLookupErrorCode, PrResolvedState, type PrStateResolver, type PrStatusSnapshot, type PresetInfo, type ProjectBrowserToolsOptions, type ProjectedBrowserTool, type ProjectedBrowserTools, type ProjectedProvider, type ProjectedToolResult, ProvisionInFlight, QuotaReadableProfile, type RegisterBrainToolsOptions, type RegisterDeviceToolsOptions, type RegisterPairingToolsOptions, type RegisterReviewToolsOptions, type RegisterWebSearchToolsOptions, RemainingQuotaReader, type RemoteStatus, type ResolveNativeLinkInput, ResolvedAuthSpec, ResolvedModelRole, type ReuseResolution, type ReviewComposeContext, type ReviewLedger, type ReviewLedgerFilter, type ReviewRun, type ReviewRunInput, type ReviewRunStatus, type ReviewRunner, type ReviewSignature, type ReviewSigningKey, type ReviewerRunResult, type ReviewerSessionHost, type RouteAwareLaunchConfig, type RouteAwareLaunchConfigInput, RouteSpec, type RuntimeMeta, SIGN_NAMESPACE, 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, type SentinelMatchClause, type SentinelSpec, type SentinelStatus, type SentinelTarget, type SentinelUntil, type SentinelView, SessionDescriptor, SessionEndReason, SessionMessage, type SessionMessageSentRecord, type SessionObserver, SessionUsage, type SessionUsageWithSubtree, type SessionWaitEvent, type SessionWaitResult, SessionsRegistry, type SkillPackInventoryEntry, type SkillsByHarnessEntry, SpawnDefaultsConfig, type StallWatchdogRegistry, type StallWatchdogSummary, type SubtreeChildUsage, type SubtreeUsageTotals, TaskLedger, type ToolListMeasurement, type TransmitterBinding, type TransmitterBindingStore, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, UsageReadContext, UsageReadResult, UsageRollup, UsageSnapshotRecord, UserPreset, type VerifySignedAttestationResult, type WatcherDescriptor, type WatcherStartInput, type WebSearchInput, type WebSearchOutput, type WebSearchResult, type WorkspaceBrainSubscriber, type WorkspaceBrainSubscriberOptions, type WorkspaceBrains, WorkspaceFs, WorktreeAutoReclaimer, WorktreeField, type WorktreeGcClass, type WorktreeGcOutcomeView, type WorktreeGcPlanEntryView, type WorktreeGcReclaimReason, type WorktreeGcResult, type WorktreeGcRunInput, type WorktreeGcRunner, WorktreeIsolationMode, WorktreeProvisioner, type WorktreeStatusLister, type WorktreeStatusView, addHarnessPreset, allowedSignersLine, appendConversationRecord, attachSandbox, bucketDir, bucketSessionsFile, bucketTranscriptDir, buildCatalogProviderModels, buildHostLoadReport, buildMcpConfigSnippet, buildRouteAwareLaunchConfig, canonicalForModeId, claudeProjectSlug, collectGcCandidates, collectHostSample, composeSessionObservers, composedFromRangeSha, computeHostWarnings, continueInterruptedSessions, continueSkipReason, conversationIndexPath, createActivityProjector, createDaemonReviewerHost, createDefaultHostProbes, createDeviceRegistry, createFileStepCache, createGateway, createHostLoadService, createHostRegistry, createInboundEndpointStore, createJoinTokenRegistry, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPrProvenanceReconciler, createReviewLaneExecutor, createReviewLedger, createReviewPackLoader, createReviewRunner, createScopeTokenRegistry, createWorkspaceBrainSubscriber, createWorkspaceBrains, daemonRegistryDir, declaredPresetToProviderPreset, defaultBrowserAdapterIds, defaultBrowserAdapterResolution, defaultReviewKeysDir, defaultReviewLedgerRoot, defaultReviewPackCacheDir, defineBraveSearchHttpDriver, defineSerperHttpDriver, describeOwner, enrichRollupWithProviderQuota, enrichWithRemainingQuota, ensureReviewSigningKey, evaluateCostBudget, execGh, extractHelpSection, fetchPrStatus, fileExists, findComposeCandidate, findConversationRecord, findNativeMode, findPrForCommit, formatToolCall, formatToolResult, getDefaultHarnessPreset, getHarnessPreset, getHostLoadService, getMcpCredentialDeps, getToolHelp, githubRepoOf, harnessPresetsPath, hostPlaceholders, injectMcpAppBridge, isAgentCliAuthConfigured, isSafeBucketSlug, listBuckets, listHarnessPresets, listPresets, listToolHelpTopics, loadHarnessPresets, loadWorkspaceModelRoles, locateConversationByNativePath, locateConversationBySessionId, makeBrowserAdapterLister, makeSandboxCredsStore, makeSandboxResolver, measureTool, measureToolList, migrateLegacySessionsFile, migrationMarkerPath, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeInbound, normalizeModeId, normalizeRemote, parsePrUrl, prHeadSha, projectBrowserTools, readConversationIndex, readDaemonRegistry, readRegisteredSlugs, readRuntimeMeta, readSandboxLedger, readSessionForBrain, readUsageSnapshots, reapGcEntry, reapOrphanedDescendants, reconcileSandboxLedger, recordSandboxBoot, recordSandboxLiveness, recordSandboxOrigin, recordSandboxState, registerBrainTools, registerBuiltinRoutes, registerDeviceTools, registerPairingTools, registerReviewTools, registerSandboxAttachTool, registerWebSearchTools, removeHarnessPreset, removeSandboxLedgerEntry, repoSlug, resolveBucketSlug, resolveEffectiveLlmEndpointFlag, resolveNativeLink, resolvePosture, resolvePrincipal, resolveReuseFromLedger, resolveReviewerPreset, rollupSessionSubtree, runContinueOnBootPass, runCrashDetectPass, runEagerResumePass, runIdleReapPass, runShellLane, runStallWatchdogPass, sandboxLedgerPath, setDefaultPreset, setMcpCredentialDeps, signAttestation, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, toWorktreeStatusView, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, updateHarnessPreset, upsertSandboxLedger, verifyInboundSignature, verifySignedAttestation, webSearchTool, withPr, withPrStatus, writeDaemonRegistryEntry };