@agentproto/driver-agent-cli 2.0.0 → 2.1.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/{chunk-LP542BMX.mjs → chunk-QL3CS6E4.mjs} +279 -134
- package/dist/chunk-QL3CS6E4.mjs.map +1 -0
- package/dist/index.d.ts +92 -7
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/manifest/index.d.ts +3 -2
- package/dist/manifest/index.mjs +2 -2
- package/dist/{schema-BqxySb_M.d.ts → schema-PGrcCZqt.d.ts} +152 -6
- package/package.json +4 -3
- package/dist/chunk-LP542BMX.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,82 @@
|
|
|
1
|
-
import { A as AgentCliHandle, a as AgentCliRuntime, b as AgentCliDefinition, c as
|
|
2
|
-
export { h as AgentCliAuth, i as AgentCliCapabilities, j as AgentCliConnectOptions, k as AgentCliContinuation, l as AgentCliFrontmatter, m as AgentCliInstallMethod, n as AgentCliMcpBlock, o as AgentCliMode, p as AgentCliModelEntry, q as AgentCliModels, r as AgentCliOption, s as AgentCliOptionType, t as AgentCliPinnedSessionTuning, u as AgentCliPresetDeclaration, v as AgentCliProtocol, w as
|
|
3
|
-
import {
|
|
4
|
-
import { AcpMcpServer, StreamEvent } from '@agentproto/acp';
|
|
1
|
+
import { A as AgentCliHandle, a as AgentCliRuntime, b as AgentCliDefinition, c as AgentCliRuntimeSession, d as AgentCliClient, S as SetModelResult, e as AgentCliPrintConfig, R as RuntimeConfig, C as ContinuationStrategyId, f as AgentCliStartOptions, T as TurnContext, g as ContinuationKeyScope } from './schema-PGrcCZqt.js';
|
|
2
|
+
export { h as AgentCliAuth, i as AgentCliCapabilities, j as AgentCliConnectOptions, k as AgentCliContinuation, l as AgentCliFrontmatter, m as AgentCliInstallMethod, n as AgentCliMcpBlock, o as AgentCliMode, p as AgentCliModelEntry, q as AgentCliModels, r as AgentCliOption, s as AgentCliOptionType, t as AgentCliPinnedSessionTuning, u as AgentCliPresetDeclaration, v as AgentCliProtocol, w as AgentCliRouteSelection, x as AgentCliSession, y as AgentCliSessionMode, z as AgentCliSetupPersist, B as AgentCliSetupSkipIf, D as AgentCliSetupStep, E as AgentCliVersionCheck, F as RuntimeConfigInput, G as SetEffortResult, H as SetSessionModeResult, I as agentCliFrontmatterSchema, J as runtimeConfigSchema } from './schema-PGrcCZqt.js';
|
|
3
|
+
import { StreamEvent, AcpMcpServer } from '@agentproto/acp';
|
|
5
4
|
export { StreamEvent } from '@agentproto/acp';
|
|
6
|
-
import '
|
|
5
|
+
import { ChildProcess } from 'node:child_process';
|
|
6
|
+
import { SandboxMode } from '@agentproto/command-sandbox';
|
|
7
|
+
export { SessionConfigOption, SessionMode } from '@agentproto/acp/client';
|
|
7
8
|
import 'zod';
|
|
8
9
|
|
|
9
10
|
declare const defineAgentCli: (def: AgentCliDefinition) => Readonly<AgentCliDefinition>;
|
|
10
11
|
declare function createAgentCliRuntime(definition: AgentCliHandle): AgentCliRuntime;
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Live-session control surface, built once from a connected protocol arm.
|
|
15
|
+
*
|
|
16
|
+
* `AgentCliRuntimeSession` requires six members beyond
|
|
17
|
+
* `send`/`cancel`/`close`: the three mid-session switches (`setModel`,
|
|
18
|
+
* `setSessionMode`, `setEffort`, SPEC §3.9/§3.4a) and the three
|
|
19
|
+
* read-surface snapshots (`availableConfigOptions`, `availableModes`,
|
|
20
|
+
* `currentModeId`). All six are pure delegation to the arm — none of
|
|
21
|
+
* them touch the child process, the spawn, or the transport.
|
|
22
|
+
*
|
|
23
|
+
* They used to live inline inside `createAgentCliRuntime`, which made
|
|
24
|
+
* them unreachable for any host that builds its OWN session over a
|
|
25
|
+
* different transport. Those hosts exist and are the whole point of
|
|
26
|
+
* `createAcpProtocolArm` being exported: guilde runs one runtime whose
|
|
27
|
+
* child lives in an e2b sandbox and another whose child lives on a
|
|
28
|
+
* remote daemon behind a WS tunnel, both driving the same ACP arm. Every
|
|
29
|
+
* such host had to hand-copy this block, and silently broke the day the
|
|
30
|
+
* interface grew a seventh member.
|
|
31
|
+
*
|
|
32
|
+
* So it lives here, exported, and `createAgentCliRuntime` consumes it
|
|
33
|
+
* like everyone else — one implementation, one place to extend.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The slice of `AgentCliRuntimeSession` {@link createArmSessionControls}
|
|
38
|
+
* supplies. Spread it into the session literal alongside the
|
|
39
|
+
* transport-specific `sessionId`/`send`/`cancel`/`close`.
|
|
40
|
+
*/
|
|
41
|
+
type ArmSessionControls = Pick<AgentCliRuntimeSession, "setModel" | "setSessionMode" | "setEffort" | "availableConfigOptions" | "availableModes" | "currentModeId">;
|
|
42
|
+
/**
|
|
43
|
+
* Build the control surface from a CONNECTED arm.
|
|
44
|
+
*
|
|
45
|
+
* Call this after `arm.connect()` has resolved: the read-surface fields
|
|
46
|
+
* are snapshots, so an ACP arm's captured `newSession`/`loadSession`
|
|
47
|
+
* response has to already be populated. Arms that don't model this
|
|
48
|
+
* (print, proprietary) leave the getters undefined and are defaulted
|
|
49
|
+
* here to the same empty/absent shape their `setModel`-style
|
|
50
|
+
* counterparts use for "not supported".
|
|
51
|
+
*
|
|
52
|
+
* Every switch resolves — none throws, none tears down the session, even
|
|
53
|
+
* when the underlying agent rejects the request. See
|
|
54
|
+
* {@link SetModelResult} and friends for the reason vocabulary.
|
|
55
|
+
*/
|
|
56
|
+
declare function createArmSessionControls(arm: AgentCliClient, definition: AgentCliHandle): ArmSessionControls;
|
|
57
|
+
/**
|
|
58
|
+
* Switch the active model via a `/model <id>` control turn, for adapters
|
|
59
|
+
* whose ACP session config doesn't select the model (`models.apply:
|
|
60
|
+
* "command"`, e.g. hermes). The turn is fully drained so the switch
|
|
61
|
+
* completes before the caller's next real turn. Best-effort: a transport
|
|
62
|
+
* failure or a missing acknowledgement is warned and reported as
|
|
63
|
+
* `{applied:false, reason}`, never thrown — the session simply continues
|
|
64
|
+
* on whatever model it already had. Shared by the spawn-time apply
|
|
65
|
+
* (return value ignored there) and the mid-session `setModel("command")`
|
|
66
|
+
* path (return value surfaced to the caller).
|
|
67
|
+
*/
|
|
68
|
+
declare function applyModelCommand(arm: AgentCliClient, modelId: string): Promise<SetModelResult>;
|
|
69
|
+
/**
|
|
70
|
+
* Send a turn and yield the arm's events for it.
|
|
71
|
+
*
|
|
72
|
+
* Re-attaches the recent stderr tail to error events. The ACP layer
|
|
73
|
+
* surfaces a terse `{message: "Invalid params"}`; the child's stderr
|
|
74
|
+
* almost always has a more useful line ("npx claude-agent-acp: not
|
|
75
|
+
* authenticated, run `claude login`"). Hosts read `error.data` when
|
|
76
|
+
* present, falling back to `message` for older payloads.
|
|
77
|
+
*/
|
|
78
|
+
declare function promptTurn(arm: AgentCliClient, turnId: string, message: unknown): AsyncIterable<StreamEvent>;
|
|
79
|
+
|
|
12
80
|
/**
|
|
13
81
|
* Agent CLI as a model port — turn ANY AIP-45 agent CLI runtime into a generic
|
|
14
82
|
* `complete({system?, prompt}) → {result}` executor. This is the one bridge that
|
|
@@ -249,6 +317,13 @@ interface PrintArmOptions {
|
|
|
249
317
|
* (e.g. Claude Code), which don't load MCP config from this path.
|
|
250
318
|
*/
|
|
251
319
|
mcpServers?: AcpMcpServer[];
|
|
320
|
+
/** OS-level confinement for the per-turn spawn — see
|
|
321
|
+
* `AgentCliStartOptions.commandSandbox` in `../types.ts` and
|
|
322
|
+
* `wrapAgentCliSpawn`'s doc for the fail-closed contract. */
|
|
323
|
+
commandSandbox?: SandboxMode;
|
|
324
|
+
/** Extra write-capable paths beyond the default toolchain set, e.g. the
|
|
325
|
+
* per-session `CLAUDE_CONFIG_DIR` temp dir set up by the caller. */
|
|
326
|
+
extraWritePaths?: string[];
|
|
252
327
|
}
|
|
253
328
|
declare function createPrintSession(opts: PrintArmOptions): AgentCliRuntimeSession;
|
|
254
329
|
/**
|
|
@@ -397,6 +472,16 @@ interface ComposedSpawn {
|
|
|
397
472
|
*/
|
|
398
473
|
envUnset: string[];
|
|
399
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* Optional spawn-time hints that are outside the pure runtime config.
|
|
477
|
+
* Today the only consumer is auth-aware codex model handling: the
|
|
478
|
+
* composer can be told to skip `models.apply:"arg"` when the caller has
|
|
479
|
+
* already determined that the current auth mode must preserve the CLI's
|
|
480
|
+
* default model.
|
|
481
|
+
*/
|
|
482
|
+
interface ComposeSpawnOptions {
|
|
483
|
+
skipModelArg?: boolean;
|
|
484
|
+
}
|
|
400
485
|
/**
|
|
401
486
|
* Compose the final spawn args from a manifest + per-call config.
|
|
402
487
|
* Pure — no I/O, no sandbox access, no global state. Safe to call
|
|
@@ -410,7 +495,7 @@ interface ComposedSpawn {
|
|
|
410
495
|
* a misconfigured operator fails fast at compose time, not at the
|
|
411
496
|
* point the strategy tries to acquire a session.
|
|
412
497
|
*/
|
|
413
|
-
declare function composeSpawn(handle: AgentCliHandle, config?: RuntimeConfig): ComposedSpawn;
|
|
498
|
+
declare function composeSpawn(handle: AgentCliHandle, config?: RuntimeConfig, opts?: ComposeSpawnOptions): ComposedSpawn;
|
|
414
499
|
/**
|
|
415
500
|
* Resolve the continuation strategy id to use for this call. Operator
|
|
416
501
|
* config wins; manifest default is the fallback; "none" if neither
|
|
@@ -632,4 +717,4 @@ declare function configureNativeResume(hooks: NativeResumeHooks): void;
|
|
|
632
717
|
declare const SPEC_NAME: "agentcli-interactive/v1";
|
|
633
718
|
declare const SPEC_VERSION: "0.1.0-alpha";
|
|
634
719
|
|
|
635
|
-
export { type AcpPermissionHandler, type AcpPermissionOutcome, type AcpPermissionRequestParams, type AcquireContext, AgentCliClient, AgentCliDefinition, AgentCliHandle, type AgentCliModelOptions, AgentCliPrintConfig, AgentCliRuntime, AgentCliRuntimeSession, AgentCliStartOptions, type ComposedSpawn, ContinuationKeyScope, type ContinuationStrategy, ContinuationStrategyId, type FileReadingOptions, LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, type MastraMapperState, type MastracodeMcpServerConfig, type ModelLike, type NativeResumeHooks, PROVIDER_KEY_ENV, type PrintArmOptions, type ProprietaryProtocolOptions, type ReleaseContext, type ReleaseOutcome, RuntimeConfig, RuntimeConfigError, SPEC_NAME, SPEC_VERSION, TurnContext, autoAllowPermissionHandler, composePrompt, composeSpawn, configureNativeResume, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, datasetPreamble, defineAgentCli, deriveKeyFromScope, getContinuationStrategy, inferLegacyModeKind, isLegacyExtractedModeId, listContinuationStrategies, makeAgentCliModel, mapMastraEvent, planModePermissionHandler, registerContinuationStrategy, resolveCliEnv, resolveContinuationStrategy, toFileBasedMcpServers };
|
|
720
|
+
export { type AcpPermissionHandler, type AcpPermissionOutcome, type AcpPermissionRequestParams, type AcquireContext, AgentCliClient, AgentCliDefinition, AgentCliHandle, type AgentCliModelOptions, AgentCliPrintConfig, AgentCliRuntime, AgentCliRuntimeSession, AgentCliStartOptions, type ArmSessionControls, type ComposedSpawn, ContinuationKeyScope, type ContinuationStrategy, ContinuationStrategyId, type FileReadingOptions, LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, type MastraMapperState, type MastracodeMcpServerConfig, type ModelLike, type NativeResumeHooks, PROVIDER_KEY_ENV, type PrintArmOptions, type ProprietaryProtocolOptions, type ReleaseContext, type ReleaseOutcome, RuntimeConfig, RuntimeConfigError, SPEC_NAME, SPEC_VERSION, SetModelResult, TurnContext, applyModelCommand, autoAllowPermissionHandler, composePrompt, composeSpawn, configureNativeResume, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, datasetPreamble, defineAgentCli, deriveKeyFromScope, getContinuationStrategy, inferLegacyModeKind, isLegacyExtractedModeId, listContinuationStrategies, makeAgentCliModel, mapMastraEvent, planModePermissionHandler, promptTurn, registerContinuationStrategy, resolveCliEnv, resolveContinuationStrategy, toFileBasedMcpServers };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, inferLegacyModeKind, isLegacyExtractedModeId, mapMastraEvent, planModePermissionHandler, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers } from './chunk-
|
|
1
|
+
export { LEGACY_GATEWAY_MODE_IDS, LEGACY_POSTURE_MODE_IDS, RuntimeConfigError, agentCliFrontmatterSchema, applyModelCommand, autoAllowPermissionHandler, composeSpawn, createAcpProtocolArm, createAgentCliRuntime, createArmSessionControls, createMastraMapperState, createPrintSession, createProprietaryProtocolArm, defineAgentCli, inferLegacyModeKind, isLegacyExtractedModeId, mapMastraEvent, planModePermissionHandler, promptTurn, resolveContinuationStrategy, runtimeConfigSchema, toFileBasedMcpServers } from './chunk-QL3CS6E4.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @agentproto/driver-agent-cli v0.1.0-alpha
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/model.ts","../src/continuation/strategies/none.ts","../src/continuation/types.ts","../src/continuation/strategies/pinned-session.ts","../src/continuation/strategies/transcript.ts","../src/continuation/strategies/native-resume.ts","../src/continuation/registry.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Agent CLI as a model port — turn ANY AIP-45 agent CLI runtime into a generic\n * `complete({system?, prompt}) → {result}` executor. This is the one bridge that\n * lets the SAME registry (hermes, claude-code, opencode, codex, openclaw, …)\n * back any prompt→completion seam: a report's chapter writer, a corpus\n * distiller, a Mastra tool's judgment step. The executor swaps, the prompts\n * (built by each seam's engine) don't.\n *\n * It drives the CLI over **ACP**: per `complete()` it spawns a fresh session,\n * sends one user turn, concatenates the `text-delta` stream until `turn-end`,\n * then closes. Lives here (not in a product) so seams BELOW the products —\n * `@agentproto/corpus` distill, the CLI — can consume it without importing\n * upward. The runner is injectable so assembly is unit-tested without a binary.\n */\n\nimport type { AgentCliRuntime } from \"./types.js\"\n\n/**\n * The minimal structural model port every seam consumes. Anything with this\n * `complete` shape satisfies the corpus `ReportModelPort` / `DistillPort`-backing\n * model / an AIP `ModelPort` — duck-typed, no nominal coupling.\n */\nexport interface ModelLike {\n complete(req: {\n system?: string\n prompt: string\n [k: string]: unknown\n }): Promise<{ result: string }>\n}\n\n/**\n * The \"file-reading sub-agent\" tier — opt-in across every file-IO-capable\n * executor. When `datasetDir` is set the executor is rooted there and granted\n * its own read tools, so instead of being limited to the excerpts a seam quotes\n * in the prompt it can open the primary sources directly and ground first-hand.\n */\nexport interface FileReadingOptions {\n /** Absolute path to the dataset/source root the executor may read from. */\n datasetDir?: string\n}\n\n/** The instruction prepended to a completion when {@link FileReadingOptions.datasetDir} is set. */\nexport function datasetPreamble(datasetDir: string): string {\n return (\n `You have direct read access to the source files under \\`${datasetDir}\\` ` +\n `(e.g. \\`sources/\\` raw captures, \\`entries/\\` refined notes). Use your ` +\n `file-reading tools to consult the primary sources directly when grounding ` +\n `claims — do not rely only on the excerpts quoted in this prompt.`\n )\n}\n\n/** Compose system + prompt with an optional source-access preamble (shared by every executor). */\nexport function composePrompt(\n system: string | undefined,\n prompt: string,\n datasetDir?: string\n): string {\n const head = datasetDir ? `${datasetPreamble(datasetDir)}\\n\\n` : \"\"\n return system ? `${head}${system}\\n\\n${prompt}` : `${head}${prompt}`\n}\n\n/** Provider keys an agent CLI may route through, forwarded from the parent env by default. */\nexport const PROVIDER_KEY_ENV = [\n \"OPENROUTER_API_KEY\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n] as const\n\nexport interface AgentCliModelOptions extends FileReadingOptions {\n /**\n * Env handed to the spawned CLI process — the provider key it routes through.\n * Defaults to forwarding {@link PROVIDER_KEY_ENV} from the parent process env.\n */\n env?: Record<string, string>\n /** Working directory for the CLI process. Defaults to `datasetDir` when set. */\n cwd?: string\n /** Timeout per completion (ms). Default 5 min. */\n timeoutMs?: number\n /**\n * Injectable runner (composed prompt → completion text). Defaults to driving\n * the runtime over ACP. Override in tests to avoid the CLI.\n */\n run?: (prompt: string) => Promise<string>\n}\n\n/** Build the env for the spawned CLI: explicit override, else forwarded provider keys. */\nexport function resolveCliEnv(\n opts: Pick<AgentCliModelOptions, \"env\">\n): Record<string, string> {\n if (opts.env) return opts.env\n const env: Record<string, string> = {}\n for (const k of PROVIDER_KEY_ENV) {\n const v = process.env[k]\n if (v) env[k] = v\n }\n return env\n}\n\n/** Drive one ACP turn on `runtime`, concatenating the text deltas. */\nasync function driveTurn(\n runtime: AgentCliRuntime,\n prompt: string,\n opts: AgentCliModelOptions\n): Promise<string> {\n const controller = new AbortController()\n const timer = setTimeout(\n () => controller.abort(),\n opts.timeoutMs ?? 5 * 60 * 1000\n )\n\n const cwd = opts.cwd ?? opts.datasetDir\n const session = await runtime.start({\n env: resolveCliEnv(opts),\n signal: controller.signal,\n ...(cwd ? { cwd } : {}),\n })\n\n try {\n let text = \"\"\n for await (const evt of session.send({ role: \"user\", content: prompt })) {\n if (evt.kind === \"text-delta\") {\n text += evt.text\n } else if (evt.kind === \"error\") {\n throw new Error(`${runtime.definition.id} model: ${evt.error.message}`)\n } else if (evt.kind === \"turn-end\") {\n if (evt.reason !== \"completed\")\n throw new Error(`${runtime.definition.id} model: turn ${evt.reason}`)\n break\n }\n }\n if (controller.signal.aborted)\n throw new Error(`${runtime.definition.id} model: timed out`)\n return text.trim()\n } finally {\n clearTimeout(timer)\n await session.close()\n }\n}\n\n/**\n * Build a {@link ModelLike} backed by an AIP-45 agent-CLI runtime. Hand it any\n * `*Runtime()` from the registry (Hermes, claude-code, opencode, …); per-CLI\n * presets are one-liners over this.\n */\nexport function makeAgentCliModel(\n runtime: AgentCliRuntime,\n opts: AgentCliModelOptions = {}\n): ModelLike {\n const run = opts.run ?? ((prompt: string) => driveTurn(runtime, prompt, opts))\n return {\n async complete({ system, prompt }) {\n return {\n result: await run(composePrompt(system, prompt, opts.datasetDir)),\n }\n },\n }\n}\n","/**\n * `none` strategy — pre-AIP-45-extension behaviour.\n *\n * Spawn a fresh session per acquire; close it on release. No state,\n * no reuse. The default when a manifest declares no `continuation`\n * block (back-compat for adapters that haven't been updated).\n */\n\nimport type { ContinuationStrategy } from \"../types.js\"\n\nexport const noneStrategy: ContinuationStrategy = {\n id: \"none\",\n async acquire(ctx) {\n return ctx.runtime.start(ctx.startOptions)\n },\n async release(ctx) {\n await ctx.session.close()\n },\n}\n","/**\n * AIP-45 ContinuationStrategy interface.\n *\n * A continuation strategy decides HOW prior conversation turns reach a\n * spawned CLI on subsequent invocations. Built-ins handle:\n *\n * - `none` — fresh session per call (current pre-AIP-45 behaviour)\n * - `pinned-session` — keep the spawned child alive, reuse across turns\n * - `transcript` — caller-supplied preamble prepended to each turn\n * - `native-resume` — pass a session id to the CLI's own `--resume` flag\n *\n * Adapter packages MAY register custom strategies via the registry —\n * for example, a Goose-specific strategy that uses MCP-side session\n * load semantics. Custom strategy ids require a follow-up AIP that\n * opens the `ContinuationStrategyId` enum (so the manifest schema can\n * validate them).\n *\n * The strategy owns the SESSION LIFECYCLE: `acquire` returns a session\n * the caller can `send()` against, and `release` decides whether the\n * session lives on (pinned-session) or closes immediately (none). The\n * runner / generation strategy MUST go through `acquire`/`release` —\n * it MUST NOT call `runtime.start()` / `session.close()` directly when\n * a strategy is active.\n */\n\nimport type {\n AgentCliRuntime,\n AgentCliRuntimeSession,\n AgentCliStartOptions,\n ContinuationKeyScope,\n ContinuationStrategyId,\n RuntimeConfig,\n TurnContext,\n} from \"../types.js\"\n\n/**\n * Per-acquire context the strategy gets. The runner builds this from\n * the manifest, the operator config, and the current turn's identity.\n */\nexport interface AcquireContext {\n runtime: AgentCliRuntime\n /** Already-composed start options (cwd / env / signal / config /\n * turnCtx). Strategies MAY override individual fields when they\n * call `runtime.start(...)` themselves. */\n startOptions: AgentCliStartOptions\n /** Per-call config (already validated against the manifest). */\n config: RuntimeConfig\n /** Identity context for key derivation. */\n turnCtx: TurnContext\n}\n\n/**\n * Strategies can hint to the runner about how the turn played out so\n * the strategy can decide whether to keep the session alive (normal\n * end), reset its TTL but keep it (transient error), or evict it\n * (dead-process error).\n */\nexport type ReleaseOutcome =\n | { kind: \"completed\" }\n | { kind: \"cancelled\" }\n | { kind: \"error\"; reason: \"transient\" | \"fatal\"; message: string }\n\nexport interface ReleaseContext {\n session: AgentCliRuntimeSession\n outcome: ReleaseOutcome\n turnCtx: TurnContext\n}\n\n/**\n * The strategy contract. `acquire` returns a session ready for the\n * caller to `send()` against — fresh OR reused. `release` decides\n * the session's fate. Strategies MAY hold internal state (e.g.\n * the pinned-session map) keyed by `turnCtx`.\n */\nexport interface ContinuationStrategy {\n readonly id: ContinuationStrategyId\n acquire(ctx: AcquireContext): Promise<AgentCliRuntimeSession>\n release(ctx: ReleaseContext): Promise<void>\n}\n\n/**\n * Derive a stable pin key from `turnCtx` according to the manifest's\n * `pinned_session.key_scope`. Missing scope fields downgrade to a\n * less-specific key with a warning — pinning still works, it just\n * collides more.\n *\n * Returns `null` when EVERY scope field the manifest asked for is\n * missing (no key derivable; strategy falls back to per-spawn).\n */\nexport function deriveKeyFromScope(\n scope: ContinuationKeyScope[],\n turnCtx: TurnContext\n): string | null {\n const parts: string[] = []\n for (const s of scope) {\n const v = turnCtx[s]\n if (v) parts.push(`${s}=${v}`)\n }\n return parts.length === 0 ? null : parts.join(\"|\")\n}\n","/**\n * `pinned-session` strategy — keep the spawned child alive across\n * turns so the CLI's in-memory model context carries over.\n *\n * Suitable for manifests that declare `session.mode: persistent` AND\n * `context_carryover: true` (Claude Code, OpenCode, ...). Acquires\n * either reuse a live pinned session or spawn fresh and pin; releases\n * keep the session alive and reset its idle TTL. The strategy\n * auto-evicts after the manifest's `pinned_session.idle_timeout_ms`.\n *\n * The pin key is derived from `turnCtx` according to the manifest's\n * `pinned_session.key_scope` (default: `[conversation, operator]` —\n * different conversations and different operators each get their own\n * child process).\n *\n * Lost on process restart. DB-backed pin persistence is a follow-up\n * (track sessionId in `cli_sessions` table, then optionally fall back\n * to native-resume / transcript on restart).\n */\n\nimport type {\n AgentCliRuntimeSession,\n AgentCliRuntime,\n AgentCliStartOptions,\n} from \"../../types.js\"\nimport type { ContinuationStrategy } from \"../types.js\"\nimport { deriveKeyFromScope } from \"../types.js\"\n\ninterface PinnedEntry {\n session: AgentCliRuntimeSession\n /** Cached so retry-after-eviction can recreate without re-resolving\n * the runtime entry from outside. */\n runtime: AgentCliRuntime\n /** Cached so eviction-and-retry uses the same start options. */\n startOptions: AgentCliStartOptions\n idleTimer: ReturnType<typeof setTimeout> | null\n}\n\nconst DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000\n\nconst pins = new Map<string, PinnedEntry>()\n\nfunction clearIdleTimer(entry: PinnedEntry): void {\n if (entry.idleTimer) {\n clearTimeout(entry.idleTimer)\n entry.idleTimer = null\n }\n}\n\nfunction scheduleIdleEviction(\n key: string,\n entry: PinnedEntry,\n idleTimeoutMs: number\n): void {\n clearIdleTimer(entry)\n entry.idleTimer = setTimeout(() => {\n pins.delete(key)\n entry.session.close().catch(err => {\n console.warn(\n `[pinned-session] idle close failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n })\n console.log(\n `[pinned-session] ${key} idle ${idleTimeoutMs / 60_000}m → closed`\n )\n }, idleTimeoutMs)\n // Don't keep the event loop alive just for the idle close — the\n // child will be reaped on process exit anyway. Without `unref`\n // a stale pin would block graceful shutdown.\n entry.idleTimer.unref?.()\n}\n\nfunction evictPin(key: string): void {\n const entry = pins.get(key)\n if (!entry) return\n clearIdleTimer(entry)\n pins.delete(key)\n entry.session.close().catch(err => {\n console.warn(\n `[pinned-session] evict close failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n })\n}\n\nexport const pinnedSessionStrategy: ContinuationStrategy = {\n id: \"pinned-session\",\n\n async acquire(ctx) {\n const tuning = ctx.runtime.definition.continuation?.pinned_session\n const scope = tuning?.key_scope ?? [\"conversation\", \"operator\"]\n const key = deriveKeyFromScope(scope, ctx.turnCtx)\n const idleTimeoutMs = tuning?.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS\n\n if (key === null) {\n // No identity to pin against — fall back to per-spawn behaviour.\n // Warn so the host learns to populate turnCtx.\n console.warn(\n `[pinned-session] turnCtx has no fields matching key_scope ${JSON.stringify(scope)}; falling back to per-spawn (no pin).`\n )\n return ctx.runtime.start(ctx.startOptions)\n }\n\n const existing = pins.get(key)\n if (existing) {\n // Cancel the idle timer — this turn is reusing the pin.\n clearIdleTimer(existing)\n return existing.session\n }\n\n const session = await ctx.runtime.start(ctx.startOptions)\n const entry: PinnedEntry = {\n session,\n runtime: ctx.runtime,\n startOptions: ctx.startOptions,\n idleTimer: null,\n }\n pins.set(key, entry)\n scheduleIdleEviction(key, entry, idleTimeoutMs)\n return session\n },\n\n async release(ctx) {\n // Find the entry by identity — ReleaseContext doesn't carry `runtime`,\n // so we match by session reference. Acceptable since the pin map is small.\n let foundKey: string | null = null\n for (const [k, e] of pins) {\n if (e.session === ctx.session) {\n foundKey = k\n break\n }\n }\n\n if (!foundKey) {\n // Session wasn't pinned (per-spawn fallback path) — close it\n // like the `none` strategy would.\n await ctx.session.close()\n return\n }\n\n const entry = pins.get(foundKey)!\n const tuning = entry.runtime.definition.continuation?.pinned_session\n const idleTimeoutMs = tuning?.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS\n\n // Fatal errors → evict so the next turn re-spawns. Transient\n // errors and normal completion → reset the idle TTL and keep.\n // Cancelled (user aborted) is treated like normal completion —\n // the user wanted to stop this turn, not the whole session.\n if (ctx.outcome.kind === \"error\" && ctx.outcome.reason === \"fatal\") {\n evictPin(foundKey)\n return\n }\n\n scheduleIdleEviction(foundKey, entry, idleTimeoutMs)\n },\n}\n\n/**\n * Test helper — drop all pinned entries and clear timers. Not part\n * of the public API; exposed under `__test__` so tests can reset the\n * module's singleton state between runs.\n */\nexport const __test__ = {\n resetPins(): void {\n for (const [k] of pins) evictPin(k)\n },\n pinCount(): number {\n return pins.size\n },\n}\n","/**\n * `transcript` strategy — works for any CLI, including those with\n * `resumable: false` and ephemeral sessions.\n *\n * The driver doesn't know about Mastra memory or the host's\n * conversation log — that's the host's domain. The host supplies the\n * preamble at acquire-time via `startOptions.config.options` (the\n * convention is option id `__transcript`, see below) and the strategy\n * is otherwise identical to `none` — fresh session per acquire,\n * close on release.\n *\n * In practice the host does the prepending itself before calling\n * `runtime.start` (it controls the `message` text). This strategy\n * exists mostly as a NAMED policy choice in the manifest — declaring\n * it tells the host \"use the transcript-replay path for this CLI\"\n * without the host needing to inspect capabilities.\n *\n * Token-costly but stateless and survives API restarts.\n */\n\nimport type { ContinuationStrategy } from \"../types.js\"\n\nexport const transcriptStrategy: ContinuationStrategy = {\n id: \"transcript\",\n async acquire(ctx) {\n return ctx.runtime.start(ctx.startOptions)\n },\n async release(ctx) {\n await ctx.session.close()\n },\n}\n","/**\n * `native-resume` strategy — reattach to the agent's own session by id\n * (ACP `loadSession`, MCP equivalent, or argv-style `--resume`).\n *\n * Two-step lifecycle:\n * 1. **acquire**: look up a persisted sessionId for `turnCtx` via\n * `loadHook`. If found, pass it to `runtime.start` as\n * `resumeSessionId` so the protocol arm reattaches. If not, spawn\n * fresh — and after the session is up, capture the new id from\n * `session.sessionId` and persist it via `saveHook`.\n * 2. **release**: close the spawned process. The session lives in\n * the agent's storage layer (e.g. Claude Code's JSONL files);\n * cold-start resume on the next acquire reads from that store.\n *\n * Hooks are registered once per host process via\n * `configureNativeResume({ load, save })`. Without hooks the strategy\n * degrades to per-spawn behaviour with a one-line warning — it's not\n * fatal because the spawn still works, just without continuity.\n *\n * Requires the manifest to declare `capabilities.resumable: true`\n * AND the agent to advertise the matching protocol capability (e.g.\n * ACP `loadSession: true`). The schema enforces the manifest side at\n * validation; runtime capability mismatch surfaces from the protocol\n * arm as the agent's own error.\n */\n\nimport type { ContinuationStrategy, AcquireContext } from \"../types.js\"\nimport { deriveKeyFromScope } from \"../types.js\"\nimport type { TurnContext } from \"../../types.js\"\n\nexport interface NativeResumeHooks {\n /** Look up a persisted sessionId for the given identity scope. Return\n * undefined when no prior session exists — strategy spawns fresh. */\n load: (turnCtx: TurnContext) => Promise<string | undefined>\n /** Persist a freshly-established sessionId so the next cold start\n * can resume. Called once per \"fresh spawn\" acquire (not per turn).\n * Idempotent / upsert semantics expected on the host side. */\n save: (turnCtx: TurnContext, sessionId: string) => Promise<void>\n /** Optional: drop the persisted entry when a session is detected as\n * unresumable (agent rejected loadSession with a hard error). */\n forget?: (turnCtx: TurnContext) => Promise<void>\n}\n\nlet _hooks: NativeResumeHooks | null = null\n\n/**\n * Register the host's session-id load/save callbacks. Call once at\n * boot. Subsequent calls overwrite — useful in tests; in prod treat\n * the registration as exclusive.\n */\nexport function configureNativeResume(hooks: NativeResumeHooks): void {\n _hooks = hooks\n}\n\n/** Reset to no-hooks. Test helper; not part of public API. */\nexport function __resetNativeResumeForTests(): void {\n _hooks = null\n}\n\nexport const nativeResumeStrategy: ContinuationStrategy = {\n id: \"native-resume\",\n async acquire(ctx: AcquireContext) {\n if (!_hooks) {\n console.warn(\n \"[native-resume] no hooks registered (call configureNativeResume at boot); falling back to per-spawn — no continuity.\"\n )\n return ctx.runtime.start(ctx.startOptions)\n }\n // Use the same key-derivation as pinned-session so a host can\n // declare its scope ONCE in the manifest (`continuation.pinned_session.key_scope`)\n // and have both strategies key off the same identity. Native-resume\n // doesn't have its own key_scope today; it inherits.\n const scope =\n ctx.runtime.definition.continuation?.pinned_session?.key_scope ?? [\n \"conversation\",\n \"operator\",\n ]\n const key = deriveKeyFromScope(scope, ctx.turnCtx)\n if (key === null) {\n console.warn(\n `[native-resume] turnCtx has no fields matching key_scope ${JSON.stringify(scope)}; falling back to per-spawn (no resume).`\n )\n return ctx.runtime.start(ctx.startOptions)\n }\n\n const existingId = await _hooks.load(ctx.turnCtx).catch(err => {\n console.warn(\n `[native-resume] load hook failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n return undefined\n })\n\n let session\n let resumed = false\n if (existingId) {\n try {\n session = await ctx.runtime.start({\n ...ctx.startOptions,\n resumeSessionId: existingId,\n })\n resumed = true\n } catch (err) {\n // Most likely the agent rejected the id (session expired,\n // wiped, mismatched cwd). Drop the stale pin and spawn fresh\n // so the user gets continuity going forward instead of being\n // stuck on a dead reference.\n console.warn(\n `[native-resume] resume failed for ${key} (id=${existingId.slice(0, 12)}…), starting fresh:`,\n err instanceof Error ? err.message : err\n )\n if (_hooks.forget) {\n await _hooks.forget(ctx.turnCtx).catch(() => undefined)\n }\n session = await ctx.runtime.start(ctx.startOptions)\n }\n } else {\n session = await ctx.runtime.start(ctx.startOptions)\n }\n\n // Persist the established id when this is a NEW session (resume\n // path keeps the same id we already have, no need to re-save).\n // The runtime guarantees session.sessionId reflects the protocol\n // session id when the arm exposes it.\n if (!resumed && session.sessionId) {\n await _hooks.save(ctx.turnCtx, session.sessionId).catch(err => {\n console.warn(\n `[native-resume] save hook failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n })\n }\n return session\n },\n\n async release(ctx) {\n // The protocol session lives in the agent's own storage; closing\n // the spawned subprocess is fine — `loadSession` on the next\n // acquire reattaches via the persisted id.\n await ctx.session.close()\n },\n}\n","/**\n * Continuation strategy registry.\n *\n * Module-scoped singleton — all built-ins are registered at import\n * time, custom strategies (from adapter packages) register via\n * `registerContinuationStrategy`. The runner looks up by id;\n * unregistered ids throw at acquire-time so the caller fails fast\n * with a clear \"this strategy id isn't registered\" message.\n */\n\nimport type { ContinuationStrategyId } from \"../types.js\"\nimport type { ContinuationStrategy } from \"./types.js\"\nimport { noneStrategy } from \"./strategies/none.js\"\nimport { pinnedSessionStrategy } from \"./strategies/pinned-session.js\"\nimport { transcriptStrategy } from \"./strategies/transcript.js\"\nimport { nativeResumeStrategy } from \"./strategies/native-resume.js\"\n\nconst registry = new Map<ContinuationStrategyId, ContinuationStrategy>()\n\n/**\n * Register (or replace) a continuation strategy. Adapter packages\n * MAY register custom strategies on import — but they MUST first\n * land an AIP that opens the `ContinuationStrategyId` enum so the\n * manifest schema accepts the new id.\n */\nexport function registerContinuationStrategy(\n strategy: ContinuationStrategy\n): void {\n registry.set(strategy.id, strategy)\n}\n\nexport function getContinuationStrategy(\n id: ContinuationStrategyId\n): ContinuationStrategy {\n const s = registry.get(id)\n if (!s) {\n throw new Error(\n `[agent-cli] No continuation strategy registered for id '${id}'. Built-ins: ${Array.from(registry.keys()).join(\", \")}.`\n )\n }\n return s\n}\n\nexport function listContinuationStrategies(): ContinuationStrategyId[] {\n return Array.from(registry.keys())\n}\n\n// Register built-ins eagerly at module load so any importer of the\n// registry sees them. Custom strategies layer on top.\nregisterContinuationStrategy(noneStrategy)\nregisterContinuationStrategy(pinnedSessionStrategy)\nregisterContinuationStrategy(transcriptStrategy)\nregisterContinuationStrategy(nativeResumeStrategy)\n","/**\n * @agentproto/driver-agent-cli — AIP-45 AGENT-CLI.md `defineAgentCli`\n * reference impl.\n *\n * Spec: https://agentproto.sh/docs/aip-45\n *\n * Authoring paths:\n * - TS: `defineAgentCli({...})` → `AgentCliHandle`\n * - MD: `parseAgentCliManifest(src) → agentCliFromManifest({...})` → `AgentCliHandle`\n *\n * Runtime: `createAgentCliRuntime(handle)` → spawn binary, dispatch\n * turns through the protocol arm (acp / mcp / proprietary), normalise\n * events to {@link StreamEvent}.\n */\n\nexport const SPEC_NAME = \"agentcli-interactive/v1\" as const\nexport const SPEC_VERSION = \"0.1.0-alpha\" as const\n\nexport {\n defineAgentCli,\n createAgentCliRuntime,\n} from \"./define-agent-cli.js\"\n// Agent CLI → generic model port: one executor backing every prompt→completion\n// seam (report writer, corpus distiller, Mastra judgment step) over any AIP-45 CLI.\nexport {\n makeAgentCliModel,\n resolveCliEnv,\n composePrompt,\n datasetPreamble,\n PROVIDER_KEY_ENV,\n} from \"./model.js\"\nexport type {\n ModelLike,\n FileReadingOptions,\n AgentCliModelOptions,\n} from \"./model.js\"\n// Exposed so callers can build a sandbox-resident `AgentCliRuntime`\n// against the same protocol layer the host-spawn factory uses, by\n// passing a `ChildProcess`-shaped duck whose stdio is bridged to a\n// remote subprocess (e2b sandbox, ssh, etc.). See guilde's\n// `cli-session-spawn/sandbox-runtime.ts` for a worked example.\nexport {\n createAcpProtocolArm,\n autoAllowPermissionHandler,\n planModePermissionHandler,\n type AcpPermissionHandler,\n type AcpPermissionOutcome,\n type AcpPermissionRequestParams,\n} from \"./protocol/acp-client.js\"\nexport {\n createPrintSession,\n mapMastraEvent,\n createMastraMapperState,\n type PrintArmOptions,\n type MastraMapperState,\n} from \"./protocol/print-arm.js\"\n// Generic proprietary-protocol arm loader — dynamically imports the\n// manifest's `adapter` package. Exported so proprietary adapter packages\n// (and their tests) can drive the same loader `createAgentCliRuntime`\n// uses, without duplicating the load-and-validate logic.\nexport {\n createProprietaryProtocolArm,\n type ProprietaryProtocolOptions,\n} from \"./protocol/proprietary.js\"\nexport {\n agentCliFrontmatterSchema,\n runtimeConfigSchema,\n type AgentCliFrontmatter,\n type RuntimeConfigInput,\n} from \"./schema.js\"\nexport {\n toFileBasedMcpServers,\n type MastracodeMcpServerConfig,\n} from \"./mcp-servers.js\"\nexport {\n composeSpawn,\n resolveContinuationStrategy,\n RuntimeConfigError,\n type ComposedSpawn,\n} from \"./manifest/compose.js\"\n// Legacy AIP-45 mode-id classification (SPEC §3.4a) — the single source the\n// daemon's `decomposeMode` shim reuses so the route/posture id set never drifts.\nexport {\n LEGACY_GATEWAY_MODE_IDS,\n LEGACY_POSTURE_MODE_IDS,\n inferLegacyModeKind,\n isLegacyExtractedModeId,\n} from \"./legacy-modes.js\"\nexport {\n registerContinuationStrategy,\n getContinuationStrategy,\n listContinuationStrategies,\n} from \"./continuation/registry.js\"\nexport {\n configureNativeResume,\n type NativeResumeHooks,\n} from \"./continuation/strategies/native-resume.js\"\nexport {\n deriveKeyFromScope,\n type ContinuationStrategy,\n type AcquireContext,\n type ReleaseContext,\n type ReleaseOutcome,\n} from \"./continuation/types.js\"\nexport type {\n AgentCliDefinition,\n AgentCliHandle,\n AgentCliProtocol,\n AgentCliSessionMode,\n AgentCliClient,\n AgentCliConnectOptions,\n AgentCliRuntime,\n AgentCliRuntimeSession,\n AgentCliStartOptions,\n AgentCliCapabilities,\n AgentCliInstallMethod,\n AgentCliVersionCheck,\n AgentCliAuth,\n AgentCliSetupStep,\n AgentCliSetupSkipIf,\n AgentCliSetupPersist,\n AgentCliSession,\n AgentCliModels,\n AgentCliModelEntry,\n AgentCliMcpBlock,\n AgentCliMode,\n AgentCliOption,\n AgentCliOptionType,\n AgentCliPresetDeclaration,\n AgentCliContinuation,\n AgentCliPinnedSessionTuning,\n AgentCliPrintConfig,\n ContinuationStrategyId,\n ContinuationKeyScope,\n RuntimeConfig,\n TurnContext,\n StreamEvent,\n} from \"./types.js\"\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/model.ts","../src/continuation/strategies/none.ts","../src/continuation/types.ts","../src/continuation/strategies/pinned-session.ts","../src/continuation/strategies/transcript.ts","../src/continuation/strategies/native-resume.ts","../src/continuation/registry.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Agent CLI as a model port — turn ANY AIP-45 agent CLI runtime into a generic\n * `complete({system?, prompt}) → {result}` executor. This is the one bridge that\n * lets the SAME registry (hermes, claude-code, opencode, codex, openclaw, …)\n * back any prompt→completion seam: a report's chapter writer, a corpus\n * distiller, a Mastra tool's judgment step. The executor swaps, the prompts\n * (built by each seam's engine) don't.\n *\n * It drives the CLI over **ACP**: per `complete()` it spawns a fresh session,\n * sends one user turn, concatenates the `text-delta` stream until `turn-end`,\n * then closes. Lives here (not in a product) so seams BELOW the products —\n * `@agentproto/corpus` distill, the CLI — can consume it without importing\n * upward. The runner is injectable so assembly is unit-tested without a binary.\n */\n\nimport type { AgentCliRuntime } from \"./types.js\"\n\n/**\n * The minimal structural model port every seam consumes. Anything with this\n * `complete` shape satisfies the corpus `ReportModelPort` / `DistillPort`-backing\n * model / an AIP `ModelPort` — duck-typed, no nominal coupling.\n */\nexport interface ModelLike {\n complete(req: {\n system?: string\n prompt: string\n [k: string]: unknown\n }): Promise<{ result: string }>\n}\n\n/**\n * The \"file-reading sub-agent\" tier — opt-in across every file-IO-capable\n * executor. When `datasetDir` is set the executor is rooted there and granted\n * its own read tools, so instead of being limited to the excerpts a seam quotes\n * in the prompt it can open the primary sources directly and ground first-hand.\n */\nexport interface FileReadingOptions {\n /** Absolute path to the dataset/source root the executor may read from. */\n datasetDir?: string\n}\n\n/** The instruction prepended to a completion when {@link FileReadingOptions.datasetDir} is set. */\nexport function datasetPreamble(datasetDir: string): string {\n return (\n `You have direct read access to the source files under \\`${datasetDir}\\` ` +\n `(e.g. \\`sources/\\` raw captures, \\`entries/\\` refined notes). Use your ` +\n `file-reading tools to consult the primary sources directly when grounding ` +\n `claims — do not rely only on the excerpts quoted in this prompt.`\n )\n}\n\n/** Compose system + prompt with an optional source-access preamble (shared by every executor). */\nexport function composePrompt(\n system: string | undefined,\n prompt: string,\n datasetDir?: string\n): string {\n const head = datasetDir ? `${datasetPreamble(datasetDir)}\\n\\n` : \"\"\n return system ? `${head}${system}\\n\\n${prompt}` : `${head}${prompt}`\n}\n\n/** Provider keys an agent CLI may route through, forwarded from the parent env by default. */\nexport const PROVIDER_KEY_ENV = [\n \"OPENROUTER_API_KEY\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n] as const\n\nexport interface AgentCliModelOptions extends FileReadingOptions {\n /**\n * Env handed to the spawned CLI process — the provider key it routes through.\n * Defaults to forwarding {@link PROVIDER_KEY_ENV} from the parent process env.\n */\n env?: Record<string, string>\n /** Working directory for the CLI process. Defaults to `datasetDir` when set. */\n cwd?: string\n /** Timeout per completion (ms). Default 5 min. */\n timeoutMs?: number\n /**\n * Injectable runner (composed prompt → completion text). Defaults to driving\n * the runtime over ACP. Override in tests to avoid the CLI.\n */\n run?: (prompt: string) => Promise<string>\n}\n\n/** Build the env for the spawned CLI: explicit override, else forwarded provider keys. */\nexport function resolveCliEnv(\n opts: Pick<AgentCliModelOptions, \"env\">\n): Record<string, string> {\n if (opts.env) return opts.env\n const env: Record<string, string> = {}\n for (const k of PROVIDER_KEY_ENV) {\n const v = process.env[k]\n if (v) env[k] = v\n }\n return env\n}\n\n/** Drive one ACP turn on `runtime`, concatenating the text deltas. */\nasync function driveTurn(\n runtime: AgentCliRuntime,\n prompt: string,\n opts: AgentCliModelOptions\n): Promise<string> {\n const controller = new AbortController()\n const timer = setTimeout(\n () => controller.abort(),\n opts.timeoutMs ?? 5 * 60 * 1000\n )\n\n const cwd = opts.cwd ?? opts.datasetDir\n const session = await runtime.start({\n env: resolveCliEnv(opts),\n signal: controller.signal,\n ...(cwd ? { cwd } : {}),\n })\n\n try {\n let text = \"\"\n for await (const evt of session.send({ role: \"user\", content: prompt })) {\n if (evt.kind === \"text-delta\") {\n text += evt.text\n } else if (evt.kind === \"error\") {\n throw new Error(`${runtime.definition.id} model: ${evt.error.message}`)\n } else if (evt.kind === \"turn-end\") {\n if (evt.reason !== \"completed\")\n throw new Error(`${runtime.definition.id} model: turn ${evt.reason}`)\n break\n }\n }\n if (controller.signal.aborted)\n throw new Error(`${runtime.definition.id} model: timed out`)\n return text.trim()\n } finally {\n clearTimeout(timer)\n await session.close()\n }\n}\n\n/**\n * Build a {@link ModelLike} backed by an AIP-45 agent-CLI runtime. Hand it any\n * `*Runtime()` from the registry (Hermes, claude-code, opencode, …); per-CLI\n * presets are one-liners over this.\n */\nexport function makeAgentCliModel(\n runtime: AgentCliRuntime,\n opts: AgentCliModelOptions = {}\n): ModelLike {\n const run = opts.run ?? ((prompt: string) => driveTurn(runtime, prompt, opts))\n return {\n async complete({ system, prompt }) {\n return {\n result: await run(composePrompt(system, prompt, opts.datasetDir)),\n }\n },\n }\n}\n","/**\n * `none` strategy — pre-AIP-45-extension behaviour.\n *\n * Spawn a fresh session per acquire; close it on release. No state,\n * no reuse. The default when a manifest declares no `continuation`\n * block (back-compat for adapters that haven't been updated).\n */\n\nimport type { ContinuationStrategy } from \"../types.js\"\n\nexport const noneStrategy: ContinuationStrategy = {\n id: \"none\",\n async acquire(ctx) {\n return ctx.runtime.start(ctx.startOptions)\n },\n async release(ctx) {\n await ctx.session.close()\n },\n}\n","/**\n * AIP-45 ContinuationStrategy interface.\n *\n * A continuation strategy decides HOW prior conversation turns reach a\n * spawned CLI on subsequent invocations. Built-ins handle:\n *\n * - `none` — fresh session per call (current pre-AIP-45 behaviour)\n * - `pinned-session` — keep the spawned child alive, reuse across turns\n * - `transcript` — caller-supplied preamble prepended to each turn\n * - `native-resume` — pass a session id to the CLI's own `--resume` flag\n *\n * Adapter packages MAY register custom strategies via the registry —\n * for example, a Goose-specific strategy that uses MCP-side session\n * load semantics. Custom strategy ids require a follow-up AIP that\n * opens the `ContinuationStrategyId` enum (so the manifest schema can\n * validate them).\n *\n * The strategy owns the SESSION LIFECYCLE: `acquire` returns a session\n * the caller can `send()` against, and `release` decides whether the\n * session lives on (pinned-session) or closes immediately (none). The\n * runner / generation strategy MUST go through `acquire`/`release` —\n * it MUST NOT call `runtime.start()` / `session.close()` directly when\n * a strategy is active.\n */\n\nimport type {\n AgentCliRuntime,\n AgentCliRuntimeSession,\n AgentCliStartOptions,\n ContinuationKeyScope,\n ContinuationStrategyId,\n RuntimeConfig,\n TurnContext,\n} from \"../types.js\"\n\n/**\n * Per-acquire context the strategy gets. The runner builds this from\n * the manifest, the operator config, and the current turn's identity.\n */\nexport interface AcquireContext {\n runtime: AgentCliRuntime\n /** Already-composed start options (cwd / env / signal / config /\n * turnCtx). Strategies MAY override individual fields when they\n * call `runtime.start(...)` themselves. */\n startOptions: AgentCliStartOptions\n /** Per-call config (already validated against the manifest). */\n config: RuntimeConfig\n /** Identity context for key derivation. */\n turnCtx: TurnContext\n}\n\n/**\n * Strategies can hint to the runner about how the turn played out so\n * the strategy can decide whether to keep the session alive (normal\n * end), reset its TTL but keep it (transient error), or evict it\n * (dead-process error).\n */\nexport type ReleaseOutcome =\n | { kind: \"completed\" }\n | { kind: \"cancelled\" }\n | { kind: \"error\"; reason: \"transient\" | \"fatal\"; message: string }\n\nexport interface ReleaseContext {\n session: AgentCliRuntimeSession\n outcome: ReleaseOutcome\n turnCtx: TurnContext\n}\n\n/**\n * The strategy contract. `acquire` returns a session ready for the\n * caller to `send()` against — fresh OR reused. `release` decides\n * the session's fate. Strategies MAY hold internal state (e.g.\n * the pinned-session map) keyed by `turnCtx`.\n */\nexport interface ContinuationStrategy {\n readonly id: ContinuationStrategyId\n acquire(ctx: AcquireContext): Promise<AgentCliRuntimeSession>\n release(ctx: ReleaseContext): Promise<void>\n}\n\n/**\n * Derive a stable pin key from `turnCtx` according to the manifest's\n * `pinned_session.key_scope`. Missing scope fields downgrade to a\n * less-specific key with a warning — pinning still works, it just\n * collides more.\n *\n * Returns `null` when EVERY scope field the manifest asked for is\n * missing (no key derivable; strategy falls back to per-spawn).\n */\nexport function deriveKeyFromScope(\n scope: ContinuationKeyScope[],\n turnCtx: TurnContext\n): string | null {\n const parts: string[] = []\n for (const s of scope) {\n const v = turnCtx[s]\n if (v) parts.push(`${s}=${v}`)\n }\n return parts.length === 0 ? null : parts.join(\"|\")\n}\n","/**\n * `pinned-session` strategy — keep the spawned child alive across\n * turns so the CLI's in-memory model context carries over.\n *\n * Suitable for manifests that declare `session.mode: persistent` AND\n * `context_carryover: true` (Claude Code, OpenCode, ...). Acquires\n * either reuse a live pinned session or spawn fresh and pin; releases\n * keep the session alive and reset its idle TTL. The strategy\n * auto-evicts after the manifest's `pinned_session.idle_timeout_ms`.\n *\n * The pin key is derived from `turnCtx` according to the manifest's\n * `pinned_session.key_scope` (default: `[conversation, operator]` —\n * different conversations and different operators each get their own\n * child process).\n *\n * Lost on process restart. DB-backed pin persistence is a follow-up\n * (track sessionId in `cli_sessions` table, then optionally fall back\n * to native-resume / transcript on restart).\n */\n\nimport type {\n AgentCliRuntimeSession,\n AgentCliRuntime,\n AgentCliStartOptions,\n} from \"../../types.js\"\nimport type { ContinuationStrategy } from \"../types.js\"\nimport { deriveKeyFromScope } from \"../types.js\"\n\ninterface PinnedEntry {\n session: AgentCliRuntimeSession\n /** Cached so retry-after-eviction can recreate without re-resolving\n * the runtime entry from outside. */\n runtime: AgentCliRuntime\n /** Cached so eviction-and-retry uses the same start options. */\n startOptions: AgentCliStartOptions\n idleTimer: ReturnType<typeof setTimeout> | null\n}\n\nconst DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000\n\nconst pins = new Map<string, PinnedEntry>()\n\nfunction clearIdleTimer(entry: PinnedEntry): void {\n if (entry.idleTimer) {\n clearTimeout(entry.idleTimer)\n entry.idleTimer = null\n }\n}\n\nfunction scheduleIdleEviction(\n key: string,\n entry: PinnedEntry,\n idleTimeoutMs: number\n): void {\n clearIdleTimer(entry)\n entry.idleTimer = setTimeout(() => {\n pins.delete(key)\n entry.session.close().catch(err => {\n console.warn(\n `[pinned-session] idle close failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n })\n console.log(\n `[pinned-session] ${key} idle ${idleTimeoutMs / 60_000}m → closed`\n )\n }, idleTimeoutMs)\n // Don't keep the event loop alive just for the idle close — the\n // child will be reaped on process exit anyway. Without `unref`\n // a stale pin would block graceful shutdown.\n entry.idleTimer.unref?.()\n}\n\nfunction evictPin(key: string): void {\n const entry = pins.get(key)\n if (!entry) return\n clearIdleTimer(entry)\n pins.delete(key)\n entry.session.close().catch(err => {\n console.warn(\n `[pinned-session] evict close failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n })\n}\n\nexport const pinnedSessionStrategy: ContinuationStrategy = {\n id: \"pinned-session\",\n\n async acquire(ctx) {\n const tuning = ctx.runtime.definition.continuation?.pinned_session\n const scope = tuning?.key_scope ?? [\"conversation\", \"operator\"]\n const key = deriveKeyFromScope(scope, ctx.turnCtx)\n const idleTimeoutMs = tuning?.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS\n\n if (key === null) {\n // No identity to pin against — fall back to per-spawn behaviour.\n // Warn so the host learns to populate turnCtx.\n console.warn(\n `[pinned-session] turnCtx has no fields matching key_scope ${JSON.stringify(scope)}; falling back to per-spawn (no pin).`\n )\n return ctx.runtime.start(ctx.startOptions)\n }\n\n const existing = pins.get(key)\n if (existing) {\n // Cancel the idle timer — this turn is reusing the pin.\n clearIdleTimer(existing)\n return existing.session\n }\n\n const session = await ctx.runtime.start(ctx.startOptions)\n const entry: PinnedEntry = {\n session,\n runtime: ctx.runtime,\n startOptions: ctx.startOptions,\n idleTimer: null,\n }\n pins.set(key, entry)\n scheduleIdleEviction(key, entry, idleTimeoutMs)\n return session\n },\n\n async release(ctx) {\n // Find the entry by identity — ReleaseContext doesn't carry `runtime`,\n // so we match by session reference. Acceptable since the pin map is small.\n let foundKey: string | null = null\n for (const [k, e] of pins) {\n if (e.session === ctx.session) {\n foundKey = k\n break\n }\n }\n\n if (!foundKey) {\n // Session wasn't pinned (per-spawn fallback path) — close it\n // like the `none` strategy would.\n await ctx.session.close()\n return\n }\n\n const entry = pins.get(foundKey)!\n const tuning = entry.runtime.definition.continuation?.pinned_session\n const idleTimeoutMs = tuning?.idle_timeout_ms ?? DEFAULT_IDLE_TIMEOUT_MS\n\n // Fatal errors → evict so the next turn re-spawns. Transient\n // errors and normal completion → reset the idle TTL and keep.\n // Cancelled (user aborted) is treated like normal completion —\n // the user wanted to stop this turn, not the whole session.\n if (ctx.outcome.kind === \"error\" && ctx.outcome.reason === \"fatal\") {\n evictPin(foundKey)\n return\n }\n\n scheduleIdleEviction(foundKey, entry, idleTimeoutMs)\n },\n}\n\n/**\n * Test helper — drop all pinned entries and clear timers. Not part\n * of the public API; exposed under `__test__` so tests can reset the\n * module's singleton state between runs.\n */\nexport const __test__ = {\n resetPins(): void {\n for (const [k] of pins) evictPin(k)\n },\n pinCount(): number {\n return pins.size\n },\n}\n","/**\n * `transcript` strategy — works for any CLI, including those with\n * `resumable: false` and ephemeral sessions.\n *\n * The driver doesn't know about Mastra memory or the host's\n * conversation log — that's the host's domain. The host supplies the\n * preamble at acquire-time via `startOptions.config.options` (the\n * convention is option id `__transcript`, see below) and the strategy\n * is otherwise identical to `none` — fresh session per acquire,\n * close on release.\n *\n * In practice the host does the prepending itself before calling\n * `runtime.start` (it controls the `message` text). This strategy\n * exists mostly as a NAMED policy choice in the manifest — declaring\n * it tells the host \"use the transcript-replay path for this CLI\"\n * without the host needing to inspect capabilities.\n *\n * Token-costly but stateless and survives API restarts.\n */\n\nimport type { ContinuationStrategy } from \"../types.js\"\n\nexport const transcriptStrategy: ContinuationStrategy = {\n id: \"transcript\",\n async acquire(ctx) {\n return ctx.runtime.start(ctx.startOptions)\n },\n async release(ctx) {\n await ctx.session.close()\n },\n}\n","/**\n * `native-resume` strategy — reattach to the agent's own session by id\n * (ACP `loadSession`, MCP equivalent, or argv-style `--resume`).\n *\n * Two-step lifecycle:\n * 1. **acquire**: look up a persisted sessionId for `turnCtx` via\n * `loadHook`. If found, pass it to `runtime.start` as\n * `resumeSessionId` so the protocol arm reattaches. If not, spawn\n * fresh — and after the session is up, capture the new id from\n * `session.sessionId` and persist it via `saveHook`.\n * 2. **release**: close the spawned process. The session lives in\n * the agent's storage layer (e.g. Claude Code's JSONL files);\n * cold-start resume on the next acquire reads from that store.\n *\n * Hooks are registered once per host process via\n * `configureNativeResume({ load, save })`. Without hooks the strategy\n * degrades to per-spawn behaviour with a one-line warning — it's not\n * fatal because the spawn still works, just without continuity.\n *\n * Requires the manifest to declare `capabilities.resumable: true`\n * AND the agent to advertise the matching protocol capability (e.g.\n * ACP `loadSession: true`). The schema enforces the manifest side at\n * validation; runtime capability mismatch surfaces from the protocol\n * arm as the agent's own error.\n */\n\nimport type { ContinuationStrategy, AcquireContext } from \"../types.js\"\nimport { deriveKeyFromScope } from \"../types.js\"\nimport type { TurnContext } from \"../../types.js\"\n\nexport interface NativeResumeHooks {\n /** Look up a persisted sessionId for the given identity scope. Return\n * undefined when no prior session exists — strategy spawns fresh. */\n load: (turnCtx: TurnContext) => Promise<string | undefined>\n /** Persist a freshly-established sessionId so the next cold start\n * can resume. Called once per \"fresh spawn\" acquire (not per turn).\n * Idempotent / upsert semantics expected on the host side. */\n save: (turnCtx: TurnContext, sessionId: string) => Promise<void>\n /** Optional: drop the persisted entry when a session is detected as\n * unresumable (agent rejected loadSession with a hard error). */\n forget?: (turnCtx: TurnContext) => Promise<void>\n}\n\nlet _hooks: NativeResumeHooks | null = null\n\n/**\n * Register the host's session-id load/save callbacks. Call once at\n * boot. Subsequent calls overwrite — useful in tests; in prod treat\n * the registration as exclusive.\n */\nexport function configureNativeResume(hooks: NativeResumeHooks): void {\n _hooks = hooks\n}\n\n/** Reset to no-hooks. Test helper; not part of public API. */\nexport function __resetNativeResumeForTests(): void {\n _hooks = null\n}\n\nexport const nativeResumeStrategy: ContinuationStrategy = {\n id: \"native-resume\",\n async acquire(ctx: AcquireContext) {\n if (!_hooks) {\n console.warn(\n \"[native-resume] no hooks registered (call configureNativeResume at boot); falling back to per-spawn — no continuity.\"\n )\n return ctx.runtime.start(ctx.startOptions)\n }\n // Use the same key-derivation as pinned-session so a host can\n // declare its scope ONCE in the manifest (`continuation.pinned_session.key_scope`)\n // and have both strategies key off the same identity. Native-resume\n // doesn't have its own key_scope today; it inherits.\n const scope =\n ctx.runtime.definition.continuation?.pinned_session?.key_scope ?? [\n \"conversation\",\n \"operator\",\n ]\n const key = deriveKeyFromScope(scope, ctx.turnCtx)\n if (key === null) {\n console.warn(\n `[native-resume] turnCtx has no fields matching key_scope ${JSON.stringify(scope)}; falling back to per-spawn (no resume).`\n )\n return ctx.runtime.start(ctx.startOptions)\n }\n\n const existingId = await _hooks.load(ctx.turnCtx).catch(err => {\n console.warn(\n `[native-resume] load hook failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n return undefined\n })\n\n let session\n let resumed = false\n if (existingId) {\n try {\n session = await ctx.runtime.start({\n ...ctx.startOptions,\n resumeSessionId: existingId,\n })\n resumed = true\n } catch (err) {\n // Most likely the agent rejected the id (session expired,\n // wiped, mismatched cwd). Drop the stale pin and spawn fresh\n // so the user gets continuity going forward instead of being\n // stuck on a dead reference.\n console.warn(\n `[native-resume] resume failed for ${key} (id=${existingId.slice(0, 12)}…), starting fresh:`,\n err instanceof Error ? err.message : err\n )\n if (_hooks.forget) {\n await _hooks.forget(ctx.turnCtx).catch(() => undefined)\n }\n session = await ctx.runtime.start(ctx.startOptions)\n }\n } else {\n session = await ctx.runtime.start(ctx.startOptions)\n }\n\n // Persist the established id when this is a NEW session (resume\n // path keeps the same id we already have, no need to re-save).\n // The runtime guarantees session.sessionId reflects the protocol\n // session id when the arm exposes it.\n if (!resumed && session.sessionId) {\n await _hooks.save(ctx.turnCtx, session.sessionId).catch(err => {\n console.warn(\n `[native-resume] save hook failed for ${key}:`,\n err instanceof Error ? err.message : err\n )\n })\n }\n return session\n },\n\n async release(ctx) {\n // The protocol session lives in the agent's own storage; closing\n // the spawned subprocess is fine — `loadSession` on the next\n // acquire reattaches via the persisted id.\n await ctx.session.close()\n },\n}\n","/**\n * Continuation strategy registry.\n *\n * Module-scoped singleton — all built-ins are registered at import\n * time, custom strategies (from adapter packages) register via\n * `registerContinuationStrategy`. The runner looks up by id;\n * unregistered ids throw at acquire-time so the caller fails fast\n * with a clear \"this strategy id isn't registered\" message.\n */\n\nimport type { ContinuationStrategyId } from \"../types.js\"\nimport type { ContinuationStrategy } from \"./types.js\"\nimport { noneStrategy } from \"./strategies/none.js\"\nimport { pinnedSessionStrategy } from \"./strategies/pinned-session.js\"\nimport { transcriptStrategy } from \"./strategies/transcript.js\"\nimport { nativeResumeStrategy } from \"./strategies/native-resume.js\"\n\nconst registry = new Map<ContinuationStrategyId, ContinuationStrategy>()\n\n/**\n * Register (or replace) a continuation strategy. Adapter packages\n * MAY register custom strategies on import — but they MUST first\n * land an AIP that opens the `ContinuationStrategyId` enum so the\n * manifest schema accepts the new id.\n */\nexport function registerContinuationStrategy(\n strategy: ContinuationStrategy\n): void {\n registry.set(strategy.id, strategy)\n}\n\nexport function getContinuationStrategy(\n id: ContinuationStrategyId\n): ContinuationStrategy {\n const s = registry.get(id)\n if (!s) {\n throw new Error(\n `[agent-cli] No continuation strategy registered for id '${id}'. Built-ins: ${Array.from(registry.keys()).join(\", \")}.`\n )\n }\n return s\n}\n\nexport function listContinuationStrategies(): ContinuationStrategyId[] {\n return Array.from(registry.keys())\n}\n\n// Register built-ins eagerly at module load so any importer of the\n// registry sees them. Custom strategies layer on top.\nregisterContinuationStrategy(noneStrategy)\nregisterContinuationStrategy(pinnedSessionStrategy)\nregisterContinuationStrategy(transcriptStrategy)\nregisterContinuationStrategy(nativeResumeStrategy)\n","/**\n * @agentproto/driver-agent-cli — AIP-45 AGENT-CLI.md `defineAgentCli`\n * reference impl.\n *\n * Spec: https://agentproto.sh/docs/aip-45\n *\n * Authoring paths:\n * - TS: `defineAgentCli({...})` → `AgentCliHandle`\n * - MD: `parseAgentCliManifest(src) → agentCliFromManifest({...})` → `AgentCliHandle`\n *\n * Runtime: `createAgentCliRuntime(handle)` → spawn binary, dispatch\n * turns through the protocol arm (acp / mcp / proprietary), normalise\n * events to {@link StreamEvent}.\n */\n\nexport const SPEC_NAME = \"agentcli-interactive/v1\" as const\nexport const SPEC_VERSION = \"0.1.0-alpha\" as const\n\nexport {\n defineAgentCli,\n createAgentCliRuntime,\n} from \"./define-agent-cli.js\"\n// The live-session control surface (setModel/setSessionMode/setEffort +\n// the availableConfigOptions/availableModes/currentModeId read-surface),\n// factored out of `createAgentCliRuntime` so a host that builds its OWN\n// `AgentCliRuntimeSession` over another transport (sandbox-resident,\n// tunnel-resident) delegates to the same implementation instead of\n// hand-copying it and drifting on the next interface change.\nexport {\n createArmSessionControls,\n applyModelCommand,\n promptTurn,\n type ArmSessionControls,\n} from \"./session-controls.js\"\n// Agent CLI → generic model port: one executor backing every prompt→completion\n// seam (report writer, corpus distiller, Mastra judgment step) over any AIP-45 CLI.\nexport {\n makeAgentCliModel,\n resolveCliEnv,\n composePrompt,\n datasetPreamble,\n PROVIDER_KEY_ENV,\n} from \"./model.js\"\nexport type {\n ModelLike,\n FileReadingOptions,\n AgentCliModelOptions,\n} from \"./model.js\"\n// Exposed so callers can build a sandbox-resident `AgentCliRuntime`\n// against the same protocol layer the host-spawn factory uses, by\n// passing a `ChildProcess`-shaped duck whose stdio is bridged to a\n// remote subprocess (e2b sandbox, ssh, etc.). See guilde's\n// `cli-session-spawn/sandbox-runtime.ts` for a worked example.\nexport {\n createAcpProtocolArm,\n autoAllowPermissionHandler,\n planModePermissionHandler,\n type AcpPermissionHandler,\n type AcpPermissionOutcome,\n type AcpPermissionRequestParams,\n} from \"./protocol/acp-client.js\"\nexport {\n createPrintSession,\n mapMastraEvent,\n createMastraMapperState,\n type PrintArmOptions,\n type MastraMapperState,\n} from \"./protocol/print-arm.js\"\n// Generic proprietary-protocol arm loader — dynamically imports the\n// manifest's `adapter` package. Exported so proprietary adapter packages\n// (and their tests) can drive the same loader `createAgentCliRuntime`\n// uses, without duplicating the load-and-validate logic.\nexport {\n createProprietaryProtocolArm,\n type ProprietaryProtocolOptions,\n} from \"./protocol/proprietary.js\"\nexport {\n agentCliFrontmatterSchema,\n runtimeConfigSchema,\n type AgentCliFrontmatter,\n type RuntimeConfigInput,\n} from \"./schema.js\"\nexport {\n toFileBasedMcpServers,\n type MastracodeMcpServerConfig,\n} from \"./mcp-servers.js\"\nexport {\n composeSpawn,\n resolveContinuationStrategy,\n RuntimeConfigError,\n type ComposedSpawn,\n} from \"./manifest/compose.js\"\n// Legacy AIP-45 mode-id classification (SPEC §3.4a) — the single source the\n// daemon's `decomposeMode` shim reuses so the route/posture id set never drifts.\nexport {\n LEGACY_GATEWAY_MODE_IDS,\n LEGACY_POSTURE_MODE_IDS,\n inferLegacyModeKind,\n isLegacyExtractedModeId,\n} from \"./legacy-modes.js\"\nexport {\n registerContinuationStrategy,\n getContinuationStrategy,\n listContinuationStrategies,\n} from \"./continuation/registry.js\"\nexport {\n configureNativeResume,\n type NativeResumeHooks,\n} from \"./continuation/strategies/native-resume.js\"\nexport {\n deriveKeyFromScope,\n type ContinuationStrategy,\n type AcquireContext,\n type ReleaseContext,\n type ReleaseOutcome,\n} from \"./continuation/types.js\"\nexport type {\n AgentCliDefinition,\n AgentCliHandle,\n AgentCliProtocol,\n AgentCliSessionMode,\n AgentCliClient,\n AgentCliConnectOptions,\n AgentCliRuntime,\n AgentCliRuntimeSession,\n AgentCliStartOptions,\n AgentCliCapabilities,\n AgentCliInstallMethod,\n AgentCliVersionCheck,\n AgentCliAuth,\n AgentCliSetupStep,\n AgentCliSetupSkipIf,\n AgentCliSetupPersist,\n AgentCliSession,\n AgentCliModels,\n AgentCliModelEntry,\n AgentCliMcpBlock,\n AgentCliMode,\n AgentCliRouteSelection,\n AgentCliOption,\n AgentCliOptionType,\n AgentCliPresetDeclaration,\n AgentCliContinuation,\n AgentCliPinnedSessionTuning,\n AgentCliPrintConfig,\n ContinuationStrategyId,\n ContinuationKeyScope,\n RuntimeConfig,\n TurnContext,\n StreamEvent,\n // Result vocabularies for the three mid-session switches, and the two\n // read-surface element types. Exported so a host can name what\n // `AgentCliRuntimeSession`'s members hand back.\n SetModelResult,\n SetSessionModeResult,\n SetEffortResult,\n SessionConfigOption,\n SessionMode,\n} from \"./types.js\"\n"]}
|
package/dist/manifest/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { l as AgentCliFrontmatter, A as AgentCliHandle } from '../schema-
|
|
2
|
-
export {
|
|
1
|
+
import { l as AgentCliFrontmatter, A as AgentCliHandle } from '../schema-PGrcCZqt.js';
|
|
2
|
+
export { I as agentCliFrontmatterSchema } from '../schema-PGrcCZqt.js';
|
|
3
3
|
import '@agentproto/acp';
|
|
4
4
|
import '@agentproto/acp/client';
|
|
5
|
+
import '@agentproto/command-sandbox';
|
|
5
6
|
import 'zod';
|
|
6
7
|
|
|
7
8
|
/**
|
package/dist/manifest/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { agentCliFrontmatterSchema, defineAgentCli } from '../chunk-
|
|
2
|
-
export { agentCliFrontmatterSchema } from '../chunk-
|
|
1
|
+
import { agentCliFrontmatterSchema, defineAgentCli } from '../chunk-QL3CS6E4.mjs';
|
|
2
|
+
export { agentCliFrontmatterSchema } from '../chunk-QL3CS6E4.mjs';
|
|
3
3
|
import matter from 'gray-matter';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AcpMcpServer, StreamEvent, AcpPermissionResolution } from '@agentproto/acp';
|
|
2
2
|
import { SessionConfigOption, SessionMode } from '@agentproto/acp/client';
|
|
3
|
+
import { SandboxMode } from '@agentproto/command-sandbox';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -65,8 +66,21 @@ interface AgentCliAuth {
|
|
|
65
66
|
*/
|
|
66
67
|
interface AgentCliAuthSubscription {
|
|
67
68
|
/** Env var SET to the resolved subscription credential (the OAuth/bearer
|
|
68
|
-
* token).
|
|
69
|
-
|
|
69
|
+
* token). Omitted for an {@link external} (file-based) subscription — that
|
|
70
|
+
* form injects NOTHING, so there is no var to set. */
|
|
71
|
+
setEnv?: string;
|
|
72
|
+
/**
|
|
73
|
+
* File-based subscription: the CLI reads its OWN local-login file
|
|
74
|
+
* (`~/.codex/auth.json`, `~/.gemini/oauth_creds.json`, …) rather than a
|
|
75
|
+
* bearer the runtime injects. When true, the runtime SETS no credential env
|
|
76
|
+
* var (there is none) — it only SCRUBS the conflicting api-key vars
|
|
77
|
+
* ({@link conflictEnv} + the provider's api-key var) so a leftover key can't
|
|
78
|
+
* silently flip the CLI to api-key billing, and the host verifies the login
|
|
79
|
+
* is present (fail-loud) before the spawn. Money-safe by construction: an
|
|
80
|
+
* OAuth bearer is NEVER injected into an api-key channel because no bearer is
|
|
81
|
+
* injected at all. Mutually exclusive with {@link setEnv}.
|
|
82
|
+
*/
|
|
83
|
+
external?: boolean;
|
|
70
84
|
/**
|
|
71
85
|
* Sibling billing-credential env vars the SAME consumer also honors and
|
|
72
86
|
* that must therefore be scrubbed in EVERY resolved mode except when the
|
|
@@ -240,7 +254,7 @@ interface AgentCliModels {
|
|
|
240
254
|
* turn after `newSession` and drain it. The agent's reply is checked
|
|
241
255
|
* for a "switched" acknowledgement; a failure is warned, not fatal.
|
|
242
256
|
* - "arg" — this CLI takes its model as a CLI argument, not an ACP
|
|
243
|
-
* session config or control turn
|
|
257
|
+
* session config or control turn.
|
|
244
258
|
* The requested model is composed into `bin_args` at spawn time via
|
|
245
259
|
* `bin_args_template` (below) — no post-`newSession` ACP call is
|
|
246
260
|
* made at all.
|
|
@@ -274,6 +288,15 @@ interface AgentCliCapabilities {
|
|
|
274
288
|
* Paired with the daemon's POST /files/upload route.
|
|
275
289
|
*/
|
|
276
290
|
file_attach?: boolean;
|
|
291
|
+
/**
|
|
292
|
+
* The adapter has a verified native CLI resume path into a real
|
|
293
|
+
* terminal / TUI session (e.g. `claude --resume <id>` or
|
|
294
|
+
* `hermes --resume <id> --tui`). When true, the daemon MAY offer
|
|
295
|
+
* provider-native terminal restart for this adapter. ACP-level
|
|
296
|
+
* resumability (`resumable`) alone does NOT imply this — a JSON-RPC
|
|
297
|
+
* session id is not a native TUI resume. Default false.
|
|
298
|
+
*/
|
|
299
|
+
nativeTerminalResume?: boolean;
|
|
277
300
|
}
|
|
278
301
|
/**
|
|
279
302
|
* Support status for a declared mode. Absent ⇒ treated as `"active"`.
|
|
@@ -558,6 +581,13 @@ interface AgentCliPrintConfig {
|
|
|
558
581
|
*/
|
|
559
582
|
event_schema?: "claude-stream-json" | "mastra-jsonl";
|
|
560
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* How a spawn's ROUTE (billing endpoint / gateway) relates to the chosen
|
|
586
|
+
* model — the UI-facing route-choice axis a capability-derived spawn
|
|
587
|
+
* drill-down dispatches off (AIP-45 launch-menu drill-down, WP1). See
|
|
588
|
+
* {@link AgentCliDefinition.routeSelection}.
|
|
589
|
+
*/
|
|
590
|
+
type AgentCliRouteSelection = "free" | "derived-from-model";
|
|
561
591
|
interface AgentCliDefinition {
|
|
562
592
|
name: string;
|
|
563
593
|
id: string;
|
|
@@ -599,6 +629,57 @@ interface AgentCliDefinition {
|
|
|
599
629
|
* Only the Claude adapters set it. See {@link AgentCliAuthSubscription}.
|
|
600
630
|
*/
|
|
601
631
|
authSubscription?: AgentCliAuthSubscription;
|
|
632
|
+
/**
|
|
633
|
+
* Declares how THIS adapter receives a GATEWAY-routed bearer credential —
|
|
634
|
+
* distinct from a gateway preset's own `keyEnv`
|
|
635
|
+
* (`@agentproto/provider-presets` — the var the OPERATOR's `providers.json`
|
|
636
|
+
* store is keyed under) and from {@link authSubscription}'s `setEnv` (this
|
|
637
|
+
* adapter's OWN native/subscription bearer, unrelated to a third-party
|
|
638
|
+
* gateway). When a `route.gateway` preset/custom route resolves AND this is
|
|
639
|
+
* declared, the runtime's `resolveAuthSpec` injects the resolved gateway
|
|
640
|
+
* credential into `setEnv` here INSTEAD of the preset's `keyEnv` — e.g.
|
|
641
|
+
* claude-code/claude-sdk read a gateway bearer via `ANTHROPIC_AUTH_TOKEN`
|
|
642
|
+
* (the Anthropic SDK's `Authorization: Bearer` var), never a preset's own
|
|
643
|
+
* conventional key-env name (`OPENROUTER_API_KEY`, `MOONSHOT_API_KEY`, …).
|
|
644
|
+
* Omit when the adapter reads a gateway credential directly off the
|
|
645
|
+
* preset's own `keyEnv` (e.g. hermes, which genuinely reads
|
|
646
|
+
* `OPENROUTER_API_KEY`) — the fix is adapter-driven, never a blanket
|
|
647
|
+
* rename of every adapter's gateway var.
|
|
648
|
+
*/
|
|
649
|
+
gatewayAuth?: {
|
|
650
|
+
setEnv: string;
|
|
651
|
+
};
|
|
652
|
+
/**
|
|
653
|
+
* True when the adapter's api-key auth is derived from the requested model
|
|
654
|
+
* rather than a fixed `provider` (e.g. `pi`, `opencode`). When set, the
|
|
655
|
+
* runtime resolver allows `"api-key"` mode on the model-derived direct
|
|
656
|
+
* endpoint and includes it in eligibility manifests for by-model routers.
|
|
657
|
+
*/
|
|
658
|
+
modelDerivedApiKey?: boolean;
|
|
659
|
+
/**
|
|
660
|
+
* How this adapter's spawn ROUTE (billing endpoint / gateway) relates to
|
|
661
|
+
* the chosen model — the UI-facing route-choice axis a capability-derived
|
|
662
|
+
* spawn drill-down dispatches off (AIP-45 launch-menu drill-down, WP1):
|
|
663
|
+
*
|
|
664
|
+
* - `"free"` (default) — the same model can take different routes; the
|
|
665
|
+
* route is an independent user choice. The Claude adapters route to a
|
|
666
|
+
* gateway by pre-wiring `ANTHROPIC_BASE_URL` through a mode, so e.g.
|
|
667
|
+
* `claude-opus-4-8` can go direct-Anthropic OR via any gateway.
|
|
668
|
+
* - `"derived-from-model"` — the endpoint falls out of the model id's
|
|
669
|
+
* own vendor prefix, so there is nothing independent to choose. A
|
|
670
|
+
* by-model router (`hermes`, `mastracode`, `pi`, `opencode`) reads the
|
|
671
|
+
* provider straight off the `<provider>/<id>` prefix; picking the model
|
|
672
|
+
* already fixes the route, so the connection step is a read-only badge
|
|
673
|
+
* rather than a choice.
|
|
674
|
+
*
|
|
675
|
+
* Absent ⇒ `"free"` (back-compat: an adapter that never declared this axis
|
|
676
|
+
* keeps presenting a route choice). This is the ROUTE-CHOICE axis and is
|
|
677
|
+
* DISTINCT from {@link modelDerivedApiKey} (the AUTH-derivation axis, #553):
|
|
678
|
+
* an adapter can derive its route from the model without deriving its
|
|
679
|
+
* api-key from it, and vice versa. Where both apply they agree — a
|
|
680
|
+
* model-derived-auth by-model router is also route-derived.
|
|
681
|
+
*/
|
|
682
|
+
routeSelection?: AgentCliRouteSelection;
|
|
602
683
|
/**
|
|
603
684
|
* When the runtime billing-auth resolver ENGAGES credential injection:
|
|
604
685
|
* - `"when-configured"` (default) — only when an operator explicitly set
|
|
@@ -978,6 +1059,43 @@ interface AgentCliStartOptions {
|
|
|
978
1059
|
* this driver injects nothing and runs ambient.
|
|
979
1060
|
*/
|
|
980
1061
|
auth?: ResolvedAuthSpec;
|
|
1062
|
+
/**
|
|
1063
|
+
* Decomposed posture axis (SPEC §3.4a) — what the agent may DO, in the
|
|
1064
|
+
* agentproto-canonical vocabulary (`"plan"`, `"accept-edits"`, `"bypass"`,
|
|
1065
|
+
* `"read-only"`, `"default"`). Applied at spawn-time via the adapter's
|
|
1066
|
+
* existing mechanism (e.g. claude-code's CLAUDE_CONFIG_DIR permission
|
|
1067
|
+
* settings), independently of a legacy `config.mode`. When undefined, the
|
|
1068
|
+
* adapter spawns in its own default posture.
|
|
1069
|
+
*/
|
|
1070
|
+
posture?: string;
|
|
1071
|
+
/**
|
|
1072
|
+
* Decomposed contextProfile axis (SPEC §3.1) — what enters context. When it
|
|
1073
|
+
* matches a manifest-declared mode with `kind: "context"` (e.g. claude-code's
|
|
1074
|
+
* `"lean"`), that mode's env/argv patches are applied at spawn. Distinct from
|
|
1075
|
+
* both `posture` and legacy `config.mode` — each axis is independent.
|
|
1076
|
+
*/
|
|
1077
|
+
contextProfile?: string;
|
|
1078
|
+
/**
|
|
1079
|
+
* OS-level confinement for the spawned child itself (macOS Seatbelt /
|
|
1080
|
+
* Linux bubblewrap, `@agentproto/command-sandbox`) — confines the
|
|
1081
|
+
* adapter's own process tree, unlike `posture`/`contextProfile` which
|
|
1082
|
+
* only shape what the adapter is TOLD to do. This is a SEPARATE axis
|
|
1083
|
+
* from AIP-36 `sandbox` (the remote-box session provider,
|
|
1084
|
+
* `resolveSandboxProvider`/`SandboxProviderHandle` in
|
|
1085
|
+
* `@agentproto/runtime`): that boots a whole nested daemon on a
|
|
1086
|
+
* different machine/box; this wraps THIS host's spawn argv so even an
|
|
1087
|
+
* in-process Bash tool the ACP permission seam can't see is denied
|
|
1088
|
+
* out-of-workspace reads/writes (and, under `"strict"`, network).
|
|
1089
|
+
* Undefined ⇒ falls back to the workspace's `.agentproto/
|
|
1090
|
+
* command-sandbox.json` `adapterSpawn` key (see `wrapAgentCliSpawn`'s
|
|
1091
|
+
* doc), or stays unconfined if that's unset too — unchanged behaviour
|
|
1092
|
+
* for every caller that never engages this axis at all. `"workspace"`/
|
|
1093
|
+
* `"strict"` with no backend available for this platform is a
|
|
1094
|
+
* FAIL-CLOSED refusal to spawn, mirroring `command_execute`'s own
|
|
1095
|
+
* fail-closed contract in `@agentproto/runtime`'s `command-tools.ts` —
|
|
1096
|
+
* see `define-agent-cli.ts` / `print-arm.ts` for where this is applied.
|
|
1097
|
+
*/
|
|
1098
|
+
commandSandbox?: SandboxMode;
|
|
981
1099
|
}
|
|
982
1100
|
/**
|
|
983
1101
|
* The resolved billing-auth spec the runtime hands the driver — see
|
|
@@ -990,8 +1108,15 @@ interface ResolvedAuthSpec {
|
|
|
990
1108
|
/** The resolved secret value for `mode`, or absent when nothing resolved
|
|
991
1109
|
* (⇒ fail-fast on engage). Never read ambiently. */
|
|
992
1110
|
credential?: string;
|
|
993
|
-
/** Env var SET to `credential` on engage.
|
|
1111
|
+
/** Env var SET to `credential` on engage. Empty string for an
|
|
1112
|
+
* {@link externalCredential} subscription (nothing is set). */
|
|
994
1113
|
setEnv: string;
|
|
1114
|
+
/** File-based subscription (see `AgentCliAuthSubscription.external`): the CLI
|
|
1115
|
+
* reads its OWN local-login file, so the driver injects NO credential — it
|
|
1116
|
+
* only applies {@link unsetEnv} (the api-key scrub) and does NOT fail-fast on
|
|
1117
|
+
* a missing `credential` (there deliberately is none). Money-safe: no bearer
|
|
1118
|
+
* ever reaches an env var. Absent/false ⇒ today's inject-a-credential path. */
|
|
1119
|
+
externalCredential?: boolean;
|
|
995
1120
|
/** Conflicting billing-credential (and, in native mode, gateway-hygiene)
|
|
996
1121
|
* env vars DELETED on engage — unless this spawn's own mode/option patch
|
|
997
1122
|
* explicitly set the key. */
|
|
@@ -1011,6 +1136,17 @@ interface ResolvedAuthSpec {
|
|
|
1011
1136
|
* `defaults.adapters.<slug>.auth` block. Never used to authenticate —
|
|
1012
1137
|
* only read by the fail-fast message. */
|
|
1013
1138
|
ignoredApiKeyInStore?: boolean;
|
|
1139
|
+
/** Present ONLY when the runtime resolved an explicit gateway route (a
|
|
1140
|
+
* preset/custom route) — the `base_url` it also routes into the adapter's
|
|
1141
|
+
* base_url option. Its PRESENCE is the driver's signal that this api-key
|
|
1142
|
+
* credential is COUPLED to that gateway base_url (they were resolved
|
|
1143
|
+
* together), so billing-auth must engage even though ANTHROPIC_BASE_URL is
|
|
1144
|
+
* already in the spawn env — distinguishing it from a base_url set MANUALLY
|
|
1145
|
+
* via option with a native credential (no baseUrl), where engaging would
|
|
1146
|
+
* leak a native credential to a foreign host. Never set for native/
|
|
1147
|
+
* subscription specs. The driver reads only its presence, not its value
|
|
1148
|
+
* (the value reaches the child via the base_url option). */
|
|
1149
|
+
baseUrl?: string;
|
|
1014
1150
|
}
|
|
1015
1151
|
/**
|
|
1016
1152
|
* Operator-side runtime configuration. Mirrors the `runtime.config`
|
|
@@ -1318,10 +1454,19 @@ declare const agentCliFrontmatterSchema: z.ZodObject<{
|
|
|
1318
1454
|
}, z.core.$strict>>;
|
|
1319
1455
|
provider: z.ZodOptional<z.ZodString>;
|
|
1320
1456
|
authSubscription: z.ZodOptional<z.ZodObject<{
|
|
1321
|
-
setEnv: z.ZodString
|
|
1457
|
+
setEnv: z.ZodOptional<z.ZodString>;
|
|
1458
|
+
external: z.ZodOptional<z.ZodBoolean>;
|
|
1322
1459
|
conflictEnv: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1323
1460
|
unsetEnvAdd: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1324
1461
|
}, z.core.$strict>>;
|
|
1462
|
+
gatewayAuth: z.ZodOptional<z.ZodObject<{
|
|
1463
|
+
setEnv: z.ZodString;
|
|
1464
|
+
}, z.core.$strict>>;
|
|
1465
|
+
modelDerivedApiKey: z.ZodOptional<z.ZodBoolean>;
|
|
1466
|
+
routeSelection: z.ZodOptional<z.ZodEnum<{
|
|
1467
|
+
free: "free";
|
|
1468
|
+
"derived-from-model": "derived-from-model";
|
|
1469
|
+
}>>;
|
|
1325
1470
|
authEnforce: z.ZodOptional<z.ZodEnum<{
|
|
1326
1471
|
always: "always";
|
|
1327
1472
|
"when-configured": "when-configured";
|
|
@@ -1397,6 +1542,7 @@ declare const agentCliFrontmatterSchema: z.ZodObject<{
|
|
|
1397
1542
|
multimodal: z.ZodOptional<z.ZodBoolean>;
|
|
1398
1543
|
resumable: z.ZodOptional<z.ZodBoolean>;
|
|
1399
1544
|
bidirectional: z.ZodOptional<z.ZodBoolean>;
|
|
1545
|
+
nativeTerminalResume: z.ZodOptional<z.ZodBoolean>;
|
|
1400
1546
|
file_attach: z.ZodOptional<z.ZodBoolean>;
|
|
1401
1547
|
}, z.core.$strict>>;
|
|
1402
1548
|
modes: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1513,4 +1659,4 @@ declare const runtimeConfigSchema: z.ZodObject<{
|
|
|
1513
1659
|
}, z.core.$strict>;
|
|
1514
1660
|
type RuntimeConfigInput = z.infer<typeof runtimeConfigSchema>;
|
|
1515
1661
|
|
|
1516
|
-
export { type AgentCliHandle as A, type
|
|
1662
|
+
export { type AgentCliHandle as A, type AgentCliSetupSkipIf as B, type ContinuationStrategyId as C, type AgentCliSetupStep as D, type AgentCliVersionCheck as E, type RuntimeConfigInput as F, type SetEffortResult as G, type SetSessionModeResult as H, agentCliFrontmatterSchema as I, runtimeConfigSchema as J, type RuntimeConfig as R, type SetModelResult as S, type TurnContext as T, type AgentCliRuntime as a, type AgentCliDefinition as b, type AgentCliRuntimeSession as c, type AgentCliClient as d, type AgentCliPrintConfig as e, type AgentCliStartOptions as f, type ContinuationKeyScope as g, type AgentCliAuth as h, type AgentCliCapabilities as i, type AgentCliConnectOptions as j, type AgentCliContinuation as k, type AgentCliFrontmatter as l, type AgentCliInstallMethod as m, type AgentCliMcpBlock as n, type AgentCliMode as o, type AgentCliModelEntry as p, type AgentCliModels as q, type AgentCliOption as r, type AgentCliOptionType as s, type AgentCliPinnedSessionTuning as t, type AgentCliPresetDeclaration as u, type AgentCliProtocol as v, type AgentCliRouteSelection as w, type AgentCliSession as x, type AgentCliSessionMode as y, type AgentCliSetupPersist as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/driver-agent-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "@agentproto/driver-agent-cli — AIP-45 AGENT-CLI.md reference implementation. Multi-protocol runner that loads an AGENT-CLI.md manifest, spawns the binary, and dispatches turns through an ACP / MCP / proprietary arm. ACP arm delegates to @agentproto/acp; emits the canonical StreamEvent taxonomy regardless of underlying protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentproto",
|
|
@@ -53,8 +53,9 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"gray-matter": "^4.0.3",
|
|
55
55
|
"zod": "^4.4.3",
|
|
56
|
-
"@agentproto/
|
|
57
|
-
"@agentproto/define-doctype": "0.1.1"
|
|
56
|
+
"@agentproto/command-sandbox": "0.2.0",
|
|
57
|
+
"@agentproto/define-doctype": "0.1.1",
|
|
58
|
+
"@agentproto/acp": "0.7.0"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"@types/node": "^25.6.2",
|