@actant/acp 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +23 -2
- package/dist/index.js +124 -54
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -64,13 +64,14 @@ declare class AcpConnection {
|
|
|
64
64
|
private readonly terminalManager;
|
|
65
65
|
private enforcer;
|
|
66
66
|
private auditLogger;
|
|
67
|
+
private _earlyExitPromise;
|
|
67
68
|
constructor(options?: AcpConnectionOptions);
|
|
68
69
|
/** Update the permission policy at runtime (hot-reload). */
|
|
69
70
|
updatePermissionPolicy(config: PermissionsConfig): void;
|
|
70
71
|
get isConnected(): boolean;
|
|
71
72
|
get agentCapabilities(): InitializeResponse | null;
|
|
72
73
|
get rawConnection(): ClientSideConnection | null;
|
|
73
|
-
spawn(command: string, args: string[], cwd: string): Promise<void>;
|
|
74
|
+
spawn(command: string, args: string[], cwd: string, resolvePackage?: string): Promise<void>;
|
|
74
75
|
initialize(): Promise<InitializeResponse>;
|
|
75
76
|
newSession(cwd: string, mcpServers?: NewSessionResponse["modes"] extends unknown ? unknown[] : never[]): Promise<AcpSessionInfo>;
|
|
76
77
|
loadSession(sessionId: string, cwd: string): Promise<void>;
|
|
@@ -209,6 +210,8 @@ interface ConnectOptions {
|
|
|
209
210
|
args: string[];
|
|
210
211
|
cwd: string;
|
|
211
212
|
connectionOptions?: AcpConnectionOptions;
|
|
213
|
+
/** npm package providing the binary (from BackendDescriptor.resolvePackage). */
|
|
214
|
+
resolvePackage?: string;
|
|
212
215
|
}
|
|
213
216
|
/**
|
|
214
217
|
* Manages a pool of ACP connections keyed by agent instance name.
|
|
@@ -279,4 +282,22 @@ declare class LocalTerminalManager {
|
|
|
279
282
|
private getTerminal;
|
|
280
283
|
}
|
|
281
284
|
|
|
282
|
-
|
|
285
|
+
interface ResolvedAcpBinary {
|
|
286
|
+
command: string;
|
|
287
|
+
prependArgs: string[];
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Resolve an ACP binary command to an executable path.
|
|
291
|
+
*
|
|
292
|
+
* Resolution order:
|
|
293
|
+
* 1. Check if the command is already on PATH → return as-is
|
|
294
|
+
* 2. If `resolvePackage` is provided → resolve bin script from that npm package
|
|
295
|
+
* in node_modules, run via `node <script-path>`
|
|
296
|
+
* 3. Return original command (caller will get a proper spawn error)
|
|
297
|
+
*
|
|
298
|
+
* @param command The command name (e.g. "claude-agent-acp.cmd")
|
|
299
|
+
* @param resolvePackage npm package that provides the binary (from BackendDescriptor)
|
|
300
|
+
*/
|
|
301
|
+
declare function resolveAcpBinary(command: string, resolvePackage?: string): ResolvedAcpBinary;
|
|
302
|
+
|
|
303
|
+
export { AcpCommunicator, AcpConnection, AcpConnectionManager, type AcpConnectionOptions, AcpGateway, type AcpSessionInfo, type ClientCallbackHandler, ClientCallbackRouter, type ConnectOptions, type GatewayOptions, LocalTerminalManager, type ResolvedAcpBinary, type UpstreamHandler, resolveAcpBinary };
|
package/dist/index.js
CHANGED
|
@@ -5,13 +5,61 @@ import {
|
|
|
5
5
|
ClientSideConnection,
|
|
6
6
|
ndJsonStream
|
|
7
7
|
} from "@agentclientprotocol/sdk";
|
|
8
|
-
import { createLogger as
|
|
8
|
+
import { createLogger as createLogger3, isWindows as isWindows2 } from "@actant/shared";
|
|
9
|
+
|
|
10
|
+
// src/binary-resolver.ts
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
import { dirname, join } from "path";
|
|
13
|
+
import { readFileSync } from "fs";
|
|
14
|
+
import { execSync } from "child_process";
|
|
15
|
+
import { createLogger, isWindows } from "@actant/shared";
|
|
16
|
+
var logger = createLogger("binary-resolver");
|
|
17
|
+
function resolveAcpBinary(command, resolvePackage) {
|
|
18
|
+
if (isOnPath(command)) {
|
|
19
|
+
return { command, prependArgs: [] };
|
|
20
|
+
}
|
|
21
|
+
if (!resolvePackage) {
|
|
22
|
+
return { command, prependArgs: [] };
|
|
23
|
+
}
|
|
24
|
+
const bareName = command.replace(/\.cmd$/, "");
|
|
25
|
+
const scriptPath = resolveScriptFromPackage(resolvePackage, bareName);
|
|
26
|
+
if (scriptPath) {
|
|
27
|
+
logger.info({ bareName, resolvePackage, scriptPath }, "Resolved ACP binary from backend dependency");
|
|
28
|
+
const nodeCmd = isWindows() && process.execPath.includes(" ") ? `"${process.execPath}"` : process.execPath;
|
|
29
|
+
return { command: nodeCmd, prependArgs: [scriptPath] };
|
|
30
|
+
}
|
|
31
|
+
return { command, prependArgs: [] };
|
|
32
|
+
}
|
|
33
|
+
function isOnPath(command) {
|
|
34
|
+
try {
|
|
35
|
+
const which = isWindows() ? "where.exe" : "which";
|
|
36
|
+
execSync(`${which} ${command}`, { stdio: "ignore" });
|
|
37
|
+
return true;
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function resolveScriptFromPackage(packageName, binName) {
|
|
43
|
+
try {
|
|
44
|
+
const require2 = createRequire(import.meta.url);
|
|
45
|
+
const pkgJsonPath = require2.resolve(`${packageName}/package.json`);
|
|
46
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
47
|
+
const binField = pkgJson.bin;
|
|
48
|
+
const relBinPath = typeof binField === "string" ? binField : binField?.[binName];
|
|
49
|
+
if (!relBinPath) return null;
|
|
50
|
+
return join(dirname(pkgJsonPath), relBinPath);
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/connection.ts
|
|
9
57
|
import { PermissionPolicyEnforcer, PermissionAuditLogger } from "@actant/core";
|
|
10
58
|
|
|
11
59
|
// src/terminal-manager.ts
|
|
12
60
|
import { spawn } from "child_process";
|
|
13
|
-
import { createLogger } from "@actant/shared";
|
|
14
|
-
var
|
|
61
|
+
import { createLogger as createLogger2 } from "@actant/shared";
|
|
62
|
+
var logger2 = createLogger2("acp-terminal");
|
|
15
63
|
var LocalTerminalManager = class {
|
|
16
64
|
terminals = /* @__PURE__ */ new Map();
|
|
17
65
|
counter = 0;
|
|
@@ -37,7 +85,7 @@ var LocalTerminalManager = class {
|
|
|
37
85
|
resolve({ exitCode: code ?? null, signal: signal ?? null });
|
|
38
86
|
});
|
|
39
87
|
proc.on("error", (err) => {
|
|
40
|
-
|
|
88
|
+
logger2.error({ terminalId: id, error: err }, "Terminal process error");
|
|
41
89
|
resolve({ exitCode: 1, signal: null });
|
|
42
90
|
});
|
|
43
91
|
});
|
|
@@ -65,7 +113,7 @@ var LocalTerminalManager = class {
|
|
|
65
113
|
terminal.exitStatus = status;
|
|
66
114
|
});
|
|
67
115
|
this.terminals.set(id, terminal);
|
|
68
|
-
|
|
116
|
+
logger2.info({ terminalId: id, command: params.command, cwd: params.cwd }, "Terminal created");
|
|
69
117
|
return { terminalId: id };
|
|
70
118
|
}
|
|
71
119
|
async terminalOutput(params) {
|
|
@@ -103,7 +151,7 @@ var LocalTerminalManager = class {
|
|
|
103
151
|
}
|
|
104
152
|
term.disposed = true;
|
|
105
153
|
this.terminals.delete(params.terminalId);
|
|
106
|
-
|
|
154
|
+
logger2.debug({ terminalId: params.terminalId }, "Terminal released");
|
|
107
155
|
return {};
|
|
108
156
|
}
|
|
109
157
|
disposeAll() {
|
|
@@ -125,7 +173,7 @@ var LocalTerminalManager = class {
|
|
|
125
173
|
};
|
|
126
174
|
|
|
127
175
|
// src/connection.ts
|
|
128
|
-
var
|
|
176
|
+
var logger3 = createLogger3("acp-connection");
|
|
129
177
|
var AcpConnection = class {
|
|
130
178
|
child = null;
|
|
131
179
|
conn = null;
|
|
@@ -136,6 +184,7 @@ var AcpConnection = class {
|
|
|
136
184
|
terminalManager;
|
|
137
185
|
enforcer = null;
|
|
138
186
|
auditLogger;
|
|
187
|
+
_earlyExitPromise = null;
|
|
139
188
|
constructor(options) {
|
|
140
189
|
this.options = options ?? {};
|
|
141
190
|
this.terminalManager = new LocalTerminalManager();
|
|
@@ -165,24 +214,42 @@ var AcpConnection = class {
|
|
|
165
214
|
/* ---------------------------------------------------------------- */
|
|
166
215
|
/* Lifecycle */
|
|
167
216
|
/* ---------------------------------------------------------------- */
|
|
168
|
-
async spawn(command, args, cwd) {
|
|
217
|
+
async spawn(command, args, cwd, resolvePackage) {
|
|
169
218
|
if (this.child) throw new Error("AcpConnection already spawned");
|
|
219
|
+
const resolved = resolveAcpBinary(command, resolvePackage);
|
|
220
|
+
const finalCommand = resolved.command;
|
|
221
|
+
const finalArgs = [...resolved.prependArgs, ...args];
|
|
170
222
|
const env = { ...process.env, ...this.options.env };
|
|
171
|
-
|
|
172
|
-
this.child = spawn2(
|
|
223
|
+
logger3.info({ command: finalCommand, args: finalArgs, cwd }, "Spawning ACP agent subprocess");
|
|
224
|
+
this.child = spawn2(finalCommand, finalArgs, {
|
|
173
225
|
cwd,
|
|
174
226
|
stdio: ["pipe", "pipe", "pipe"],
|
|
175
227
|
env,
|
|
176
|
-
shell:
|
|
228
|
+
shell: isWindows2()
|
|
177
229
|
});
|
|
178
230
|
if (!this.child.stdout || !this.child.stdin) {
|
|
179
231
|
throw new Error("Failed to create stdio pipes for ACP agent");
|
|
180
232
|
}
|
|
233
|
+
const stderrChunks = [];
|
|
181
234
|
this.child.stderr?.on("data", (chunk) => {
|
|
182
|
-
|
|
235
|
+
const text = chunk.toString().trim();
|
|
236
|
+
if (text) stderrChunks.push(text);
|
|
237
|
+
logger3.debug({ stderr: text }, "ACP agent stderr");
|
|
183
238
|
});
|
|
184
239
|
this.child.on("error", (err) => {
|
|
185
|
-
|
|
240
|
+
logger3.error({ error: err }, "ACP agent process error");
|
|
241
|
+
});
|
|
242
|
+
this._earlyExitPromise = new Promise((_resolve, reject) => {
|
|
243
|
+
this.child.on("exit", (code, signal) => {
|
|
244
|
+
const stderr = stderrChunks.join("\n");
|
|
245
|
+
const detail = stderr ? `
|
|
246
|
+
stderr: ${stderr}` : "";
|
|
247
|
+
reject(new Error(
|
|
248
|
+
`ACP agent process exited unexpectedly (code=${code}, signal=${signal}). Command: ${finalCommand} ${finalArgs.join(" ")}${detail}`
|
|
249
|
+
));
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
this._earlyExitPromise.catch(() => {
|
|
186
253
|
});
|
|
187
254
|
const webWritable = Writable.toWeb(this.child.stdin);
|
|
188
255
|
const webReadable = Readable.toWeb(this.child.stdout);
|
|
@@ -192,12 +259,12 @@ var AcpConnection = class {
|
|
|
192
259
|
stream
|
|
193
260
|
);
|
|
194
261
|
this.conn.signal.addEventListener("abort", () => {
|
|
195
|
-
|
|
262
|
+
logger3.info("ACP connection closed");
|
|
196
263
|
});
|
|
197
264
|
}
|
|
198
265
|
async initialize() {
|
|
199
266
|
if (!this.conn) throw new Error("AcpConnection not spawned");
|
|
200
|
-
|
|
267
|
+
const initPromise = this.conn.initialize({
|
|
201
268
|
protocolVersion: 1,
|
|
202
269
|
clientCapabilities: {
|
|
203
270
|
fs: { readTextFile: true, writeTextFile: true },
|
|
@@ -209,7 +276,9 @@ var AcpConnection = class {
|
|
|
209
276
|
version: "0.1.0"
|
|
210
277
|
}
|
|
211
278
|
});
|
|
212
|
-
|
|
279
|
+
this.initResponse = this._earlyExitPromise ? await Promise.race([initPromise, this._earlyExitPromise]) : await initPromise;
|
|
280
|
+
this._earlyExitPromise = null;
|
|
281
|
+
logger3.info({
|
|
213
282
|
agentName: this.initResponse.agentInfo?.name,
|
|
214
283
|
protocolVersion: this.initResponse.protocolVersion,
|
|
215
284
|
loadSession: this.initResponse.agentCapabilities?.loadSession
|
|
@@ -231,7 +300,7 @@ var AcpConnection = class {
|
|
|
231
300
|
configOptions: response.configOptions
|
|
232
301
|
};
|
|
233
302
|
this.sessions.set(response.sessionId, info);
|
|
234
|
-
|
|
303
|
+
logger3.info({ sessionId: response.sessionId, cwd }, "ACP session created");
|
|
235
304
|
return info;
|
|
236
305
|
}
|
|
237
306
|
async loadSession(sessionId, cwd) {
|
|
@@ -240,23 +309,23 @@ var AcpConnection = class {
|
|
|
240
309
|
throw new Error("Agent does not support loadSession capability");
|
|
241
310
|
}
|
|
242
311
|
await this.conn.loadSession({ sessionId, cwd, mcpServers: [] });
|
|
243
|
-
|
|
312
|
+
logger3.info({ sessionId }, "ACP session loaded");
|
|
244
313
|
}
|
|
245
314
|
async setSessionMode(sessionId, modeId) {
|
|
246
315
|
if (!this.conn) throw new Error("AcpConnection not initialized");
|
|
247
316
|
await this.conn.setSessionMode({ sessionId, modeId });
|
|
248
|
-
|
|
317
|
+
logger3.info({ sessionId, modeId }, "Session mode set");
|
|
249
318
|
}
|
|
250
319
|
async setSessionConfigOption(sessionId, configId, value) {
|
|
251
320
|
if (!this.conn) throw new Error("AcpConnection not initialized");
|
|
252
321
|
const result = await this.conn.setSessionConfigOption({ sessionId, configId, value });
|
|
253
|
-
|
|
322
|
+
logger3.info({ sessionId, configId, value }, "Session config option set");
|
|
254
323
|
return result;
|
|
255
324
|
}
|
|
256
325
|
async authenticate(methodId) {
|
|
257
326
|
if (!this.conn) throw new Error("AcpConnection not initialized");
|
|
258
327
|
await this.conn.authenticate({ methodId });
|
|
259
|
-
|
|
328
|
+
logger3.info({ methodId }, "Authenticated");
|
|
260
329
|
}
|
|
261
330
|
/* ---------------------------------------------------------------- */
|
|
262
331
|
/* Prompt */
|
|
@@ -364,7 +433,7 @@ var AcpConnection = class {
|
|
|
364
433
|
});
|
|
365
434
|
child.kill("SIGTERM");
|
|
366
435
|
});
|
|
367
|
-
|
|
436
|
+
logger3.info("ACP agent subprocess terminated");
|
|
368
437
|
}
|
|
369
438
|
this.conn = null;
|
|
370
439
|
this.initResponse = null;
|
|
@@ -428,7 +497,7 @@ var AcpConnection = class {
|
|
|
428
497
|
if (!allowOption) return { outcome: { outcome: "cancelled" } };
|
|
429
498
|
return { outcome: { outcome: "selected", optionId: allowOption.optionId } };
|
|
430
499
|
}
|
|
431
|
-
|
|
500
|
+
logger3.warn({ sessionId: params.sessionId }, "Permission request denied (no handler)");
|
|
432
501
|
return { outcome: { outcome: "cancelled" } };
|
|
433
502
|
}
|
|
434
503
|
async localSessionUpdate(params) {
|
|
@@ -460,9 +529,9 @@ var AcpConnection = class {
|
|
|
460
529
|
}
|
|
461
530
|
async localWriteTextFile(params) {
|
|
462
531
|
const { writeFile, mkdir } = await import("fs/promises");
|
|
463
|
-
const { dirname } = await import("path");
|
|
532
|
+
const { dirname: dirname2 } = await import("path");
|
|
464
533
|
try {
|
|
465
|
-
await mkdir(
|
|
534
|
+
await mkdir(dirname2(params.path), { recursive: true });
|
|
466
535
|
await writeFile(params.path, params.content, "utf-8");
|
|
467
536
|
return {};
|
|
468
537
|
} catch {
|
|
@@ -488,12 +557,12 @@ var AcpConnection = class {
|
|
|
488
557
|
};
|
|
489
558
|
|
|
490
559
|
// src/connection-manager.ts
|
|
491
|
-
import { createLogger as
|
|
560
|
+
import { createLogger as createLogger6 } from "@actant/shared";
|
|
492
561
|
import { PermissionPolicyEnforcer as PermissionPolicyEnforcer2, PermissionAuditLogger as PermissionAuditLogger2 } from "@actant/core";
|
|
493
562
|
|
|
494
563
|
// src/callback-router.ts
|
|
495
|
-
import { createLogger as
|
|
496
|
-
var
|
|
564
|
+
import { createLogger as createLogger4 } from "@actant/shared";
|
|
565
|
+
var logger4 = createLogger4("acp-callback-router");
|
|
497
566
|
var ClientCallbackRouter = class {
|
|
498
567
|
constructor(local) {
|
|
499
568
|
this.local = local;
|
|
@@ -512,7 +581,7 @@ var ClientCallbackRouter = class {
|
|
|
512
581
|
attachUpstream(handler, capabilities) {
|
|
513
582
|
this.upstream = handler;
|
|
514
583
|
this.ideCapabilities = capabilities;
|
|
515
|
-
|
|
584
|
+
logger4.info({
|
|
516
585
|
terminal: !!capabilities.terminal,
|
|
517
586
|
fsRead: !!capabilities.fs?.readTextFile,
|
|
518
587
|
fsWrite: !!capabilities.fs?.writeTextFile
|
|
@@ -524,7 +593,7 @@ var ClientCallbackRouter = class {
|
|
|
524
593
|
detachUpstream() {
|
|
525
594
|
this.upstream = null;
|
|
526
595
|
this.ideCapabilities = null;
|
|
527
|
-
|
|
596
|
+
logger4.info("Upstream IDE detached \u2014 local mode");
|
|
528
597
|
}
|
|
529
598
|
get isLeaseActive() {
|
|
530
599
|
return this.upstream != null;
|
|
@@ -553,7 +622,7 @@ var ClientCallbackRouter = class {
|
|
|
553
622
|
try {
|
|
554
623
|
return await this.upstream.requestPermission(params);
|
|
555
624
|
} catch (err) {
|
|
556
|
-
|
|
625
|
+
logger4.warn({ error: err }, "Failed to forward requestPermission to IDE, falling back");
|
|
557
626
|
}
|
|
558
627
|
}
|
|
559
628
|
return this.local.requestPermission(params);
|
|
@@ -572,7 +641,7 @@ var ClientCallbackRouter = class {
|
|
|
572
641
|
try {
|
|
573
642
|
return await this.upstream.readTextFile(params);
|
|
574
643
|
} catch (err) {
|
|
575
|
-
|
|
644
|
+
logger4.warn({ path: params.path, error: err }, "IDE readTextFile failed, falling back");
|
|
576
645
|
}
|
|
577
646
|
}
|
|
578
647
|
return this.local.readTextFile(params);
|
|
@@ -582,7 +651,7 @@ var ClientCallbackRouter = class {
|
|
|
582
651
|
try {
|
|
583
652
|
return await this.upstream.writeTextFile(params);
|
|
584
653
|
} catch (err) {
|
|
585
|
-
|
|
654
|
+
logger4.warn({ path: params.path, error: err }, "IDE writeTextFile failed, falling back");
|
|
586
655
|
}
|
|
587
656
|
}
|
|
588
657
|
return this.local.writeTextFile(params);
|
|
@@ -592,7 +661,7 @@ var ClientCallbackRouter = class {
|
|
|
592
661
|
try {
|
|
593
662
|
return await this.upstream.createTerminal(params);
|
|
594
663
|
} catch (err) {
|
|
595
|
-
|
|
664
|
+
logger4.warn({ error: err }, "IDE createTerminal failed, falling back");
|
|
596
665
|
}
|
|
597
666
|
}
|
|
598
667
|
if (this.local.createTerminal) return this.local.createTerminal(params);
|
|
@@ -603,7 +672,7 @@ var ClientCallbackRouter = class {
|
|
|
603
672
|
try {
|
|
604
673
|
return await this.upstream.terminalOutput(params);
|
|
605
674
|
} catch (err) {
|
|
606
|
-
|
|
675
|
+
logger4.warn({ error: err }, "IDE terminalOutput failed, falling back");
|
|
607
676
|
}
|
|
608
677
|
}
|
|
609
678
|
if (this.local.terminalOutput) return this.local.terminalOutput(params);
|
|
@@ -614,7 +683,7 @@ var ClientCallbackRouter = class {
|
|
|
614
683
|
try {
|
|
615
684
|
return await this.upstream.waitForTerminalExit(params);
|
|
616
685
|
} catch (err) {
|
|
617
|
-
|
|
686
|
+
logger4.warn({ error: err }, "IDE waitForTerminalExit failed, falling back");
|
|
618
687
|
}
|
|
619
688
|
}
|
|
620
689
|
if (this.local.waitForTerminalExit) return this.local.waitForTerminalExit(params);
|
|
@@ -625,7 +694,7 @@ var ClientCallbackRouter = class {
|
|
|
625
694
|
try {
|
|
626
695
|
return await this.upstream.killTerminal(params);
|
|
627
696
|
} catch (err) {
|
|
628
|
-
|
|
697
|
+
logger4.warn({ error: err }, "IDE killTerminal failed, falling back");
|
|
629
698
|
}
|
|
630
699
|
}
|
|
631
700
|
if (this.local.killTerminal) return this.local.killTerminal(params);
|
|
@@ -636,7 +705,7 @@ var ClientCallbackRouter = class {
|
|
|
636
705
|
try {
|
|
637
706
|
return await this.upstream.releaseTerminal(params);
|
|
638
707
|
} catch (err) {
|
|
639
|
-
|
|
708
|
+
logger4.warn({ error: err }, "IDE releaseTerminal failed, falling back");
|
|
640
709
|
}
|
|
641
710
|
}
|
|
642
711
|
if (this.local.releaseTerminal) return this.local.releaseTerminal(params);
|
|
@@ -650,8 +719,8 @@ import {
|
|
|
650
719
|
AgentSideConnection,
|
|
651
720
|
ndJsonStream as ndJsonStream2
|
|
652
721
|
} from "@agentclientprotocol/sdk";
|
|
653
|
-
import { createLogger as
|
|
654
|
-
var
|
|
722
|
+
import { createLogger as createLogger5 } from "@actant/shared";
|
|
723
|
+
var logger5 = createLogger5("acp-gateway");
|
|
655
724
|
var AcpGateway = class {
|
|
656
725
|
upstream = null;
|
|
657
726
|
downstream;
|
|
@@ -692,7 +761,7 @@ var AcpGateway = class {
|
|
|
692
761
|
stream
|
|
693
762
|
);
|
|
694
763
|
this.upstream.signal.addEventListener("abort", () => {
|
|
695
|
-
|
|
764
|
+
logger5.info("Upstream IDE disconnected from Gateway");
|
|
696
765
|
for (const handle of this.terminalHandles.values()) {
|
|
697
766
|
handle.release().catch(() => {
|
|
698
767
|
});
|
|
@@ -701,7 +770,7 @@ var AcpGateway = class {
|
|
|
701
770
|
this.callbackRouter.detachUpstream();
|
|
702
771
|
this.ideCapabilities = null;
|
|
703
772
|
});
|
|
704
|
-
|
|
773
|
+
logger5.info("Upstream IDE connected to Gateway");
|
|
705
774
|
}
|
|
706
775
|
/**
|
|
707
776
|
* Disconnect the upstream IDE.
|
|
@@ -819,7 +888,7 @@ var AcpGateway = class {
|
|
|
819
888
|
};
|
|
820
889
|
|
|
821
890
|
// src/connection-manager.ts
|
|
822
|
-
var
|
|
891
|
+
var logger6 = createLogger6("acp-connection-manager");
|
|
823
892
|
var AcpConnectionManager = class {
|
|
824
893
|
connections = /* @__PURE__ */ new Map();
|
|
825
894
|
primarySessions = /* @__PURE__ */ new Map();
|
|
@@ -853,7 +922,7 @@ var AcpConnectionManager = class {
|
|
|
853
922
|
this.connections.set(name, connWithRouter);
|
|
854
923
|
this.routers.set(name, router);
|
|
855
924
|
try {
|
|
856
|
-
await connWithRouter.spawn(options.command, options.args, options.cwd);
|
|
925
|
+
await connWithRouter.spawn(options.command, options.args, options.cwd, options.resolvePackage);
|
|
857
926
|
await connWithRouter.initialize();
|
|
858
927
|
const session = await connWithRouter.newSession(options.cwd);
|
|
859
928
|
this.primarySessions.set(name, session.sessionId);
|
|
@@ -862,7 +931,7 @@ var AcpConnectionManager = class {
|
|
|
862
931
|
callbackRouter: router
|
|
863
932
|
});
|
|
864
933
|
this.gateways.set(name, gateway);
|
|
865
|
-
|
|
934
|
+
logger6.info({ name, sessionId: session.sessionId }, "ACP agent connected (gateway-ready)");
|
|
866
935
|
return session;
|
|
867
936
|
} catch (err) {
|
|
868
937
|
await connWithRouter.close().catch(() => {
|
|
@@ -916,12 +985,12 @@ var AcpConnectionManager = class {
|
|
|
916
985
|
await conn.close();
|
|
917
986
|
this.connections.delete(name);
|
|
918
987
|
this.primarySessions.delete(name);
|
|
919
|
-
|
|
988
|
+
logger6.info({ name }, "ACP agent disconnected");
|
|
920
989
|
}
|
|
921
990
|
async disposeAll() {
|
|
922
991
|
const names = Array.from(this.connections.keys());
|
|
923
992
|
await Promise.allSettled(names.map((n) => this.disconnect(n)));
|
|
924
|
-
|
|
993
|
+
logger6.info({ count: names.length }, "All ACP connections disposed");
|
|
925
994
|
}
|
|
926
995
|
/**
|
|
927
996
|
* Update the permission policy for a named connection at runtime.
|
|
@@ -980,8 +1049,8 @@ function buildLocalHandler(_conn, options, enforcer, auditLogger) {
|
|
|
980
1049
|
},
|
|
981
1050
|
writeTextFile: async (params) => {
|
|
982
1051
|
const { writeFile, mkdir } = await import("fs/promises");
|
|
983
|
-
const { dirname } = await import("path");
|
|
984
|
-
await mkdir(
|
|
1052
|
+
const { dirname: dirname2 } = await import("path");
|
|
1053
|
+
await mkdir(dirname2(params.path), { recursive: true });
|
|
985
1054
|
await writeFile(params.path, params.content, "utf-8");
|
|
986
1055
|
return {};
|
|
987
1056
|
},
|
|
@@ -994,20 +1063,20 @@ function buildLocalHandler(_conn, options, enforcer, auditLogger) {
|
|
|
994
1063
|
}
|
|
995
1064
|
|
|
996
1065
|
// src/communicator.ts
|
|
997
|
-
import { createLogger as
|
|
998
|
-
var
|
|
1066
|
+
import { createLogger as createLogger7 } from "@actant/shared";
|
|
1067
|
+
var logger7 = createLogger7("acp-communicator");
|
|
999
1068
|
var AcpCommunicator = class {
|
|
1000
1069
|
constructor(connection, sessionId) {
|
|
1001
1070
|
this.connection = connection;
|
|
1002
1071
|
this.sessionId = sessionId;
|
|
1003
1072
|
}
|
|
1004
1073
|
async runPrompt(_workspaceDir, prompt, _options) {
|
|
1005
|
-
|
|
1074
|
+
logger7.debug({ sessionId: this.sessionId, promptLength: prompt.length }, "Sending ACP prompt");
|
|
1006
1075
|
const result = await this.connection.prompt(this.sessionId, prompt);
|
|
1007
1076
|
return { text: result.text, sessionId: this.sessionId };
|
|
1008
1077
|
}
|
|
1009
1078
|
async *streamPrompt(_workspaceDir, prompt, _options) {
|
|
1010
|
-
|
|
1079
|
+
logger7.debug({ sessionId: this.sessionId, promptLength: prompt.length }, "Streaming ACP prompt");
|
|
1011
1080
|
for await (const notification of this.connection.streamPrompt(this.sessionId, prompt)) {
|
|
1012
1081
|
const chunks = mapNotificationToChunks(notification);
|
|
1013
1082
|
for (const chunk of chunks) {
|
|
@@ -1091,6 +1160,7 @@ export {
|
|
|
1091
1160
|
AcpConnectionManager,
|
|
1092
1161
|
AcpGateway,
|
|
1093
1162
|
ClientCallbackRouter,
|
|
1094
|
-
LocalTerminalManager
|
|
1163
|
+
LocalTerminalManager,
|
|
1164
|
+
resolveAcpBinary
|
|
1095
1165
|
};
|
|
1096
1166
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connection.ts","../src/terminal-manager.ts","../src/connection-manager.ts","../src/callback-router.ts","../src/gateway.ts","../src/communicator.ts"],"sourcesContent":["import { spawn, type ChildProcess } from \"node:child_process\";\nimport { Writable, Readable } from \"node:stream\";\nimport {\n ClientSideConnection,\n ndJsonStream,\n type Client,\n type Agent,\n type InitializeResponse,\n type NewSessionResponse,\n type PromptResponse,\n type SessionNotification,\n type ContentBlock,\n type RequestPermissionRequest,\n type RequestPermissionResponse,\n type ReadTextFileRequest,\n type ReadTextFileResponse,\n type WriteTextFileRequest,\n type WriteTextFileResponse,\n type CreateTerminalRequest,\n type CreateTerminalResponse,\n type TerminalOutputRequest,\n type TerminalOutputResponse,\n type WaitForTerminalExitRequest,\n type WaitForTerminalExitResponse,\n type KillTerminalCommandRequest,\n type KillTerminalCommandResponse,\n type ReleaseTerminalRequest,\n type ReleaseTerminalResponse,\n} from \"@agentclientprotocol/sdk\";\nimport { createLogger, isWindows } from \"@actant/shared\";\nimport type { PermissionsConfig } from \"@actant/shared\";\nimport { PermissionPolicyEnforcer, PermissionAuditLogger } from \"@actant/core\";\nimport { LocalTerminalManager } from \"./terminal-manager\";\n\nconst logger = createLogger(\"acp-connection\");\n\n/* ------------------------------------------------------------------ */\n/* Client callback delegation */\n/* ------------------------------------------------------------------ */\n\n/**\n * Pluggable handler for every Client callback the Agent can invoke.\n * Implementations decide whether to handle locally or forward to IDE.\n */\nexport interface ClientCallbackHandler {\n requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;\n sessionUpdate(params: SessionNotification): Promise<void>;\n readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;\n writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;\n createTerminal?(params: CreateTerminalRequest): Promise<CreateTerminalResponse>;\n terminalOutput?(params: TerminalOutputRequest): Promise<TerminalOutputResponse>;\n waitForTerminalExit?(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse>;\n killTerminal?(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse>;\n releaseTerminal?(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse>;\n}\n\n/* ------------------------------------------------------------------ */\n/* Options & session info */\n/* ------------------------------------------------------------------ */\n\nexport interface AcpConnectionOptions {\n /** Auto-approve all tool permission requests (fallback when no permissionPolicy). */\n autoApprove?: boolean;\n /** Permission policy for the ACP Client allowlist (Layer 2 enforcement). */\n permissionPolicy?: PermissionsConfig;\n /** Instance name for audit logging. */\n instanceName?: string;\n /** Global session update listener. */\n onSessionUpdate?: (notification: SessionNotification) => void;\n /** Env vars to pass to the agent subprocess. */\n env?: Record<string, string>;\n /**\n * Override the default local Client callbacks.\n * When provided, AcpConnection delegates ALL Client requests to this handler\n * instead of using the built-in local implementation.\n * Used by AcpGateway to route callbacks to IDE or local depending on lease state.\n */\n callbackHandler?: ClientCallbackHandler;\n}\n\nexport interface AcpSessionInfo {\n sessionId: string;\n modes?: NewSessionResponse[\"modes\"];\n configOptions?: NewSessionResponse[\"configOptions\"];\n}\n\n/* ------------------------------------------------------------------ */\n/* AcpConnection */\n/* ------------------------------------------------------------------ */\n\n/**\n * Wraps a ClientSideConnection + child process lifecycle.\n * Manages spawn → initialize → session/new → prompt → cancel → close.\n *\n * Implements ALL ACP Client callbacks:\n * - requestPermission (auto-approve or delegate)\n * - sessionUpdate\n * - fs/read_text_file (with line/limit)\n * - fs/write_text_file\n * - terminal/* (create, output, wait_for_exit, kill, release)\n */\nexport class AcpConnection {\n private child: ChildProcess | null = null;\n private conn: ClientSideConnection | null = null;\n private initResponse: InitializeResponse | null = null;\n private sessions = new Map<string, AcpSessionInfo>();\n private updateListeners = new Map<string, ((n: SessionNotification) => void)[]>();\n private readonly options: AcpConnectionOptions;\n private readonly terminalManager: LocalTerminalManager;\n private enforcer: PermissionPolicyEnforcer | null = null;\n private auditLogger: PermissionAuditLogger;\n\n constructor(options?: AcpConnectionOptions) {\n this.options = options ?? {};\n this.terminalManager = new LocalTerminalManager();\n this.auditLogger = new PermissionAuditLogger(options?.instanceName);\n if (options?.permissionPolicy) {\n this.enforcer = new PermissionPolicyEnforcer(options.permissionPolicy);\n }\n }\n\n /** Update the permission policy at runtime (hot-reload). */\n updatePermissionPolicy(config: PermissionsConfig): void {\n if (this.enforcer) {\n this.enforcer.updateConfig(config);\n } else {\n this.enforcer = new PermissionPolicyEnforcer(config);\n }\n this.auditLogger.logUpdated(\"runtime\");\n }\n\n get isConnected(): boolean {\n return this.conn != null && !this.conn.signal.aborted;\n }\n\n get agentCapabilities(): InitializeResponse | null {\n return this.initResponse;\n }\n\n get rawConnection(): ClientSideConnection | null {\n return this.conn;\n }\n\n /* ---------------------------------------------------------------- */\n /* Lifecycle */\n /* ---------------------------------------------------------------- */\n\n async spawn(command: string, args: string[], cwd: string): Promise<void> {\n if (this.child) throw new Error(\"AcpConnection already spawned\");\n\n const env = { ...process.env, ...this.options.env };\n logger.info({ command, args, cwd }, \"Spawning ACP agent subprocess\");\n\n this.child = spawn(command, args, {\n cwd,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n shell: isWindows(),\n });\n\n if (!this.child.stdout || !this.child.stdin) {\n throw new Error(\"Failed to create stdio pipes for ACP agent\");\n }\n\n this.child.stderr?.on(\"data\", (chunk: Buffer) => {\n logger.debug({ stderr: chunk.toString().trim() }, \"ACP agent stderr\");\n });\n this.child.on(\"error\", (err) => {\n logger.error({ error: err }, \"ACP agent process error\");\n });\n\n const webWritable = Writable.toWeb(this.child.stdin) as WritableStream<Uint8Array>;\n const webReadable = Readable.toWeb(this.child.stdout) as ReadableStream<Uint8Array>;\n const stream = ndJsonStream(webWritable, webReadable);\n\n this.conn = new ClientSideConnection(\n (_agent: Agent): Client => this.buildClient(),\n stream,\n );\n\n this.conn.signal.addEventListener(\"abort\", () => {\n logger.info(\"ACP connection closed\");\n });\n }\n\n async initialize(): Promise<InitializeResponse> {\n if (!this.conn) throw new Error(\"AcpConnection not spawned\");\n\n this.initResponse = await this.conn.initialize({\n protocolVersion: 1,\n clientCapabilities: {\n fs: { readTextFile: true, writeTextFile: true },\n terminal: true,\n },\n clientInfo: {\n name: \"actant\",\n title: \"Actant Daemon\",\n version: \"0.1.0\",\n },\n });\n\n logger.info({\n agentName: this.initResponse.agentInfo?.name,\n protocolVersion: this.initResponse.protocolVersion,\n loadSession: this.initResponse.agentCapabilities?.loadSession,\n }, \"ACP initialized\");\n\n return this.initResponse;\n }\n\n /* ---------------------------------------------------------------- */\n /* Session management */\n /* ---------------------------------------------------------------- */\n\n async newSession(cwd: string, mcpServers: NewSessionResponse[\"modes\"] extends unknown ? unknown[] : never[] = []): Promise<AcpSessionInfo> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n\n const response = await this.conn.newSession({\n cwd,\n mcpServers: mcpServers as never[],\n });\n const info: AcpSessionInfo = {\n sessionId: response.sessionId,\n modes: response.modes,\n configOptions: response.configOptions,\n };\n this.sessions.set(response.sessionId, info);\n\n logger.info({ sessionId: response.sessionId, cwd }, \"ACP session created\");\n return info;\n }\n\n async loadSession(sessionId: string, cwd: string): Promise<void> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n if (!this.initResponse?.agentCapabilities?.loadSession) {\n throw new Error(\"Agent does not support loadSession capability\");\n }\n await this.conn.loadSession({ sessionId, cwd, mcpServers: [] });\n logger.info({ sessionId }, \"ACP session loaded\");\n }\n\n async setSessionMode(sessionId: string, modeId: string): Promise<void> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n await this.conn.setSessionMode({ sessionId, modeId });\n logger.info({ sessionId, modeId }, \"Session mode set\");\n }\n\n async setSessionConfigOption(sessionId: string, configId: string, value: string): Promise<unknown> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n const result = await this.conn.setSessionConfigOption({ sessionId, configId, value });\n logger.info({ sessionId, configId, value }, \"Session config option set\");\n return result;\n }\n\n async authenticate(methodId: string): Promise<void> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n await this.conn.authenticate({ methodId });\n logger.info({ methodId }, \"Authenticated\");\n }\n\n /* ---------------------------------------------------------------- */\n /* Prompt */\n /* ---------------------------------------------------------------- */\n\n /**\n * Send a prompt with arbitrary content blocks.\n * For text-only convenience, use the string overload.\n */\n async prompt(\n sessionId: string,\n content: string | ContentBlock[],\n ): Promise<{ stopReason: string; text: string }> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n\n const promptBlocks: ContentBlock[] = typeof content === \"string\"\n ? [{ type: \"text\", text: content }]\n : content;\n\n let collectedText = \"\";\n const listener = (notification: SessionNotification) => {\n const update = notification.update;\n if (update.sessionUpdate === \"agent_message_chunk\" && update.content.type === \"text\") {\n collectedText += update.content.text;\n }\n };\n this.addUpdateListener(sessionId, listener);\n\n try {\n const response: PromptResponse = await this.conn.prompt({\n sessionId,\n prompt: promptBlocks,\n });\n return { stopReason: response.stopReason, text: collectedText };\n } finally {\n this.removeUpdateListener(sessionId, listener);\n }\n }\n\n /**\n * Stream prompt — yields every SessionNotification as it arrives.\n */\n async *streamPrompt(\n sessionId: string,\n content: string | ContentBlock[],\n ): AsyncIterable<SessionNotification> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n\n const promptBlocks: ContentBlock[] = typeof content === \"string\"\n ? [{ type: \"text\", text: content }]\n : content;\n\n const queue: SessionNotification[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n const listener = (notification: SessionNotification) => {\n queue.push(notification);\n resolve?.();\n };\n this.addUpdateListener(sessionId, listener);\n\n const promptPromise = this.conn.prompt({\n sessionId,\n prompt: promptBlocks,\n }).then(() => {\n done = true;\n resolve?.();\n }).catch((err) => {\n done = true;\n resolve?.();\n throw err;\n });\n\n try {\n while (!done || queue.length > 0) {\n if (queue.length === 0 && !done) {\n await new Promise<void>((r) => { resolve = r; });\n resolve = null;\n }\n while (queue.length > 0) {\n const item = queue.shift();\n if (item) yield item;\n }\n }\n await promptPromise;\n } finally {\n this.removeUpdateListener(sessionId, listener);\n }\n }\n\n async cancel(sessionId: string): Promise<void> {\n if (!this.conn) return;\n await this.conn.cancel({ sessionId });\n }\n\n /* ---------------------------------------------------------------- */\n /* Session accessors */\n /* ---------------------------------------------------------------- */\n\n getSession(sessionId: string): AcpSessionInfo | undefined {\n return this.sessions.get(sessionId);\n }\n\n listSessions(): string[] {\n return Array.from(this.sessions.keys());\n }\n\n /* ---------------------------------------------------------------- */\n /* Close */\n /* ---------------------------------------------------------------- */\n\n async close(): Promise<void> {\n this.terminalManager.disposeAll();\n\n if (this.child) {\n const child = this.child;\n this.child = null;\n\n if (child.stdin && !child.stdin.destroyed) {\n child.stdin.end();\n }\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => { child.kill(\"SIGKILL\"); resolve(); }, 5000);\n child.once(\"exit\", () => { clearTimeout(timer); resolve(); });\n child.kill(\"SIGTERM\");\n });\n logger.info(\"ACP agent subprocess terminated\");\n }\n\n this.conn = null;\n this.initResponse = null;\n this.sessions.clear();\n this.updateListeners.clear();\n }\n\n /* ---------------------------------------------------------------- */\n /* Build the Client callback implementation */\n /* ---------------------------------------------------------------- */\n\n private buildClient(): Client {\n const handler = this.options.callbackHandler;\n\n if (handler) {\n return {\n requestPermission: (p) => handler.requestPermission(p),\n sessionUpdate: async (p) => {\n await handler.sessionUpdate(p);\n this.dispatchToListeners(p);\n },\n readTextFile: (p) => handler.readTextFile(p),\n writeTextFile: (p) => handler.writeTextFile(p),\n createTerminal: handler.createTerminal?.bind(handler),\n terminalOutput: handler.terminalOutput?.bind(handler),\n waitForTerminalExit: handler.waitForTerminalExit?.bind(handler),\n killTerminal: handler.killTerminal?.bind(handler),\n releaseTerminal: handler.releaseTerminal?.bind(handler),\n };\n }\n\n return {\n requestPermission: (p) => this.localRequestPermission(p),\n sessionUpdate: (p) => this.localSessionUpdate(p),\n readTextFile: (p) => this.localReadTextFile(p),\n writeTextFile: (p) => this.localWriteTextFile(p),\n createTerminal: (p) => this.terminalManager.createTerminal(p),\n terminalOutput: (p) => this.terminalManager.terminalOutput(p),\n waitForTerminalExit: (p) => this.terminalManager.waitForExit(p),\n killTerminal: (p) => this.terminalManager.killTerminal(p),\n releaseTerminal: (p) => this.terminalManager.releaseTerminal(p),\n };\n }\n\n /* ---------------------------------------------------------------- */\n /* Local callback implementations */\n /* ---------------------------------------------------------------- */\n\n private async localRequestPermission(\n params: RequestPermissionRequest,\n ): Promise<RequestPermissionResponse> {\n // Layer 2: Policy-based enforcement via PermissionPolicyEnforcer\n if (this.enforcer && params.options.length > 0) {\n const toolInfo = {\n kind: params.toolCall?.kind ?? undefined,\n title: params.toolCall?.title ?? undefined,\n toolCallId: params.toolCall?.toolCallId ?? \"unknown\",\n };\n const decision = this.enforcer.evaluate(toolInfo);\n this.auditLogger.logEvaluation(toolInfo, decision);\n\n if (decision.action === \"allow\" || decision.action === \"deny\") {\n const outcome = this.enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n // \"ask\" decision: fall through to autoApprove or cancelled\n }\n\n // Fallback: legacy autoApprove behavior\n if (this.options.autoApprove && params.options.length > 0) {\n const allowOption = params.options.find(\n (o) => o.kind === \"allow_once\" || o.kind === \"allow_always\",\n ) ?? params.options[0];\n if (!allowOption) return { outcome: { outcome: \"cancelled\" } };\n return { outcome: { outcome: \"selected\", optionId: allowOption.optionId } };\n }\n logger.warn({ sessionId: params.sessionId }, \"Permission request denied (no handler)\");\n return { outcome: { outcome: \"cancelled\" } };\n }\n\n private async localSessionUpdate(params: SessionNotification): Promise<void> {\n this.options.onSessionUpdate?.(params);\n this.dispatchToListeners(params);\n }\n\n private dispatchToListeners(params: SessionNotification): void {\n const listeners = this.updateListeners.get(params.sessionId);\n if (listeners) {\n for (const listener of listeners) {\n listener(params);\n }\n }\n }\n\n private async localReadTextFile(\n params: ReadTextFileRequest,\n ): Promise<ReadTextFileResponse> {\n const { readFile } = await import(\"node:fs/promises\");\n try {\n const raw = await readFile(params.path, \"utf-8\");\n\n if (params.line != null || params.limit != null) {\n const lines = raw.split(\"\\n\");\n const start = Math.max(0, (params.line ?? 1) - 1);\n const end = params.limit != null ? start + params.limit : lines.length;\n return { content: lines.slice(start, end).join(\"\\n\") };\n }\n return { content: raw };\n } catch {\n throw new Error(`Cannot read file: ${params.path}`);\n }\n }\n\n private async localWriteTextFile(\n params: WriteTextFileRequest,\n ): Promise<WriteTextFileResponse> {\n const { writeFile, mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n try {\n await mkdir(dirname(params.path), { recursive: true });\n await writeFile(params.path, params.content, \"utf-8\");\n return {};\n } catch {\n throw new Error(`Cannot write file: ${params.path}`);\n }\n }\n\n /* ---------------------------------------------------------------- */\n /* Update listener management */\n /* ---------------------------------------------------------------- */\n\n addUpdateListener(sessionId: string, listener: (n: SessionNotification) => void): void {\n const existing = this.updateListeners.get(sessionId) ?? [];\n existing.push(listener);\n this.updateListeners.set(sessionId, existing);\n }\n\n removeUpdateListener(sessionId: string, listener: (n: SessionNotification) => void): void {\n const existing = this.updateListeners.get(sessionId);\n if (existing) {\n const idx = existing.indexOf(listener);\n if (idx >= 0) existing.splice(idx, 1);\n if (existing.length === 0) this.updateListeners.delete(sessionId);\n }\n }\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { createLogger } from \"@actant/shared\";\nimport type {\n CreateTerminalRequest,\n CreateTerminalResponse,\n TerminalOutputRequest,\n TerminalOutputResponse,\n WaitForTerminalExitRequest,\n WaitForTerminalExitResponse,\n KillTerminalCommandRequest,\n KillTerminalCommandResponse,\n ReleaseTerminalRequest,\n ReleaseTerminalResponse,\n TerminalExitStatus,\n} from \"@agentclientprotocol/sdk\";\n\nconst logger = createLogger(\"acp-terminal\");\n\ninterface ManagedTerminal {\n id: string;\n process: ChildProcess;\n output: Buffer[];\n totalBytes: number;\n outputByteLimit: number;\n exitStatus: TerminalExitStatus | null;\n exitPromise: Promise<TerminalExitStatus>;\n disposed: boolean;\n}\n\n/**\n * Manages local terminal processes for ACP Client terminal/* callbacks.\n * Each terminal is a child process with captured stdout/stderr output.\n */\nexport class LocalTerminalManager {\n private terminals = new Map<string, ManagedTerminal>();\n private counter = 0;\n\n async createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse> {\n const id = `term_${++this.counter}_${Date.now()}`;\n\n const envEntries: Record<string, string> = { ...process.env } as Record<string, string>;\n if (params.env) {\n for (const entry of params.env) {\n envEntries[entry.name] = entry.value;\n }\n }\n\n const proc = spawn(params.command, params.args ?? [], {\n cwd: params.cwd ?? undefined,\n env: envEntries,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: true,\n });\n\n const limit = params.outputByteLimit ?? 1024 * 1024; // 1MB default\n const output: Buffer[] = [];\n let totalBytes = 0;\n\n const exitPromise = new Promise<TerminalExitStatus>((resolve) => {\n proc.on(\"exit\", (code, signal) => {\n resolve({ exitCode: code ?? null, signal: signal ?? null });\n });\n proc.on(\"error\", (err) => {\n logger.error({ terminalId: id, error: err }, \"Terminal process error\");\n resolve({ exitCode: 1, signal: null });\n });\n });\n\n const appendOutput = (chunk: Buffer) => {\n output.push(chunk);\n totalBytes += chunk.length;\n // Truncate from beginning if over limit\n while (totalBytes > limit && output.length > 1) {\n const removed = output.shift();\n if (removed) totalBytes -= removed.length;\n }\n };\n\n proc.stdout?.on(\"data\", appendOutput);\n proc.stderr?.on(\"data\", appendOutput);\n\n const terminal: ManagedTerminal = {\n id,\n process: proc,\n output,\n totalBytes,\n outputByteLimit: limit,\n exitStatus: null,\n exitPromise,\n disposed: false,\n };\n\n // Keep exitStatus updated via closure\n exitPromise.then((status) => { terminal.exitStatus = status; });\n\n this.terminals.set(id, terminal);\n logger.info({ terminalId: id, command: params.command, cwd: params.cwd }, \"Terminal created\");\n return { terminalId: id };\n }\n\n async terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse> {\n const term = this.getTerminal(params.terminalId);\n const outputStr = Buffer.concat(term.output).toString(\"utf-8\");\n const truncated = term.totalBytes > term.outputByteLimit;\n\n return {\n output: outputStr,\n truncated,\n ...(term.exitStatus != null ? { exitStatus: term.exitStatus } : {}),\n };\n }\n\n async waitForExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse> {\n const term = this.getTerminal(params.terminalId);\n const status = await term.exitPromise;\n return { exitCode: status.exitCode, signal: status.signal };\n }\n\n async killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse> {\n const term = this.getTerminal(params.terminalId);\n if (!term.process.killed && term.exitStatus == null) {\n term.process.kill(\"SIGTERM\");\n // Give it 3s to die gracefully, then SIGKILL\n setTimeout(() => {\n if (term.exitStatus == null && !term.process.killed) {\n term.process.kill(\"SIGKILL\");\n }\n }, 3000);\n }\n return {};\n }\n\n async releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse> {\n const term = this.terminals.get(params.terminalId);\n if (!term) return {};\n\n if (!term.process.killed && term.exitStatus == null) {\n term.process.kill(\"SIGKILL\");\n }\n term.disposed = true;\n this.terminals.delete(params.terminalId);\n logger.debug({ terminalId: params.terminalId }, \"Terminal released\");\n return {};\n }\n\n disposeAll(): void {\n for (const [id, term] of this.terminals) {\n if (!term.process.killed && term.exitStatus == null) {\n term.process.kill(\"SIGKILL\");\n }\n term.disposed = true;\n this.terminals.delete(id);\n }\n }\n\n private getTerminal(terminalId: string): ManagedTerminal {\n const term = this.terminals.get(terminalId);\n if (!term) {\n throw new Error(`Terminal \"${terminalId}\" not found or already released`);\n }\n return term;\n }\n}\n","import type { Socket } from \"node:net\";\nimport { createLogger } from \"@actant/shared\";\nimport type { PermissionsConfig } from \"@actant/shared\";\nimport { PermissionPolicyEnforcer, PermissionAuditLogger } from \"@actant/core\";\nimport { AcpConnection, type AcpConnectionOptions, type AcpSessionInfo, type ClientCallbackHandler } from \"./connection\";\nimport { ClientCallbackRouter } from \"./callback-router\";\nimport { AcpGateway } from \"./gateway\";\nimport { LocalTerminalManager } from \"./terminal-manager\";\n\nconst logger = createLogger(\"acp-connection-manager\");\n\nexport interface ConnectOptions {\n command: string;\n args: string[];\n cwd: string;\n connectionOptions?: AcpConnectionOptions;\n}\n\n/**\n * Manages a pool of ACP connections keyed by agent instance name.\n * Handles spawn → initialize → session lifecycle for each agent.\n * Supports Gateway mode for Session Lease (IDE ↔ Gateway ↔ Agent).\n */\nexport class AcpConnectionManager {\n private connections = new Map<string, AcpConnection>();\n private primarySessions = new Map<string, string>();\n private routers = new Map<string, ClientCallbackRouter>();\n private gateways = new Map<string, AcpGateway>();\n private enforcers = new Map<string, PermissionPolicyEnforcer>();\n\n /**\n * Spawn an ACP agent process, initialize, and create a default session.\n * Uses ClientCallbackRouter so Gateway can later attach an IDE upstream.\n * When connectionOptions.permissionPolicy is set, creates a PermissionPolicyEnforcer\n * for Layer 2 ACP Client allowlist enforcement.\n */\n async connect(name: string, options: ConnectOptions): Promise<AcpSessionInfo> {\n if (this.connections.has(name)) {\n throw new Error(`ACP connection for \"${name}\" already exists`);\n }\n\n // Create enforcer if permission policy is provided\n let enforcer: PermissionPolicyEnforcer | undefined;\n let auditLogger: PermissionAuditLogger | undefined;\n if (options.connectionOptions?.permissionPolicy) {\n enforcer = new PermissionPolicyEnforcer(options.connectionOptions.permissionPolicy);\n auditLogger = new PermissionAuditLogger(name);\n this.enforcers.set(name, enforcer);\n }\n\n // Build a local-only AcpConnection first; the router wraps it\n // so we can later attach an IDE upstream without reinitializing.\n const localConn = new AcpConnection(options.connectionOptions);\n\n // Create a router using the connection's built-in local callbacks as fallback.\n // We create a \"local handler\" that is the default AcpConnection behavior.\n const localHandler: ClientCallbackHandler = buildLocalHandler(localConn, options.connectionOptions, enforcer, auditLogger);\n const router = new ClientCallbackRouter(localHandler);\n\n // Now create the real connection with the router as callback handler\n const connWithRouter = new AcpConnection({\n ...options.connectionOptions,\n callbackHandler: router,\n });\n\n this.connections.set(name, connWithRouter);\n this.routers.set(name, router);\n\n try {\n await connWithRouter.spawn(options.command, options.args, options.cwd);\n await connWithRouter.initialize();\n const session = await connWithRouter.newSession(options.cwd);\n this.primarySessions.set(name, session.sessionId);\n\n // Pre-create a Gateway for this connection (inactive until IDE connects)\n const gateway = new AcpGateway({\n downstream: connWithRouter,\n callbackRouter: router,\n });\n this.gateways.set(name, gateway);\n\n logger.info({ name, sessionId: session.sessionId }, \"ACP agent connected (gateway-ready)\");\n return session;\n } catch (err) {\n await connWithRouter.close().catch(() => {});\n this.connections.delete(name);\n this.primarySessions.delete(name);\n this.routers.delete(name);\n throw err;\n }\n }\n\n /**\n * Accept an IDE connection on the Gateway for a named agent.\n * The IDE socket carries ACP protocol messages.\n */\n acceptLeaseSocket(name: string, socket: Socket): void {\n const gateway = this.gateways.get(name);\n if (!gateway) {\n throw new Error(`No gateway for agent \"${name}\". Is the agent connected via ACP?`);\n }\n gateway.acceptSocket(socket);\n }\n\n /**\n * Disconnect IDE from the Gateway.\n */\n disconnectLease(name: string): void {\n this.gateways.get(name)?.disconnectUpstream();\n }\n\n getConnection(name: string): AcpConnection | undefined {\n return this.connections.get(name);\n }\n\n getGateway(name: string): AcpGateway | undefined {\n return this.gateways.get(name);\n }\n\n getRouter(name: string): ClientCallbackRouter | undefined {\n return this.routers.get(name);\n }\n\n getPrimarySessionId(name: string): string | undefined {\n return this.primarySessions.get(name);\n }\n\n has(name: string): boolean {\n const conn = this.connections.get(name);\n return conn != null && conn.isConnected;\n }\n\n async disconnect(name: string): Promise<void> {\n this.gateways.get(name)?.disconnectUpstream();\n this.gateways.delete(name);\n this.routers.delete(name);\n this.enforcers.delete(name);\n\n const conn = this.connections.get(name);\n if (!conn) return;\n await conn.close();\n this.connections.delete(name);\n this.primarySessions.delete(name);\n logger.info({ name }, \"ACP agent disconnected\");\n }\n\n async disposeAll(): Promise<void> {\n const names = Array.from(this.connections.keys());\n await Promise.allSettled(names.map((n) => this.disconnect(n)));\n logger.info({ count: names.length }, \"All ACP connections disposed\");\n }\n\n /**\n * Update the permission policy for a named connection at runtime.\n * Propagates to both the AcpConnection and the local handler enforcer.\n */\n updatePermissionPolicy(name: string, config: PermissionsConfig): void {\n const conn = this.connections.get(name);\n if (conn) {\n conn.updatePermissionPolicy(config);\n }\n const enforcer = this.enforcers.get(name);\n if (enforcer) {\n enforcer.updateConfig(config);\n }\n }\n}\n\n/**\n * Build a local ClientCallbackHandler from connection defaults.\n * This is the \"Mode A\" handler used when no IDE is connected.\n * When a permissionPolicy is provided, uses PermissionPolicyEnforcer for smart decisions.\n */\nfunction buildLocalHandler(\n _conn: AcpConnection,\n options?: AcpConnectionOptions,\n enforcer?: PermissionPolicyEnforcer,\n auditLogger?: PermissionAuditLogger,\n): ClientCallbackHandler {\n const terminalManager = new LocalTerminalManager();\n\n return {\n requestPermission: async (params) => {\n // Layer 2: Policy-based enforcement\n if (enforcer && params.options.length > 0) {\n const toolInfo = {\n kind: params.toolCall?.kind ?? undefined,\n title: params.toolCall?.title ?? undefined,\n toolCallId: params.toolCall?.toolCallId ?? \"unknown\",\n };\n const decision = enforcer.evaluate(toolInfo);\n auditLogger?.logEvaluation(toolInfo, decision);\n\n if (decision.action === \"allow\" || decision.action === \"deny\") {\n const outcome = enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n }\n\n // Fallback: legacy autoApprove\n if (options?.autoApprove && params.options.length > 0) {\n const opt = params.options.find(\n (o) => o.kind === \"allow_once\" || o.kind === \"allow_always\",\n ) ?? params.options[0];\n if (!opt) return { outcome: { outcome: \"cancelled\" } };\n return { outcome: { outcome: \"selected\", optionId: opt.optionId } };\n }\n return { outcome: { outcome: \"cancelled\" } };\n },\n\n sessionUpdate: async (params) => {\n options?.onSessionUpdate?.(params);\n },\n\n readTextFile: async (params) => {\n const { readFile } = await import(\"node:fs/promises\");\n const raw = await readFile(params.path, \"utf-8\");\n if (params.line != null || params.limit != null) {\n const lines = raw.split(\"\\n\");\n const start = Math.max(0, (params.line ?? 1) - 1);\n const end = params.limit != null ? start + params.limit : lines.length;\n return { content: lines.slice(start, end).join(\"\\n\") };\n }\n return { content: raw };\n },\n\n writeTextFile: async (params) => {\n const { writeFile, mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n await mkdir(dirname(params.path), { recursive: true });\n await writeFile(params.path, params.content, \"utf-8\");\n return {};\n },\n\n createTerminal: (p) => terminalManager.createTerminal(p),\n terminalOutput: (p) => terminalManager.terminalOutput(p),\n waitForTerminalExit: (p) => terminalManager.waitForExit(p),\n killTerminal: (p) => terminalManager.killTerminal(p),\n releaseTerminal: (p) => terminalManager.releaseTerminal(p),\n };\n}\n","import type {\n RequestPermissionRequest,\n RequestPermissionResponse,\n SessionNotification,\n ReadTextFileRequest,\n ReadTextFileResponse,\n WriteTextFileRequest,\n WriteTextFileResponse,\n CreateTerminalRequest,\n CreateTerminalResponse,\n TerminalOutputRequest,\n TerminalOutputResponse,\n WaitForTerminalExitRequest,\n WaitForTerminalExitResponse,\n KillTerminalCommandRequest,\n KillTerminalCommandResponse,\n ReleaseTerminalRequest,\n ReleaseTerminalResponse,\n ClientCapabilities,\n} from \"@agentclientprotocol/sdk\";\nimport { createLogger } from \"@actant/shared\";\nimport type { PermissionPolicyEnforcer } from \"@actant/core\";\nimport type { ClientCallbackHandler } from \"./connection\";\n\nconst logger = createLogger(\"acp-callback-router\");\n\n/**\n * Upstream (IDE) handler interface.\n * When a lease is active, agent callbacks are forwarded to the IDE\n * through this interface, which wraps the AgentSideConnection facing the IDE.\n */\nexport interface UpstreamHandler {\n requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;\n sessionUpdate(params: SessionNotification): Promise<void>;\n readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;\n writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;\n createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse>;\n terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse>;\n waitForTerminalExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse>;\n killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse>;\n releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse>;\n}\n\n/**\n * Routes Client callbacks from the Agent to either:\n * (A) the IDE (upstream) — when a lease is active and IDE supports the capability\n * (B) local handlers (impersonation) — when no lease or IDE lacks the capability\n *\n * The Agent always sees full capabilities; the router handles fallback transparently.\n */\nexport class ClientCallbackRouter implements ClientCallbackHandler {\n private upstream: UpstreamHandler | null = null;\n private ideCapabilities: ClientCapabilities | null = null;\n private enforcer: PermissionPolicyEnforcer | null = null;\n\n constructor(private readonly local: ClientCallbackHandler) {}\n\n /** Attach a PermissionPolicyEnforcer for pre-filtering in lease mode. */\n setEnforcer(enforcer: PermissionPolicyEnforcer | null): void {\n this.enforcer = enforcer;\n }\n\n /**\n * Activate lease-forwarding mode.\n * Callbacks will be routed to the IDE for supported capabilities.\n */\n attachUpstream(handler: UpstreamHandler, capabilities: ClientCapabilities): void {\n this.upstream = handler;\n this.ideCapabilities = capabilities;\n logger.info({\n terminal: !!capabilities.terminal,\n fsRead: !!capabilities.fs?.readTextFile,\n fsWrite: !!capabilities.fs?.writeTextFile,\n }, \"Upstream IDE attached — lease forwarding active\");\n }\n\n /**\n * Deactivate lease-forwarding. All callbacks revert to local handlers.\n */\n detachUpstream(): void {\n this.upstream = null;\n this.ideCapabilities = null;\n logger.info(\"Upstream IDE detached — local mode\");\n }\n\n get isLeaseActive(): boolean {\n return this.upstream != null;\n }\n\n /* ---------------------------------------------------------------- */\n /* ClientCallbackHandler implementation */\n /* ---------------------------------------------------------------- */\n\n async requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {\n // Pre-filter with enforcer: deny/allow decisions bypass IDE forwarding\n if (this.enforcer && params.options.length > 0) {\n const toolInfo = {\n kind: params.toolCall?.kind ?? undefined,\n title: params.toolCall?.title ?? undefined,\n toolCallId: params.toolCall?.toolCallId ?? \"unknown\",\n };\n const decision = this.enforcer.evaluate(toolInfo);\n if (decision.action === \"deny\") {\n const outcome = this.enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n if (decision.action === \"allow\") {\n const outcome = this.enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n // \"ask\" → fall through to upstream IDE or local\n }\n\n if (this.upstream) {\n try {\n return await this.upstream.requestPermission(params);\n } catch (err) {\n logger.warn({ error: err }, \"Failed to forward requestPermission to IDE, falling back\");\n }\n }\n return this.local.requestPermission(params);\n }\n\n async sessionUpdate(params: SessionNotification): Promise<void> {\n // Always notify local listeners (for internal state tracking)\n await this.local.sessionUpdate(params);\n // Also forward to IDE when lease is active\n if (this.upstream) {\n try {\n await this.upstream.sessionUpdate(params);\n } catch {\n // Best-effort: IDE might have disconnected\n }\n }\n }\n\n async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {\n if (this.upstream && this.ideCapabilities?.fs?.readTextFile) {\n try {\n return await this.upstream.readTextFile(params);\n } catch (err) {\n logger.warn({ path: params.path, error: err }, \"IDE readTextFile failed, falling back\");\n }\n }\n return this.local.readTextFile(params);\n }\n\n async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {\n if (this.upstream && this.ideCapabilities?.fs?.writeTextFile) {\n try {\n return await this.upstream.writeTextFile(params);\n } catch (err) {\n logger.warn({ path: params.path, error: err }, \"IDE writeTextFile failed, falling back\");\n }\n }\n return this.local.writeTextFile(params);\n }\n\n async createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.createTerminal(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE createTerminal failed, falling back\");\n }\n }\n if (this.local.createTerminal) return this.local.createTerminal(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.terminalOutput(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE terminalOutput failed, falling back\");\n }\n }\n if (this.local.terminalOutput) return this.local.terminalOutput(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async waitForTerminalExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.waitForTerminalExit(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE waitForTerminalExit failed, falling back\");\n }\n }\n if (this.local.waitForTerminalExit) return this.local.waitForTerminalExit(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.killTerminal(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE killTerminal failed, falling back\");\n }\n }\n if (this.local.killTerminal) return this.local.killTerminal(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.releaseTerminal(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE releaseTerminal failed, falling back\");\n }\n }\n if (this.local.releaseTerminal) return this.local.releaseTerminal(params);\n throw new Error(\"Terminal not supported\");\n }\n}\n","import { Duplex } from \"node:stream\";\nimport type { Socket } from \"node:net\";\nimport {\n AgentSideConnection,\n TerminalHandle,\n ndJsonStream,\n type Agent,\n type InitializeResponse,\n type ClientCapabilities,\n type NewSessionResponse,\n type LoadSessionResponse,\n type SetSessionConfigOptionResponse,\n} from \"@agentclientprotocol/sdk\";\nimport { createLogger } from \"@actant/shared\";\nimport type { AcpConnection } from \"./connection\";\nimport { ClientCallbackRouter, type UpstreamHandler } from \"./callback-router\";\n\nconst logger = createLogger(\"acp-gateway\");\n\nexport interface GatewayOptions {\n /** The downstream AcpConnection (Daemon → Agent). */\n downstream: AcpConnection;\n /** The callback router to attach upstream when IDE connects. */\n callbackRouter: ClientCallbackRouter;\n}\n\n/**\n * ACP Gateway — bridges upstream IDE (ACP Client) and downstream Agent (ACP Server).\n *\n * Architecture:\n * IDE ← ACP/socket → AgentSideConnection (upstream)\n * ↕ (bridged)\n * ClientSideConnection (downstream) ← ACP/stdio → Agent\n *\n * The Gateway:\n * - Exposes an Agent interface to the IDE via AgentSideConnection\n * - Forwards IDE requests (prompt, cancel, etc.) to the downstream Agent\n * - Routes Agent callbacks (permissions, fs, terminal) to IDE or local\n * via the ClientCallbackRouter\n */\nexport class AcpGateway {\n private upstream: AgentSideConnection | null = null;\n private readonly downstream: AcpConnection;\n private readonly callbackRouter: ClientCallbackRouter;\n private ideCapabilities: ClientCapabilities | null = null;\n /**\n * WORKAROUND for SDK API limitation (see #95):\n * AgentSideConnection exposes flat methods for fs (readTextFile, writeTextFile)\n * but wraps terminal ops behind TerminalHandle. Ideally the Gateway should be\n * stateless — the IDE (Client) manages its own terminal state keyed by terminalId.\n * We maintain this map only because the SDK doesn't expose flat terminalOutput(),\n * waitForTerminalExit(), killTerminal(), releaseTerminal() on AgentSideConnection.\n * Remove this once the SDK adds flat terminal methods.\n */\n private terminalHandles = new Map<string, TerminalHandle>();\n\n constructor(options: GatewayOptions) {\n this.downstream = options.downstream;\n this.callbackRouter = options.callbackRouter;\n }\n\n get isUpstreamConnected(): boolean {\n return this.upstream != null && !this.upstream.signal.aborted;\n }\n\n /**\n * Accept an IDE connection on a Unix/named-pipe socket.\n * Creates an AgentSideConnection that bridges to the downstream Agent.\n */\n acceptSocket(socket: Socket): void {\n if (this.upstream && !this.upstream.signal.aborted) {\n throw new Error(\"Gateway already has an active upstream connection\");\n }\n\n const { readable, writable } = Duplex.toWeb(socket as unknown as Duplex);\n const stream = ndJsonStream(\n writable as WritableStream<Uint8Array>,\n readable as ReadableStream<Uint8Array>,\n );\n\n this.upstream = new AgentSideConnection(\n (conn: AgentSideConnection): Agent => this.buildAgentHandler(conn),\n stream,\n );\n\n this.upstream.signal.addEventListener(\"abort\", () => {\n logger.info(\"Upstream IDE disconnected from Gateway\");\n for (const handle of this.terminalHandles.values()) {\n handle.release().catch(() => {});\n }\n this.terminalHandles.clear();\n this.callbackRouter.detachUpstream();\n this.ideCapabilities = null;\n });\n\n logger.info(\"Upstream IDE connected to Gateway\");\n }\n\n /**\n * Disconnect the upstream IDE.\n */\n disconnectUpstream(): void {\n for (const handle of this.terminalHandles.values()) {\n handle.release().catch(() => {});\n }\n this.terminalHandles.clear();\n this.callbackRouter.detachUpstream();\n this.upstream = null;\n this.ideCapabilities = null;\n }\n\n /* ---------------------------------------------------------------- */\n /* Agent handler (facing IDE) */\n /* ---------------------------------------------------------------- */\n\n private buildAgentHandler(conn: AgentSideConnection): Agent {\n const cachedInit = this.downstream.agentCapabilities;\n\n const upstreamHandler: UpstreamHandler = {\n requestPermission: (p) => conn.requestPermission(p),\n sessionUpdate: (p) => conn.sessionUpdate(p),\n readTextFile: (p) => conn.readTextFile(p),\n writeTextFile: (p) => conn.writeTextFile(p),\n // Terminal forwarding via TerminalHandle map.\n // SDK limitation: AgentSideConnection doesn't expose flat terminalOutput() etc.\n // so we store handles from createTerminal and delegate through them.\n // The IDE (Client) owns the real terminal state; this map is purely an SDK\n // adapter and should be removed once the SDK exposes flat terminal methods.\n createTerminal: async (p) => {\n const handle = await conn.createTerminal(p);\n this.terminalHandles.set(handle.id, handle);\n return { terminalId: handle.id };\n },\n terminalOutput: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) throw new Error(`Terminal \"${p.terminalId}\" not found in Gateway handle map`);\n return handle.currentOutput();\n },\n waitForTerminalExit: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) throw new Error(`Terminal \"${p.terminalId}\" not found in Gateway handle map`);\n return handle.waitForExit();\n },\n killTerminal: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) throw new Error(`Terminal \"${p.terminalId}\" not found in Gateway handle map`);\n return handle.kill();\n },\n releaseTerminal: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) return {};\n const result = await handle.release();\n this.terminalHandles.delete(p.terminalId);\n return result ?? {};\n },\n };\n\n return {\n initialize: async (params) => {\n this.ideCapabilities = params.clientCapabilities ?? {};\n this.callbackRouter.attachUpstream(upstreamHandler, this.ideCapabilities);\n\n // Return the cached Agent capabilities to the IDE\n if (cachedInit) {\n return {\n protocolVersion: cachedInit.protocolVersion,\n agentCapabilities: cachedInit.agentCapabilities,\n agentInfo: cachedInit.agentInfo,\n authMethods: cachedInit.authMethods,\n } as InitializeResponse;\n }\n return {\n protocolVersion: 1,\n agentCapabilities: {},\n agentInfo: { name: \"actant-gateway\", version: \"0.1.0\" },\n } as InitializeResponse;\n },\n\n authenticate: async (params) => {\n await this.downstream.authenticate(params.methodId);\n return {};\n },\n\n newSession: async (params) => {\n const info = await this.downstream.newSession(\n params.cwd,\n params.mcpServers as never[],\n );\n return {\n sessionId: info.sessionId,\n modes: info.modes,\n configOptions: info.configOptions,\n } as NewSessionResponse;\n },\n\n loadSession: async (params) => {\n await this.downstream.loadSession(params.sessionId, params.cwd);\n return {} as LoadSessionResponse;\n },\n\n prompt: async (params) => {\n const conn = this.downstream.rawConnection;\n if (!conn) throw new Error(\"Downstream not connected\");\n return conn.prompt(params);\n },\n\n cancel: async (params) => {\n await this.downstream.cancel(params.sessionId);\n },\n\n setSessionMode: async (params) => {\n await this.downstream.setSessionMode(params.sessionId, params.modeId);\n },\n\n setSessionConfigOption: async (params) => {\n return await this.downstream.setSessionConfigOption(\n params.sessionId, params.configId, params.value,\n ) as unknown as SetSessionConfigOptionResponse;\n },\n };\n }\n}\n","import type { SessionNotification, ContentBlock } from \"@agentclientprotocol/sdk\";\nimport type {\n AgentCommunicator,\n PromptResult,\n RunPromptOptions,\n StreamChunk,\n} from \"@actant/core\";\nimport { createLogger } from \"@actant/shared\";\nimport type { AcpConnection } from \"./connection\";\n\ninterface PlanEntry { status: string; content: string }\ntype UnknownRecord = Record<string, unknown>;\n\nconst logger = createLogger(\"acp-communicator\");\n\n/**\n * Bridges an AcpConnection to the AgentCommunicator interface.\n * Used by AgentManager to send prompts through ACP sessions.\n */\nexport class AcpCommunicator implements AgentCommunicator {\n constructor(\n private readonly connection: AcpConnection,\n private readonly sessionId: string,\n ) {}\n\n async runPrompt(\n _workspaceDir: string,\n prompt: string,\n _options?: RunPromptOptions,\n ): Promise<PromptResult> {\n logger.debug({ sessionId: this.sessionId, promptLength: prompt.length }, \"Sending ACP prompt\");\n const result = await this.connection.prompt(this.sessionId, prompt);\n return { text: result.text, sessionId: this.sessionId };\n }\n\n async *streamPrompt(\n _workspaceDir: string,\n prompt: string,\n _options?: RunPromptOptions,\n ): AsyncIterable<StreamChunk> {\n logger.debug({ sessionId: this.sessionId, promptLength: prompt.length }, \"Streaming ACP prompt\");\n for await (const notification of this.connection.streamPrompt(this.sessionId, prompt)) {\n const chunks = mapNotificationToChunks(notification);\n for (const chunk of chunks) {\n yield chunk;\n }\n }\n }\n}\n\n/**\n * Maps a SessionNotification to zero or more StreamChunks.\n * Handles ALL notification types defined by the ACP protocol.\n */\nfunction mapNotificationToChunks(notification: SessionNotification): StreamChunk[] {\n const update = notification.update;\n\n switch (update.sessionUpdate) {\n case \"agent_message_chunk\":\n return [mapContentToChunk(update.content)].filter(Boolean) as StreamChunk[];\n\n case \"agent_thought_chunk\":\n if (update.content.type === \"text\") {\n return [{ type: \"text\", content: `[Thought] ${update.content.text}` }];\n }\n return [];\n\n case \"user_message_chunk\":\n return [];\n\n case \"tool_call\":\n return [{\n type: \"tool_use\",\n content: `[Tool: ${update.title ?? \"unknown\"}] ${update.toolCallId} (${update.kind ?? \"other\"}) [${update.status ?? \"pending\"}]`,\n }];\n\n case \"tool_call_update\": {\n const chunks: StreamChunk[] = [];\n if (update.content) {\n for (const item of update.content) {\n if (item.type === \"content\" && item.content.type === \"text\") {\n chunks.push({ type: \"text\", content: item.content.text });\n } else if (item.type === \"diff\") {\n chunks.push({\n type: \"text\",\n content: `[Diff: ${(item as UnknownRecord).path ?? \"\"}]`,\n });\n }\n }\n }\n return chunks;\n }\n\n case \"plan\": {\n const entries = (update as UnknownRecord).entries as PlanEntry[] | undefined;\n return [{\n type: \"text\",\n content: entries\n ?.map((e) => `[Plan ${e.status}] ${e.content}`)\n .join(\"\\n\") ?? \"[Plan updated]\",\n }];\n }\n\n case \"available_commands_update\":\n return [];\n\n case \"current_mode_update\":\n return [{\n type: \"text\",\n content: `[Mode changed: ${(update as UnknownRecord).modeId ?? \"unknown\"}]`,\n }];\n\n case \"config_option_update\":\n return [];\n\n default:\n return [];\n }\n}\n\nfunction mapContentToChunk(content: ContentBlock): StreamChunk | null {\n switch (content.type) {\n case \"text\":\n return { type: \"text\", content: content.text };\n case \"image\":\n return { type: \"text\", content: \"[Image content]\" };\n case \"audio\":\n return { type: \"text\", content: \"[Audio content]\" };\n case \"resource\":\n return { type: \"text\", content: `[Resource: ${((content as UnknownRecord).resource as UnknownRecord)?.uri ?? \"unknown\"}]` };\n case \"resource_link\":\n return { type: \"text\", content: `[ResourceLink: ${(content as UnknownRecord).uri ?? \"unknown\"}]` };\n default:\n return null;\n }\n}\n"],"mappings":"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","names":["spawn","createLogger","logger","createLogger","spawn","createLogger","PermissionPolicyEnforcer","PermissionAuditLogger","createLogger","logger","ndJsonStream","createLogger","logger","conn","logger","createLogger","PermissionPolicyEnforcer","PermissionAuditLogger","createLogger","logger"]}
|
|
1
|
+
{"version":3,"sources":["../src/connection.ts","../src/binary-resolver.ts","../src/terminal-manager.ts","../src/connection-manager.ts","../src/callback-router.ts","../src/gateway.ts","../src/communicator.ts"],"sourcesContent":["import { spawn, type ChildProcess } from \"node:child_process\";\nimport { Writable, Readable } from \"node:stream\";\nimport {\n ClientSideConnection,\n ndJsonStream,\n type Client,\n type Agent,\n type InitializeResponse,\n type NewSessionResponse,\n type PromptResponse,\n type SessionNotification,\n type ContentBlock,\n type RequestPermissionRequest,\n type RequestPermissionResponse,\n type ReadTextFileRequest,\n type ReadTextFileResponse,\n type WriteTextFileRequest,\n type WriteTextFileResponse,\n type CreateTerminalRequest,\n type CreateTerminalResponse,\n type TerminalOutputRequest,\n type TerminalOutputResponse,\n type WaitForTerminalExitRequest,\n type WaitForTerminalExitResponse,\n type KillTerminalCommandRequest,\n type KillTerminalCommandResponse,\n type ReleaseTerminalRequest,\n type ReleaseTerminalResponse,\n} from \"@agentclientprotocol/sdk\";\nimport { createLogger, isWindows } from \"@actant/shared\";\nimport { resolveAcpBinary } from \"./binary-resolver\";\nimport type { PermissionsConfig } from \"@actant/shared\";\nimport { PermissionPolicyEnforcer, PermissionAuditLogger } from \"@actant/core\";\nimport { LocalTerminalManager } from \"./terminal-manager\";\n\nconst logger = createLogger(\"acp-connection\");\n\n/* ------------------------------------------------------------------ */\n/* Client callback delegation */\n/* ------------------------------------------------------------------ */\n\n/**\n * Pluggable handler for every Client callback the Agent can invoke.\n * Implementations decide whether to handle locally or forward to IDE.\n */\nexport interface ClientCallbackHandler {\n requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;\n sessionUpdate(params: SessionNotification): Promise<void>;\n readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;\n writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;\n createTerminal?(params: CreateTerminalRequest): Promise<CreateTerminalResponse>;\n terminalOutput?(params: TerminalOutputRequest): Promise<TerminalOutputResponse>;\n waitForTerminalExit?(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse>;\n killTerminal?(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse>;\n releaseTerminal?(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse>;\n}\n\n/* ------------------------------------------------------------------ */\n/* Options & session info */\n/* ------------------------------------------------------------------ */\n\nexport interface AcpConnectionOptions {\n /** Auto-approve all tool permission requests (fallback when no permissionPolicy). */\n autoApprove?: boolean;\n /** Permission policy for the ACP Client allowlist (Layer 2 enforcement). */\n permissionPolicy?: PermissionsConfig;\n /** Instance name for audit logging. */\n instanceName?: string;\n /** Global session update listener. */\n onSessionUpdate?: (notification: SessionNotification) => void;\n /** Env vars to pass to the agent subprocess. */\n env?: Record<string, string>;\n /**\n * Override the default local Client callbacks.\n * When provided, AcpConnection delegates ALL Client requests to this handler\n * instead of using the built-in local implementation.\n * Used by AcpGateway to route callbacks to IDE or local depending on lease state.\n */\n callbackHandler?: ClientCallbackHandler;\n}\n\nexport interface AcpSessionInfo {\n sessionId: string;\n modes?: NewSessionResponse[\"modes\"];\n configOptions?: NewSessionResponse[\"configOptions\"];\n}\n\n/* ------------------------------------------------------------------ */\n/* AcpConnection */\n/* ------------------------------------------------------------------ */\n\n/**\n * Wraps a ClientSideConnection + child process lifecycle.\n * Manages spawn → initialize → session/new → prompt → cancel → close.\n *\n * Implements ALL ACP Client callbacks:\n * - requestPermission (auto-approve or delegate)\n * - sessionUpdate\n * - fs/read_text_file (with line/limit)\n * - fs/write_text_file\n * - terminal/* (create, output, wait_for_exit, kill, release)\n */\nexport class AcpConnection {\n private child: ChildProcess | null = null;\n private conn: ClientSideConnection | null = null;\n private initResponse: InitializeResponse | null = null;\n private sessions = new Map<string, AcpSessionInfo>();\n private updateListeners = new Map<string, ((n: SessionNotification) => void)[]>();\n private readonly options: AcpConnectionOptions;\n private readonly terminalManager: LocalTerminalManager;\n private enforcer: PermissionPolicyEnforcer | null = null;\n private auditLogger: PermissionAuditLogger;\n private _earlyExitPromise: Promise<never> | null = null;\n\n constructor(options?: AcpConnectionOptions) {\n this.options = options ?? {};\n this.terminalManager = new LocalTerminalManager();\n this.auditLogger = new PermissionAuditLogger(options?.instanceName);\n if (options?.permissionPolicy) {\n this.enforcer = new PermissionPolicyEnforcer(options.permissionPolicy);\n }\n }\n\n /** Update the permission policy at runtime (hot-reload). */\n updatePermissionPolicy(config: PermissionsConfig): void {\n if (this.enforcer) {\n this.enforcer.updateConfig(config);\n } else {\n this.enforcer = new PermissionPolicyEnforcer(config);\n }\n this.auditLogger.logUpdated(\"runtime\");\n }\n\n get isConnected(): boolean {\n return this.conn != null && !this.conn.signal.aborted;\n }\n\n get agentCapabilities(): InitializeResponse | null {\n return this.initResponse;\n }\n\n get rawConnection(): ClientSideConnection | null {\n return this.conn;\n }\n\n /* ---------------------------------------------------------------- */\n /* Lifecycle */\n /* ---------------------------------------------------------------- */\n\n async spawn(command: string, args: string[], cwd: string, resolvePackage?: string): Promise<void> {\n if (this.child) throw new Error(\"AcpConnection already spawned\");\n\n const resolved = resolveAcpBinary(command, resolvePackage);\n const finalCommand = resolved.command;\n const finalArgs = [...resolved.prependArgs, ...args];\n\n const env = { ...process.env, ...this.options.env };\n logger.info({ command: finalCommand, args: finalArgs, cwd }, \"Spawning ACP agent subprocess\");\n\n this.child = spawn(finalCommand, finalArgs, {\n cwd,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n shell: isWindows(),\n });\n\n if (!this.child.stdout || !this.child.stdin) {\n throw new Error(\"Failed to create stdio pipes for ACP agent\");\n }\n\n const stderrChunks: string[] = [];\n this.child.stderr?.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString().trim();\n if (text) stderrChunks.push(text);\n logger.debug({ stderr: text }, \"ACP agent stderr\");\n });\n this.child.on(\"error\", (err) => {\n logger.error({ error: err }, \"ACP agent process error\");\n });\n\n this._earlyExitPromise = new Promise<never>((_resolve, reject) => {\n this.child!.on(\"exit\", (code, signal) => {\n const stderr = stderrChunks.join(\"\\n\");\n const detail = stderr\n ? `\\n stderr: ${stderr}`\n : \"\";\n reject(new Error(\n `ACP agent process exited unexpectedly (code=${code}, signal=${signal}).` +\n ` Command: ${finalCommand} ${finalArgs.join(\" \")}${detail}`,\n ));\n });\n });\n this._earlyExitPromise.catch(() => {});\n\n const webWritable = Writable.toWeb(this.child.stdin) as WritableStream<Uint8Array>;\n const webReadable = Readable.toWeb(this.child.stdout) as ReadableStream<Uint8Array>;\n const stream = ndJsonStream(webWritable, webReadable);\n\n this.conn = new ClientSideConnection(\n (_agent: Agent): Client => this.buildClient(),\n stream,\n );\n\n this.conn.signal.addEventListener(\"abort\", () => {\n logger.info(\"ACP connection closed\");\n });\n }\n\n async initialize(): Promise<InitializeResponse> {\n if (!this.conn) throw new Error(\"AcpConnection not spawned\");\n\n const initPromise = this.conn.initialize({\n protocolVersion: 1,\n clientCapabilities: {\n fs: { readTextFile: true, writeTextFile: true },\n terminal: true,\n },\n clientInfo: {\n name: \"actant\",\n title: \"Actant Daemon\",\n version: \"0.1.0\",\n },\n });\n\n this.initResponse = this._earlyExitPromise\n ? await Promise.race([initPromise, this._earlyExitPromise])\n : await initPromise;\n\n this._earlyExitPromise = null;\n\n logger.info({\n agentName: this.initResponse.agentInfo?.name,\n protocolVersion: this.initResponse.protocolVersion,\n loadSession: this.initResponse.agentCapabilities?.loadSession,\n }, \"ACP initialized\");\n\n return this.initResponse;\n }\n\n /* ---------------------------------------------------------------- */\n /* Session management */\n /* ---------------------------------------------------------------- */\n\n async newSession(cwd: string, mcpServers: NewSessionResponse[\"modes\"] extends unknown ? unknown[] : never[] = []): Promise<AcpSessionInfo> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n\n const response = await this.conn.newSession({\n cwd,\n mcpServers: mcpServers as never[],\n });\n const info: AcpSessionInfo = {\n sessionId: response.sessionId,\n modes: response.modes,\n configOptions: response.configOptions,\n };\n this.sessions.set(response.sessionId, info);\n\n logger.info({ sessionId: response.sessionId, cwd }, \"ACP session created\");\n return info;\n }\n\n async loadSession(sessionId: string, cwd: string): Promise<void> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n if (!this.initResponse?.agentCapabilities?.loadSession) {\n throw new Error(\"Agent does not support loadSession capability\");\n }\n await this.conn.loadSession({ sessionId, cwd, mcpServers: [] });\n logger.info({ sessionId }, \"ACP session loaded\");\n }\n\n async setSessionMode(sessionId: string, modeId: string): Promise<void> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n await this.conn.setSessionMode({ sessionId, modeId });\n logger.info({ sessionId, modeId }, \"Session mode set\");\n }\n\n async setSessionConfigOption(sessionId: string, configId: string, value: string): Promise<unknown> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n const result = await this.conn.setSessionConfigOption({ sessionId, configId, value });\n logger.info({ sessionId, configId, value }, \"Session config option set\");\n return result;\n }\n\n async authenticate(methodId: string): Promise<void> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n await this.conn.authenticate({ methodId });\n logger.info({ methodId }, \"Authenticated\");\n }\n\n /* ---------------------------------------------------------------- */\n /* Prompt */\n /* ---------------------------------------------------------------- */\n\n /**\n * Send a prompt with arbitrary content blocks.\n * For text-only convenience, use the string overload.\n */\n async prompt(\n sessionId: string,\n content: string | ContentBlock[],\n ): Promise<{ stopReason: string; text: string }> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n\n const promptBlocks: ContentBlock[] = typeof content === \"string\"\n ? [{ type: \"text\", text: content }]\n : content;\n\n let collectedText = \"\";\n const listener = (notification: SessionNotification) => {\n const update = notification.update;\n if (update.sessionUpdate === \"agent_message_chunk\" && update.content.type === \"text\") {\n collectedText += update.content.text;\n }\n };\n this.addUpdateListener(sessionId, listener);\n\n try {\n const response: PromptResponse = await this.conn.prompt({\n sessionId,\n prompt: promptBlocks,\n });\n return { stopReason: response.stopReason, text: collectedText };\n } finally {\n this.removeUpdateListener(sessionId, listener);\n }\n }\n\n /**\n * Stream prompt — yields every SessionNotification as it arrives.\n */\n async *streamPrompt(\n sessionId: string,\n content: string | ContentBlock[],\n ): AsyncIterable<SessionNotification> {\n if (!this.conn) throw new Error(\"AcpConnection not initialized\");\n\n const promptBlocks: ContentBlock[] = typeof content === \"string\"\n ? [{ type: \"text\", text: content }]\n : content;\n\n const queue: SessionNotification[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n const listener = (notification: SessionNotification) => {\n queue.push(notification);\n resolve?.();\n };\n this.addUpdateListener(sessionId, listener);\n\n const promptPromise = this.conn.prompt({\n sessionId,\n prompt: promptBlocks,\n }).then(() => {\n done = true;\n resolve?.();\n }).catch((err) => {\n done = true;\n resolve?.();\n throw err;\n });\n\n try {\n while (!done || queue.length > 0) {\n if (queue.length === 0 && !done) {\n await new Promise<void>((r) => { resolve = r; });\n resolve = null;\n }\n while (queue.length > 0) {\n const item = queue.shift();\n if (item) yield item;\n }\n }\n await promptPromise;\n } finally {\n this.removeUpdateListener(sessionId, listener);\n }\n }\n\n async cancel(sessionId: string): Promise<void> {\n if (!this.conn) return;\n await this.conn.cancel({ sessionId });\n }\n\n /* ---------------------------------------------------------------- */\n /* Session accessors */\n /* ---------------------------------------------------------------- */\n\n getSession(sessionId: string): AcpSessionInfo | undefined {\n return this.sessions.get(sessionId);\n }\n\n listSessions(): string[] {\n return Array.from(this.sessions.keys());\n }\n\n /* ---------------------------------------------------------------- */\n /* Close */\n /* ---------------------------------------------------------------- */\n\n async close(): Promise<void> {\n this.terminalManager.disposeAll();\n\n if (this.child) {\n const child = this.child;\n this.child = null;\n\n if (child.stdin && !child.stdin.destroyed) {\n child.stdin.end();\n }\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => { child.kill(\"SIGKILL\"); resolve(); }, 5000);\n child.once(\"exit\", () => { clearTimeout(timer); resolve(); });\n child.kill(\"SIGTERM\");\n });\n logger.info(\"ACP agent subprocess terminated\");\n }\n\n this.conn = null;\n this.initResponse = null;\n this.sessions.clear();\n this.updateListeners.clear();\n }\n\n /* ---------------------------------------------------------------- */\n /* Build the Client callback implementation */\n /* ---------------------------------------------------------------- */\n\n private buildClient(): Client {\n const handler = this.options.callbackHandler;\n\n if (handler) {\n return {\n requestPermission: (p) => handler.requestPermission(p),\n sessionUpdate: async (p) => {\n await handler.sessionUpdate(p);\n this.dispatchToListeners(p);\n },\n readTextFile: (p) => handler.readTextFile(p),\n writeTextFile: (p) => handler.writeTextFile(p),\n createTerminal: handler.createTerminal?.bind(handler),\n terminalOutput: handler.terminalOutput?.bind(handler),\n waitForTerminalExit: handler.waitForTerminalExit?.bind(handler),\n killTerminal: handler.killTerminal?.bind(handler),\n releaseTerminal: handler.releaseTerminal?.bind(handler),\n };\n }\n\n return {\n requestPermission: (p) => this.localRequestPermission(p),\n sessionUpdate: (p) => this.localSessionUpdate(p),\n readTextFile: (p) => this.localReadTextFile(p),\n writeTextFile: (p) => this.localWriteTextFile(p),\n createTerminal: (p) => this.terminalManager.createTerminal(p),\n terminalOutput: (p) => this.terminalManager.terminalOutput(p),\n waitForTerminalExit: (p) => this.terminalManager.waitForExit(p),\n killTerminal: (p) => this.terminalManager.killTerminal(p),\n releaseTerminal: (p) => this.terminalManager.releaseTerminal(p),\n };\n }\n\n /* ---------------------------------------------------------------- */\n /* Local callback implementations */\n /* ---------------------------------------------------------------- */\n\n private async localRequestPermission(\n params: RequestPermissionRequest,\n ): Promise<RequestPermissionResponse> {\n // Layer 2: Policy-based enforcement via PermissionPolicyEnforcer\n if (this.enforcer && params.options.length > 0) {\n const toolInfo = {\n kind: params.toolCall?.kind ?? undefined,\n title: params.toolCall?.title ?? undefined,\n toolCallId: params.toolCall?.toolCallId ?? \"unknown\",\n };\n const decision = this.enforcer.evaluate(toolInfo);\n this.auditLogger.logEvaluation(toolInfo, decision);\n\n if (decision.action === \"allow\" || decision.action === \"deny\") {\n const outcome = this.enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n // \"ask\" decision: fall through to autoApprove or cancelled\n }\n\n // Fallback: legacy autoApprove behavior\n if (this.options.autoApprove && params.options.length > 0) {\n const allowOption = params.options.find(\n (o) => o.kind === \"allow_once\" || o.kind === \"allow_always\",\n ) ?? params.options[0];\n if (!allowOption) return { outcome: { outcome: \"cancelled\" } };\n return { outcome: { outcome: \"selected\", optionId: allowOption.optionId } };\n }\n logger.warn({ sessionId: params.sessionId }, \"Permission request denied (no handler)\");\n return { outcome: { outcome: \"cancelled\" } };\n }\n\n private async localSessionUpdate(params: SessionNotification): Promise<void> {\n this.options.onSessionUpdate?.(params);\n this.dispatchToListeners(params);\n }\n\n private dispatchToListeners(params: SessionNotification): void {\n const listeners = this.updateListeners.get(params.sessionId);\n if (listeners) {\n for (const listener of listeners) {\n listener(params);\n }\n }\n }\n\n private async localReadTextFile(\n params: ReadTextFileRequest,\n ): Promise<ReadTextFileResponse> {\n const { readFile } = await import(\"node:fs/promises\");\n try {\n const raw = await readFile(params.path, \"utf-8\");\n\n if (params.line != null || params.limit != null) {\n const lines = raw.split(\"\\n\");\n const start = Math.max(0, (params.line ?? 1) - 1);\n const end = params.limit != null ? start + params.limit : lines.length;\n return { content: lines.slice(start, end).join(\"\\n\") };\n }\n return { content: raw };\n } catch {\n throw new Error(`Cannot read file: ${params.path}`);\n }\n }\n\n private async localWriteTextFile(\n params: WriteTextFileRequest,\n ): Promise<WriteTextFileResponse> {\n const { writeFile, mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n try {\n await mkdir(dirname(params.path), { recursive: true });\n await writeFile(params.path, params.content, \"utf-8\");\n return {};\n } catch {\n throw new Error(`Cannot write file: ${params.path}`);\n }\n }\n\n /* ---------------------------------------------------------------- */\n /* Update listener management */\n /* ---------------------------------------------------------------- */\n\n addUpdateListener(sessionId: string, listener: (n: SessionNotification) => void): void {\n const existing = this.updateListeners.get(sessionId) ?? [];\n existing.push(listener);\n this.updateListeners.set(sessionId, existing);\n }\n\n removeUpdateListener(sessionId: string, listener: (n: SessionNotification) => void): void {\n const existing = this.updateListeners.get(sessionId);\n if (existing) {\n const idx = existing.indexOf(listener);\n if (idx >= 0) existing.splice(idx, 1);\n if (existing.length === 0) this.updateListeners.delete(sessionId);\n }\n }\n}\n","import { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { createLogger, isWindows } from \"@actant/shared\";\n\nconst logger = createLogger(\"binary-resolver\");\n\nexport interface ResolvedAcpBinary {\n command: string;\n prependArgs: string[];\n}\n\n/**\n * Resolve an ACP binary command to an executable path.\n *\n * Resolution order:\n * 1. Check if the command is already on PATH → return as-is\n * 2. If `resolvePackage` is provided → resolve bin script from that npm package\n * in node_modules, run via `node <script-path>`\n * 3. Return original command (caller will get a proper spawn error)\n *\n * @param command The command name (e.g. \"claude-agent-acp.cmd\")\n * @param resolvePackage npm package that provides the binary (from BackendDescriptor)\n */\nexport function resolveAcpBinary(command: string, resolvePackage?: string): ResolvedAcpBinary {\n if (isOnPath(command)) {\n return { command, prependArgs: [] };\n }\n\n if (!resolvePackage) {\n return { command, prependArgs: [] };\n }\n\n const bareName = command.replace(/\\.cmd$/, \"\");\n const scriptPath = resolveScriptFromPackage(resolvePackage, bareName);\n if (scriptPath) {\n logger.info({ bareName, resolvePackage, scriptPath }, \"Resolved ACP binary from backend dependency\");\n const nodeCmd = isWindows() && process.execPath.includes(\" \")\n ? `\"${process.execPath}\"`\n : process.execPath;\n return { command: nodeCmd, prependArgs: [scriptPath] };\n }\n\n return { command, prependArgs: [] };\n}\n\nfunction isOnPath(command: string): boolean {\n try {\n const which = isWindows() ? \"where.exe\" : \"which\";\n execSync(`${which} ${command}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction resolveScriptFromPackage(packageName: string, binName: string): string | null {\n try {\n const require = createRequire(import.meta.url);\n const pkgJsonPath = require.resolve(`${packageName}/package.json`);\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n\n const binField = pkgJson.bin;\n const relBinPath = typeof binField === \"string\"\n ? binField\n : binField?.[binName];\n\n if (!relBinPath) return null;\n\n return join(dirname(pkgJsonPath), relBinPath);\n } catch {\n return null;\n }\n}\n","import { spawn, type ChildProcess } from \"node:child_process\";\nimport { createLogger } from \"@actant/shared\";\nimport type {\n CreateTerminalRequest,\n CreateTerminalResponse,\n TerminalOutputRequest,\n TerminalOutputResponse,\n WaitForTerminalExitRequest,\n WaitForTerminalExitResponse,\n KillTerminalCommandRequest,\n KillTerminalCommandResponse,\n ReleaseTerminalRequest,\n ReleaseTerminalResponse,\n TerminalExitStatus,\n} from \"@agentclientprotocol/sdk\";\n\nconst logger = createLogger(\"acp-terminal\");\n\ninterface ManagedTerminal {\n id: string;\n process: ChildProcess;\n output: Buffer[];\n totalBytes: number;\n outputByteLimit: number;\n exitStatus: TerminalExitStatus | null;\n exitPromise: Promise<TerminalExitStatus>;\n disposed: boolean;\n}\n\n/**\n * Manages local terminal processes for ACP Client terminal/* callbacks.\n * Each terminal is a child process with captured stdout/stderr output.\n */\nexport class LocalTerminalManager {\n private terminals = new Map<string, ManagedTerminal>();\n private counter = 0;\n\n async createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse> {\n const id = `term_${++this.counter}_${Date.now()}`;\n\n const envEntries: Record<string, string> = { ...process.env } as Record<string, string>;\n if (params.env) {\n for (const entry of params.env) {\n envEntries[entry.name] = entry.value;\n }\n }\n\n const proc = spawn(params.command, params.args ?? [], {\n cwd: params.cwd ?? undefined,\n env: envEntries,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: true,\n });\n\n const limit = params.outputByteLimit ?? 1024 * 1024; // 1MB default\n const output: Buffer[] = [];\n let totalBytes = 0;\n\n const exitPromise = new Promise<TerminalExitStatus>((resolve) => {\n proc.on(\"exit\", (code, signal) => {\n resolve({ exitCode: code ?? null, signal: signal ?? null });\n });\n proc.on(\"error\", (err) => {\n logger.error({ terminalId: id, error: err }, \"Terminal process error\");\n resolve({ exitCode: 1, signal: null });\n });\n });\n\n const appendOutput = (chunk: Buffer) => {\n output.push(chunk);\n totalBytes += chunk.length;\n // Truncate from beginning if over limit\n while (totalBytes > limit && output.length > 1) {\n const removed = output.shift();\n if (removed) totalBytes -= removed.length;\n }\n };\n\n proc.stdout?.on(\"data\", appendOutput);\n proc.stderr?.on(\"data\", appendOutput);\n\n const terminal: ManagedTerminal = {\n id,\n process: proc,\n output,\n totalBytes,\n outputByteLimit: limit,\n exitStatus: null,\n exitPromise,\n disposed: false,\n };\n\n // Keep exitStatus updated via closure\n exitPromise.then((status) => { terminal.exitStatus = status; });\n\n this.terminals.set(id, terminal);\n logger.info({ terminalId: id, command: params.command, cwd: params.cwd }, \"Terminal created\");\n return { terminalId: id };\n }\n\n async terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse> {\n const term = this.getTerminal(params.terminalId);\n const outputStr = Buffer.concat(term.output).toString(\"utf-8\");\n const truncated = term.totalBytes > term.outputByteLimit;\n\n return {\n output: outputStr,\n truncated,\n ...(term.exitStatus != null ? { exitStatus: term.exitStatus } : {}),\n };\n }\n\n async waitForExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse> {\n const term = this.getTerminal(params.terminalId);\n const status = await term.exitPromise;\n return { exitCode: status.exitCode, signal: status.signal };\n }\n\n async killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse> {\n const term = this.getTerminal(params.terminalId);\n if (!term.process.killed && term.exitStatus == null) {\n term.process.kill(\"SIGTERM\");\n // Give it 3s to die gracefully, then SIGKILL\n setTimeout(() => {\n if (term.exitStatus == null && !term.process.killed) {\n term.process.kill(\"SIGKILL\");\n }\n }, 3000);\n }\n return {};\n }\n\n async releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse> {\n const term = this.terminals.get(params.terminalId);\n if (!term) return {};\n\n if (!term.process.killed && term.exitStatus == null) {\n term.process.kill(\"SIGKILL\");\n }\n term.disposed = true;\n this.terminals.delete(params.terminalId);\n logger.debug({ terminalId: params.terminalId }, \"Terminal released\");\n return {};\n }\n\n disposeAll(): void {\n for (const [id, term] of this.terminals) {\n if (!term.process.killed && term.exitStatus == null) {\n term.process.kill(\"SIGKILL\");\n }\n term.disposed = true;\n this.terminals.delete(id);\n }\n }\n\n private getTerminal(terminalId: string): ManagedTerminal {\n const term = this.terminals.get(terminalId);\n if (!term) {\n throw new Error(`Terminal \"${terminalId}\" not found or already released`);\n }\n return term;\n }\n}\n","import type { Socket } from \"node:net\";\nimport { createLogger } from \"@actant/shared\";\nimport type { PermissionsConfig } from \"@actant/shared\";\nimport { PermissionPolicyEnforcer, PermissionAuditLogger } from \"@actant/core\";\nimport { AcpConnection, type AcpConnectionOptions, type AcpSessionInfo, type ClientCallbackHandler } from \"./connection\";\nimport { ClientCallbackRouter } from \"./callback-router\";\nimport { AcpGateway } from \"./gateway\";\nimport { LocalTerminalManager } from \"./terminal-manager\";\n\nconst logger = createLogger(\"acp-connection-manager\");\n\nexport interface ConnectOptions {\n command: string;\n args: string[];\n cwd: string;\n connectionOptions?: AcpConnectionOptions;\n /** npm package providing the binary (from BackendDescriptor.resolvePackage). */\n resolvePackage?: string;\n}\n\n/**\n * Manages a pool of ACP connections keyed by agent instance name.\n * Handles spawn → initialize → session lifecycle for each agent.\n * Supports Gateway mode for Session Lease (IDE ↔ Gateway ↔ Agent).\n */\nexport class AcpConnectionManager {\n private connections = new Map<string, AcpConnection>();\n private primarySessions = new Map<string, string>();\n private routers = new Map<string, ClientCallbackRouter>();\n private gateways = new Map<string, AcpGateway>();\n private enforcers = new Map<string, PermissionPolicyEnforcer>();\n\n /**\n * Spawn an ACP agent process, initialize, and create a default session.\n * Uses ClientCallbackRouter so Gateway can later attach an IDE upstream.\n * When connectionOptions.permissionPolicy is set, creates a PermissionPolicyEnforcer\n * for Layer 2 ACP Client allowlist enforcement.\n */\n async connect(name: string, options: ConnectOptions): Promise<AcpSessionInfo> {\n if (this.connections.has(name)) {\n throw new Error(`ACP connection for \"${name}\" already exists`);\n }\n\n // Create enforcer if permission policy is provided\n let enforcer: PermissionPolicyEnforcer | undefined;\n let auditLogger: PermissionAuditLogger | undefined;\n if (options.connectionOptions?.permissionPolicy) {\n enforcer = new PermissionPolicyEnforcer(options.connectionOptions.permissionPolicy);\n auditLogger = new PermissionAuditLogger(name);\n this.enforcers.set(name, enforcer);\n }\n\n // Build a local-only AcpConnection first; the router wraps it\n // so we can later attach an IDE upstream without reinitializing.\n const localConn = new AcpConnection(options.connectionOptions);\n\n // Create a router using the connection's built-in local callbacks as fallback.\n // We create a \"local handler\" that is the default AcpConnection behavior.\n const localHandler: ClientCallbackHandler = buildLocalHandler(localConn, options.connectionOptions, enforcer, auditLogger);\n const router = new ClientCallbackRouter(localHandler);\n\n // Now create the real connection with the router as callback handler\n const connWithRouter = new AcpConnection({\n ...options.connectionOptions,\n callbackHandler: router,\n });\n\n this.connections.set(name, connWithRouter);\n this.routers.set(name, router);\n\n try {\n await connWithRouter.spawn(options.command, options.args, options.cwd, options.resolvePackage);\n await connWithRouter.initialize();\n const session = await connWithRouter.newSession(options.cwd);\n this.primarySessions.set(name, session.sessionId);\n\n // Pre-create a Gateway for this connection (inactive until IDE connects)\n const gateway = new AcpGateway({\n downstream: connWithRouter,\n callbackRouter: router,\n });\n this.gateways.set(name, gateway);\n\n logger.info({ name, sessionId: session.sessionId }, \"ACP agent connected (gateway-ready)\");\n return session;\n } catch (err) {\n await connWithRouter.close().catch(() => {});\n this.connections.delete(name);\n this.primarySessions.delete(name);\n this.routers.delete(name);\n throw err;\n }\n }\n\n /**\n * Accept an IDE connection on the Gateway for a named agent.\n * The IDE socket carries ACP protocol messages.\n */\n acceptLeaseSocket(name: string, socket: Socket): void {\n const gateway = this.gateways.get(name);\n if (!gateway) {\n throw new Error(`No gateway for agent \"${name}\". Is the agent connected via ACP?`);\n }\n gateway.acceptSocket(socket);\n }\n\n /**\n * Disconnect IDE from the Gateway.\n */\n disconnectLease(name: string): void {\n this.gateways.get(name)?.disconnectUpstream();\n }\n\n getConnection(name: string): AcpConnection | undefined {\n return this.connections.get(name);\n }\n\n getGateway(name: string): AcpGateway | undefined {\n return this.gateways.get(name);\n }\n\n getRouter(name: string): ClientCallbackRouter | undefined {\n return this.routers.get(name);\n }\n\n getPrimarySessionId(name: string): string | undefined {\n return this.primarySessions.get(name);\n }\n\n has(name: string): boolean {\n const conn = this.connections.get(name);\n return conn != null && conn.isConnected;\n }\n\n async disconnect(name: string): Promise<void> {\n this.gateways.get(name)?.disconnectUpstream();\n this.gateways.delete(name);\n this.routers.delete(name);\n this.enforcers.delete(name);\n\n const conn = this.connections.get(name);\n if (!conn) return;\n await conn.close();\n this.connections.delete(name);\n this.primarySessions.delete(name);\n logger.info({ name }, \"ACP agent disconnected\");\n }\n\n async disposeAll(): Promise<void> {\n const names = Array.from(this.connections.keys());\n await Promise.allSettled(names.map((n) => this.disconnect(n)));\n logger.info({ count: names.length }, \"All ACP connections disposed\");\n }\n\n /**\n * Update the permission policy for a named connection at runtime.\n * Propagates to both the AcpConnection and the local handler enforcer.\n */\n updatePermissionPolicy(name: string, config: PermissionsConfig): void {\n const conn = this.connections.get(name);\n if (conn) {\n conn.updatePermissionPolicy(config);\n }\n const enforcer = this.enforcers.get(name);\n if (enforcer) {\n enforcer.updateConfig(config);\n }\n }\n}\n\n/**\n * Build a local ClientCallbackHandler from connection defaults.\n * This is the \"Mode A\" handler used when no IDE is connected.\n * When a permissionPolicy is provided, uses PermissionPolicyEnforcer for smart decisions.\n */\nfunction buildLocalHandler(\n _conn: AcpConnection,\n options?: AcpConnectionOptions,\n enforcer?: PermissionPolicyEnforcer,\n auditLogger?: PermissionAuditLogger,\n): ClientCallbackHandler {\n const terminalManager = new LocalTerminalManager();\n\n return {\n requestPermission: async (params) => {\n // Layer 2: Policy-based enforcement\n if (enforcer && params.options.length > 0) {\n const toolInfo = {\n kind: params.toolCall?.kind ?? undefined,\n title: params.toolCall?.title ?? undefined,\n toolCallId: params.toolCall?.toolCallId ?? \"unknown\",\n };\n const decision = enforcer.evaluate(toolInfo);\n auditLogger?.logEvaluation(toolInfo, decision);\n\n if (decision.action === \"allow\" || decision.action === \"deny\") {\n const outcome = enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n }\n\n // Fallback: legacy autoApprove\n if (options?.autoApprove && params.options.length > 0) {\n const opt = params.options.find(\n (o) => o.kind === \"allow_once\" || o.kind === \"allow_always\",\n ) ?? params.options[0];\n if (!opt) return { outcome: { outcome: \"cancelled\" } };\n return { outcome: { outcome: \"selected\", optionId: opt.optionId } };\n }\n return { outcome: { outcome: \"cancelled\" } };\n },\n\n sessionUpdate: async (params) => {\n options?.onSessionUpdate?.(params);\n },\n\n readTextFile: async (params) => {\n const { readFile } = await import(\"node:fs/promises\");\n const raw = await readFile(params.path, \"utf-8\");\n if (params.line != null || params.limit != null) {\n const lines = raw.split(\"\\n\");\n const start = Math.max(0, (params.line ?? 1) - 1);\n const end = params.limit != null ? start + params.limit : lines.length;\n return { content: lines.slice(start, end).join(\"\\n\") };\n }\n return { content: raw };\n },\n\n writeTextFile: async (params) => {\n const { writeFile, mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n await mkdir(dirname(params.path), { recursive: true });\n await writeFile(params.path, params.content, \"utf-8\");\n return {};\n },\n\n createTerminal: (p) => terminalManager.createTerminal(p),\n terminalOutput: (p) => terminalManager.terminalOutput(p),\n waitForTerminalExit: (p) => terminalManager.waitForExit(p),\n killTerminal: (p) => terminalManager.killTerminal(p),\n releaseTerminal: (p) => terminalManager.releaseTerminal(p),\n };\n}\n","import type {\n RequestPermissionRequest,\n RequestPermissionResponse,\n SessionNotification,\n ReadTextFileRequest,\n ReadTextFileResponse,\n WriteTextFileRequest,\n WriteTextFileResponse,\n CreateTerminalRequest,\n CreateTerminalResponse,\n TerminalOutputRequest,\n TerminalOutputResponse,\n WaitForTerminalExitRequest,\n WaitForTerminalExitResponse,\n KillTerminalCommandRequest,\n KillTerminalCommandResponse,\n ReleaseTerminalRequest,\n ReleaseTerminalResponse,\n ClientCapabilities,\n} from \"@agentclientprotocol/sdk\";\nimport { createLogger } from \"@actant/shared\";\nimport type { PermissionPolicyEnforcer } from \"@actant/core\";\nimport type { ClientCallbackHandler } from \"./connection\";\n\nconst logger = createLogger(\"acp-callback-router\");\n\n/**\n * Upstream (IDE) handler interface.\n * When a lease is active, agent callbacks are forwarded to the IDE\n * through this interface, which wraps the AgentSideConnection facing the IDE.\n */\nexport interface UpstreamHandler {\n requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;\n sessionUpdate(params: SessionNotification): Promise<void>;\n readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse>;\n writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse>;\n createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse>;\n terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse>;\n waitForTerminalExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse>;\n killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse>;\n releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse>;\n}\n\n/**\n * Routes Client callbacks from the Agent to either:\n * (A) the IDE (upstream) — when a lease is active and IDE supports the capability\n * (B) local handlers (impersonation) — when no lease or IDE lacks the capability\n *\n * The Agent always sees full capabilities; the router handles fallback transparently.\n */\nexport class ClientCallbackRouter implements ClientCallbackHandler {\n private upstream: UpstreamHandler | null = null;\n private ideCapabilities: ClientCapabilities | null = null;\n private enforcer: PermissionPolicyEnforcer | null = null;\n\n constructor(private readonly local: ClientCallbackHandler) {}\n\n /** Attach a PermissionPolicyEnforcer for pre-filtering in lease mode. */\n setEnforcer(enforcer: PermissionPolicyEnforcer | null): void {\n this.enforcer = enforcer;\n }\n\n /**\n * Activate lease-forwarding mode.\n * Callbacks will be routed to the IDE for supported capabilities.\n */\n attachUpstream(handler: UpstreamHandler, capabilities: ClientCapabilities): void {\n this.upstream = handler;\n this.ideCapabilities = capabilities;\n logger.info({\n terminal: !!capabilities.terminal,\n fsRead: !!capabilities.fs?.readTextFile,\n fsWrite: !!capabilities.fs?.writeTextFile,\n }, \"Upstream IDE attached — lease forwarding active\");\n }\n\n /**\n * Deactivate lease-forwarding. All callbacks revert to local handlers.\n */\n detachUpstream(): void {\n this.upstream = null;\n this.ideCapabilities = null;\n logger.info(\"Upstream IDE detached — local mode\");\n }\n\n get isLeaseActive(): boolean {\n return this.upstream != null;\n }\n\n /* ---------------------------------------------------------------- */\n /* ClientCallbackHandler implementation */\n /* ---------------------------------------------------------------- */\n\n async requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {\n // Pre-filter with enforcer: deny/allow decisions bypass IDE forwarding\n if (this.enforcer && params.options.length > 0) {\n const toolInfo = {\n kind: params.toolCall?.kind ?? undefined,\n title: params.toolCall?.title ?? undefined,\n toolCallId: params.toolCall?.toolCallId ?? \"unknown\",\n };\n const decision = this.enforcer.evaluate(toolInfo);\n if (decision.action === \"deny\") {\n const outcome = this.enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n if (decision.action === \"allow\") {\n const outcome = this.enforcer.buildOutcome(decision, params.options);\n return { outcome };\n }\n // \"ask\" → fall through to upstream IDE or local\n }\n\n if (this.upstream) {\n try {\n return await this.upstream.requestPermission(params);\n } catch (err) {\n logger.warn({ error: err }, \"Failed to forward requestPermission to IDE, falling back\");\n }\n }\n return this.local.requestPermission(params);\n }\n\n async sessionUpdate(params: SessionNotification): Promise<void> {\n // Always notify local listeners (for internal state tracking)\n await this.local.sessionUpdate(params);\n // Also forward to IDE when lease is active\n if (this.upstream) {\n try {\n await this.upstream.sessionUpdate(params);\n } catch {\n // Best-effort: IDE might have disconnected\n }\n }\n }\n\n async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {\n if (this.upstream && this.ideCapabilities?.fs?.readTextFile) {\n try {\n return await this.upstream.readTextFile(params);\n } catch (err) {\n logger.warn({ path: params.path, error: err }, \"IDE readTextFile failed, falling back\");\n }\n }\n return this.local.readTextFile(params);\n }\n\n async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {\n if (this.upstream && this.ideCapabilities?.fs?.writeTextFile) {\n try {\n return await this.upstream.writeTextFile(params);\n } catch (err) {\n logger.warn({ path: params.path, error: err }, \"IDE writeTextFile failed, falling back\");\n }\n }\n return this.local.writeTextFile(params);\n }\n\n async createTerminal(params: CreateTerminalRequest): Promise<CreateTerminalResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.createTerminal(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE createTerminal failed, falling back\");\n }\n }\n if (this.local.createTerminal) return this.local.createTerminal(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async terminalOutput(params: TerminalOutputRequest): Promise<TerminalOutputResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.terminalOutput(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE terminalOutput failed, falling back\");\n }\n }\n if (this.local.terminalOutput) return this.local.terminalOutput(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async waitForTerminalExit(params: WaitForTerminalExitRequest): Promise<WaitForTerminalExitResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.waitForTerminalExit(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE waitForTerminalExit failed, falling back\");\n }\n }\n if (this.local.waitForTerminalExit) return this.local.waitForTerminalExit(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async killTerminal(params: KillTerminalCommandRequest): Promise<KillTerminalCommandResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.killTerminal(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE killTerminal failed, falling back\");\n }\n }\n if (this.local.killTerminal) return this.local.killTerminal(params);\n throw new Error(\"Terminal not supported\");\n }\n\n async releaseTerminal(params: ReleaseTerminalRequest): Promise<ReleaseTerminalResponse> {\n if (this.upstream && this.ideCapabilities?.terminal) {\n try {\n return await this.upstream.releaseTerminal(params);\n } catch (err) {\n logger.warn({ error: err }, \"IDE releaseTerminal failed, falling back\");\n }\n }\n if (this.local.releaseTerminal) return this.local.releaseTerminal(params);\n throw new Error(\"Terminal not supported\");\n }\n}\n","import { Duplex } from \"node:stream\";\nimport type { Socket } from \"node:net\";\nimport {\n AgentSideConnection,\n TerminalHandle,\n ndJsonStream,\n type Agent,\n type InitializeResponse,\n type ClientCapabilities,\n type NewSessionResponse,\n type LoadSessionResponse,\n type SetSessionConfigOptionResponse,\n} from \"@agentclientprotocol/sdk\";\nimport { createLogger } from \"@actant/shared\";\nimport type { AcpConnection } from \"./connection\";\nimport { ClientCallbackRouter, type UpstreamHandler } from \"./callback-router\";\n\nconst logger = createLogger(\"acp-gateway\");\n\nexport interface GatewayOptions {\n /** The downstream AcpConnection (Daemon → Agent). */\n downstream: AcpConnection;\n /** The callback router to attach upstream when IDE connects. */\n callbackRouter: ClientCallbackRouter;\n}\n\n/**\n * ACP Gateway — bridges upstream IDE (ACP Client) and downstream Agent (ACP Server).\n *\n * Architecture:\n * IDE ← ACP/socket → AgentSideConnection (upstream)\n * ↕ (bridged)\n * ClientSideConnection (downstream) ← ACP/stdio → Agent\n *\n * The Gateway:\n * - Exposes an Agent interface to the IDE via AgentSideConnection\n * - Forwards IDE requests (prompt, cancel, etc.) to the downstream Agent\n * - Routes Agent callbacks (permissions, fs, terminal) to IDE or local\n * via the ClientCallbackRouter\n */\nexport class AcpGateway {\n private upstream: AgentSideConnection | null = null;\n private readonly downstream: AcpConnection;\n private readonly callbackRouter: ClientCallbackRouter;\n private ideCapabilities: ClientCapabilities | null = null;\n /**\n * WORKAROUND for SDK API limitation (see #95):\n * AgentSideConnection exposes flat methods for fs (readTextFile, writeTextFile)\n * but wraps terminal ops behind TerminalHandle. Ideally the Gateway should be\n * stateless — the IDE (Client) manages its own terminal state keyed by terminalId.\n * We maintain this map only because the SDK doesn't expose flat terminalOutput(),\n * waitForTerminalExit(), killTerminal(), releaseTerminal() on AgentSideConnection.\n * Remove this once the SDK adds flat terminal methods.\n */\n private terminalHandles = new Map<string, TerminalHandle>();\n\n constructor(options: GatewayOptions) {\n this.downstream = options.downstream;\n this.callbackRouter = options.callbackRouter;\n }\n\n get isUpstreamConnected(): boolean {\n return this.upstream != null && !this.upstream.signal.aborted;\n }\n\n /**\n * Accept an IDE connection on a Unix/named-pipe socket.\n * Creates an AgentSideConnection that bridges to the downstream Agent.\n */\n acceptSocket(socket: Socket): void {\n if (this.upstream && !this.upstream.signal.aborted) {\n throw new Error(\"Gateway already has an active upstream connection\");\n }\n\n const { readable, writable } = Duplex.toWeb(socket as unknown as Duplex);\n const stream = ndJsonStream(\n writable as WritableStream<Uint8Array>,\n readable as ReadableStream<Uint8Array>,\n );\n\n this.upstream = new AgentSideConnection(\n (conn: AgentSideConnection): Agent => this.buildAgentHandler(conn),\n stream,\n );\n\n this.upstream.signal.addEventListener(\"abort\", () => {\n logger.info(\"Upstream IDE disconnected from Gateway\");\n for (const handle of this.terminalHandles.values()) {\n handle.release().catch(() => {});\n }\n this.terminalHandles.clear();\n this.callbackRouter.detachUpstream();\n this.ideCapabilities = null;\n });\n\n logger.info(\"Upstream IDE connected to Gateway\");\n }\n\n /**\n * Disconnect the upstream IDE.\n */\n disconnectUpstream(): void {\n for (const handle of this.terminalHandles.values()) {\n handle.release().catch(() => {});\n }\n this.terminalHandles.clear();\n this.callbackRouter.detachUpstream();\n this.upstream = null;\n this.ideCapabilities = null;\n }\n\n /* ---------------------------------------------------------------- */\n /* Agent handler (facing IDE) */\n /* ---------------------------------------------------------------- */\n\n private buildAgentHandler(conn: AgentSideConnection): Agent {\n const cachedInit = this.downstream.agentCapabilities;\n\n const upstreamHandler: UpstreamHandler = {\n requestPermission: (p) => conn.requestPermission(p),\n sessionUpdate: (p) => conn.sessionUpdate(p),\n readTextFile: (p) => conn.readTextFile(p),\n writeTextFile: (p) => conn.writeTextFile(p),\n // Terminal forwarding via TerminalHandle map.\n // SDK limitation: AgentSideConnection doesn't expose flat terminalOutput() etc.\n // so we store handles from createTerminal and delegate through them.\n // The IDE (Client) owns the real terminal state; this map is purely an SDK\n // adapter and should be removed once the SDK exposes flat terminal methods.\n createTerminal: async (p) => {\n const handle = await conn.createTerminal(p);\n this.terminalHandles.set(handle.id, handle);\n return { terminalId: handle.id };\n },\n terminalOutput: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) throw new Error(`Terminal \"${p.terminalId}\" not found in Gateway handle map`);\n return handle.currentOutput();\n },\n waitForTerminalExit: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) throw new Error(`Terminal \"${p.terminalId}\" not found in Gateway handle map`);\n return handle.waitForExit();\n },\n killTerminal: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) throw new Error(`Terminal \"${p.terminalId}\" not found in Gateway handle map`);\n return handle.kill();\n },\n releaseTerminal: async (p) => {\n const handle = this.terminalHandles.get(p.terminalId);\n if (!handle) return {};\n const result = await handle.release();\n this.terminalHandles.delete(p.terminalId);\n return result ?? {};\n },\n };\n\n return {\n initialize: async (params) => {\n this.ideCapabilities = params.clientCapabilities ?? {};\n this.callbackRouter.attachUpstream(upstreamHandler, this.ideCapabilities);\n\n // Return the cached Agent capabilities to the IDE\n if (cachedInit) {\n return {\n protocolVersion: cachedInit.protocolVersion,\n agentCapabilities: cachedInit.agentCapabilities,\n agentInfo: cachedInit.agentInfo,\n authMethods: cachedInit.authMethods,\n } as InitializeResponse;\n }\n return {\n protocolVersion: 1,\n agentCapabilities: {},\n agentInfo: { name: \"actant-gateway\", version: \"0.1.0\" },\n } as InitializeResponse;\n },\n\n authenticate: async (params) => {\n await this.downstream.authenticate(params.methodId);\n return {};\n },\n\n newSession: async (params) => {\n const info = await this.downstream.newSession(\n params.cwd,\n params.mcpServers as never[],\n );\n return {\n sessionId: info.sessionId,\n modes: info.modes,\n configOptions: info.configOptions,\n } as NewSessionResponse;\n },\n\n loadSession: async (params) => {\n await this.downstream.loadSession(params.sessionId, params.cwd);\n return {} as LoadSessionResponse;\n },\n\n prompt: async (params) => {\n const conn = this.downstream.rawConnection;\n if (!conn) throw new Error(\"Downstream not connected\");\n return conn.prompt(params);\n },\n\n cancel: async (params) => {\n await this.downstream.cancel(params.sessionId);\n },\n\n setSessionMode: async (params) => {\n await this.downstream.setSessionMode(params.sessionId, params.modeId);\n },\n\n setSessionConfigOption: async (params) => {\n return await this.downstream.setSessionConfigOption(\n params.sessionId, params.configId, params.value,\n ) as unknown as SetSessionConfigOptionResponse;\n },\n };\n }\n}\n","import type { SessionNotification, ContentBlock } from \"@agentclientprotocol/sdk\";\nimport type {\n AgentCommunicator,\n PromptResult,\n RunPromptOptions,\n StreamChunk,\n} from \"@actant/core\";\nimport { createLogger } from \"@actant/shared\";\nimport type { AcpConnection } from \"./connection\";\n\ninterface PlanEntry { status: string; content: string }\ntype UnknownRecord = Record<string, unknown>;\n\nconst logger = createLogger(\"acp-communicator\");\n\n/**\n * Bridges an AcpConnection to the AgentCommunicator interface.\n * Used by AgentManager to send prompts through ACP sessions.\n */\nexport class AcpCommunicator implements AgentCommunicator {\n constructor(\n private readonly connection: AcpConnection,\n private readonly sessionId: string,\n ) {}\n\n async runPrompt(\n _workspaceDir: string,\n prompt: string,\n _options?: RunPromptOptions,\n ): Promise<PromptResult> {\n logger.debug({ sessionId: this.sessionId, promptLength: prompt.length }, \"Sending ACP prompt\");\n const result = await this.connection.prompt(this.sessionId, prompt);\n return { text: result.text, sessionId: this.sessionId };\n }\n\n async *streamPrompt(\n _workspaceDir: string,\n prompt: string,\n _options?: RunPromptOptions,\n ): AsyncIterable<StreamChunk> {\n logger.debug({ sessionId: this.sessionId, promptLength: prompt.length }, \"Streaming ACP prompt\");\n for await (const notification of this.connection.streamPrompt(this.sessionId, prompt)) {\n const chunks = mapNotificationToChunks(notification);\n for (const chunk of chunks) {\n yield chunk;\n }\n }\n }\n}\n\n/**\n * Maps a SessionNotification to zero or more StreamChunks.\n * Handles ALL notification types defined by the ACP protocol.\n */\nfunction mapNotificationToChunks(notification: SessionNotification): StreamChunk[] {\n const update = notification.update;\n\n switch (update.sessionUpdate) {\n case \"agent_message_chunk\":\n return [mapContentToChunk(update.content)].filter(Boolean) as StreamChunk[];\n\n case \"agent_thought_chunk\":\n if (update.content.type === \"text\") {\n return [{ type: \"text\", content: `[Thought] ${update.content.text}` }];\n }\n return [];\n\n case \"user_message_chunk\":\n return [];\n\n case \"tool_call\":\n return [{\n type: \"tool_use\",\n content: `[Tool: ${update.title ?? \"unknown\"}] ${update.toolCallId} (${update.kind ?? \"other\"}) [${update.status ?? \"pending\"}]`,\n }];\n\n case \"tool_call_update\": {\n const chunks: StreamChunk[] = [];\n if (update.content) {\n for (const item of update.content) {\n if (item.type === \"content\" && item.content.type === \"text\") {\n chunks.push({ type: \"text\", content: item.content.text });\n } else if (item.type === \"diff\") {\n chunks.push({\n type: \"text\",\n content: `[Diff: ${(item as UnknownRecord).path ?? \"\"}]`,\n });\n }\n }\n }\n return chunks;\n }\n\n case \"plan\": {\n const entries = (update as UnknownRecord).entries as PlanEntry[] | undefined;\n return [{\n type: \"text\",\n content: entries\n ?.map((e) => `[Plan ${e.status}] ${e.content}`)\n .join(\"\\n\") ?? \"[Plan updated]\",\n }];\n }\n\n case \"available_commands_update\":\n return [];\n\n case \"current_mode_update\":\n return [{\n type: \"text\",\n content: `[Mode changed: ${(update as UnknownRecord).modeId ?? \"unknown\"}]`,\n }];\n\n case \"config_option_update\":\n return [];\n\n default:\n return [];\n }\n}\n\nfunction mapContentToChunk(content: ContentBlock): StreamChunk | null {\n switch (content.type) {\n case \"text\":\n return { type: \"text\", content: content.text };\n case \"image\":\n return { type: \"text\", content: \"[Image content]\" };\n case \"audio\":\n return { type: \"text\", content: \"[Audio content]\" };\n case \"resource\":\n return { type: \"text\", content: `[Resource: ${((content as UnknownRecord).resource as UnknownRecord)?.uri ?? \"unknown\"}]` };\n case \"resource_link\":\n return { type: \"text\", content: `[ResourceLink: ${(content as UnknownRecord).uri ?? \"unknown\"}]` };\n default:\n return null;\n }\n}\n"],"mappings":"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","names":["spawn","createLogger","isWindows","require","createLogger","logger","logger","createLogger","spawn","isWindows","dirname","createLogger","PermissionPolicyEnforcer","PermissionAuditLogger","createLogger","logger","ndJsonStream","createLogger","logger","conn","logger","createLogger","PermissionPolicyEnforcer","PermissionAuditLogger","dirname","createLogger","logger"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actant/acp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Agent Client Protocol adapter for the Actant platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@agentclientprotocol/sdk": "^0.14.1",
|
|
37
|
-
"@
|
|
38
|
-
"@actant/core": "0.2.
|
|
37
|
+
"@zed-industries/claude-agent-acp": "^0.18.0",
|
|
38
|
+
"@actant/core": "0.2.2",
|
|
39
|
+
"@actant/shared": "0.2.2"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
42
|
"build": "tsup",
|