@agentproto/runtime 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/config-BRKy_SAF.d.ts +569 -0
- package/dist/config.d.ts +1 -272
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +399 -3
- package/dist/index.mjs +7437 -6477
- package/dist/index.mjs.map +1 -1
- package/dist/resume-strategies.mjs +868 -42
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/workspaces-config.d.ts +11 -1
- package/dist/workspaces-config.mjs +22 -2
- package/dist/workspaces-config.mjs.map +1 -1
- package/package.json +9 -9
- package/dist/spawn-defaults-DAbADRd4.d.ts +0 -256
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { B as BuildHeartbeatAgent } from './heartbeat-COGpMrJS.js';
|
|
|
3
3
|
export { H as HeartbeatAgent, a as HeartbeatRunner, R as RuntimeEvent, b as RuntimeEvents, p as parseDuration } from './heartbeat-COGpMrJS.js';
|
|
4
4
|
import { AcpPermissionResolution, AcpMcpServer } from '@agentproto/acp';
|
|
5
5
|
import { ChildProcess } from 'node:child_process';
|
|
6
|
-
import { R as ResolvedAuthSpec, D as DeclaredAdapterOption, A as AdapterAuthDescriptor } from './
|
|
7
|
-
export { a as AuthEcho, b as AuthResolutionError, C as CredentialSource, c as DefaultsAdapterAuthConfig, d as DefaultsAdapterConfig, e as ResolvedSpawnAuthMaterial, f as ResolvedSpawnDefaults, S as SpawnDefaultsConfig, g as credentialFingerprint, n as normalizeSkillsOption, r as resolveAuthSpec, h as resolveSpawnDefaults } from './
|
|
6
|
+
import { W as WorktreeIsolationMode, R as ResolvedAuthSpec, D as DeclaredAdapterOption, A as AdapterAuthDescriptor } from './config-BRKy_SAF.js';
|
|
7
|
+
export { a as AuthEcho, b as AuthResolutionError, C as CredentialSource, c as DefaultsAdapterAuthConfig, d as DefaultsAdapterConfig, e as ResolvedSpawnAuthMaterial, f as ResolvedSpawnDefaults, S as SpawnDefaultsConfig, g as credentialFingerprint, n as normalizeSkillsOption, r as resolveAuthSpec, h as resolveSpawnDefaults } from './config-BRKy_SAF.js';
|
|
8
8
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
9
|
import { AdapterHandle, SetupField, AdapterResolver, AdapterLister, AdapterEntry } from '@agentproto/provider-kit';
|
|
10
10
|
import { SandboxProvider } from '@agentproto/sandbox';
|
|
@@ -495,6 +495,23 @@ interface SessionDescriptor {
|
|
|
495
495
|
* the daemon's. Lets the UI show "crashed with the daemon" instead of a
|
|
496
496
|
* bare "killed" that reads as deliberate. */
|
|
497
497
|
endedReason?: "daemon-restart";
|
|
498
|
+
/** Whether a turn was actually in flight the INSTANT `status` flipped to
|
|
499
|
+
* "killed" — captured before anything else runs, because `busy` itself
|
|
500
|
+
* cannot be trusted after the fact: `runAgentTurn`'s `finally` is what
|
|
501
|
+
* clears `busy`, and that `finally` never fires for a generator that's
|
|
502
|
+
* never resumed (a killed child mid-tool-call, or a dead daemon), so a
|
|
503
|
+
* post-hoc read of `busy` on a killed session may just be showing you
|
|
504
|
+
* whatever it froze at. This field exists because `status: "killed"`
|
|
505
|
+
* alone can't tell a human's Stop mid-turn apart from a supervisor
|
|
506
|
+
* reaping a child that had already finished — both leave `exitCode:
|
|
507
|
+
* null`, and `turnsCompleted` alone is too weak (a session killed
|
|
508
|
+
* mid-SECOND-turn also has `turnsCompleted: 1`). `killedMidTurn: true`
|
|
509
|
+
* paired with any `turnsCompleted` means interrupted; `false`/absent
|
|
510
|
+
* alongside `turnsCompleted > 0` means the work was done before the
|
|
511
|
+
* kill — see activityFor in the vscode package for the read. Set by
|
|
512
|
+
* `kill()`, `shutdownImpl`'s force-kill, and `loadHistorySnapshot`'s
|
|
513
|
+
* wasAlive reclassification; absent for every other terminal path. */
|
|
514
|
+
killedMidTurn?: boolean;
|
|
498
515
|
/** Last time anything was written to stdout/stderr. Lets the UI
|
|
499
516
|
* spot stuck sessions ("running for 2h, last output 12min ago"). */
|
|
500
517
|
lastOutputAt?: string;
|
|
@@ -514,6 +531,10 @@ interface SessionDescriptor {
|
|
|
514
531
|
/** Free-text label the spawner can attach (e.g. conversation id,
|
|
515
532
|
* operator name) so the UI can group/filter. */
|
|
516
533
|
label?: string;
|
|
534
|
+
/** Derived from the session's FIRST prompt — what this conversation is
|
|
535
|
+
* about, for a UI that would otherwise show the adapter's argv. Distinct
|
|
536
|
+
* from `label`, which the spawner supplies and which always wins. */
|
|
537
|
+
title?: string;
|
|
517
538
|
/** True when the session was spawned under a real PTY (node-pty)
|
|
518
539
|
* instead of `child_process.spawn`. PTY sessions carry raw ANSI
|
|
519
540
|
* bytes (alt-screen, key bindings, colors); attach goes through
|
|
@@ -529,6 +550,25 @@ interface SessionDescriptor {
|
|
|
529
550
|
argv?: readonly string[];
|
|
530
551
|
/** Working directory the session was spawned in. Cloned by restart. */
|
|
531
552
|
cwd?: string;
|
|
553
|
+
/** Root of the git worktree the session was spawned in — the session→
|
|
554
|
+
* worktree edge, resolved from `cwd` at spawn time
|
|
555
|
+
* (`resolveWorktreeIdentity`). Distinct from `cwd`, which may be a
|
|
556
|
+
* subdirectory of it. Absent when `cwd` isn't inside a linked worktree (a
|
|
557
|
+
* plain checkout, a non-repo dir) and for every session persisted before
|
|
558
|
+
* this field existed.
|
|
559
|
+
*
|
|
560
|
+
* Recorded rather than computed at read time because it can't be
|
|
561
|
+
* recovered later: a worktree removed after the session ran leaves nothing
|
|
562
|
+
* on disk to re-resolve. */
|
|
563
|
+
worktreePath?: string;
|
|
564
|
+
/** Generation id of that worktree, read at spawn from the provision marker
|
|
565
|
+
* (`agentproto-worktree.json` in the worktree's private gitdir, written by
|
|
566
|
+
* `worktree.provision`). Absent whenever `worktreePath` is, and also for a
|
|
567
|
+
* worktree created by a bare `git worktree add` — nothing writes a marker
|
|
568
|
+
* there. The marker is what distinguishes generations, so a
|
|
569
|
+
* `worktreePath` without an id identifies a PATH, which a later worktree
|
|
570
|
+
* may reuse; the pair identifies one specific worktree. */
|
|
571
|
+
worktreeId?: string;
|
|
532
572
|
/** Adapter slug for agent-cli sessions — restart uses this with
|
|
533
573
|
* `/sessions/agent` to spin up a fresh ACP runtime. Undefined for
|
|
534
574
|
* pty/command kinds. */
|
|
@@ -818,6 +858,22 @@ interface SessionsRegistry {
|
|
|
818
858
|
enqueuePrompt(id: string, message: unknown, opts?: {
|
|
819
859
|
interrupt?: boolean;
|
|
820
860
|
}): Promise<void>;
|
|
861
|
+
/** Cancel the in-flight turn on a live agent-cli session and leave the
|
|
862
|
+
* session itself alive and idle — the bare "interrupt, no next prompt"
|
|
863
|
+
* primitive `sendPrompt`/`enqueuePrompt`'s `opts.interrupt` arm lacks
|
|
864
|
+
* on its own, since that arm always exists to redirect onto a NEW
|
|
865
|
+
* prompt. Reuses the same `interruptInFlightTurn` helper those two
|
|
866
|
+
* share.
|
|
867
|
+
*
|
|
868
|
+
* Idempotent by design: idle, unknown-alive (starting/running only —
|
|
869
|
+
* same liveness `validateAgentTurn` checks), or already-terminal
|
|
870
|
+
* (exited/killed/error) all resolve `{ wasBusy: false }` rather than
|
|
871
|
+
* throwing — a no-op interrupt is not an error. Throws only when the
|
|
872
|
+
* id is unknown, or when `cancel()` itself rejects ("does not support
|
|
873
|
+
* interrupt", propagated from `interruptInFlightTurn`). */
|
|
874
|
+
interruptSession(id: string): Promise<{
|
|
875
|
+
wasBusy: boolean;
|
|
876
|
+
}>;
|
|
821
877
|
/** Stamp `lastActivityAt` on a live agent-cli session's descriptor
|
|
822
878
|
* and schedule a debounced persist. Called from the `onActivity`
|
|
823
879
|
* callback threaded down through the driver → ACP client, which
|
|
@@ -1789,6 +1845,19 @@ interface PolicyRunState {
|
|
|
1789
1845
|
nextPolicyId?: string;
|
|
1790
1846
|
error?: string;
|
|
1791
1847
|
}
|
|
1848
|
+
/**
|
|
1849
|
+
* Does `policy` watch `sessionId`? True when the id is the representative
|
|
1850
|
+
* `sessionId` or appears anywhere in the fan-in `sessionIds` group — the two
|
|
1851
|
+
* ways `AttachPolicyInput` can name a session.
|
|
1852
|
+
*
|
|
1853
|
+
* This is the reverse of the policy→session link, and it is deliberately
|
|
1854
|
+
* computed on demand over `list()` rather than persisted: a session→policy
|
|
1855
|
+
* index in policies.json (or a `policies` field on the session record) would
|
|
1856
|
+
* be a second source of truth to keep in sync across attach, fan-in nudges,
|
|
1857
|
+
* `next` chaining, and snapshot reload. A filtered pass is O(policies) on a
|
|
1858
|
+
* set the daemon already holds in memory.
|
|
1859
|
+
*/
|
|
1860
|
+
declare function policyWatchesSession(policy: PolicyRunState, sessionId: string): boolean;
|
|
1792
1861
|
interface CompletionPolicySupervisor {
|
|
1793
1862
|
/**
|
|
1794
1863
|
* Attach a completion policy to an already-running session.
|
|
@@ -2153,6 +2222,127 @@ type SandboxProviderResolver = AdapterResolver<SandboxProviderHandle>;
|
|
|
2153
2222
|
/** List every sandbox provider with its live status + capabilities. */
|
|
2154
2223
|
type SandboxProviderLister = AdapterLister<SandboxAdapterInfo>;
|
|
2155
2224
|
|
|
2225
|
+
/**
|
|
2226
|
+
* Policy layer for `agent_start.worktree` — the config-driven decision of
|
|
2227
|
+
* WHETHER to isolate a spawn into its own git worktree, kept deliberately
|
|
2228
|
+
* separate from HOW one is provisioned.
|
|
2229
|
+
*
|
|
2230
|
+
* This module holds no dependency on `@agentproto/worktree`. Same reasoning
|
|
2231
|
+
* as `worktree-identity.ts`'s docblock, only stronger: provisioning runs the
|
|
2232
|
+
* `worktree.provision` TOOL (git + the base tree's `agentproto.json` setup
|
|
2233
|
+
* hooks), which would drag the driver/harness/provider graph into
|
|
2234
|
+
* `@agentproto/runtime` for a capability the runtime only ever *triggers*.
|
|
2235
|
+
* So the concrete provisioner is an INJECTED PORT ({@link WorktreeProvisioner})
|
|
2236
|
+
* wired at the composition root by a host that already depends on the
|
|
2237
|
+
* worktree package (the CLI). The runtime owns only the pure decision
|
|
2238
|
+
* ({@link decideWorktreeIsolation}) and the config/env resolution
|
|
2239
|
+
* ({@link loadWorktreeIsolation}) — both trivially unit-testable without git.
|
|
2240
|
+
*
|
|
2241
|
+
* Mirrors `agent_start.sandbox`'s `resolveSandboxProvider` injection shape,
|
|
2242
|
+
* except sandbox can default its resolver inside the runtime (the runtime
|
|
2243
|
+
* depends on `@agentproto/sandbox`); worktree cannot, so an unwired daemon
|
|
2244
|
+
* simply has no provisioner and a spawn that would need one fails loud rather
|
|
2245
|
+
* than silently spawning unisolated.
|
|
2246
|
+
*/
|
|
2247
|
+
|
|
2248
|
+
/** Env override for the isolation policy. Highest-priority source, ahead of
|
|
2249
|
+
* the `worktrees.isolation` config field — see `loadWorktreeIsolation`. */
|
|
2250
|
+
declare const WORKTREE_ISOLATION_ENV = "AGENTPROTO_WORKTREES_ISOLATION";
|
|
2251
|
+
/** The default when nothing is configured. Back-compat-preserving: a caller
|
|
2252
|
+
* that passes no `worktree` field spawns exactly where it asked. */
|
|
2253
|
+
declare const DEFAULT_WORKTREE_ISOLATION: WorktreeIsolationMode;
|
|
2254
|
+
/**
|
|
2255
|
+
* The `agent_start.worktree` field. `true` isolates with an auto-minted slug;
|
|
2256
|
+
* an object additionally pins the slug and/or base ref; `false` (or omitted)
|
|
2257
|
+
* is "no explicit request" — the policy mode decides.
|
|
2258
|
+
*/
|
|
2259
|
+
type WorktreeField = boolean | {
|
|
2260
|
+
slug?: string;
|
|
2261
|
+
base?: string;
|
|
2262
|
+
};
|
|
2263
|
+
/** The caller's explicit request, normalized — `undefined` when the field is
|
|
2264
|
+
* absent or `false`, otherwise the (possibly empty) slug/base overrides. */
|
|
2265
|
+
interface WorktreeRequest {
|
|
2266
|
+
slug?: string;
|
|
2267
|
+
base?: string;
|
|
2268
|
+
}
|
|
2269
|
+
/** What the runtime hands the provisioner. `cwd` is where the session would
|
|
2270
|
+
* otherwise spawn; the provisioner resolves the owning repo from it. */
|
|
2271
|
+
interface WorktreeProvisionRequest {
|
|
2272
|
+
cwd: string;
|
|
2273
|
+
/** Explicit slug from the caller; omitted ⇒ the provisioner mints a
|
|
2274
|
+
* collision-free one (see the host implementation). */
|
|
2275
|
+
slug?: string;
|
|
2276
|
+
/** Base ref the worktree branch is cut from; omitted ⇒ the provisioner's
|
|
2277
|
+
* default (`origin/main`). */
|
|
2278
|
+
base?: string;
|
|
2279
|
+
/** Free-text label (the session's `label`) the provisioner may fold into a
|
|
2280
|
+
* minted slug for human readability. Never load-bearing for correctness. */
|
|
2281
|
+
labelHint?: string;
|
|
2282
|
+
}
|
|
2283
|
+
/** The provisioner's outcome. `isolated: false` is NOT a failure — it means
|
|
2284
|
+
* there was nothing to isolate (`cwd` sits in no git repo), and the caller
|
|
2285
|
+
* should spawn plain at the original cwd. A genuine failure throws. */
|
|
2286
|
+
type WorktreeProvisionOutcome = {
|
|
2287
|
+
isolated: true;
|
|
2288
|
+
cwd: string;
|
|
2289
|
+
branch: string;
|
|
2290
|
+
} | {
|
|
2291
|
+
isolated: false;
|
|
2292
|
+
reason: "not-a-git-repo";
|
|
2293
|
+
};
|
|
2294
|
+
/**
|
|
2295
|
+
* Injected port: provision a git worktree for `req.cwd` and return the
|
|
2296
|
+
* worktree's own cwd for the spawn to land in. Wired at the composition root
|
|
2297
|
+
* by the CLI (over `@agentproto/worktree`); absent on a bare runtime.
|
|
2298
|
+
*/
|
|
2299
|
+
type WorktreeProvisioner = (req: WorktreeProvisionRequest) => Promise<WorktreeProvisionOutcome>;
|
|
2300
|
+
/** The pure decision's three outcomes. */
|
|
2301
|
+
type WorktreeDecision = {
|
|
2302
|
+
action: "spawn-in-place";
|
|
2303
|
+
} | {
|
|
2304
|
+
action: "provision";
|
|
2305
|
+
request: WorktreeRequest;
|
|
2306
|
+
} | {
|
|
2307
|
+
action: "reject";
|
|
2308
|
+
message: string;
|
|
2309
|
+
};
|
|
2310
|
+
/**
|
|
2311
|
+
* Normalize the raw field into an explicit request, or `undefined` when the
|
|
2312
|
+
* caller made no request (`false` / omitted). An object with no overrides
|
|
2313
|
+
* still counts as a request (`{}`) — the caller opted in, just without pins.
|
|
2314
|
+
*/
|
|
2315
|
+
declare function normalizeWorktreeField(field: WorktreeField | undefined): WorktreeRequest | undefined;
|
|
2316
|
+
/**
|
|
2317
|
+
* The resolution matrix — mode × explicit-request × depth — with no side
|
|
2318
|
+
* effects. Every branch is exercised in `worktree-isolation.test.ts`.
|
|
2319
|
+
*
|
|
2320
|
+
* Depth-0 gate: a nested spawn (`depth > 0`, i.e. made through the scoped
|
|
2321
|
+
* orchestrator sub-gateway) NEVER provisions — it inherits its parent's
|
|
2322
|
+
* ground, per AIP-46 §Delegation. This bites before the mode is even
|
|
2323
|
+
* consulted, so `always` too provisions only at the root and an explicit
|
|
2324
|
+
* request from a nested spawn is a silent no-op (spawn-in-place), not a
|
|
2325
|
+
* reject: the child is meant to share the parent's tree.
|
|
2326
|
+
*/
|
|
2327
|
+
declare function decideWorktreeIsolation(input: {
|
|
2328
|
+
mode: WorktreeIsolationMode;
|
|
2329
|
+
field: WorktreeField | undefined;
|
|
2330
|
+
depth: number;
|
|
2331
|
+
}): WorktreeDecision;
|
|
2332
|
+
/** Parse a raw string into a valid mode, or `undefined` when it isn't one. */
|
|
2333
|
+
declare function parseWorktreeIsolationMode(raw: string | undefined): WorktreeIsolationMode | undefined;
|
|
2334
|
+
/**
|
|
2335
|
+
* Resolve the effective isolation mode: env > config field > default. Mirrors
|
|
2336
|
+
* `resolveWorktreesRoot`'s precedence (there's no flag layer — this is read
|
|
2337
|
+
* daemon-side at spawn, not from an invocation). Never throws: an unreadable
|
|
2338
|
+
* config falls through to the default.
|
|
2339
|
+
*/
|
|
2340
|
+
declare function loadWorktreeIsolation(loadCfg?: () => Promise<{
|
|
2341
|
+
worktrees?: {
|
|
2342
|
+
isolation?: WorktreeIsolationMode;
|
|
2343
|
+
};
|
|
2344
|
+
}>): Promise<WorktreeIsolationMode>;
|
|
2345
|
+
|
|
2156
2346
|
/**
|
|
2157
2347
|
* Pluggable adapter resolver — keeps the runtime package free of any
|
|
2158
2348
|
* @agentproto/cli dep. The host (cli `serve`, playground, embedding
|
|
@@ -2566,6 +2756,158 @@ declare function declaredPresetToProviderPreset(decl: DeclaredAdapterPreset): Pr
|
|
|
2566
2756
|
*/
|
|
2567
2757
|
declare function listPresets(env?: Record<string, string | undefined>, adapterPresets?: readonly DeclaredAdapterPreset[]): AdapterEntry<PresetInfo>[];
|
|
2568
2758
|
|
|
2759
|
+
/**
|
|
2760
|
+
* Per-workspace state buckets — AIP-46 §State partitioning.
|
|
2761
|
+
*
|
|
2762
|
+
* AIP-46's premise is "a single host serve many bound directories", and
|
|
2763
|
+
* §Workspaces delivered the addressing half of it: a slug resolves to a
|
|
2764
|
+
* path. The state those directories generate stayed pooled in one global
|
|
2765
|
+
* `~/.agentproto/sessions.json` with `workspaceSlug` demoted to a column
|
|
2766
|
+
* on each row — a label, not a boundary.
|
|
2767
|
+
*
|
|
2768
|
+
* What that costs is measurable rather than theoretical. `HISTORY_CAP`
|
|
2769
|
+
* bounds retention across the *union* of every workspace, so the cap is
|
|
2770
|
+
* spent by whoever was busiest. A store pooling a few hundred rows from
|
|
2771
|
+
* several workspaces sits at that ceiling in ordinary use, and the
|
|
2772
|
+
* workspace contributing a handful of them is one busy afternoon in a
|
|
2773
|
+
* NEIGHBOUR away from losing all of them — having done nothing itself.
|
|
2774
|
+
* The eviction is silent and lands on the quietest workspace.
|
|
2775
|
+
*
|
|
2776
|
+
* This module is the slug→bucket rule and nothing more:
|
|
2777
|
+
*
|
|
2778
|
+
* ~/.agentproto/
|
|
2779
|
+
* ├── workspaces.json # the registry (workspaces-config.ts)
|
|
2780
|
+
* └── workspaces/ # one bucket per workspace (here)
|
|
2781
|
+
* ├── agentik-studio/sessions.json
|
|
2782
|
+
* └── default/sessions.json
|
|
2783
|
+
*
|
|
2784
|
+
* The registry (a file) and the state (a directory) are deliberate
|
|
2785
|
+
* siblings: one names the workspaces, the other holds what each
|
|
2786
|
+
* accumulated.
|
|
2787
|
+
*
|
|
2788
|
+
* ## Membership is the validation
|
|
2789
|
+
*
|
|
2790
|
+
* `workspaceSlug` arrives on a spawn request — it is caller input
|
|
2791
|
+
* (`session-spawn.ts` passes `input.workspaceSlug` straight through when
|
|
2792
|
+
* an explicit `cwd` accompanies it, so nothing sanitises it on the way
|
|
2793
|
+
* to the descriptor). A bucket is a directory name. Joining the two
|
|
2794
|
+
* without a check hands the caller `../../` under the daemon's own state
|
|
2795
|
+
* root, as the daemon's UID.
|
|
2796
|
+
*
|
|
2797
|
+
* So a slug does not become a directory name by being cleaned up — it
|
|
2798
|
+
* becomes one by coming *back from* the registry lookup. The registry's
|
|
2799
|
+
* slugs were sanitised by `sanitizeSlug` on the way in, so the only
|
|
2800
|
+
* strings that ever reach the filesystem are ones the host itself
|
|
2801
|
+
* minted. An unregistered slug isn't rejected or escaped; it fails to
|
|
2802
|
+
* match and lands in `default` like any other unregistered work. This is
|
|
2803
|
+
* why the rule is membership rather than sanitisation: you cannot forget
|
|
2804
|
+
* to validate a value you never chose.
|
|
2805
|
+
*
|
|
2806
|
+
* ## What this does NOT buy
|
|
2807
|
+
*
|
|
2808
|
+
* Partitioning bounds what a workspace's state *costs* other workspaces.
|
|
2809
|
+
* It does not bound who may read it — every bucket is still served to
|
|
2810
|
+
* every authorised caller, because no workspace-scoped credential
|
|
2811
|
+
* exists to serve them differently (pairings carry no workspace concept
|
|
2812
|
+
* at all; the orchestrator scope-token's `session_list` is daemon-wide
|
|
2813
|
+
* by documented debt, `orchestrator-gateway.ts`). The files moved; the
|
|
2814
|
+
* access did not. AIP-46 §Security Considerations says this in the
|
|
2815
|
+
* negative — do not read this module as an isolation control.
|
|
2816
|
+
*/
|
|
2817
|
+
/** The bucket every record lands in when its slug doesn't resolve —
|
|
2818
|
+
* absent, empty, or naming a workspace that isn't registered.
|
|
2819
|
+
*
|
|
2820
|
+
* A real bucket, not an error state. Refusing to persist an
|
|
2821
|
+
* unregistered session would make this a breaking change for every
|
|
2822
|
+
* one-off `cwd` spawn, and the obvious workaround (auto-register)
|
|
2823
|
+
* turns a registry of the user's intent into a registry of everything
|
|
2824
|
+
* that ever ran. The cost is stated plainly in the AIP: `default`'s
|
|
2825
|
+
* occupants get no separation from *each other* — registering a
|
|
2826
|
+
* workspace is what buys that. */
|
|
2827
|
+
declare const DEFAULT_BUCKET = "default";
|
|
2828
|
+
/** Root of the per-workspace state buckets. Sibling of the
|
|
2829
|
+
* `workspaces.json` registry that names them. */
|
|
2830
|
+
declare const BUCKETS_ROOT: () => string;
|
|
2831
|
+
/** The pre-partition global snapshot. Still read (to migrate from) and
|
|
2832
|
+
* never written after the split — see `migrateLegacySessionsFile`. */
|
|
2833
|
+
declare const LEGACY_SESSIONS_FILE: () => string;
|
|
2834
|
+
/** Marker recording that the legacy split already ran. Its presence —
|
|
2835
|
+
* not the legacy file's absence — is what makes migration
|
|
2836
|
+
* once-and-only-once, so a user who deletes rows from a bucket doesn't
|
|
2837
|
+
* get them resurrected on the next boot. */
|
|
2838
|
+
declare const migrationMarkerPath: (root: string) => string;
|
|
2839
|
+
declare const bucketDir: (root: string, slug: string) => string;
|
|
2840
|
+
declare const bucketSessionsFile: (root: string, slug: string) => string;
|
|
2841
|
+
/** Per-bucket transcript directory (AIP-46 §Layout).
|
|
2842
|
+
*
|
|
2843
|
+
* Not yet wired: the registry still writes transcripts to the shared
|
|
2844
|
+
* `~/.agentproto/sessions/`. Moving them needs the read side to move
|
|
2845
|
+
* too, and several readers currently ignore the configured base dir
|
|
2846
|
+
* entirely (`http-server.ts` and `transcript-export.ts` call
|
|
2847
|
+
* `sessionEventsPath(id)` with no `baseDir`, so they resolve off
|
|
2848
|
+
* `homedir()` regardless) — a pre-existing bug that a partial move
|
|
2849
|
+
* would turn into missing transcripts. Exported so the follow-up has
|
|
2850
|
+
* the path rule in one place. The AIP makes transcripts a SHOULD, not
|
|
2851
|
+
* a MUST, for exactly this reason. */
|
|
2852
|
+
declare const bucketTranscriptDir: (root: string, slug: string) => string;
|
|
2853
|
+
declare const isSafeBucketSlug: (slug: string) => boolean;
|
|
2854
|
+
/**
|
|
2855
|
+
* The slug→bucket rule (AIP-46 §Bucket resolution).
|
|
2856
|
+
*
|
|
2857
|
+
* 1. non-empty AND registered → that workspace's bucket
|
|
2858
|
+
* 2. otherwise → `default`
|
|
2859
|
+
*
|
|
2860
|
+
* `registered` must come from the workspaces registry. Passing a set
|
|
2861
|
+
* built from caller input defeats the entire point of this function.
|
|
2862
|
+
*/
|
|
2863
|
+
declare function resolveBucketSlug(workspaceSlug: string | undefined | null, registered: ReadonlySet<string>): string;
|
|
2864
|
+
/** Registered slugs, read fresh. Cheap (the registry is <1KB) and read
|
|
2865
|
+
* per persist rather than cached at boot, so a workspace registered
|
|
2866
|
+
* while the daemon is up starts bucketing immediately instead of
|
|
2867
|
+
* silently pooling into `default` until restart. Never throws: a
|
|
2868
|
+
* missing/corrupt registry degrades to "nothing is registered", i.e.
|
|
2869
|
+
* everything lands in `default` — today's pooled behaviour, which is
|
|
2870
|
+
* the right failure direction. */
|
|
2871
|
+
declare function readRegisteredSlugs(configPath?: string): ReadonlySet<string>;
|
|
2872
|
+
/** Bucket directories that exist on disk. Order is not meaningful. */
|
|
2873
|
+
declare function listBuckets(root: string): string[];
|
|
2874
|
+
interface MigrationMarker {
|
|
2875
|
+
version: 1;
|
|
2876
|
+
migratedAt: string;
|
|
2877
|
+
/** Absolute path of the legacy artifact this split read from. Left
|
|
2878
|
+
* untouched on disk — recorded so the provenance survives. */
|
|
2879
|
+
from: string;
|
|
2880
|
+
/** Total records read out of the legacy artifact. */
|
|
2881
|
+
rows: number;
|
|
2882
|
+
/** Records landed, per bucket. Sums to `rows` — the migration never
|
|
2883
|
+
* drops a record it cannot place; it sends it to `default`. */
|
|
2884
|
+
byBucket: Record<string, number>;
|
|
2885
|
+
}
|
|
2886
|
+
/**
|
|
2887
|
+
* Split the legacy global snapshot into buckets (AIP-46 §Migration).
|
|
2888
|
+
*
|
|
2889
|
+
* **Additive by mandate.** The legacy file is opened read-only and left
|
|
2890
|
+
* exactly where it is — never deleted, truncated, or rewritten. It is
|
|
2891
|
+
* the user's data and their only rollback; the buckets are a derivative
|
|
2892
|
+
* until they decide otherwise. Reclaiming it is a separate, human-gated
|
|
2893
|
+
* call, and this module deliberately ships no GC: a real store is backed
|
|
2894
|
+
* by a transcript directory that can reach hundreds of megabytes and may
|
|
2895
|
+
* be someone's only copy of months of work — a deleter that guesses
|
|
2896
|
+
* wrong there is unrecoverable.
|
|
2897
|
+
*
|
|
2898
|
+
* Idempotent via the marker, not via the legacy file's absence — the
|
|
2899
|
+
* file stays, so absence would never fire and every boot would re-import
|
|
2900
|
+
* rows the user had since deleted from a bucket.
|
|
2901
|
+
*
|
|
2902
|
+
* Returns the marker it wrote, or `null` when there was nothing to do
|
|
2903
|
+
* (already migrated, or no legacy file).
|
|
2904
|
+
*/
|
|
2905
|
+
declare function migrateLegacySessionsFile(opts: {
|
|
2906
|
+
root: string;
|
|
2907
|
+
legacyFile: string;
|
|
2908
|
+
registered: ReadonlySet<string>;
|
|
2909
|
+
}): MigrationMarker | null;
|
|
2910
|
+
|
|
2569
2911
|
/** A journal-file StepCache scoped to one cacheKey. Best-effort: read/parse
|
|
2570
2912
|
* failures degrade to "no cache" (a miss), never throw into the run. */
|
|
2571
2913
|
declare function createFileStepCache(cacheKey: string, opts?: {
|
|
@@ -2690,6 +3032,26 @@ declare function readRuntimeMeta(workspace: string): Promise<{
|
|
|
2690
3032
|
*/
|
|
2691
3033
|
declare function sweepStaleRuntimeMetas(workspaces: readonly string[], currentWorkspace: string): Promise<string[]>;
|
|
2692
3034
|
|
|
3035
|
+
/**
|
|
3036
|
+
* Read-only probe: does a credential actually RESOLVE for an adapter slug's
|
|
3037
|
+
* billing auth? Used by `adapter_list` to report an HONEST status instead of
|
|
3038
|
+
* claiming "ready" on a host with zero credentials for an adapter that hard-
|
|
3039
|
+
* fails every spawn (claude-code, `authEnforce: "always"`).
|
|
3040
|
+
*
|
|
3041
|
+
* THE TRAP (see the money regression test in `__tests__/auth-probe.test.ts`):
|
|
3042
|
+
* a probe that answers "is auth configured?" by checking `providers.json`
|
|
3043
|
+
* alone would report `true` for a spawn that still throws
|
|
3044
|
+
* `missing_auth_credential` — the store lookup at `session-spawn.ts:612-617`
|
|
3045
|
+
* is gated on `explicit` (PR #321: an unconfigured `always`-enforcing adapter
|
|
3046
|
+
* must never pick up a leftover store key and bill org credits instead of the
|
|
3047
|
+
* Max subscription). So this mirrors `session-spawn.ts`'s resolution exactly
|
|
3048
|
+
* — same `resolveSpawnDefaults` + `resolveAuthSpec`, same explicit gate on
|
|
3049
|
+
* the store lookup — rather than reimplementing the precedence: a second
|
|
3050
|
+
* copy of this logic WILL drift, and the drift is denominated in money.
|
|
3051
|
+
*/
|
|
3052
|
+
|
|
3053
|
+
declare function isAgentCliAuthConfigured(slug: string, descriptor: AdapterAuthDescriptor, model?: string): Promise<boolean>;
|
|
3054
|
+
|
|
2693
3055
|
/**
|
|
2694
3056
|
* MCP tools for event-driven orchestration:
|
|
2695
3057
|
* - session_events_poll — cheap cursor-based snapshot of session events
|
|
@@ -2844,6 +3206,30 @@ interface CreateGatewayOptions {
|
|
|
2844
3206
|
* tool family, and the `/sessions/:id/pty` WebSocket. Without it,
|
|
2845
3207
|
* those routes return 501 / the MCP tools aren't registered. */
|
|
2846
3208
|
spawnPty?: PtyFactory;
|
|
3209
|
+
/** Enable filesystem persistence for every store this gateway owns —
|
|
3210
|
+
* the sessions registry plus the supervisor / routine / cron / workflow
|
|
3211
|
+
* / inbound-watcher run stores. Defaults to `true`, i.e. production is
|
|
3212
|
+
* unchanged.
|
|
3213
|
+
*
|
|
3214
|
+
* Tests pass `false`. Without it, a test gateway writes its fake rows
|
|
3215
|
+
* into the *developer's real* `~/.agentproto/sessions.json` (and the
|
|
3216
|
+
* sibling `policies.json` / `routine-runs.json` / `cron-jobs.json` /
|
|
3217
|
+
* `workflow-runs.json`): those paths resolve off `homedir()`, and the
|
|
3218
|
+
* gateway opted each store into persistence unconditionally. Since
|
|
3219
|
+
* `loadHistorySnapshot` re-reads sessions.json at boot, the real daemon
|
|
3220
|
+
* then restores the fakes and shows them in the dashboard — and against
|
|
3221
|
+
* `HISTORY_CAP` (200) they evict genuine history.
|
|
3222
|
+
*
|
|
3223
|
+
* The sibling stores already default to persist-off when constructed
|
|
3224
|
+
* directly (see `createRoutineRunner`); this knob is what lets a
|
|
3225
|
+
* gateway stop overriding that on their behalf. */
|
|
3226
|
+
persist?: boolean;
|
|
3227
|
+
/** Override the sessions-registry persistence path — tests pin a tmpdir
|
|
3228
|
+
* so an assertion can look at the file the gateway would have written
|
|
3229
|
+
* instead of the developer's real one. Defaults to
|
|
3230
|
+
* `~/.agentproto/sessions.json`. The structured-transcript dir follows
|
|
3231
|
+
* this path's parent, so pinning it isolates transcripts too. */
|
|
3232
|
+
persistPath?: string;
|
|
2847
3233
|
/** Override the per-boot bearer token. Default: `randomUUID()`.
|
|
2848
3234
|
* Tests can pin a known value; production should always let
|
|
2849
3235
|
* the gateway generate fresh. The token is written into
|
|
@@ -2881,6 +3267,16 @@ interface CreateGatewayOptions {
|
|
|
2881
3267
|
/** Optional sandbox provider lister — mirrors `listAgentAdapters`.
|
|
2882
3268
|
* Overrides the default catalog-driven lister behind `list_sandbox_providers`. */
|
|
2883
3269
|
listSandboxProviders?: SandboxProviderLister;
|
|
3270
|
+
/**
|
|
3271
|
+
* Optional git-worktree provisioner powering `agent_start.worktree` and the
|
|
3272
|
+
* `worktrees.isolation` policy. Injected here (rather than defaulted inside
|
|
3273
|
+
* the runtime like `resolveSandboxProvider`) because provisioning runs the
|
|
3274
|
+
* `@agentproto/worktree` TOOL, a dependency the runtime deliberately does
|
|
3275
|
+
* NOT take — see `worktree-identity.ts` / `worktree-isolation.ts`. The CLI
|
|
3276
|
+
* wires it. Omitted → a spawn the policy says to isolate is rejected with
|
|
3277
|
+
* `worktree_provisioner_not_enabled` (never silently spawned unisolated).
|
|
3278
|
+
*/
|
|
3279
|
+
provisionWorktree?: WorktreeProvisioner;
|
|
2884
3280
|
/**
|
|
2885
3281
|
* Optional E2E pairing registry (see `createPairingRegistry`). When wired,
|
|
2886
3282
|
* the gateway mounts the `/pairings/*` REST routes and the `pair_*` MCP
|
|
@@ -2938,4 +3334,4 @@ interface GatewayHandle {
|
|
|
2938
3334
|
*/
|
|
2939
3335
|
declare function createGateway(opts: CreateGatewayOptions): Promise<GatewayHandle>;
|
|
2940
3336
|
|
|
2941
|
-
export { AdapterAuthDescriptor, type AdapterListEntry, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AttachPolicyInput, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, type CommitSpec, type CompletionPolicySupervisor, type CreateGatewayOptions, type CreateOfferInput, type CreatedOffer, DEFAULT_ORCHESTRATOR_TOOLS, DeclaredAdapterOption, type DeclaredAdapterPreset, type GateSpec, type GatewayHandle, type InboundWatcher, type JudgeGateSpec, type McpCredentialDeps, type OnFailSpec, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, PAIRINGS_VERSION, type PairingChannelContext, type PairingChannelHandle, type PairingChannelMode, type PairingRecord, type PairingRegistry, type PairingRegistryDeps, type PendingPermission, type PermissionRespondInput, type PermissionRespondResult, type PolicyRunState, type PolicyRunStatus, type PresetInfo, type PricingResolver, type RegisterBrowserInput, type RegisterPairingToolsOptions, type RegisterSessionInput, ResolvedAuthSpec, type RuntimeMeta, type SandboxAdapterInfo, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type ScopeTokenRegistry, type SessionDescriptor, type SessionKind, type SessionObserver, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, type SpawnSessionInput, type TokenPricing, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageComputeInput, type UsageSource, type WatcherDescriptor, type WatcherStartInput, WorkspaceFs, composeSessionObservers, createFileStepCache, createGateway, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createScopeTokenRegistry, daemonRegistryDir, declaredPresetToProviderPreset, deriveSessionUsage, formatToolCall, formatToolResult, getMcpCredentialDeps, listPresets, makeBrowserAdapterLister, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, projectSessionUsage, readDaemonRegistry, readRuntimeMeta, registerPairingTools, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, writeDaemonRegistryEntry };
|
|
3337
|
+
export { AdapterAuthDescriptor, type AdapterListEntry, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AttachPolicyInput, BUCKETS_ROOT, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, type CommitSpec, type CompletionPolicySupervisor, type CreateGatewayOptions, type CreateOfferInput, type CreatedOffer, DEFAULT_BUCKET, DEFAULT_ORCHESTRATOR_TOOLS, DEFAULT_WORKTREE_ISOLATION, DeclaredAdapterOption, type DeclaredAdapterPreset, type GateSpec, type GatewayHandle, type InboundWatcher, type JudgeGateSpec, LEGACY_SESSIONS_FILE, type McpCredentialDeps, type MigrationMarker, type OnFailSpec, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, PAIRINGS_VERSION, type PairingChannelContext, type PairingChannelHandle, type PairingChannelMode, type PairingRecord, type PairingRegistry, type PairingRegistryDeps, type PendingPermission, type PermissionRespondInput, type PermissionRespondResult, type PolicyRunState, type PolicyRunStatus, type PresetInfo, type PricingResolver, type RegisterBrowserInput, type RegisterPairingToolsOptions, type RegisterSessionInput, ResolvedAuthSpec, type RuntimeMeta, type SandboxAdapterInfo, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type ScopeTokenRegistry, type SessionDescriptor, type SessionKind, type SessionObserver, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, type SpawnSessionInput, type TokenPricing, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageComputeInput, type UsageSource, WORKTREE_ISOLATION_ENV, type WatcherDescriptor, type WatcherStartInput, WorkspaceFs, type WorktreeDecision, type WorktreeField, WorktreeIsolationMode, type WorktreeProvisionOutcome, type WorktreeProvisionRequest, type WorktreeProvisioner, type WorktreeRequest, bucketDir, bucketSessionsFile, bucketTranscriptDir, composeSessionObservers, createFileStepCache, createGateway, createOrchestratorInjector, createOrchestratorMcpServerFactory, createPairingRegistry, createScopeTokenRegistry, daemonRegistryDir, decideWorktreeIsolation, declaredPresetToProviderPreset, deriveSessionUsage, formatToolCall, formatToolResult, getMcpCredentialDeps, isAgentCliAuthConfigured, isSafeBucketSlug, listBuckets, listPresets, loadWorktreeIsolation, makeBrowserAdapterLister, migrateLegacySessionsFile, migrationMarkerPath, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, normalizeWorktreeField, parseWorktreeIsolationMode, policyWatchesSession, projectSessionUsage, readDaemonRegistry, readRegisteredSlugs, readRuntimeMeta, registerPairingTools, resolveBucketSlug, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, writeDaemonRegistryEntry };
|