@chances-ai/wire 24.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/rpc/acp/adapter.d.ts +32 -0
  2. package/dist/rpc/acp/adapter.d.ts.map +1 -0
  3. package/dist/rpc/acp/adapter.js +185 -0
  4. package/dist/rpc/acp/adapter.js.map +1 -0
  5. package/dist/rpc/acp/engine-driver.d.ts +128 -0
  6. package/dist/rpc/acp/engine-driver.d.ts.map +1 -0
  7. package/dist/rpc/acp/engine-driver.js +550 -0
  8. package/dist/rpc/acp/engine-driver.js.map +1 -0
  9. package/dist/rpc/acp/event-map.d.ts +22 -0
  10. package/dist/rpc/acp/event-map.d.ts.map +1 -0
  11. package/dist/rpc/acp/event-map.js +205 -0
  12. package/dist/rpc/acp/event-map.js.map +1 -0
  13. package/dist/rpc/acp/load-sdk.d.ts +3 -0
  14. package/dist/rpc/acp/load-sdk.d.ts.map +1 -0
  15. package/dist/rpc/acp/load-sdk.js +24 -0
  16. package/dist/rpc/acp/load-sdk.js.map +1 -0
  17. package/dist/rpc/acp/workspace-query.d.ts +41 -0
  18. package/dist/rpc/acp/workspace-query.d.ts.map +1 -0
  19. package/dist/rpc/acp/workspace-query.js +89 -0
  20. package/dist/rpc/acp/workspace-query.js.map +1 -0
  21. package/dist/rpc/driver.d.ts +42 -0
  22. package/dist/rpc/driver.d.ts.map +1 -0
  23. package/dist/rpc/driver.js +7 -0
  24. package/dist/rpc/driver.js.map +1 -0
  25. package/dist/rpc/event-map.d.ts +8 -0
  26. package/dist/rpc/event-map.d.ts.map +1 -0
  27. package/dist/rpc/event-map.js +91 -0
  28. package/dist/rpc/event-map.js.map +1 -0
  29. package/dist/rpc/index.d.ts +13 -0
  30. package/dist/rpc/index.d.ts.map +1 -0
  31. package/dist/rpc/index.js +18 -0
  32. package/dist/rpc/index.js.map +1 -0
  33. package/dist/rpc/lines.d.ts +2 -0
  34. package/dist/rpc/lines.d.ts.map +1 -0
  35. package/dist/rpc/lines.js +24 -0
  36. package/dist/rpc/lines.js.map +1 -0
  37. package/dist/rpc/protocol.d.ts +315 -0
  38. package/dist/rpc/protocol.d.ts.map +1 -0
  39. package/dist/rpc/protocol.js +70 -0
  40. package/dist/rpc/protocol.js.map +1 -0
  41. package/dist/rpc/rpc-server.d.ts +56 -0
  42. package/dist/rpc/rpc-server.d.ts.map +1 -0
  43. package/dist/rpc/rpc-server.js +305 -0
  44. package/dist/rpc/rpc-server.js.map +1 -0
  45. package/dist/rpc/stdout-guard.d.ts +5 -0
  46. package/dist/rpc/stdout-guard.d.ts.map +1 -0
  47. package/dist/rpc/stdout-guard.js +31 -0
  48. package/dist/rpc/stdout-guard.js.map +1 -0
  49. package/dist/rpc/writer.d.ts +34 -0
  50. package/dist/rpc/writer.d.ts.map +1 -0
  51. package/dist/rpc/writer.js +85 -0
  52. package/dist/rpc/writer.js.map +1 -0
  53. package/dist/serve/acp-session-host.d.ts +120 -0
  54. package/dist/serve/acp-session-host.d.ts.map +1 -0
  55. package/dist/serve/acp-session-host.js +276 -0
  56. package/dist/serve/acp-session-host.js.map +1 -0
  57. package/dist/serve/auth.d.ts +21 -0
  58. package/dist/serve/auth.d.ts.map +1 -0
  59. package/dist/serve/auth.js +58 -0
  60. package/dist/serve/auth.js.map +1 -0
  61. package/dist/serve/highlight.d.ts +25 -0
  62. package/dist/serve/highlight.d.ts.map +1 -0
  63. package/dist/serve/highlight.js +28 -0
  64. package/dist/serve/highlight.js.map +1 -0
  65. package/dist/serve/index.d.ts +14 -0
  66. package/dist/serve/index.d.ts.map +1 -0
  67. package/dist/serve/index.js +23 -0
  68. package/dist/serve/index.js.map +1 -0
  69. package/dist/serve/pairing.d.ts +25 -0
  70. package/dist/serve/pairing.d.ts.map +1 -0
  71. package/dist/serve/pairing.js +10 -0
  72. package/dist/serve/pairing.js.map +1 -0
  73. package/dist/serve/relay-frames.d.ts +29 -0
  74. package/dist/serve/relay-frames.d.ts.map +1 -0
  75. package/dist/serve/relay-frames.js +54 -0
  76. package/dist/serve/relay-frames.js.map +1 -0
  77. package/dist/serve/relay.d.ts +146 -0
  78. package/dist/serve/relay.d.ts.map +1 -0
  79. package/dist/serve/relay.js +475 -0
  80. package/dist/serve/relay.js.map +1 -0
  81. package/dist/serve/replay-hub.d.ts +102 -0
  82. package/dist/serve/replay-hub.d.ts.map +1 -0
  83. package/dist/serve/replay-hub.js +176 -0
  84. package/dist/serve/replay-hub.js.map +1 -0
  85. package/dist/serve/tls.d.ts +20 -0
  86. package/dist/serve/tls.d.ts.map +1 -0
  87. package/dist/serve/tls.js +64 -0
  88. package/dist/serve/tls.js.map +1 -0
  89. package/dist/serve/ws-transport.d.ts +64 -0
  90. package/dist/serve/ws-transport.d.ts.map +1 -0
  91. package/dist/serve/ws-transport.js +92 -0
  92. package/dist/serve/ws-transport.js.map +1 -0
  93. package/package.json +42 -0
@@ -0,0 +1,32 @@
1
+ import type { Agent, AgentSideConnection, InitializeRequest, InitializeResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, CancelNotification } from "@agentclientprotocol/sdk";
2
+ import type { EngineHost } from "../driver.js";
3
+ /** The slice of `AgentSideConnection` the adapter drives. */
4
+ type AcpConnection = Pick<AgentSideConnection, "sessionUpdate" | "requestPermission" | "extNotification" | "signal">;
5
+ export declare class AcpAgent implements Partial<Agent> {
6
+ private readonly host;
7
+ private readonly connection;
8
+ private session;
9
+ /** Serialises sessionUpdate sends so bus-event order is preserved on the
10
+ * wire (the bus handler is sync; sessionUpdate is async). */
11
+ private sendChain;
12
+ constructor(host: EngineHost, connection: AcpConnection);
13
+ initialize(params: InitializeRequest): Promise<InitializeResponse>;
14
+ authenticate(): Promise<Record<string, never>>;
15
+ newSession(_params: NewSessionRequest): Promise<NewSessionResponse>;
16
+ prompt(params: PromptRequest): Promise<PromptResponse>;
17
+ cancel(params: CancelNotification): Promise<void>;
18
+ /** Tear down the active session subscription (called on connection close). */
19
+ dispose(): void;
20
+ private makeResolver;
21
+ }
22
+ export interface RunAcpOptions {
23
+ host: EngineHost;
24
+ input: ReadableStream<Uint8Array>;
25
+ output: WritableStream<Uint8Array>;
26
+ }
27
+ /** Boot the ACP agent over the given Web streams and resolve when the
28
+ * connection closes. Returns 0 on clean close, 2 when the SDK peer is absent
29
+ * (the caller prints install guidance). */
30
+ export declare function runAcp(opts: RunAcpOptions): Promise<number>;
31
+ export {};
32
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/rpc/acp/adapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,KAAK,EACL,mBAAmB,EAEnB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,cAAc,CAAC;AAI5D,6DAA6D;AAC7D,KAAK,aAAa,GAAG,IAAI,CAAC,mBAAmB,EAAE,eAAe,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,QAAQ,CAAC,CAAC;AAgBrH,qBAAa,QAAS,YAAW,OAAO,CAAC,KAAK,CAAC;IAO3C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAP7B,OAAO,CAAC,OAAO,CAA8B;IAC7C;iEAC6D;IAC7D,OAAO,CAAC,SAAS,CAAoC;gBAGlC,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,aAAa;IAGtC,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAkBlE,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAI9C,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA+BnE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAiCtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,8EAA8E;IAC9E,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,YAAY;CA2BrB;AASD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAClC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CACpC;AAED;;2CAE2C;AAC3C,wBAAsB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBjE"}
@@ -0,0 +1,185 @@
1
+ // ACP (Zed Agent Client Protocol) adapter — the SECOND transport over the
2
+ // same `EngineHost` seam (codex C1/C11). Implements the ACP `Agent` interface
3
+ // via `@agentclientprotocol/sdk`'s `AgentSideConnection` over `ndJsonStream`.
4
+ // One active session per process (Round-1 Q3): a second `newSession` before
5
+ // the first closes is refused. Permission asks route to ACP
6
+ // `connection.requestPermission` and collapse to the engine's
7
+ // `PermissionResolver` (allow_once → no-cache, allow_always → cache).
8
+ //
9
+ // `import type` for all SDK types (erased at compile → safe when the optional
10
+ // peer is absent); runtime classes/values come from the loaded module.
11
+ import { CancellationTokenSource, createId } from "@chances-ai/runtime";
12
+ import { chancesEventMeta, mapEventToAcp } from "./event-map.js";
13
+ import { loadAcpSdk } from "./load-sdk.js";
14
+ const PERMISSION_OPTIONS = [
15
+ { optionId: "allow_once", kind: "allow_once", name: "Allow once" },
16
+ { optionId: "allow_always", kind: "allow_always", name: "Allow always" },
17
+ { optionId: "reject_once", kind: "reject_once", name: "Reject" },
18
+ { optionId: "reject_always", kind: "reject_always", name: "Reject always" },
19
+ ];
20
+ export class AcpAgent {
21
+ host;
22
+ connection;
23
+ session = null;
24
+ /** Serialises sessionUpdate sends so bus-event order is preserved on the
25
+ * wire (the bus handler is sync; sessionUpdate is async). */
26
+ sendChain = Promise.resolve();
27
+ constructor(host, connection) {
28
+ this.host = host;
29
+ this.connection = connection;
30
+ }
31
+ async initialize(params) {
32
+ return {
33
+ // Echo the client's protocol version (the SDK validates compatibility).
34
+ protocolVersion: params.protocolVersion,
35
+ // Q3: advertise ONLY what we actually support. No loadSession / fork /
36
+ // list / resume until real multi-session ownership exists.
37
+ agentCapabilities: { loadSession: false },
38
+ // (M3) Same fidelity advertisement as the relay's `AcpEngineDriver` so a
39
+ // chances-aware ACP client reads `_meta.chances`; a plain client (Zed)
40
+ // ignores it. `reconnect: false` — stdio is point-to-point, no replay ring.
41
+ _meta: {
42
+ chances: {
43
+ capabilities: { reconnect: false, toolChunks: true, fidelity: ["usage", "chunk", "compaction", "subagent", "reset"] },
44
+ },
45
+ },
46
+ };
47
+ }
48
+ async authenticate() {
49
+ return {};
50
+ }
51
+ async newSession(_params) {
52
+ if (this.session) {
53
+ throw new Error("a session is already active (one session per process in v1)");
54
+ }
55
+ // The resolver reads `this.session` lazily — it's only invoked during a
56
+ // later `prompt`, by which point `this.session` is set (no build cycle).
57
+ const built = this.host.build(this.makeResolver());
58
+ const unsub = built.bus.onAny((e) => {
59
+ const sid = this.session?.id;
60
+ if (!sid)
61
+ return;
62
+ // chances-only fidelity → a `_chances/unstable/event` extension notification
63
+ // (the SAME shared helper the relay driver uses, so the two ACP transports
64
+ // don't drift). A plain ACP client ignores the unknown method.
65
+ const chances = chancesEventMeta(e);
66
+ if (chances) {
67
+ this.sendChain = this.sendChain.then(() => this.connection.extNotification("_chances/unstable/event", { sessionId: sid, _meta: { chances } }).catch(() => { }));
68
+ return;
69
+ }
70
+ // Zed (stdio) wants the live-PTY stream too → toolChunks on.
71
+ for (const update of mapEventToAcp(e, { toolChunks: true })) {
72
+ this.sendChain = this.sendChain.then(() => this.connection.sessionUpdate({ sessionId: sid, update }).catch(() => { }));
73
+ }
74
+ });
75
+ this.session = { id: built.sessionId, built, cts: null, unsub };
76
+ return { sessionId: built.sessionId };
77
+ }
78
+ async prompt(params) {
79
+ const sess = this.session;
80
+ if (!sess || sess.id !== params.sessionId) {
81
+ throw new Error(`unknown session: ${params.sessionId}`);
82
+ }
83
+ // (Round-2 S2) One turn at a time per session: a second concurrent
84
+ // `session/prompt` would run the same engine twice and `cancel()` would
85
+ // only target the most recently assigned token. Reject the overlap.
86
+ if (sess.cts) {
87
+ throw new Error("a prompt is already running for this session");
88
+ }
89
+ const text = textFromContent(params.prompt);
90
+ const cts = new CancellationTokenSource();
91
+ sess.cts = cts;
92
+ let result = { text: "", inputTokens: 0, outputTokens: 0, costUsd: 0 };
93
+ try {
94
+ result = await sess.built.runTurn(text, cts.token);
95
+ }
96
+ catch (err) {
97
+ if (cts.token.isCancelled)
98
+ return { stopReason: "cancelled" };
99
+ throw err; // surfaces as a JSON-RPC error response to the client
100
+ }
101
+ finally {
102
+ sess.cts = null;
103
+ }
104
+ // Fold token usage into the response (parity with the relay driver — codex
105
+ // M3 SHOULD); cost rides `_meta.chances`. A plain ACP client reads the
106
+ // standard `usage` fields and ignores `_meta`.
107
+ return {
108
+ stopReason: "end_turn",
109
+ usage: { inputTokens: result.inputTokens, outputTokens: result.outputTokens, totalTokens: result.inputTokens + result.outputTokens },
110
+ _meta: { chances: { costUsd: result.costUsd } },
111
+ };
112
+ }
113
+ async cancel(params) {
114
+ if (this.session?.id === params.sessionId)
115
+ this.session.cts?.cancel();
116
+ }
117
+ /** Tear down the active session subscription (called on connection close). */
118
+ dispose() {
119
+ this.session?.cts?.cancel();
120
+ this.session?.unsub();
121
+ this.session = null;
122
+ }
123
+ makeResolver() {
124
+ return async (req) => {
125
+ // (5.10b) Narrow the union before reading authorization-only fields
126
+ // (`summary`/`args`). No remote question UI yet — a question declines.
127
+ if (req.kind === "question")
128
+ return { kind: "question", answers: {}, declined: true };
129
+ const sid = this.session?.id;
130
+ if (!sid)
131
+ return { allow: false };
132
+ const res = await this.connection.requestPermission({
133
+ sessionId: sid,
134
+ toolCall: {
135
+ toolCallId: req.callId ?? createId("tool"),
136
+ title: req.summary,
137
+ rawInput: (req.args ?? {}),
138
+ },
139
+ options: PERMISSION_OPTIONS,
140
+ });
141
+ if (res.outcome.outcome !== "selected")
142
+ return { allow: false }; // cancelled
143
+ switch (res.outcome.optionId) {
144
+ case "allow_once":
145
+ return { allow: true, remember: false };
146
+ case "allow_always":
147
+ return { allow: true, remember: true };
148
+ default:
149
+ return { allow: false }; // reject_once / reject_always
150
+ }
151
+ };
152
+ }
153
+ }
154
+ function textFromContent(blocks) {
155
+ return blocks
156
+ .map((b) => (b.type === "text" ? b.text : ""))
157
+ .filter((s) => s.length > 0)
158
+ .join("\n");
159
+ }
160
+ /** Boot the ACP agent over the given Web streams and resolve when the
161
+ * connection closes. Returns 0 on clean close, 2 when the SDK peer is absent
162
+ * (the caller prints install guidance). */
163
+ export async function runAcp(opts) {
164
+ const sdk = await loadAcpSdk();
165
+ if (!sdk)
166
+ return 2;
167
+ const stream = sdk.ndJsonStream(opts.output, opts.input);
168
+ // Holder dodges TS narrowing the callback-assigned local to `never`. The
169
+ // SDK invokes `toAgent` synchronously inside the ctor, so it's set below.
170
+ const holder = {};
171
+ const connection = new sdk.AgentSideConnection((conn) => {
172
+ holder.agent = new AcpAgent(opts.host, conn);
173
+ return holder.agent;
174
+ }, stream);
175
+ // Resolve when the peer closes the connection.
176
+ await new Promise((resolve) => {
177
+ if (connection.signal.aborted)
178
+ return resolve();
179
+ connection.signal.addEventListener("abort", () => resolve(), { once: true });
180
+ });
181
+ holder.agent?.dispose();
182
+ await opts.host.dispose();
183
+ return 0;
184
+ }
185
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/rpc/acp/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * (v20 M3 / docs/6.4a §3) `AcpEngineDriver` — the ACP twin of `RpcServer`. It
3
+ * projects the SAME `EngineHost` seam onto an ACP (Agent Client Protocol) wire:
4
+ * JSON-RPC 2.0 + session semantics. Structurally identical to `RpcServer`
5
+ * (`run(lines: AsyncIterable<string>)` over an injected `ByteSink`), so the M2
6
+ * `SessionHost`/`ReplayHub` fan-out + seq/replay carry over with a one-line
7
+ * swap — but it speaks ACP, not the bespoke `chances-rpc` frames.
8
+ *
9
+ * **Self-rolled framing, NOT the ACP SDK's connection runtime** (user decision
10
+ * D1, docs/6.4a §1): the SDK's `AgentSideConnection` is point-to-point (it owns
11
+ * the JSON-RPC id correlation for ONE socket), which collides with M2's fan-out
12
+ * (one session, many sockets, any may answer a permission). So we roll the
13
+ * JSON-RPC framing ourselves on top of the fan-out, using the SDK only for its
14
+ * **types** (`import type` → erased; the driver compiles with or without the
15
+ * optional peer, exactly like the stdio adapter; `smoke-compile-rpc` gates both).
16
+ *
17
+ * Correlation is by **id pass-through**, no mapping table:
18
+ * - `session/prompt` request id → remembered as the active turn; the terminal
19
+ * `session/prompt` RESPONSE echoes it with `{ stopReason, usage }` (the
20
+ * chances `result` frame folded into the ACP response; the immediate `prompt`
21
+ * ack chances-rpc sends has no ACP equivalent and is simply not emitted).
22
+ * - `session/request_permission` is an agent→client REQUEST whose id we mint
23
+ * (`perm_*`); ANY attached socket may answer it (fan-out — the relay routes
24
+ * the response back here), and we dedup by id. **Fail-closed**: a cancelled/
25
+ * unknown outcome, or an errored response, denies (matches goose + v16).
26
+ * - chances-only fidelity (compaction/subagent/error) rides a
27
+ * `_chances/unstable/event` notification carrying `_meta.chances` — a plain
28
+ * ACP client ignores the unknown method; ours reads it.
29
+ *
30
+ * Socket-free + timer-free at the seam: tests drive `run()` with a fake
31
+ * `EngineHost` + scripted ACP lines and assert the emitted ACP message sequence.
32
+ */
33
+ import { type ByteSink } from "../writer.js";
34
+ import type { EngineHost } from "../driver.js";
35
+ /** ACP protocol version we speak (SDK `PROTOCOL_VERSION` = 1). */
36
+ export declare const ACP_PROTOCOL_VERSION: 1;
37
+ export interface AcpEngineDriverOptions {
38
+ host: EngineHost;
39
+ /** Outbound sink (the M2 `ReplayHub`, or a recorder in tests). */
40
+ sink: ByteSink;
41
+ agent: {
42
+ name: string;
43
+ version: string;
44
+ };
45
+ /** Auto-approve every tool permission (trusted automation). Default false. */
46
+ autoApprove?: boolean;
47
+ /** stderr-style sink for routed `log` events + the writer's high-water warning. */
48
+ logSink?: (line: string) => void;
49
+ /** (v23 M5) Advertise `_meta.chances.capabilities.workspaceQueries` in
50
+ * `initialize` so a GUI client shows the file/code/git panes. The driver does
51
+ * NOT handle the query methods — the relay (`AcpSessionHost`) intercepts them
52
+ * and replies off-ring — so this is set true only by a relay whose host
53
+ * supports the queries. stdio transports leave it false (Zed has its own
54
+ * editor; `rpc` is programmatic). */
55
+ workspaceQueries?: boolean;
56
+ }
57
+ export declare class AcpEngineDriver {
58
+ private readonly host;
59
+ private readonly writer;
60
+ private readonly agent;
61
+ private readonly autoApprove;
62
+ private readonly logSink;
63
+ private toolChunks;
64
+ private built;
65
+ private unsub;
66
+ private sessionId;
67
+ private activeTurn;
68
+ /** Tracked so shutdown can await the terminal prompt response before closing. */
69
+ private activePrompt;
70
+ /** Open asks (permission OR question): minted id → the resolver's `resolve` +
71
+ * the serialized request (kept so a fresh attach can re-send a still-open ask
72
+ * the ring evicted) + its `kind` (so a response/deny resolves the right shape). */
73
+ private readonly pending;
74
+ private readonly resolvedIds;
75
+ private readonly resolvedSet;
76
+ private readonly workspaceQueries;
77
+ private shuttingDown;
78
+ constructor(opts: AcpEngineDriverOptions);
79
+ run(lines: AsyncIterable<string>): Promise<number>;
80
+ /** Idempotent shutdown — same order as `RpcServer` (cancel turn → deny pending
81
+ * → await the in-flight prompt's terminal response → dispose → flush → close). */
82
+ shutdown(): Promise<void>;
83
+ /** Whether a turn is in flight, so a reconnecting client can lock its composer. */
84
+ get busy(): boolean;
85
+ /** Ids of still-open `session/request_permission` asks at attach time. */
86
+ pendingPermissionIds(): string[];
87
+ /** Serialized lines of every still-open permission request, re-sent right
88
+ * after the welcome so a parked turn stays answerable even if the ring
89
+ * evicted the ask. The client de-dups by permission id. */
90
+ openPermissionFrames(): string[];
91
+ private onEvent;
92
+ private handleLine;
93
+ private handleMethod;
94
+ /** Runs one turn. The caller (`handleMethod`'s prompt case) has already
95
+ * validated the session + rejected an overlapping turn, so this always starts. */
96
+ private handlePrompt;
97
+ /** True if `params.sessionId` addresses our singleton session. An ABSENT id is
98
+ * tolerated (first-party clients always send ours); a PRESENT but mismatched id
99
+ * is rejected so a plain ACP client can't drive/cancel a bogus session (codex
100
+ * M3 SHOULD). */
101
+ private isOurSession;
102
+ /** The standard ACP `SessionModelState` (modelId = `provider/model`). */
103
+ private modelState;
104
+ private handleSetModel;
105
+ /** (v22) Set the session approval mode. UNLIKE set_model this is allowed
106
+ * mid-turn — the mode applies to the NEXT permission check, which is the whole
107
+ * point of cycling it while a turn streams (claude-code parity; mirrors the
108
+ * TUI Stage-1 fix). A switch to `yolo` carries its own consent (the GUI
109
+ * confirms client-side before sending), so we latch it. */
110
+ private handleSetApproval;
111
+ private makeResolver;
112
+ /** A client answered a `session/request_permission` request (JSON-RPC
113
+ * response). Fail-closed: an error response, a non-`selected` outcome, or an
114
+ * unknown `optionId` all deny. Dedups duplicate/foreign answers. */
115
+ private resolvePermission;
116
+ /** (v22) A client answered a `_chances/unstable/request_question` request.
117
+ * Fail-closed: an error response, a malformed body, or an explicit `declined`
118
+ * all resolve to a declined QuestionDecision (the ask tool turns that into a
119
+ * deterministic "declined" result). Dedups duplicate/foreign answers. */
120
+ private resolveQuestion;
121
+ private denyAllPending;
122
+ private markResolved;
123
+ private initializeResult;
124
+ private enqueueNotification;
125
+ private respond;
126
+ private error;
127
+ }
128
+ //# sourceMappingURL=engine-driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-driver.d.ts","sourceRoot":"","sources":["../../../src/rpc/acp/engine-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,cAAc,CAAC;AAG5D,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,EAAG,CAAU,CAAC;AAwD/C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,CAAC;IACjB,kEAAkE;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mFAAmF;IACnF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;;;0CAKsC;IACtC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,UAAU,CAAQ;IAE1B,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,UAAU,CAAsE;IACxF,iFAAiF;IACjF,OAAO,CAAC,YAAY,CAA8B;IAClD;;wFAEoF;IACpF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6H;IACrJ,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,YAAY,CAAS;gBAEjB,IAAI,EAAE,sBAAsB;IASlC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBxD;uFACmF;IAC7E,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB/B,mFAAmF;IACnF,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,0EAA0E;IAC1E,oBAAoB,IAAI,MAAM,EAAE;IAGhC;;gEAE4D;IAC5D,oBAAoB,IAAI,MAAM,EAAE;IAMhC,OAAO,CAAC,OAAO;IAkBf,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,YAAY;IA6EpB;uFACmF;YACrE,YAAY;IA2B1B;;;sBAGkB;IAClB,OAAO,CAAC,YAAY;IAKpB,yEAAyE;IACzE,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,cAAc;IAUtB;;;;gEAI4D;IAC5D,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,YAAY;IAkDpB;;yEAEqE;IACrE,OAAO,CAAC,iBAAiB;IA6BzB;;;8EAG0E;IAC1E,OAAO,CAAC,eAAe;IAyBvB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,mBAAmB;IAG3B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;CAGd"}