@victor-software-house/pi-acp 0.13.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -8,7 +8,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
8
8
|
import { Hono } from "hono";
|
|
9
9
|
import { AgentSideConnection, RequestError, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
|
-
import { DefaultResourceLoader, SessionManager, createAgentSession, createReadToolDefinition, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { DefaultResourceLoader, SessionManager, createAgentSession, createBashToolDefinition, createReadToolDefinition, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import * as z from "zod";
|
|
13
13
|
import { parse } from "yaml";
|
|
14
14
|
import { $ } from "bun";
|
|
@@ -184,6 +184,78 @@ function resolveIdleMs() {
|
|
|
184
184
|
return n * 1e3;
|
|
185
185
|
}
|
|
186
186
|
//#endregion
|
|
187
|
+
//#region src/acp/acp-bash-operations.ts
|
|
188
|
+
const POLL_INTERVAL_MS = 100;
|
|
189
|
+
const SHELL_PATH = "/bin/sh";
|
|
190
|
+
function createAcpBashOperations(deps) {
|
|
191
|
+
const { conn, getSessionId } = deps;
|
|
192
|
+
return { async exec(command, cwd, options) {
|
|
193
|
+
const sessionId = getSessionId();
|
|
194
|
+
if (sessionId === "") throw new Error("pi-acp acp-bash: sessionId not yet bound");
|
|
195
|
+
const env = options.env !== void 0 ? Object.entries(options.env).filter(([, v]) => v !== void 0).map(([name, value]) => ({
|
|
196
|
+
name,
|
|
197
|
+
value: String(value)
|
|
198
|
+
})) : [];
|
|
199
|
+
const createParams = {
|
|
200
|
+
sessionId,
|
|
201
|
+
command: SHELL_PATH,
|
|
202
|
+
args: ["-c", command],
|
|
203
|
+
cwd,
|
|
204
|
+
env
|
|
205
|
+
};
|
|
206
|
+
const terminal = await conn.createTerminal(createParams);
|
|
207
|
+
let lastOutputLen = 0;
|
|
208
|
+
let cancelled = false;
|
|
209
|
+
const abortHandler = () => {
|
|
210
|
+
cancelled = true;
|
|
211
|
+
terminal.kill().catch(() => {});
|
|
212
|
+
};
|
|
213
|
+
options.signal?.addEventListener("abort", abortHandler);
|
|
214
|
+
const pollLoop = async () => {
|
|
215
|
+
while (!cancelled) {
|
|
216
|
+
try {
|
|
217
|
+
const snap = await terminal.currentOutput();
|
|
218
|
+
if (snap.output.length > lastOutputLen) {
|
|
219
|
+
const delta = snap.output.slice(lastOutputLen);
|
|
220
|
+
lastOutputLen = snap.output.length;
|
|
221
|
+
options.onData(Buffer.from(delta, "utf8"));
|
|
222
|
+
}
|
|
223
|
+
if (snap.exitStatus !== null && snap.exitStatus !== void 0) return;
|
|
224
|
+
} catch {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const timeoutPromise = options.timeout !== void 0 && options.timeout > 0 ? new Promise((resolve) => setTimeout(() => resolve({ timedOut: true }), options.timeout)) : null;
|
|
231
|
+
try {
|
|
232
|
+
const pollPromise = pollLoop();
|
|
233
|
+
const exitPromise = terminal.waitForExit();
|
|
234
|
+
const winner = timeoutPromise !== null ? await Promise.race([exitPromise, timeoutPromise]) : await exitPromise;
|
|
235
|
+
let exitCode;
|
|
236
|
+
if ("timedOut" in winner) {
|
|
237
|
+
await terminal.kill().catch(() => {});
|
|
238
|
+
exitCode = (await terminal.waitForExit()).exitCode ?? null;
|
|
239
|
+
} else exitCode = winner.exitCode ?? null;
|
|
240
|
+
cancelled = true;
|
|
241
|
+
await pollPromise;
|
|
242
|
+
try {
|
|
243
|
+
const final = await terminal.currentOutput();
|
|
244
|
+
if (final.output.length > lastOutputLen) {
|
|
245
|
+
const delta = final.output.slice(lastOutputLen);
|
|
246
|
+
options.onData(Buffer.from(delta, "utf8"));
|
|
247
|
+
}
|
|
248
|
+
} catch {}
|
|
249
|
+
return { exitCode };
|
|
250
|
+
} finally {
|
|
251
|
+
options.signal?.removeEventListener("abort", abortHandler);
|
|
252
|
+
try {
|
|
253
|
+
await terminal.release();
|
|
254
|
+
} catch {}
|
|
255
|
+
}
|
|
256
|
+
} };
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
187
259
|
//#region src/acp/acp-read-operations.ts
|
|
188
260
|
function createAcpReadOperations(deps) {
|
|
189
261
|
const { conn, getSessionId } = deps;
|
|
@@ -263,41 +335,66 @@ function detectAuthError(err) {
|
|
|
263
335
|
}
|
|
264
336
|
//#endregion
|
|
265
337
|
//#region src/acp/client-capabilities.ts
|
|
266
|
-
/**
|
|
267
|
-
* Extract well-known capability flags from ACP `ClientCapabilities`.
|
|
268
|
-
*
|
|
269
|
-
* Reads from:
|
|
270
|
-
* - `_meta.terminal_output` (terminal output rendering)
|
|
271
|
-
* - `_meta.terminal-auth` (terminal auth with command metadata)
|
|
272
|
-
* - `auth._meta.gateway` (gateway auth, future use)
|
|
273
|
-
*/
|
|
274
338
|
function parseClientCapabilities(caps) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
};
|
|
281
|
-
const meta = caps._meta;
|
|
282
|
-
const terminalOutput = typeof meta === "object" && meta !== null && meta["terminal_output"] === true;
|
|
283
|
-
const terminalAuth = typeof meta === "object" && meta !== null && meta["terminal-auth"] === true;
|
|
284
|
-
let gatewayAuth = false;
|
|
285
|
-
if ("auth" in caps) {
|
|
286
|
-
const auth = caps.auth;
|
|
287
|
-
if (typeof auth === "object" && auth !== null && "_meta" in auth) {
|
|
288
|
-
const authMeta = auth._meta;
|
|
289
|
-
if (typeof authMeta === "object" && authMeta !== null && "gateway" in authMeta) gatewayAuth = authMeta["gateway"] === true;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
const fsReadTextFile = caps.fs?.readTextFile === true;
|
|
339
|
+
const safe = caps ?? {};
|
|
340
|
+
const meta = safe._meta;
|
|
341
|
+
const metaIsObject = typeof meta === "object" && meta !== null;
|
|
342
|
+
const authMeta = "auth" in safe && typeof safe.auth === "object" && safe.auth !== null && "_meta" in safe.auth ? safe.auth._meta : void 0;
|
|
343
|
+
const authMetaIsObject = typeof authMeta === "object" && authMeta !== null;
|
|
293
344
|
return {
|
|
294
|
-
terminalOutput,
|
|
295
|
-
terminalAuth,
|
|
296
|
-
gatewayAuth,
|
|
297
|
-
fsReadTextFile
|
|
345
|
+
terminalOutput: metaIsObject && meta["terminal_output"] === true,
|
|
346
|
+
terminalAuth: metaIsObject && meta["terminal-auth"] === true,
|
|
347
|
+
gatewayAuth: authMetaIsObject && authMeta["gateway"] === true,
|
|
348
|
+
fsReadTextFile: safe.fs?.readTextFile === true,
|
|
349
|
+
terminal: safe.terminal === true
|
|
298
350
|
};
|
|
299
351
|
}
|
|
300
352
|
//#endregion
|
|
353
|
+
//#region src/acp/ext-methods.ts
|
|
354
|
+
/**
|
|
355
|
+
* ACP `extMethod` / `extNotification` dispatcher.
|
|
356
|
+
*
|
|
357
|
+
* ACP spec recommends prefixing extension method names with a unique
|
|
358
|
+
* identifier (e.g., a domain name). pi-acp uses the `pi-acp/` prefix for
|
|
359
|
+
* its built-ins; client-defined methods can also be routed here by
|
|
360
|
+
* registering handlers via `register()`.
|
|
361
|
+
*
|
|
362
|
+
* Unknown request methods throw `RequestError.methodNotFound`. Unknown
|
|
363
|
+
* notification methods are silently ignored per JSON-RPC 2.0 semantics —
|
|
364
|
+
* notifications have no response channel, so erroring is meaningless.
|
|
365
|
+
*/
|
|
366
|
+
var ExtMethodDispatcher = class {
|
|
367
|
+
requestHandlers = /* @__PURE__ */ new Map();
|
|
368
|
+
notificationHandlers = /* @__PURE__ */ new Map();
|
|
369
|
+
constructor(deps) {
|
|
370
|
+
this.requestHandlers.set("pi-acp/ping", () => ({
|
|
371
|
+
ok: true,
|
|
372
|
+
ts: Date.now()
|
|
373
|
+
}));
|
|
374
|
+
this.requestHandlers.set("pi-acp/runtime-info", () => ({
|
|
375
|
+
version: deps.version,
|
|
376
|
+
uptimeMs: Date.now() - deps.startedAt,
|
|
377
|
+
sessionCount: deps.sessionCount()
|
|
378
|
+
}));
|
|
379
|
+
}
|
|
380
|
+
register(method, handler) {
|
|
381
|
+
this.requestHandlers.set(method, handler);
|
|
382
|
+
}
|
|
383
|
+
registerNotification(method, handler) {
|
|
384
|
+
this.notificationHandlers.set(method, handler);
|
|
385
|
+
}
|
|
386
|
+
async handleRequest(method, params) {
|
|
387
|
+
const handler = this.requestHandlers.get(method);
|
|
388
|
+
if (handler === void 0) throw RequestError.methodNotFound(method);
|
|
389
|
+
return await handler(params);
|
|
390
|
+
}
|
|
391
|
+
async handleNotification(method, params) {
|
|
392
|
+
const handler = this.notificationHandlers.get(method);
|
|
393
|
+
if (handler === void 0) return;
|
|
394
|
+
await handler(params);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
//#endregion
|
|
301
398
|
//#region src/acp/model-alias.ts
|
|
302
399
|
/**
|
|
303
400
|
* Tokenize a string: split on non-alphanumeric, lowercase, strip "claude".
|
|
@@ -856,6 +953,17 @@ var SessionManager$1 = class {
|
|
|
856
953
|
if (!s) throw RequestError.invalidParams(`Unknown sessionId: ${sessionId}`);
|
|
857
954
|
return s;
|
|
858
955
|
}
|
|
956
|
+
size() {
|
|
957
|
+
return this.sessions.size;
|
|
958
|
+
}
|
|
959
|
+
values() {
|
|
960
|
+
return this.sessions.values();
|
|
961
|
+
}
|
|
962
|
+
/** First registered session, or undefined. Order = insertion order. */
|
|
963
|
+
first() {
|
|
964
|
+
const it = this.sessions.values().next();
|
|
965
|
+
return it.done === true ? void 0 : it.value;
|
|
966
|
+
}
|
|
859
967
|
};
|
|
860
968
|
var PiAcpSession = class {
|
|
861
969
|
sessionId;
|
|
@@ -2007,7 +2115,7 @@ var SshBackend = class {
|
|
|
2007
2115
|
//#endregion
|
|
2008
2116
|
//#region package.json
|
|
2009
2117
|
var name = "@victor-software-house/pi-acp";
|
|
2010
|
-
var version = "0.
|
|
2118
|
+
var version = "0.15.0";
|
|
2011
2119
|
//#endregion
|
|
2012
2120
|
//#region src/acp/agent.ts
|
|
2013
2121
|
/** Builtin ACP slash commands handled directly by the adapter. */
|
|
@@ -2097,11 +2205,14 @@ var PiAcpAgent = class {
|
|
|
2097
2205
|
terminalOutput: false,
|
|
2098
2206
|
terminalAuth: false,
|
|
2099
2207
|
gatewayAuth: false,
|
|
2100
|
-
fsReadTextFile: false
|
|
2208
|
+
fsReadTextFile: false,
|
|
2209
|
+
terminal: false
|
|
2101
2210
|
};
|
|
2102
2211
|
daemonContext;
|
|
2103
2212
|
/** Unique ID for this ACP connection. Used as the ownership key in the daemon SessionRegistry. */
|
|
2104
2213
|
connectionId = randomUUID();
|
|
2214
|
+
extMethods;
|
|
2215
|
+
startedAt = Date.now();
|
|
2105
2216
|
dispose() {
|
|
2106
2217
|
if (this.daemonContext !== void 0) {
|
|
2107
2218
|
const registry = this.daemonContext.sessionRegistry;
|
|
@@ -2114,6 +2225,17 @@ var PiAcpAgent = class {
|
|
|
2114
2225
|
constructor(conn, daemonContext) {
|
|
2115
2226
|
this.conn = conn;
|
|
2116
2227
|
this.daemonContext = daemonContext;
|
|
2228
|
+
this.extMethods = new ExtMethodDispatcher({
|
|
2229
|
+
version,
|
|
2230
|
+
startedAt: this.startedAt,
|
|
2231
|
+
sessionCount: () => this.sessions.size()
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
async extMethod(method, params) {
|
|
2235
|
+
return this.extMethods.handleRequest(method, params);
|
|
2236
|
+
}
|
|
2237
|
+
async extNotification(method, params) {
|
|
2238
|
+
await this.extMethods.handleNotification(method, params);
|
|
2117
2239
|
}
|
|
2118
2240
|
registerWithDaemon(input) {
|
|
2119
2241
|
if (this.daemonContext === void 0) return;
|
|
@@ -2213,26 +2335,43 @@ var PiAcpAgent = class {
|
|
|
2213
2335
|
};
|
|
2214
2336
|
}
|
|
2215
2337
|
/**
|
|
2216
|
-
* PRD-002 §FR-6 —
|
|
2338
|
+
* PRD-002 §FR-6 + §FR-6.5 — tool overrides for ACP-FS read + ACP terminal bash.
|
|
2217
2339
|
*
|
|
2218
|
-
*
|
|
2219
|
-
*
|
|
2220
|
-
*
|
|
2221
|
-
*
|
|
2222
|
-
*
|
|
2223
|
-
* the tool-definition `Map.set` path inside AgentSession.
|
|
2340
|
+
* For each tool we override, the allowlist MUST include the original
|
|
2341
|
+
* tool name so pi's customTool registration loop (which filters by
|
|
2342
|
+
* name) can register the override; the override then shadows the
|
|
2343
|
+
* builtin via the tool-definition `Map.set` path inside AgentSession
|
|
2344
|
+
* (verified against pi source — agent-session.js:1811).
|
|
2224
2345
|
*
|
|
2225
|
-
*
|
|
2226
|
-
* `
|
|
2227
|
-
*
|
|
2346
|
+
* SessionId binding is late: pi mints the id inside `createAgentSession`
|
|
2347
|
+
* (after `customTools` is built), so we share a single mutable ref
|
|
2348
|
+
* across all overrides. The caller mutates `sessionIdRef.current`
|
|
2349
|
+
* right after createAgentSession returns, before any model turn — the
|
|
2350
|
+
* tools aren't invoked until prompt-time, so the late binding is safe.
|
|
2228
2351
|
*
|
|
2229
|
-
* Returns `null` when
|
|
2230
|
-
*
|
|
2231
|
-
* everything locally.
|
|
2352
|
+
* Returns `null` when neither capability is advertised; callers skip
|
|
2353
|
+
* the overlay and pi's built-in tools handle everything locally.
|
|
2232
2354
|
*/
|
|
2233
|
-
|
|
2234
|
-
|
|
2355
|
+
buildAcpToolOverlay(cwd) {
|
|
2356
|
+
const wantRead = this.clientCapabilities.fsReadTextFile;
|
|
2357
|
+
const wantBash = this.clientCapabilities.terminal;
|
|
2358
|
+
if (!wantRead && !wantBash) return null;
|
|
2235
2359
|
const sessionIdRef = { current: "" };
|
|
2360
|
+
const customTools = [];
|
|
2361
|
+
if (wantRead) {
|
|
2362
|
+
const readToolDef = createReadToolDefinition(cwd, { operations: createAcpReadOperations({
|
|
2363
|
+
conn: this.conn,
|
|
2364
|
+
getSessionId: () => sessionIdRef.current
|
|
2365
|
+
}) });
|
|
2366
|
+
customTools.push(readToolDef);
|
|
2367
|
+
}
|
|
2368
|
+
if (wantBash) {
|
|
2369
|
+
const bashToolDef = createBashToolDefinition(cwd, { operations: createAcpBashOperations({
|
|
2370
|
+
conn: this.conn,
|
|
2371
|
+
getSessionId: () => sessionIdRef.current
|
|
2372
|
+
}) });
|
|
2373
|
+
customTools.push(bashToolDef);
|
|
2374
|
+
}
|
|
2236
2375
|
return {
|
|
2237
2376
|
sessionIdRef,
|
|
2238
2377
|
tools: [
|
|
@@ -2244,10 +2383,7 @@ var PiAcpAgent = class {
|
|
|
2244
2383
|
"find",
|
|
2245
2384
|
"ls"
|
|
2246
2385
|
],
|
|
2247
|
-
customTools
|
|
2248
|
-
conn: this.conn,
|
|
2249
|
-
getSessionId: () => sessionIdRef.current
|
|
2250
|
-
}) })]
|
|
2386
|
+
customTools
|
|
2251
2387
|
};
|
|
2252
2388
|
}
|
|
2253
2389
|
async initialize(params) {
|
|
@@ -2277,7 +2413,8 @@ var PiAcpAgent = class {
|
|
|
2277
2413
|
list: {},
|
|
2278
2414
|
close: {},
|
|
2279
2415
|
resume: {},
|
|
2280
|
-
fork: {}
|
|
2416
|
+
fork: {},
|
|
2417
|
+
delete: {}
|
|
2281
2418
|
}
|
|
2282
2419
|
}
|
|
2283
2420
|
};
|
|
@@ -2298,15 +2435,15 @@ var PiAcpAgent = class {
|
|
|
2298
2435
|
sources: resourceLoader.listSources(),
|
|
2299
2436
|
manifestDiagnostics
|
|
2300
2437
|
}).text : "";
|
|
2301
|
-
const
|
|
2438
|
+
const acpToolOverlay = this.buildAcpToolOverlay(effectiveCwd);
|
|
2302
2439
|
let result;
|
|
2303
2440
|
try {
|
|
2304
2441
|
result = await createAgentSession({
|
|
2305
2442
|
cwd: effectiveCwd,
|
|
2306
2443
|
resourceLoader,
|
|
2307
|
-
...
|
|
2308
|
-
tools:
|
|
2309
|
-
customTools:
|
|
2444
|
+
...acpToolOverlay ? {
|
|
2445
|
+
tools: acpToolOverlay.tools,
|
|
2446
|
+
customTools: acpToolOverlay.customTools
|
|
2310
2447
|
} : {}
|
|
2311
2448
|
});
|
|
2312
2449
|
} catch (e) {
|
|
@@ -2317,7 +2454,7 @@ var PiAcpAgent = class {
|
|
|
2317
2454
|
throw RequestError.internalError({}, `Failed to create pi session: ${msg}`);
|
|
2318
2455
|
}
|
|
2319
2456
|
const piSession = result.session;
|
|
2320
|
-
if (
|
|
2457
|
+
if (acpToolOverlay !== null) acpToolOverlay.sessionIdRef.current = piSession.sessionManager.getSessionId();
|
|
2321
2458
|
if (piSession.modelRegistry.getAvailable().length === 0) {
|
|
2322
2459
|
piSession.dispose();
|
|
2323
2460
|
modeResult.cleanup();
|
|
@@ -2580,7 +2717,7 @@ var PiAcpAgent = class {
|
|
|
2580
2717
|
this.sessions.close(params.sessionId);
|
|
2581
2718
|
const sessionFile = await this.resolveSessionFile(params.sessionId);
|
|
2582
2719
|
if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
2583
|
-
const
|
|
2720
|
+
const acpToolOverlay = this.buildAcpToolOverlay(params.cwd);
|
|
2584
2721
|
let result;
|
|
2585
2722
|
try {
|
|
2586
2723
|
const sm = SessionManager.open(sessionFile);
|
|
@@ -2589,9 +2726,9 @@ var PiAcpAgent = class {
|
|
|
2589
2726
|
cwd: params.cwd,
|
|
2590
2727
|
sessionManager: sm,
|
|
2591
2728
|
resourceLoader,
|
|
2592
|
-
...
|
|
2593
|
-
tools:
|
|
2594
|
-
customTools:
|
|
2729
|
+
...acpToolOverlay ? {
|
|
2730
|
+
tools: acpToolOverlay.tools,
|
|
2731
|
+
customTools: acpToolOverlay.customTools
|
|
2595
2732
|
} : {}
|
|
2596
2733
|
});
|
|
2597
2734
|
} catch (e) {
|
|
@@ -2601,7 +2738,7 @@ var PiAcpAgent = class {
|
|
|
2601
2738
|
throw RequestError.internalError({}, `Failed to load pi session: ${msg}`);
|
|
2602
2739
|
}
|
|
2603
2740
|
const piSession = result.session;
|
|
2604
|
-
if (
|
|
2741
|
+
if (acpToolOverlay !== null) acpToolOverlay.sessionIdRef.current = piSession.sessionManager.getSessionId();
|
|
2605
2742
|
const session = new PiAcpSession({
|
|
2606
2743
|
sessionId: params.sessionId,
|
|
2607
2744
|
cwd: params.cwd,
|
|
@@ -2650,6 +2787,40 @@ var PiAcpAgent = class {
|
|
|
2650
2787
|
else if (local !== void 0) this.sessions.detach(params.sessionId);
|
|
2651
2788
|
return {};
|
|
2652
2789
|
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Deletes a session's on-disk file + releases any live state.
|
|
2792
|
+
*
|
|
2793
|
+
* Pi's SessionManager exposes no `delete()` method (verified against
|
|
2794
|
+
* session-manager.d.ts) — sessions are append-only JSONL files. We
|
|
2795
|
+
* unlink the file directly via `fs.rmSync`. `resolveSessionFile`
|
|
2796
|
+
* sources paths from `PiSessionManager.listAll`, so the unlinked path
|
|
2797
|
+
* is always inside `~/.pi/agent/sessions/...`.
|
|
2798
|
+
*
|
|
2799
|
+
* Refuses to delete sessions owned by ANOTHER connection in the daemon
|
|
2800
|
+
* registry — security boundary: clients may only delete sessions they
|
|
2801
|
+
* own or sessions that are not currently live. Always releases the
|
|
2802
|
+
* daemon registry entry first so the live piSession is disposed
|
|
2803
|
+
* cleanly before the file disappears.
|
|
2804
|
+
*
|
|
2805
|
+
* Gated by `sessionCapabilities.delete = {}` (advertised in initialize).
|
|
2806
|
+
*/
|
|
2807
|
+
async unstable_deleteSession(params) {
|
|
2808
|
+
const sessionFile = await this.resolveSessionFile(params.sessionId);
|
|
2809
|
+
if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
2810
|
+
const live = this.daemonContext?.sessionRegistry.get(params.sessionId);
|
|
2811
|
+
if (live !== void 0 && live.ownerConnectionId !== this.connectionId) throw RequestError.invalidParams(`Session ${params.sessionId} is owned by another connection — cannot delete`);
|
|
2812
|
+
if (live !== void 0) {
|
|
2813
|
+
if (this.releaseFromDaemon(params.sessionId).disposed) this.sessions.close(params.sessionId);
|
|
2814
|
+
} else if (this.sessions.maybeGet(params.sessionId) !== void 0) this.sessions.close(params.sessionId);
|
|
2815
|
+
try {
|
|
2816
|
+
rmSync(sessionFile, { force: true });
|
|
2817
|
+
} catch (e) {
|
|
2818
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2819
|
+
throw RequestError.internalError({}, `Failed to delete session file: ${msg}`);
|
|
2820
|
+
}
|
|
2821
|
+
this.sessionPaths.delete(params.sessionId);
|
|
2822
|
+
return { _meta: { piAcp: { deletedFile: sessionFile } } };
|
|
2823
|
+
}
|
|
2653
2824
|
async resumeSession(params) {
|
|
2654
2825
|
if (!isAbsolute(params.cwd)) throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
|
|
2655
2826
|
const existing = this.sessions.maybeGet(params.sessionId);
|
|
@@ -2686,7 +2857,7 @@ var PiAcpAgent = class {
|
|
|
2686
2857
|
}
|
|
2687
2858
|
const sessionFile = await this.resolveSessionFile(params.sessionId);
|
|
2688
2859
|
if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
2689
|
-
const
|
|
2860
|
+
const acpToolOverlay = this.buildAcpToolOverlay(params.cwd);
|
|
2690
2861
|
let result;
|
|
2691
2862
|
try {
|
|
2692
2863
|
const sm = SessionManager.open(sessionFile);
|
|
@@ -2695,9 +2866,9 @@ var PiAcpAgent = class {
|
|
|
2695
2866
|
cwd: params.cwd,
|
|
2696
2867
|
sessionManager: sm,
|
|
2697
2868
|
resourceLoader,
|
|
2698
|
-
...
|
|
2699
|
-
tools:
|
|
2700
|
-
customTools:
|
|
2869
|
+
...acpToolOverlay ? {
|
|
2870
|
+
tools: acpToolOverlay.tools,
|
|
2871
|
+
customTools: acpToolOverlay.customTools
|
|
2701
2872
|
} : {}
|
|
2702
2873
|
});
|
|
2703
2874
|
} catch (e) {
|
|
@@ -2707,7 +2878,7 @@ var PiAcpAgent = class {
|
|
|
2707
2878
|
throw RequestError.internalError({}, `Failed to resume pi session: ${msg}`);
|
|
2708
2879
|
}
|
|
2709
2880
|
const piSession = result.session;
|
|
2710
|
-
if (
|
|
2881
|
+
if (acpToolOverlay !== null) acpToolOverlay.sessionIdRef.current = piSession.sessionManager.getSessionId();
|
|
2711
2882
|
const session = new PiAcpSession({
|
|
2712
2883
|
sessionId: params.sessionId,
|
|
2713
2884
|
cwd: params.cwd,
|
|
@@ -2751,7 +2922,7 @@ var PiAcpAgent = class {
|
|
|
2751
2922
|
if (!isAbsolute(params.cwd)) throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
|
|
2752
2923
|
const sourceFile = await this.resolveSessionFile(params.sessionId);
|
|
2753
2924
|
if (sourceFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
2754
|
-
const
|
|
2925
|
+
const acpToolOverlay = this.buildAcpToolOverlay(params.cwd);
|
|
2755
2926
|
let result;
|
|
2756
2927
|
try {
|
|
2757
2928
|
const sm = SessionManager.forkFrom(sourceFile, params.cwd);
|
|
@@ -2760,9 +2931,9 @@ var PiAcpAgent = class {
|
|
|
2760
2931
|
cwd: params.cwd,
|
|
2761
2932
|
sessionManager: sm,
|
|
2762
2933
|
resourceLoader,
|
|
2763
|
-
...
|
|
2764
|
-
tools:
|
|
2765
|
-
customTools:
|
|
2934
|
+
...acpToolOverlay ? {
|
|
2935
|
+
tools: acpToolOverlay.tools,
|
|
2936
|
+
customTools: acpToolOverlay.customTools
|
|
2766
2937
|
} : {}
|
|
2767
2938
|
});
|
|
2768
2939
|
} catch (e) {
|
|
@@ -2773,7 +2944,7 @@ var PiAcpAgent = class {
|
|
|
2773
2944
|
}
|
|
2774
2945
|
const piSession = result.session;
|
|
2775
2946
|
const newSessionId = piSession.sessionManager.getSessionId();
|
|
2776
|
-
if (
|
|
2947
|
+
if (acpToolOverlay !== null) acpToolOverlay.sessionIdRef.current = newSessionId;
|
|
2777
2948
|
const newSessionFile = piSession.sessionManager.getSessionFile();
|
|
2778
2949
|
if (newSessionFile !== void 0) this.sessionPaths.set(newSessionId, newSessionFile);
|
|
2779
2950
|
const session = new PiAcpSession({
|
|
@@ -3392,4 +3563,4 @@ async function runDaemon() {
|
|
|
3392
3563
|
//#endregion
|
|
3393
3564
|
export { runDaemon };
|
|
3394
3565
|
|
|
3395
|
-
//# sourceMappingURL=daemon-
|
|
3566
|
+
//# sourceMappingURL=daemon-C-rb-cf5.mjs.map
|