@victor-software-house/pi-acp 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auto-spawn-CQ_aaNZA.mjs → client-BjK2BnaD.mjs} +34 -4
- package/dist/client-BjK2BnaD.mjs.map +1 -0
- package/dist/{serve-DmuHYqF-.mjs → daemon-xclwSgis.mjs} +926 -26
- package/dist/daemon-xclwSgis.mjs.map +1 -0
- package/dist/index.mjs +16 -25
- package/dist/index.mjs.map +1 -1
- package/dist/operator-AtBT_SZT.mjs +52 -0
- package/dist/operator-AtBT_SZT.mjs.map +1 -0
- package/dist/pi-package-DFOfbtij.mjs +3 -0
- package/dist/pi-package-aHs6rWNo.mjs +29 -0
- package/dist/pi-package-aHs6rWNo.mjs.map +1 -0
- package/dist/{socket-BUNWxnAN.mjs → socket-wvV053VI.mjs} +28 -25
- package/dist/socket-wvV053VI.mjs.map +1 -0
- package/package.json +5 -3
- package/dist/auto-spawn-CQ_aaNZA.mjs.map +0 -1
- package/dist/client-P4T6wITz.mjs +0 -35
- package/dist/client-P4T6wITz.mjs.map +0 -1
- package/dist/daemon-D76_nP59.mjs +0 -338
- package/dist/daemon-D76_nP59.mjs.map +0 -1
- package/dist/in-process-Byo-O30j.mjs +0 -31
- package/dist/in-process-Byo-O30j.mjs.map +0 -1
- package/dist/operator-DURoHk8w.mjs +0 -85
- package/dist/operator-DURoHk8w.mjs.map +0 -1
- package/dist/serve-DmuHYqF-.mjs.map +0 -1
- package/dist/socket-BUNWxnAN.mjs.map +0 -1
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { t as serveAcp } from "./serve-DmuHYqF-.mjs";
|
|
3
|
-
//#region src/runtime/in-process.ts
|
|
4
|
-
/**
|
|
5
|
-
* In-process ACP server. The v0.5 codepath, preserved as the `PI_ACP_NO_DAEMON`
|
|
6
|
-
* escape hatch and reused by the daemon's own stdio-bridge fallback.
|
|
7
|
-
*
|
|
8
|
-
* Treats process.stdin/stdout as the ACP transport. Owns the shutdown
|
|
9
|
-
* lifecycle (AgentSideConnection.closed + SIGINT/SIGTERM).
|
|
10
|
-
*/
|
|
11
|
-
function runInProcess() {
|
|
12
|
-
const handle = serveAcp({
|
|
13
|
-
input: process.stdin,
|
|
14
|
-
output: process.stdout
|
|
15
|
-
});
|
|
16
|
-
let shuttingDown = false;
|
|
17
|
-
const shutdown = () => {
|
|
18
|
-
if (shuttingDown) return;
|
|
19
|
-
shuttingDown = true;
|
|
20
|
-
handle.dispose();
|
|
21
|
-
process.exit(0);
|
|
22
|
-
};
|
|
23
|
-
handle.connection.closed.then(shutdown);
|
|
24
|
-
process.on("SIGINT", shutdown);
|
|
25
|
-
process.on("SIGTERM", shutdown);
|
|
26
|
-
process.stdout.on("error", () => process.exit(0));
|
|
27
|
-
}
|
|
28
|
-
//#endregion
|
|
29
|
-
export { runInProcess };
|
|
30
|
-
|
|
31
|
-
//# sourceMappingURL=in-process-Byo-O30j.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"in-process-Byo-O30j.mjs","names":[],"sources":["../src/runtime/in-process.ts"],"sourcesContent":["/**\n * In-process ACP server. The v0.5 codepath, preserved as the `PI_ACP_NO_DAEMON`\n * escape hatch and reused by the daemon's own stdio-bridge fallback.\n *\n * Treats process.stdin/stdout as the ACP transport. Owns the shutdown\n * lifecycle (AgentSideConnection.closed + SIGINT/SIGTERM).\n */\n\nimport { serveAcp } from \"@pi-acp/runtime/serve\";\n\nexport function runInProcess(): void {\n\tconst handle = serveAcp({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\t// No DaemonContext: behavior identical to v0.5.\n\t});\n\n\tlet shuttingDown = false;\n\tconst shutdown = (): void => {\n\t\tif (shuttingDown) return;\n\t\tshuttingDown = true;\n\t\thandle.dispose();\n\t\tprocess.exit(0);\n\t};\n\n\tvoid handle.connection.closed.then(shutdown);\n\n\tprocess.on(\"SIGINT\", shutdown);\n\tprocess.on(\"SIGTERM\", shutdown);\n\tprocess.stdout.on(\"error\", () => process.exit(0));\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,eAAqB;CACpC,MAAM,SAAS,SAAS;EACvB,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAEhB,CAAC;CAEF,IAAI,eAAe;CACnB,MAAM,iBAAuB;AAC5B,MAAI,aAAc;AAClB,iBAAe;AACf,SAAO,SAAS;AAChB,UAAQ,KAAK,EAAE;;AAGX,QAAO,WAAW,OAAO,KAAK,SAAS;AAE5C,SAAQ,GAAG,UAAU,SAAS;AAC9B,SAAQ,GAAG,WAAW,SAAS;AAC/B,SAAQ,OAAO,GAAG,eAAe,QAAQ,KAAK,EAAE,CAAC"}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { n as tryConnect } from "./auto-spawn-CQ_aaNZA.mjs";
|
|
3
|
-
//#region src/client/operator.ts
|
|
4
|
-
/**
|
|
5
|
-
* Operator client modes: pi-acp --daemon-status, pi-acp --daemon-stop.
|
|
6
|
-
*
|
|
7
|
-
* Both connect to the daemon socket and send a `daemon/<method>` JSON-RPC
|
|
8
|
-
* frame; the daemon handles them inline (see src/daemon/control.ts) before
|
|
9
|
-
* the normal ACP handoff.
|
|
10
|
-
*/
|
|
11
|
-
const CONTROL_TIMEOUT_MS = 5e3;
|
|
12
|
-
async function runDaemonStatus() {
|
|
13
|
-
const socket = await tryConnect();
|
|
14
|
-
if (socket === null) {
|
|
15
|
-
process.stderr.write("pi-acp daemon: not running\n");
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
const frame = JSON.stringify({
|
|
19
|
-
jsonrpc: "2.0",
|
|
20
|
-
id: 1,
|
|
21
|
-
method: "daemon/status"
|
|
22
|
-
});
|
|
23
|
-
socket.write(`${frame}\n`);
|
|
24
|
-
const response = await readSingleFrame(socket);
|
|
25
|
-
socket.destroy();
|
|
26
|
-
if (response === null) {
|
|
27
|
-
process.stderr.write("pi-acp daemon: no response\n");
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
process.stdout.write(`${response}\n`);
|
|
31
|
-
process.exit(0);
|
|
32
|
-
}
|
|
33
|
-
async function runDaemonStop() {
|
|
34
|
-
const socket = await tryConnect();
|
|
35
|
-
if (socket === null) {
|
|
36
|
-
process.stderr.write("pi-acp daemon: not running\n");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
const frame = JSON.stringify({
|
|
40
|
-
jsonrpc: "2.0",
|
|
41
|
-
id: 1,
|
|
42
|
-
method: "daemon/shutdown"
|
|
43
|
-
});
|
|
44
|
-
socket.write(`${frame}\n`);
|
|
45
|
-
if (await readSingleFrame(socket) === null) {
|
|
46
|
-
process.stderr.write("pi-acp daemon: no response (already exiting?)\n");
|
|
47
|
-
process.exit(0);
|
|
48
|
-
}
|
|
49
|
-
await new Promise((resolve) => {
|
|
50
|
-
const timer = setTimeout(resolve, CONTROL_TIMEOUT_MS);
|
|
51
|
-
timer.unref?.();
|
|
52
|
-
socket.once("close", () => {
|
|
53
|
-
clearTimeout(timer);
|
|
54
|
-
resolve();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
process.stderr.write("pi-acp daemon: stopped\n");
|
|
58
|
-
process.exit(0);
|
|
59
|
-
}
|
|
60
|
-
async function readSingleFrame(socket) {
|
|
61
|
-
return new Promise((resolve) => {
|
|
62
|
-
let buf = Buffer.alloc(0);
|
|
63
|
-
const timer = setTimeout(() => {
|
|
64
|
-
cleanup();
|
|
65
|
-
resolve(null);
|
|
66
|
-
}, CONTROL_TIMEOUT_MS);
|
|
67
|
-
timer.unref?.();
|
|
68
|
-
const cleanup = () => {
|
|
69
|
-
clearTimeout(timer);
|
|
70
|
-
socket.off("data", onData);
|
|
71
|
-
};
|
|
72
|
-
const onData = (chunk) => {
|
|
73
|
-
buf = Buffer.concat([buf, chunk]);
|
|
74
|
-
const idx = buf.indexOf(10);
|
|
75
|
-
if (idx === -1) return;
|
|
76
|
-
cleanup();
|
|
77
|
-
resolve(buf.subarray(0, idx).toString("utf8"));
|
|
78
|
-
};
|
|
79
|
-
socket.on("data", onData);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
//#endregion
|
|
83
|
-
export { runDaemonStatus, runDaemonStop };
|
|
84
|
-
|
|
85
|
-
//# sourceMappingURL=operator-DURoHk8w.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"operator-DURoHk8w.mjs","names":[],"sources":["../src/client/operator.ts"],"sourcesContent":["/**\n * Operator client modes: pi-acp --daemon-status, pi-acp --daemon-stop.\n *\n * Both connect to the daemon socket and send a `daemon/<method>` JSON-RPC\n * frame; the daemon handles them inline (see src/daemon/control.ts) before\n * the normal ACP handoff.\n */\n\nimport { tryConnect } from \"@pi-acp/client/auto-spawn\";\n\nconst CONTROL_TIMEOUT_MS = 5000;\n\nexport async function runDaemonStatus(): Promise<void> {\n\tconst socket = await tryConnect();\n\tif (socket === null) {\n\t\tprocess.stderr.write(\"pi-acp daemon: not running\\n\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst id = 1;\n\tconst frame = JSON.stringify({ jsonrpc: \"2.0\", id, method: \"daemon/status\" });\n\tsocket.write(`${frame}\\n`);\n\n\tconst response = await readSingleFrame(socket);\n\tsocket.destroy();\n\n\tif (response === null) {\n\t\tprocess.stderr.write(\"pi-acp daemon: no response\\n\");\n\t\tprocess.exit(1);\n\t}\n\n\tprocess.stdout.write(`${response}\\n`);\n\tprocess.exit(0);\n}\n\nexport async function runDaemonStop(): Promise<void> {\n\tconst socket = await tryConnect();\n\tif (socket === null) {\n\t\tprocess.stderr.write(\"pi-acp daemon: not running\\n\");\n\t\tprocess.exit(0);\n\t}\n\n\tconst id = 1;\n\tconst frame = JSON.stringify({ jsonrpc: \"2.0\", id, method: \"daemon/shutdown\" });\n\tsocket.write(`${frame}\\n`);\n\n\tconst response = await readSingleFrame(socket);\n\tif (response === null) {\n\t\tprocess.stderr.write(\"pi-acp daemon: no response (already exiting?)\\n\");\n\t\tprocess.exit(0);\n\t}\n\n\t// Wait for the socket to close, which signals daemon shutdown completed.\n\tawait new Promise<void>((resolve) => {\n\t\tconst timer = setTimeout(resolve, CONTROL_TIMEOUT_MS);\n\t\ttimer.unref?.();\n\t\tsocket.once(\"close\", () => {\n\t\t\tclearTimeout(timer);\n\t\t\tresolve();\n\t\t});\n\t});\n\n\tprocess.stderr.write(\"pi-acp daemon: stopped\\n\");\n\tprocess.exit(0);\n}\n\nasync function readSingleFrame(socket: NodeJS.ReadableStream): Promise<string | null> {\n\treturn new Promise((resolve) => {\n\t\tlet buf = Buffer.alloc(0);\n\t\tconst timer = setTimeout(() => {\n\t\t\tcleanup();\n\t\t\tresolve(null);\n\t\t}, CONTROL_TIMEOUT_MS);\n\t\ttimer.unref?.();\n\t\tconst cleanup = (): void => {\n\t\t\tclearTimeout(timer);\n\t\t\tsocket.off(\"data\", onData);\n\t\t};\n\t\tconst onData = (chunk: Buffer): void => {\n\t\t\tbuf = Buffer.concat([buf, chunk]);\n\t\t\tconst idx = buf.indexOf(0x0a);\n\t\t\tif (idx === -1) return;\n\t\t\tcleanup();\n\t\t\tresolve(buf.subarray(0, idx).toString(\"utf8\"));\n\t\t};\n\t\tsocket.on(\"data\", onData);\n\t});\n}\n"],"mappings":";;;;;;;;;;AAUA,MAAM,qBAAqB;AAE3B,eAAsB,kBAAiC;CACtD,MAAM,SAAS,MAAM,YAAY;AACjC,KAAI,WAAW,MAAM;AACpB,UAAQ,OAAO,MAAM,+BAA+B;AACpD,UAAQ,KAAK,EAAE;;CAIhB,MAAM,QAAQ,KAAK,UAAU;EAAE,SAAS;EAAO,IAAA;EAAI,QAAQ;EAAiB,CAAC;AAC7E,QAAO,MAAM,GAAG,MAAM,IAAI;CAE1B,MAAM,WAAW,MAAM,gBAAgB,OAAO;AAC9C,QAAO,SAAS;AAEhB,KAAI,aAAa,MAAM;AACtB,UAAQ,OAAO,MAAM,+BAA+B;AACpD,UAAQ,KAAK,EAAE;;AAGhB,SAAQ,OAAO,MAAM,GAAG,SAAS,IAAI;AACrC,SAAQ,KAAK,EAAE;;AAGhB,eAAsB,gBAA+B;CACpD,MAAM,SAAS,MAAM,YAAY;AACjC,KAAI,WAAW,MAAM;AACpB,UAAQ,OAAO,MAAM,+BAA+B;AACpD,UAAQ,KAAK,EAAE;;CAIhB,MAAM,QAAQ,KAAK,UAAU;EAAE,SAAS;EAAO,IAAA;EAAI,QAAQ;EAAmB,CAAC;AAC/E,QAAO,MAAM,GAAG,MAAM,IAAI;AAG1B,KAAI,MADmB,gBAAgB,OAAO,KAC7B,MAAM;AACtB,UAAQ,OAAO,MAAM,kDAAkD;AACvE,UAAQ,KAAK,EAAE;;AAIhB,OAAM,IAAI,SAAe,YAAY;EACpC,MAAM,QAAQ,WAAW,SAAS,mBAAmB;AACrD,QAAM,SAAS;AACf,SAAO,KAAK,eAAe;AAC1B,gBAAa,MAAM;AACnB,YAAS;IACR;GACD;AAEF,SAAQ,OAAO,MAAM,2BAA2B;AAChD,SAAQ,KAAK,EAAE;;AAGhB,eAAe,gBAAgB,QAAuD;AACrF,QAAO,IAAI,SAAS,YAAY;EAC/B,IAAI,MAAM,OAAO,MAAM,EAAE;EACzB,MAAM,QAAQ,iBAAiB;AAC9B,YAAS;AACT,WAAQ,KAAK;KACX,mBAAmB;AACtB,QAAM,SAAS;EACf,MAAM,gBAAsB;AAC3B,gBAAa,MAAM;AACnB,UAAO,IAAI,QAAQ,OAAO;;EAE3B,MAAM,UAAU,UAAwB;AACvC,SAAM,OAAO,OAAO,CAAC,KAAK,MAAM,CAAC;GACjC,MAAM,MAAM,IAAI,QAAQ,GAAK;AAC7B,OAAI,QAAQ,GAAI;AAChB,YAAS;AACT,WAAQ,IAAI,SAAS,GAAG,IAAI,CAAC,SAAS,OAAO,CAAC;;AAE/C,SAAO,GAAG,QAAQ,OAAO;GACxB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serve-DmuHYqF-.mjs","names":["resolvePath","SessionManager","isTextBlock","SessionManager","pkgJson.name","pkgJson.version","PiSessionManager"],"sources":["../src/acp/auth.ts","../src/acp/auth-required.ts","../src/acp/client-capabilities.ts","../src/acp/model-alias.ts","../src/acp/pi-settings.ts","../src/acp/translate/tool-content.ts","../src/acp/unreachable.ts","../src/acp/session.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts","../package.json","../src/acp/agent.ts","../src/runtime/serve.ts"],"sourcesContent":["/**\n * Build ACP AuthMethod descriptors for terminal-based authentication.\n *\n * Supports both the registry-required \"type/args/env\" shape and Zed's\n * _meta[\"terminal-auth\"] extension for the Authenticate banner.\n */\n\nimport type { AuthMethod } from \"@agentclientprotocol/sdk\";\n\nexport const AUTH_METHOD_ID = \"pi_terminal_login\";\n\ninterface AuthMethodOptions {\n\tsupportsTerminalAuthMeta?: boolean;\n}\n\nexport function buildAuthMethods(opts?: AuthMethodOptions): AuthMethod[] {\n\tconst supportsTerminalAuthMeta = opts?.supportsTerminalAuthMeta ?? true;\n\n\tconst method: AuthMethod = {\n\t\tid: AUTH_METHOD_ID,\n\t\tname: \"Launch pi in the terminal\",\n\t\tdescription: \"Start pi in an interactive terminal to configure API keys or login\",\n\t\ttype: \"terminal\",\n\t\targs: [\"--terminal-login\"],\n\t\tenv: {},\n\t};\n\n\tif (supportsTerminalAuthMeta) {\n\t\tconst launch = resolveTerminalLaunchCommand();\n\t\tmethod._meta = {\n\t\t\t\"terminal-auth\": {\n\t\t\t\t...launch,\n\t\t\t\tlabel: \"Launch pi\",\n\t\t\t},\n\t\t};\n\t}\n\n\treturn [method];\n}\n\nfunction resolveTerminalLaunchCommand(): { command: string; args: string[] } {\n\tconst argv0 = process.argv[0] ?? \"node\";\n\tconst argv1 = process.argv[1];\n\n\tif (argv1 !== undefined && argv0.includes(\"node\") && argv1.endsWith(\".js\")) {\n\t\treturn { command: argv0, args: [argv1, \"--terminal-login\"] };\n\t}\n\n\treturn { command: \"pi-acp\", args: [\"--terminal-login\"] };\n}\n","/**\n * Detect common auth/credential errors from pi and surface them as ACP AUTH_REQUIRED.\n */\n\nimport { RequestError } from \"@agentclientprotocol/sdk\";\nimport { buildAuthMethods } from \"@pi-acp/acp/auth\";\n\nconst AUTH_ERROR_PATTERNS = [\n\t\"api key\",\n\t\"apikey\",\n\t\"missing key\",\n\t\"no key\",\n\t\"not configured\",\n\t\"unauthorized\",\n\t\"authentication\",\n\t\"permission denied\",\n\t\"forbidden\",\n\t\"401\",\n\t\"403\",\n];\n\nexport function detectAuthError(err: unknown): RequestError | null {\n\tconst text = err instanceof Error ? err.message : String(err ?? \"\");\n\tconst lower = text.toLowerCase();\n\n\tconst isAuthRelated = AUTH_ERROR_PATTERNS.some((p) => lower.includes(p));\n\tif (!isAuthRelated) return null;\n\n\treturn RequestError.authRequired(\n\t\t{ authMethods: buildAuthMethods() },\n\t\t\"Configure an API key or log in with an OAuth provider.\",\n\t);\n}\n","/**\n * Parse and represent client capabilities from the ACP initialize request.\n *\n * Both reference implementations (claude-agent-acp, codex-acp) store and\n * use `clientCapabilities` for feature detection and auth method selection.\n */\n\nimport type { ClientCapabilities } from \"@agentclientprotocol/sdk\";\n\nexport interface ClientCapabilityFlags {\n\t/** Client supports terminal output metadata (info/output/exit lifecycle). */\n\tterminalOutput: boolean;\n\t/** Client supports terminal-based authentication with command metadata. */\n\tterminalAuth: boolean;\n\t/** Client supports gateway-based authentication. */\n\tgatewayAuth: boolean;\n}\n\n/**\n * Extract well-known capability flags from ACP `ClientCapabilities`.\n *\n * Reads from:\n * - `_meta.terminal_output` (terminal output rendering)\n * - `_meta.terminal-auth` (terminal auth with command metadata)\n * - `auth._meta.gateway` (gateway auth, future use)\n */\nexport function parseClientCapabilities(\n\tcaps: ClientCapabilities | undefined | null,\n): ClientCapabilityFlags {\n\tif (caps === undefined || caps === null) {\n\t\treturn { terminalOutput: false, terminalAuth: false, gatewayAuth: false };\n\t}\n\n\t// _meta is an optional declared property, safe to access with dot\n\tconst meta = caps._meta;\n\tconst terminalOutput =\n\t\ttypeof meta === \"object\" && meta !== null && meta[\"terminal_output\"] === true;\n\tconst terminalAuth = typeof meta === \"object\" && meta !== null && meta[\"terminal-auth\"] === true;\n\n\t// gateway auth lives under auth._meta.gateway (non-standard extension)\n\tlet gatewayAuth = false;\n\tif (\"auth\" in caps) {\n\t\tconst auth = caps.auth;\n\t\tif (typeof auth === \"object\" && auth !== null && \"_meta\" in auth) {\n\t\t\tconst authMeta = auth._meta;\n\t\t\tif (typeof authMeta === \"object\" && authMeta !== null && \"gateway\" in authMeta) {\n\t\t\t\tgatewayAuth = authMeta[\"gateway\"] === true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { terminalOutput, terminalAuth, gatewayAuth };\n}\n","/**\n * Model alias resolution for user-friendly model names.\n *\n * Lets users type \"opus\", \"sonnet\", \"opus[1m]\" instead of exact\n * \"provider/modelId\" strings. Uses tokenized matching and scoring\n * following the claude-agent-acp pattern.\n */\n\ninterface ModelEntry {\n\tprovider: string;\n\tid: string;\n\tname?: string | undefined;\n}\n\ninterface ResolvedModel {\n\tprovider: string;\n\tid: string;\n}\n\n/**\n * Tokenize a string: split on non-alphanumeric, lowercase, strip \"claude\".\n */\nfunction tokenize(input: string): string[] {\n\treturn input\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((t) => t !== \"\" && t !== \"claude\");\n}\n\n/**\n * Extract a context hint in square brackets, e.g. \"opus[1m]\" -> { base: \"opus\", hint: \"1m\" }.\n */\nfunction extractContextHint(input: string): { base: string; hint: string | null } {\n\tconst match = /^(.+?)\\[([^\\]]+)\\]$/.exec(input);\n\tif (match !== null && match[1] !== undefined && match[2] !== undefined) {\n\t\treturn { base: match[1], hint: match[2] };\n\t}\n\treturn { base: input, hint: null };\n}\n\n/** Check if a string is purely numeric. */\nfunction isNumeric(s: string): boolean {\n\treturn /^\\d+$/.test(s);\n}\n\n/**\n * Score how well a model matches the given preference tokens.\n *\n * Returns a score >= 0 (higher is better), or -1 for no match.\n * Requires at least one non-numeric token to match to avoid false positives\n * from bare version numbers (e.g. \"4\" matching model version suffixes).\n */\nfunction scoreModel(model: ModelEntry, prefTokens: string[], hint: string | null): number {\n\tconst modelStr = `${model.provider}/${model.id}/${model.name ?? \"\"}`.toLowerCase();\n\tconst modelTokens = tokenize(modelStr);\n\n\tlet matched = 0;\n\tlet hasNonNumericMatch = false;\n\tfor (const pt of prefTokens) {\n\t\tif (modelTokens.some((mt) => mt.includes(pt) || pt.includes(mt))) {\n\t\t\tmatched++;\n\t\t\tif (!isNumeric(pt)) hasNonNumericMatch = true;\n\t\t}\n\t}\n\n\tif (matched === 0) return -1;\n\n\t// Require at least one non-numeric token to match -- prevents \"gpt-4\"\n\t// matching on the bare \"4\" version component.\n\tif (!hasNonNumericMatch) return -1;\n\n\tlet score = matched / prefTokens.length;\n\n\t// Bonus for hint match (e.g. \"1m\" context window hint)\n\tif (hint !== null && modelStr.includes(hint.toLowerCase())) {\n\t\tscore += 0.5;\n\t}\n\n\t// Bonus for exact substring match on model id\n\tconst pref = prefTokens.join(\"\");\n\tif (model.id.toLowerCase().includes(pref)) {\n\t\tscore += 0.25;\n\t}\n\n\treturn score;\n}\n\n/**\n * Resolve a user-friendly model preference to a concrete model.\n *\n * Matching strategy (in order):\n * 1. Exact match on \"provider/id\"\n * 2. Exact match on \"id\" alone\n * 3. Tokenized scored match with optional context hint\n *\n * Returns null if no model matches.\n */\nexport function resolveModelPreference(\n\tmodels: readonly ModelEntry[],\n\tpreference: string,\n): ResolvedModel | null {\n\tconst trimmed = preference.trim();\n\tif (trimmed === \"\") return null;\n\n\t// 1. Exact match on \"provider/id\"\n\tif (trimmed.includes(\"/\")) {\n\t\tconst [p, ...rest] = trimmed.split(\"/\");\n\t\tconst provider = p ?? \"\";\n\t\tconst id = rest.join(\"/\");\n\t\tconst exact = models.find(\n\t\t\t(m) =>\n\t\t\t\tm.provider.toLowerCase() === provider.toLowerCase() &&\n\t\t\t\tm.id.toLowerCase() === id.toLowerCase(),\n\t\t);\n\t\tif (exact !== undefined) return { provider: exact.provider, id: exact.id };\n\t}\n\n\t// 2. Exact match on id alone\n\tconst byId = models.find((m) => m.id.toLowerCase() === trimmed.toLowerCase());\n\tif (byId !== undefined) return { provider: byId.provider, id: byId.id };\n\n\t// 3. Tokenized scored match\n\tconst { base, hint } = extractContextHint(trimmed);\n\tconst prefTokens = tokenize(base);\n\tif (prefTokens.length === 0) return null;\n\n\tlet bestModel: ModelEntry | null = null;\n\tlet bestScore = -1;\n\n\tfor (const model of models) {\n\t\tconst s = scoreModel(model, prefTokens, hint);\n\t\tif (s > bestScore) {\n\t\t\tbestScore = s;\n\t\t\tbestModel = model;\n\t\t}\n\t}\n\n\t// Require at least 50% of preference tokens to match to avoid spurious hits\n\t// (e.g. \"gpt-4\" matching on the \"4\" token alone)\n\tif (bestModel === null || bestScore < 0.5) return null;\n\treturn { provider: bestModel.provider, id: bestModel.id };\n}\n","/**\n * Read pi settings from global and project config files.\n *\n * Settings are merged: project overrides global.\n * Paths follow pi-mono conventions:\n * Global: ~/.pi/agent/settings.json\n * Project: <cwd>/.pi/settings.json\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport * as z from \"zod\";\n\nconst piSettingsSchema = z.object({\n\tenableSkillCommands: z.boolean().optional(),\n\tquietStartup: z.boolean().optional(),\n\tquietStart: z.boolean().optional(),\n\tskills: z\n\t\t.object({\n\t\t\tenableSkillCommands: z.boolean().optional(),\n\t\t})\n\t\t.optional(),\n});\n\ntype PiSettings = z.infer<typeof piSettingsSchema>;\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n\treturn typeof x === \"object\" && x !== null && !Array.isArray(x);\n}\n\nfunction merge(\n\tbase: Record<string, unknown>,\n\toverride: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = { ...base };\n\tfor (const [key, val] of Object.entries(override)) {\n\t\tconst existing = result[key];\n\t\tif (isRecord(existing) && isRecord(val)) {\n\t\t\tresult[key] = merge(existing, val);\n\t\t} else {\n\t\t\tresult[key] = val;\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction readJson(path: string): Record<string, unknown> {\n\ttry {\n\t\tif (!existsSync(path)) return {};\n\t\tconst data: unknown = JSON.parse(readFileSync(path, \"utf-8\"));\n\t\treturn isRecord(data) ? data : {};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nexport function piAgentDir(): string {\n\treturn process.env.PI_CODING_AGENT_DIR !== undefined\n\t\t? resolve(process.env.PI_CODING_AGENT_DIR)\n\t\t: join(homedir(), \".pi\", \"agent\");\n}\n\nfunction resolvedSettings(cwd: string): PiSettings {\n\tconst globalPath = join(piAgentDir(), \"settings.json\");\n\tconst projectPath = resolve(cwd, \".pi\", \"settings.json\");\n\tconst merged = merge(readJson(globalPath), readJson(projectPath));\n\tconst result = piSettingsSchema.safeParse(merged);\n\treturn result.success ? result.data : {};\n}\n\nexport function skillCommandsEnabled(cwd: string): boolean {\n\tconst settings = resolvedSettings(cwd);\n\n\tif (typeof settings.enableSkillCommands === \"boolean\") {\n\t\treturn settings.enableSkillCommands;\n\t}\n\n\tif (typeof settings.skills?.enableSkillCommands === \"boolean\") {\n\t\treturn settings.skills.enableSkillCommands;\n\t}\n\n\treturn true;\n}\n","/**\n * Per-tool content formatting for ACP tool results.\n *\n * Dispatches formatting by tool name following the reference implementation\n * pattern (claude-agent-acp / codex-acp). Each tool type produces\n * `ToolCallContent[]` appropriate for its output shape.\n */\n\nimport type { ToolCallContent } from \"@agentclientprotocol/sdk\";\nimport * as z from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Zod schemas for pi tool result shapes\n// ---------------------------------------------------------------------------\n\nconst textBlockSchema = z.object({\n\ttype: z.literal(\"text\"),\n\ttext: z.string(),\n});\n\nconst imageBlockSchema = z.object({\n\ttype: z.literal(\"image\"),\n});\n\nconst contentBlockSchema = z.union([textBlockSchema, imageBlockSchema]);\n\nconst bashDetailsSchema = z.object({\n\tstdout: z.string().optional(),\n\tstderr: z.string().optional(),\n\toutput: z.string().optional(),\n\texitCode: z.number().optional(),\n\tcode: z.number().optional(),\n});\n\nconst bashResultSchema = z.object({\n\tcontent: z.array(z.unknown()).optional(),\n\tdetails: bashDetailsSchema.optional(),\n\tstdout: z.string().optional(),\n\tstderr: z.string().optional(),\n\toutput: z.string().optional(),\n\texitCode: z.number().optional(),\n\tcode: z.number().optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Extraction helpers\n// ---------------------------------------------------------------------------\n\nexport interface BashOutput {\n\toutput: string;\n\texitCode: number | undefined;\n}\n\n/**\n * Extract stdout/stderr and exit code from a pi bash/tmux result.\n */\nexport function extractBashOutput(result: unknown): BashOutput {\n\tif (result === null || result === undefined || typeof result !== \"object\") {\n\t\treturn { output: \"\", exitCode: undefined };\n\t}\n\n\tconst parsed = bashResultSchema.safeParse(result);\n\tif (!parsed.success) {\n\t\treturn { output: \"\", exitCode: undefined };\n\t}\n\n\tconst r = parsed.data;\n\tconst d = r.details;\n\n\t// Try content blocks first\n\tif (r.content !== undefined) {\n\t\tconst texts = r.content\n\t\t\t.map((block) => textBlockSchema.safeParse(block))\n\t\t\t.filter((res) => res.success)\n\t\t\t.map((res) => res.data.text);\n\t\tif (texts.length > 0) {\n\t\t\tconst exitCode = d?.exitCode ?? r.exitCode ?? d?.code ?? r.code;\n\t\t\treturn { output: texts.join(\"\"), exitCode };\n\t\t}\n\t}\n\n\tconst stdout = d?.stdout ?? r.stdout ?? d?.output ?? r.output;\n\tconst stderr = d?.stderr ?? r.stderr;\n\tconst exitCode = d?.exitCode ?? r.exitCode ?? d?.code ?? r.code;\n\n\tconst parts: string[] = [];\n\tif (stdout !== undefined && stdout.trim() !== \"\") parts.push(stdout);\n\tif (stderr !== undefined && stderr.trim() !== \"\") parts.push(stderr);\n\n\treturn { output: parts.join(\"\\n\"), exitCode };\n}\n\n/**\n * Extract text content from a pi tool result (generic).\n */\nexport function extractTextContent(result: unknown): string {\n\tif (result === null || result === undefined || typeof result !== \"object\") return \"\";\n\n\tif (\"content\" in result && Array.isArray(result.content)) {\n\t\tconst texts: string[] = [];\n\t\tfor (const block of result.content) {\n\t\t\tconst parsed = textBlockSchema.safeParse(block);\n\t\t\tif (parsed.success) texts.push(parsed.data.text);\n\t\t}\n\t\tif (texts.length > 0) return texts.join(\"\");\n\t}\n\n\ttry {\n\t\treturn JSON.stringify(result, null, 2);\n\t} catch {\n\t\treturn String(result);\n\t}\n}\n\n/**\n * Extract content blocks from a pi result, preserving type information.\n * Used for read results where images need to be preserved.\n */\nexport function extractContentBlocks(\n\tresult: unknown,\n): Array<{ type: \"text\"; text: string } | { type: \"image\" }> {\n\tif (result === null || result === undefined || typeof result !== \"object\") return [];\n\tif (!(\"content\" in result) || !Array.isArray(result.content)) return [];\n\n\tconst blocks: Array<{ type: \"text\"; text: string } | { type: \"image\" }> = [];\n\tfor (const raw of result.content) {\n\t\tconst parsed = contentBlockSchema.safeParse(raw);\n\t\tif (parsed.success) {\n\t\t\tblocks.push(parsed.data);\n\t\t}\n\t}\n\treturn blocks;\n}\n\n// ---------------------------------------------------------------------------\n// Markdown escaping via dynamic backtick fence wrapping\n// ---------------------------------------------------------------------------\n\n/**\n * Find the longest consecutive backtick sequence in a string.\n */\nfunction longestBacktickRun(text: string): number {\n\tlet max = 0;\n\tlet current = 0;\n\tfor (const ch of text) {\n\t\tif (ch === \"`\") {\n\t\t\tcurrent++;\n\t\t\tif (current > max) max = current;\n\t\t} else {\n\t\t\tcurrent = 0;\n\t\t}\n\t}\n\treturn max;\n}\n\n/**\n * Wrap text in a dynamically-sized backtick fence to prevent markdown rendering.\n *\n * Instead of character-level escaping (which fails on files containing backtick\n * sequences, indented code blocks, blockquotes, and list markers), this wraps\n * the entire text in a backtick fence whose length exceeds any backtick sequence\n * in the content. This approach is simpler and strictly more correct (following\n * the claude-agent-acp pattern).\n */\nexport function markdownEscape(text: string): string {\n\tif (text === \"\") return \"\";\n\n\tconst fenceLen = Math.max(3, longestBacktickRun(text) + 1);\n\tconst fence = \"`\".repeat(fenceLen);\n\n\t// Avoid a trailing double newline before the closing fence\n\tconst body = text.endsWith(\"\\n\") ? text.slice(0, -1) : text;\n\treturn `${fence}\\n${body}\\n${fence}`;\n}\n\n// ---------------------------------------------------------------------------\n// Per-tool content formatting\n// ---------------------------------------------------------------------------\n\n/**\n * Format tool output into `ToolCallContent[]` by tool name.\n *\n * Returns the appropriate content shape for each tool type:\n * - bash/tmux: console code fences\n * - read: markdown-escaped text (images preserved)\n * - edit/write: empty (diff handled separately)\n * - lsp: code fences\n * - errors: code fences with failed status\n * - everything else: plain text\n */\nexport function formatToolContent(\n\ttoolName: string,\n\tresult: unknown,\n\tisError: boolean,\n): ToolCallContent[] {\n\t// Error path: wrap any error text in a code fence\n\tif (isError) {\n\t\tconst text = extractTextContent(result);\n\t\tif (text === \"\") return [];\n\t\treturn [{ type: \"content\", content: { type: \"text\", text: `\\`\\`\\`\\n${text}\\n\\`\\`\\`` } }];\n\t}\n\n\tswitch (toolName) {\n\t\tcase \"bash\":\n\t\tcase \"tmux\":\n\t\t\treturn formatBashContent(result);\n\n\t\tcase \"read\":\n\t\t\treturn formatReadContent(result);\n\n\t\tcase \"edit\":\n\t\tcase \"write\":\n\t\t\t// Diff content is handled separately in handleToolEnd.\n\t\t\t// Return empty so the diff path takes precedence.\n\t\t\treturn [];\n\n\t\tcase \"lsp\":\n\t\t\treturn formatLspContent(result);\n\n\t\tdefault:\n\t\t\treturn formatFallbackContent(result);\n\t}\n}\n\nfunction formatBashContent(result: unknown): ToolCallContent[] {\n\tconst { output, exitCode } = extractBashOutput(result);\n\tif (output === \"\" && exitCode === undefined) return [];\n\n\tconst parts: string[] = [];\n\tif (output !== \"\") {\n\t\tparts.push(`\\`\\`\\`console\\n${output}\\n\\`\\`\\``);\n\t}\n\tif (exitCode !== undefined && exitCode !== 0) {\n\t\tparts.push(`exit code: ${exitCode}`);\n\t}\n\n\tconst text = parts.join(\"\\n\\n\");\n\tif (text === \"\") return [];\n\treturn [{ type: \"content\", content: { type: \"text\", text } }];\n}\n\nfunction formatReadContent(result: unknown): ToolCallContent[] {\n\tconst blocks = extractContentBlocks(result);\n\tif (blocks.length === 0) {\n\t\t// Check if the result explicitly has an empty content array\n\t\tif (\n\t\t\ttypeof result === \"object\" &&\n\t\t\tresult !== null &&\n\t\t\t\"content\" in result &&\n\t\t\tArray.isArray(result.content) &&\n\t\t\tresult.content.length === 0\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\t// Fallback to text extraction for results without content blocks\n\t\tconst text = extractTextContent(result);\n\t\tif (text === \"\") return [];\n\t\treturn [{ type: \"content\", content: { type: \"text\", text: markdownEscape(text) } }];\n\t}\n\n\tconst content: ToolCallContent[] = [];\n\tfor (const block of blocks) {\n\t\tif (block.type === \"text\") {\n\t\t\tcontent.push({\n\t\t\t\ttype: \"content\",\n\t\t\t\tcontent: { type: \"text\", text: markdownEscape(block.text) },\n\t\t\t});\n\t\t}\n\t\t// Image blocks are preserved as-is (the ACP client handles rendering)\n\t\t// We skip them here since they need their original structure from the result\n\t}\n\n\t// If we only had image blocks and no text, return empty\n\treturn content;\n}\n\nfunction formatLspContent(result: unknown): ToolCallContent[] {\n\tconst text = extractTextContent(result);\n\tif (text === \"\") return [];\n\treturn [{ type: \"content\", content: { type: \"text\", text: `\\`\\`\\`\\n${text}\\n\\`\\`\\`` } }];\n}\n\nfunction formatFallbackContent(result: unknown): ToolCallContent[] {\n\tconst text = extractTextContent(result);\n\tif (text === \"\") return [];\n\treturn [{ type: \"content\", content: { type: \"text\", text } }];\n}\n\n/**\n * Wrap streaming output text in a console code fence for bash/tmux.\n *\n * Each streaming update is self-contained (full accumulated buffer),\n * following the codex-acp pattern.\n */\nexport function wrapStreamingBashOutput(text: string): string {\n\tif (text === \"\") return \"\";\n\treturn `\\`\\`\\`console\\n${text}\\n\\`\\`\\``;\n}\n","/**\n * Exhaustive switch/case helper.\n *\n * Writes unknown values to stderr instead of silently ignoring them, aiding\n * debugging when the pi SDK adds new event types. Never write to stdout: it\n * carries the ACP NDJSON stream and any other byte poisons the protocol.\n */\nexport function unreachable(value: never, context?: string): void {\n\tconst label = context !== undefined ? `[${context}] ` : \"\";\n\tprocess.stderr.write(`${label}Unhandled value: ${String(value)}\\n`);\n}\n","import { readFileSync } from \"node:fs\";\nimport { isAbsolute, resolve as resolvePath } from \"node:path\";\nimport {\n\ttype AgentSideConnection,\n\ttype ContentBlock,\n\ttype McpServer,\n\tRequestError,\n\ttype SessionUpdate,\n\ttype ToolCallContent,\n\ttype ToolCallLocation,\n\ttype ToolKind,\n} from \"@agentclientprotocol/sdk\";\nimport type { AgentEvent, AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessageEvent, ToolCall } from \"@earendil-works/pi-ai\";\nimport type { AgentSession, AgentSessionEvent } from \"@earendil-works/pi-coding-agent\";\nimport { formatToolContent, wrapStreamingBashOutput } from \"@pi-acp/acp/translate/tool-content\";\nimport { unreachable } from \"@pi-acp/acp/unreachable\";\nimport * as z from \"zod\";\n\nexport type StopReason = \"end_turn\" | \"cancelled\" | \"max_tokens\" | \"error\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction findUniqueLineNumber(text: string, needle: string): number | undefined {\n\tif (!needle) return undefined;\n\tconst first = text.indexOf(needle);\n\tif (first < 0) return undefined;\n\tif (text.indexOf(needle, first + needle.length) >= 0) return undefined;\n\n\tlet line = 1;\n\tfor (let i = 0; i < first; i++) {\n\t\tif (text.charCodeAt(i) === 10) line++;\n\t}\n\treturn line;\n}\n\nexport interface ToolArgs {\n\tpath?: string | undefined;\n\toldText?: string | undefined;\n\t[key: string]: unknown;\n}\n\nexport function resolveToolPath(\n\targs: ToolArgs,\n\tcwd: string,\n\tline?: number,\n): ToolCallLocation[] | undefined {\n\tconst p = args.path;\n\tif (p === undefined) return undefined;\n\n\tconst resolved = isAbsolute(p) ? p : resolvePath(cwd, p);\n\treturn [{ path: resolved, ...(typeof line === \"number\" ? { line } : {}) }];\n}\n\nexport function toToolKind(toolName: string): ToolKind {\n\tswitch (toolName) {\n\t\tcase \"read\":\n\t\t\treturn \"read\";\n\t\tcase \"write\":\n\t\tcase \"edit\":\n\t\t\treturn \"edit\";\n\t\tcase \"bash\":\n\t\tcase \"tmux\":\n\t\t\treturn \"execute\";\n\t\tcase \"lsp\":\n\t\t\treturn \"search\";\n\t\tdefault:\n\t\t\treturn \"other\";\n\t}\n}\n\nconst MAX_TITLE_LEN = 80;\n\nfunction truncateTitle(text: string): string {\n\tconst oneLine = text.replace(/\\n/g, \" \").trim();\n\tif (oneLine.length <= MAX_TITLE_LEN) return oneLine;\n\treturn `${oneLine.slice(0, MAX_TITLE_LEN - 1)}…`;\n}\n\nfunction capitalize(s: string): string {\n\tif (s.length === 0) return s;\n\treturn s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/**\n * Build a descriptive tool title from tool name and args.\n *\n * Returns a short human-readable label like \"Read src/index.ts\" or \"Run ls -la\".\n */\nexport function buildToolTitle(toolName: string, args: ToolArgs): string {\n\tconst p = args.path;\n\n\tswitch (toolName) {\n\t\tcase \"read\":\n\t\t\treturn p !== undefined ? `Read ${p}` : \"Read\";\n\t\tcase \"write\":\n\t\t\treturn p !== undefined ? `Write ${p}` : \"Write\";\n\t\tcase \"edit\":\n\t\t\treturn p !== undefined ? `Edit ${p}` : \"Edit\";\n\t\tcase \"bash\": {\n\t\t\tconst command =\n\t\t\t\ttypeof args[\"command\"] === \"string\"\n\t\t\t\t\t? args[\"command\"]\n\t\t\t\t\t: typeof args[\"cmd\"] === \"string\"\n\t\t\t\t\t\t? args[\"cmd\"]\n\t\t\t\t\t\t: undefined;\n\t\t\treturn command !== undefined ? truncateTitle(`Run ${command}`) : \"bash\";\n\t\t}\n\t\tcase \"lsp\": {\n\t\t\tconst action = typeof args[\"action\"] === \"string\" ? args[\"action\"] : undefined;\n\t\t\tconst file = typeof args[\"file\"] === \"string\" ? args[\"file\"] : undefined;\n\t\t\tconst query = typeof args[\"query\"] === \"string\" ? args[\"query\"] : undefined;\n\t\t\tconst line = typeof args[\"line\"] === \"number\" ? args[\"line\"] : undefined;\n\t\t\tif (action !== undefined) {\n\t\t\t\tconst target = file !== undefined ? (line !== undefined ? `${file}:${line}` : file) : query;\n\t\t\t\treturn target !== undefined\n\t\t\t\t\t? truncateTitle(`${capitalize(action)} ${target}`)\n\t\t\t\t\t: capitalize(action);\n\t\t\t}\n\t\t\treturn \"LSP\";\n\t\t}\n\t\tcase \"tmux\": {\n\t\t\tconst action = typeof args[\"action\"] === \"string\" ? args[\"action\"] : undefined;\n\t\t\tconst command = typeof args[\"command\"] === \"string\" ? args[\"command\"] : undefined;\n\t\t\tconst name = typeof args[\"name\"] === \"string\" ? args[\"name\"] : undefined;\n\t\t\tif (action === \"run\" && command !== undefined) return truncateTitle(`Tmux: ${command}`);\n\t\t\tif (action !== undefined && name !== undefined)\n\t\t\t\treturn truncateTitle(`Tmux ${action} ${name}`);\n\t\t\tif (action !== undefined) return `Tmux ${action}`;\n\t\t\treturn \"Tmux\";\n\t\t}\n\t\tcase \"context_tag\": {\n\t\t\tconst name = typeof args[\"name\"] === \"string\" ? args[\"name\"] : undefined;\n\t\t\treturn name !== undefined ? `Tag ${name}` : \"Tag\";\n\t\t}\n\t\tcase \"context_log\":\n\t\t\treturn \"Context log\";\n\t\tcase \"context_checkout\": {\n\t\t\tconst target = typeof args[\"target\"] === \"string\" ? args[\"target\"] : undefined;\n\t\t\treturn target !== undefined ? truncateTitle(`Checkout ${target}`) : \"Checkout\";\n\t\t}\n\t\tcase \"claudemon\":\n\t\t\treturn \"Check quota\";\n\t\tdefault:\n\t\t\treturn toolName;\n\t}\n}\n\n/**\n * Map pi assistant stopReason to ACP StopReason.\n * pi: \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\"\n * ACP: \"end_turn\" | \"cancelled\" | \"max_tokens\" | \"error\"\n */\nfunction mapPiStopReason(piReason: string | null): StopReason {\n\tswitch (piReason) {\n\t\tcase \"stop\":\n\t\tcase \"toolUse\":\n\t\t\treturn \"end_turn\";\n\t\tcase \"length\":\n\t\t\treturn \"max_tokens\";\n\t\tcase \"aborted\":\n\t\t\treturn \"cancelled\";\n\t\tcase \"error\":\n\t\t\treturn \"error\";\n\t\tdefault:\n\t\t\treturn \"end_turn\";\n\t}\n}\n\nfunction extractToolCallFromPartial(ame: AssistantMessageEvent): ToolCall | undefined {\n\tif (!(\"partial\" in ame)) return undefined;\n\tconst content = ame.partial.content;\n\tconst idx = \"contentIndex\" in ame ? ame.contentIndex : 0;\n\tconst block = content[idx];\n\tif (block && \"type\" in block && block.type === \"toolCall\") return block;\n\treturn undefined;\n}\n\nfunction parseToolInput(tc: ToolCall): ToolArgs {\n\treturn tc.arguments;\n}\n\nconst toolArgsSchema = z\n\t.object({\n\t\tpath: z.string().trim().optional(),\n\t\toldText: z.string().trim().optional(),\n\t})\n\t.loose();\n\nexport function toToolArgs(raw: unknown): ToolArgs {\n\tconst result = toolArgsSchema.safeParse(raw);\n\treturn result.success ? result.data : {};\n}\n\n// ---------------------------------------------------------------------------\n// _meta builder helpers\n// ---------------------------------------------------------------------------\n\ntype PiAcpMeta = Record<string, unknown>;\n\n/** Build the `_meta.piAcp` tool name metadata. */\nfunction buildToolMeta(toolName: string, extra?: PiAcpMeta): PiAcpMeta {\n\tconst base: PiAcpMeta = { piAcp: { toolName } };\n\tif (extra !== undefined) {\n\t\treturn { ...base, ...extra };\n\t}\n\treturn base;\n}\n\n// ---------------------------------------------------------------------------\n// Terminal tool classification\n// ---------------------------------------------------------------------------\n\n/** Tools that produce terminal-style output. */\nfunction isTerminalTool(toolName: string): boolean {\n\treturn toolName === \"bash\" || toolName === \"tmux\";\n}\n\n// ---------------------------------------------------------------------------\n// Session manager\n// ---------------------------------------------------------------------------\n\nexport class SessionManager {\n\tprivate sessions = new Map<string, PiAcpSession>();\n\n\tdisposeAll(): void {\n\t\tfor (const id of this.sessions.keys()) this.close(id);\n\t}\n\n\tmaybeGet(sessionId: string): PiAcpSession | undefined {\n\t\treturn this.sessions.get(sessionId);\n\t}\n\n\tclose(sessionId: string): void {\n\t\tconst s = this.sessions.get(sessionId);\n\t\tif (!s) return;\n\t\ttry {\n\t\t\ts.dispose();\n\t\t} catch {\n\t\t\t// best-effort\n\t\t}\n\t\tthis.sessions.delete(sessionId);\n\t}\n\n\t/**\n\t * Drop this connection's PiAcpSession wrapper without disposing the\n\t * underlying pi runtime. Used when the daemon SessionRegistry reports\n\t * another client still holds the session.\n\t */\n\tdetach(sessionId: string): void {\n\t\tconst s = this.sessions.get(sessionId);\n\t\tif (!s) return;\n\t\ttry {\n\t\t\ts.unsubscribeOnly();\n\t\t} catch {\n\t\t\t// best-effort — fall back to full dispose if detach is unsupported\n\t\t}\n\t\tthis.sessions.delete(sessionId);\n\t}\n\n\tcloseAllExcept(keepSessionId: string): void {\n\t\tfor (const id of this.sessions.keys()) {\n\t\t\tif (id !== keepSessionId) this.close(id);\n\t\t}\n\t}\n\n\tregister(session: PiAcpSession): void {\n\t\tthis.sessions.set(session.sessionId, session);\n\t}\n\n\tget(sessionId: string): PiAcpSession {\n\t\tconst s = this.sessions.get(sessionId);\n\t\tif (!s) throw RequestError.invalidParams(`Unknown sessionId: ${sessionId}`);\n\t\treturn s;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// ACP session wrapping a pi AgentSession\n// ---------------------------------------------------------------------------\n\nexport interface PiAcpSessionOpts {\n\tsessionId: string;\n\tcwd: string;\n\tmcpServers: McpServer[];\n\tpiSession: AgentSession;\n\tconn: AgentSideConnection;\n\t/** Whether the client supports terminal output metadata. */\n\tsupportsTerminalOutput?: boolean | undefined;\n}\n\nexport class PiAcpSession {\n\treadonly sessionId: string;\n\treadonly cwd: string;\n\treadonly mcpServers: McpServer[];\n\treadonly piSession: AgentSession;\n\treadonly supportsTerminalOutput: boolean;\n\n\tprivate readonly conn: AgentSideConnection;\n\n\tprivate cancelRequested = false;\n\tprivate promptRunning = false;\n\tprivate pendingTurn: { resolve: (r: StopReason) => void; reject: (e: unknown) => void } | null =\n\t\tnull;\n\t/** Queued prompts waiting for the active turn to complete. */\n\tprivate pendingMessages: Array<{\n\t\tmessage: string;\n\t\timages: unknown[];\n\t\tresolve: (r: StopReason) => void;\n\t\treject: (e: unknown) => void;\n\t}> = [];\n\n\tprivate currentToolCalls = new Map<string, \"pending\" | \"in_progress\">();\n\t/** Map of toolCallId -> toolName for streaming updates (Phase 5). */\n\tprivate toolCallNames = new Map<string, string>();\n\tprivate editSnapshots = new Map<string, { path: string; oldText: string }>();\n\tprivate lastAssistantStopReason: string | null = null;\n\tprivate lastEmit: Promise<void> = Promise.resolve();\n\tprivate unsubscribe: (() => void) | undefined;\n\n\tconstructor(opts: PiAcpSessionOpts) {\n\t\tthis.sessionId = opts.sessionId;\n\t\tthis.cwd = opts.cwd;\n\t\tthis.mcpServers = opts.mcpServers;\n\t\tthis.piSession = opts.piSession;\n\t\tthis.conn = opts.conn;\n\t\tthis.supportsTerminalOutput = opts.supportsTerminalOutput ?? false;\n\t\tthis.unsubscribe = this.piSession.subscribe((ev: AgentSessionEvent) => this.handlePiEvent(ev));\n\t}\n\n\tdispose(): void {\n\t\tthis.unsubscribe?.();\n\t\tthis.piSession.dispose();\n\t}\n\n\t/**\n\t * Drop event subscription without disposing the underlying piSession.\n\t * Used when the daemon registry transfers ownership to another connection\n\t * that still holds this session.\n\t */\n\tunsubscribeOnly(): void {\n\t\tthis.unsubscribe?.();\n\t\tthis.unsubscribe = undefined;\n\t}\n\n\tasync prompt(message: string, images: unknown[] = []): Promise<StopReason> {\n\t\t// If a prompt is already running, queue this one and return a promise\n\t\t// that resolves when it eventually executes.\n\t\tif (this.promptRunning) {\n\t\t\treturn new Promise<StopReason>((resolve, reject) => {\n\t\t\t\tthis.pendingMessages.push({ message, images, resolve, reject });\n\t\t\t});\n\t\t}\n\n\t\treturn this.executePrompt(message, images);\n\t}\n\n\tasync cancel(): Promise<void> {\n\t\tthis.cancelRequested = true;\n\n\t\t// Resolve all queued prompts as cancelled\n\t\tfor (const pending of this.pendingMessages) {\n\t\t\tpending.resolve(\"cancelled\");\n\t\t}\n\t\tthis.pendingMessages = [];\n\n\t\tawait this.piSession.abort();\n\t}\n\n\tprivate executePrompt(message: string, images: unknown[]): Promise<StopReason> {\n\t\tthis.promptRunning = true;\n\n\t\tconst turnPromise = new Promise<StopReason>((resolve, reject) => {\n\t\t\tthis.cancelRequested = false;\n\t\t\tthis.pendingTurn = { resolve, reject };\n\t\t});\n\n\t\tconst imageContents = Array.isArray(images)\n\t\t\t? images.filter(\n\t\t\t\t\t(img): img is { type: \"image\"; data: string; mimeType: string } =>\n\t\t\t\t\t\ttypeof img === \"object\" && img !== null && \"type\" in img && img.type === \"image\",\n\t\t\t\t)\n\t\t\t: [];\n\n\t\tthis.piSession.prompt(message, { images: imageContents }).catch(() => {\n\t\t\tvoid this.flushEmits().finally(() => {\n\t\t\t\tconst reason: StopReason = this.cancelRequested ? \"cancelled\" : \"error\";\n\t\t\t\tthis.pendingTurn?.resolve(reason);\n\t\t\t\tthis.pendingTurn = null;\n\t\t\t});\n\t\t});\n\n\t\treturn turnPromise;\n\t}\n\n\t/**\n\t * Dequeue and execute the next pending prompt, if any.\n\t * Called after a turn completes.\n\t */\n\tprivate dequeueNextPrompt(): void {\n\t\tconst next = this.pendingMessages.shift();\n\t\tif (next === undefined) {\n\t\t\tthis.promptRunning = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.executePrompt(next.message, next.images).then(next.resolve, next.reject);\n\t}\n\n\twasCancelRequested(): boolean {\n\t\treturn this.cancelRequested;\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Internal\n\t// -----------------------------------------------------------------------\n\n\tprivate emit(update: SessionUpdate): void {\n\t\tthis.lastEmit = this.lastEmit\n\t\t\t.then(() => this.conn.sessionUpdate({ sessionId: this.sessionId, update }))\n\t\t\t.catch(() => {});\n\t}\n\n\tprivate async flushEmits(): Promise<void> {\n\t\tawait this.lastEmit;\n\t}\n\n\tprivate handlePiEvent(ev: AgentSessionEvent): void {\n\t\tif (!isAgentEvent(ev)) return;\n\n\t\tswitch (ev.type) {\n\t\t\tcase \"message_update\":\n\t\t\t\tthis.handleMessageUpdate(ev.assistantMessageEvent);\n\t\t\t\tbreak;\n\t\t\tcase \"message_end\":\n\t\t\t\tthis.handleMessageEnd(ev.message);\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis.handleToolStart(ev.toolCallId, ev.toolName, toToolArgs(ev.args));\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_update\":\n\t\t\t\tthis.handleToolUpdate(ev.toolCallId, ev.toolName, ev.partialResult);\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_end\":\n\t\t\t\tthis.handleToolEnd(ev.toolCallId, ev.toolName, ev.result, ev.isError);\n\t\t\t\tbreak;\n\t\t\tcase \"agent_end\":\n\t\t\t\tthis.handleAgentEnd();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunreachable(ev, \"handlePiEvent\");\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate handleMessageUpdate(ame: AssistantMessageEvent): void {\n\t\tif (ame.type === \"text_delta\") {\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\tcontent: { type: \"text\", text: ame.delta } satisfies ContentBlock,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (ame.type === \"thinking_delta\") {\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"agent_thought_chunk\",\n\t\t\t\tcontent: { type: \"text\", text: ame.delta } satisfies ContentBlock,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tame.type === \"toolcall_start\" ||\n\t\t\tame.type === \"toolcall_delta\" ||\n\t\t\tame.type === \"toolcall_end\"\n\t\t) {\n\t\t\tconst toolCall = ame.type === \"toolcall_end\" ? ame.toolCall : extractToolCallFromPartial(ame);\n\t\t\tif (!toolCall) return;\n\n\t\t\tconst rawInput = parseToolInput(toolCall);\n\t\t\tconst locations = resolveToolPath(rawInput, this.cwd);\n\t\t\tconst existingStatus = this.currentToolCalls.get(toolCall.id);\n\t\t\tconst status = existingStatus ?? \"pending\";\n\n\t\t\tif (!existingStatus) {\n\t\t\t\tthis.currentToolCalls.set(toolCall.id, \"pending\");\n\t\t\t\tthis.emit({\n\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\ttitle: buildToolTitle(toolCall.name, rawInput),\n\t\t\t\t\tkind: toToolKind(toolCall.name),\n\t\t\t\t\tstatus,\n\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\trawInput,\n\t\t\t\t\t_meta: buildToolMeta(toolCall.name),\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.emit({\n\t\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\t\ttoolCallId: toolCall.id,\n\t\t\t\t\tstatus,\n\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\trawInput,\n\t\t\t\t\t_meta: buildToolMeta(toolCall.name),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate handleMessageEnd(msg: AgentMessage): void {\n\t\tif (\"role\" in msg && msg.role === \"assistant\") {\n\t\t\tthis.lastAssistantStopReason = msg.stopReason;\n\t\t}\n\t}\n\n\tprivate handleToolStart(toolCallId: string, toolName: string, args: ToolArgs): void {\n\t\t// Track toolName for streaming updates (Phase 5)\n\t\tthis.toolCallNames.set(toolCallId, toolName);\n\n\t\tlet line: number | undefined;\n\n\t\tif ((toolName === \"edit\" || toolName === \"write\") && args.path !== undefined) {\n\t\t\ttry {\n\t\t\t\tconst abs = isAbsolute(args.path) ? args.path : resolvePath(this.cwd, args.path);\n\t\t\t\tlet oldText = \"\";\n\t\t\t\ttry {\n\t\t\t\t\toldText = readFileSync(abs, \"utf8\");\n\t\t\t\t} catch {\n\t\t\t\t\t// File may not exist yet for write -- treat as empty.\n\t\t\t\t}\n\t\t\t\tthis.editSnapshots.set(toolCallId, { path: abs, oldText });\n\t\t\t\tif (toolName === \"edit\") {\n\t\t\t\t\tline = findUniqueLineNumber(oldText, args.oldText ?? \"\");\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// snapshot failure is non-fatal\n\t\t\t}\n\t\t}\n\n\t\tconst locations = resolveToolPath(args, this.cwd, line);\n\n\t\t// Build terminal metadata for bash/tmux when client supports it\n\t\tconst terminalMeta =\n\t\t\tthis.supportsTerminalOutput && isTerminalTool(toolName)\n\t\t\t\t? { terminal_info: { terminal_id: toolCallId, cwd: this.cwd } }\n\t\t\t\t: undefined;\n\t\tconst meta = buildToolMeta(toolName, terminalMeta);\n\n\t\t// Build content for terminal-aware clients\n\t\tconst terminalContent: ToolCallContent[] | undefined =\n\t\t\tthis.supportsTerminalOutput && isTerminalTool(toolName)\n\t\t\t\t? [{ type: \"terminal\" as const, terminalId: toolCallId }]\n\t\t\t\t: undefined;\n\n\t\tif (!this.currentToolCalls.has(toolCallId)) {\n\t\t\tthis.currentToolCalls.set(toolCallId, \"in_progress\");\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\ttoolCallId,\n\t\t\t\ttitle: buildToolTitle(toolName, args),\n\t\t\t\tkind: toToolKind(toolName),\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t...(terminalContent !== undefined ? { content: terminalContent } : {}),\n\t\t\t\trawInput: args,\n\t\t\t\t_meta: meta,\n\t\t\t});\n\t\t} else {\n\t\t\tthis.currentToolCalls.set(toolCallId, \"in_progress\");\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\ttitle: buildToolTitle(toolName, args),\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t...(terminalContent !== undefined ? { content: terminalContent } : {}),\n\t\t\t\trawInput: args,\n\t\t\t\t_meta: meta,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate handleToolUpdate(toolCallId: string, toolName: string, partialResult: unknown): void {\n\t\t// Look up tool name from our map (Phase 5), fall back to event's toolName\n\t\tconst name = this.toolCallNames.get(toolCallId) ?? toolName;\n\n\t\tif (this.supportsTerminalOutput && isTerminalTool(name)) {\n\t\t\t// Terminal-aware path: emit only _meta.terminal_output, no content\n\t\t\tconst text = extractStreamingText(partialResult);\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t_meta: buildToolMeta(name, {\n\t\t\t\t\tterminal_output: { terminal_id: toolCallId, data: text },\n\t\t\t\t}),\n\t\t\t\trawOutput: partialResult,\n\t\t\t});\n\t\t} else if (isTerminalTool(name)) {\n\t\t\t// Non-terminal fallback: wrap in console code fence\n\t\t\tconst text = extractStreamingText(partialResult);\n\t\t\tconst wrapped = wrapStreamingBashOutput(text);\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\tcontent: wrapped\n\t\t\t\t\t? ([\n\t\t\t\t\t\t\t{ type: \"content\", content: { type: \"text\", text: wrapped } },\n\t\t\t\t\t\t] satisfies ToolCallContent[])\n\t\t\t\t\t: null,\n\t\t\t\t_meta: buildToolMeta(name),\n\t\t\t\trawOutput: partialResult,\n\t\t\t});\n\t\t} else {\n\t\t\t// Other tools: plain text content\n\t\t\tconst text = extractStreamingText(partialResult);\n\t\t\tthis.emit({\n\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\ttoolCallId,\n\t\t\t\tstatus: \"in_progress\",\n\t\t\t\tcontent: text\n\t\t\t\t\t? ([{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[])\n\t\t\t\t\t: null,\n\t\t\t\t_meta: buildToolMeta(name),\n\t\t\t\trawOutput: partialResult,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate handleToolEnd(\n\t\ttoolCallId: string,\n\t\ttoolName: string,\n\t\tresult: unknown,\n\t\tisError: boolean,\n\t): void {\n\t\tconst snapshot = this.editSnapshots.get(toolCallId);\n\t\tlet content: ToolCallContent[] | null = null;\n\n\t\t// Diff path for edit/write\n\t\tif (!isError && snapshot) {\n\t\t\ttry {\n\t\t\t\tconst newText = readFileSync(snapshot.path, \"utf8\");\n\t\t\t\tif (newText !== snapshot.oldText) {\n\t\t\t\t\tconst formatted = formatToolContent(toolName, result, isError);\n\t\t\t\t\tcontent = [\n\t\t\t\t\t\t{ type: \"diff\", path: snapshot.path, oldText: snapshot.oldText, newText },\n\t\t\t\t\t\t...formatted,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// fall back to formatted content\n\t\t\t}\n\t\t}\n\n\t\t// If no diff content, use formatted tool content\n\t\tif (content === null) {\n\t\t\tconst formatted = formatToolContent(toolName, result, isError);\n\t\t\tcontent = formatted.length > 0 ? formatted : null;\n\t\t}\n\n\t\t// Last resort: if formatToolContent returns empty and no diff, generate plain text\n\t\tif (content === null && !isError && toolName !== \"edit\" && toolName !== \"write\") {\n\t\t\tconst text = extractStreamingText(result);\n\t\t\tif (text) {\n\t\t\t\tcontent = [{ type: \"content\", content: { type: \"text\", text } }];\n\t\t\t}\n\t\t}\n\n\t\t// For terminal tools: emit a separate terminal_output update before terminal_exit.\n\t\t// This ensures Zed renders output before the exit status (following claude-agent-acp).\n\t\tif (this.supportsTerminalOutput && isTerminalTool(toolName)) {\n\t\t\tconst outputText = extractStreamingText(result);\n\t\t\tif (outputText !== \"\") {\n\t\t\t\tthis.emit({\n\t\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\t\ttoolCallId,\n\t\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t\t_meta: buildToolMeta(toolName, {\n\t\t\t\t\t\tterminal_output: { terminal_id: toolCallId, data: outputText },\n\t\t\t\t\t}),\n\t\t\t\t\trawOutput: result,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Build terminal exit metadata for bash/tmux\n\t\tconst terminalExitMeta =\n\t\t\tthis.supportsTerminalOutput && isTerminalTool(toolName)\n\t\t\t\t? {\n\t\t\t\t\t\tterminal_exit: {\n\t\t\t\t\t\t\tterminal_id: toolCallId,\n\t\t\t\t\t\t\texit_code: extractExitCode(result),\n\t\t\t\t\t\t\tsignal: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\tconst meta = buildToolMeta(toolName, terminalExitMeta);\n\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\ttoolCallId,\n\t\t\tstatus: isError ? \"failed\" : \"completed\",\n\t\t\tcontent,\n\t\t\t_meta: meta,\n\t\t\trawOutput: result,\n\t\t});\n\n\t\tthis.currentToolCalls.delete(toolCallId);\n\t\tthis.editSnapshots.delete(toolCallId);\n\t\tthis.toolCallNames.delete(toolCallId);\n\t}\n\n\tprivate handleAgentEnd(): void {\n\t\tthis.emitUsageUpdate();\n\t\tvoid this.flushEmits().finally(() => {\n\t\t\tconst reason: StopReason = this.cancelRequested\n\t\t\t\t? \"cancelled\"\n\t\t\t\t: mapPiStopReason(this.lastAssistantStopReason);\n\t\t\tthis.lastAssistantStopReason = null;\n\t\t\tthis.pendingTurn?.resolve(reason);\n\t\t\tthis.pendingTurn = null;\n\t\t\tthis.dequeueNextPrompt();\n\t\t});\n\t}\n\n\t/**\n\t * Emit a usage_update notification with current context and cost data.\n\t */\n\tprivate emitUsageUpdate(): void {\n\t\tconst contextUsage = this.piSession.getContextUsage?.();\n\t\tconst stats = this.piSession.getSessionStats();\n\n\t\tconst used = contextUsage?.tokens ?? 0;\n\t\tconst size = contextUsage?.contextWindow ?? 0;\n\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"usage_update\",\n\t\t\tused,\n\t\t\tsize,\n\t\t\tcost: stats.cost > 0 ? { amount: stats.cost, currency: \"USD\" } : null,\n\t\t});\n\t}\n\n\t/**\n\t * Build ACP Usage data from pi session stats for prompt response.\n\t */\n\tgetUsage(): {\n\t\tinputTokens: number;\n\t\toutputTokens: number;\n\t\tcachedReadTokens: number;\n\t\tcachedWriteTokens: number;\n\t} {\n\t\tconst stats = this.piSession.getSessionStats();\n\t\treturn {\n\t\t\tinputTokens: stats.tokens.input,\n\t\t\toutputTokens: stats.tokens.output,\n\t\t\tcachedReadTokens: stats.tokens.cacheRead,\n\t\t\tcachedWriteTokens: stats.tokens.cacheWrite,\n\t\t};\n\t}\n\n\t/**\n\t * Get cumulative session cost.\n\t */\n\tgetCost(): number {\n\t\treturn this.piSession.getSessionStats().cost;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Streaming text extraction (lightweight, no formatting)\n// ---------------------------------------------------------------------------\n\nfunction isTextBlock(v: unknown): v is { type: \"text\"; text: string } {\n\treturn (\n\t\ttypeof v === \"object\" &&\n\t\tv !== null &&\n\t\t\"type\" in v &&\n\t\tv.type === \"text\" &&\n\t\t\"text\" in v &&\n\t\ttypeof v.text === \"string\"\n\t);\n}\n\nfunction extractStreamingText(result: unknown): string {\n\tif (result === null || result === undefined) return \"\";\n\tif (typeof result === \"string\") return result;\n\tif (typeof result !== \"object\") return String(result);\n\n\t// Content blocks\n\tif (\"content\" in result && Array.isArray(result.content)) {\n\t\tconst texts: string[] = [];\n\t\tfor (const raw of result.content) {\n\t\t\tif (isTextBlock(raw)) {\n\t\t\t\ttexts.push(raw.text);\n\t\t\t}\n\t\t}\n\t\tif (texts.length > 0) return texts.join(\"\");\n\t}\n\n\t// Details fields\n\tif (\"details\" in result) {\n\t\tconst details = result.details;\n\t\tif (typeof details === \"object\" && details !== null) {\n\t\t\tif (\"stdout\" in details && typeof details.stdout === \"string\" && details.stdout.trim() !== \"\")\n\t\t\t\treturn details.stdout;\n\t\t\tif (\"output\" in details && typeof details.output === \"string\" && details.output.trim() !== \"\")\n\t\t\t\treturn details.output;\n\t\t}\n\t}\n\n\t// Top-level output/stdout\n\tif (\"output\" in result && typeof result.output === \"string\" && result.output.trim() !== \"\")\n\t\treturn result.output;\n\tif (\"stdout\" in result && typeof result.stdout === \"string\" && result.stdout.trim() !== \"\")\n\t\treturn result.stdout;\n\n\treturn \"\";\n}\n\nfunction extractExitCode(result: unknown): number | null {\n\tif (result === null || result === undefined || typeof result !== \"object\") return null;\n\n\tif (\"details\" in result) {\n\t\tconst details = result.details;\n\t\tif (typeof details === \"object\" && details !== null) {\n\t\t\tif (\"exitCode\" in details && typeof details.exitCode === \"number\") return details.exitCode;\n\t\t\tif (\"code\" in details && typeof details.code === \"number\") return details.code;\n\t\t}\n\t}\n\n\tif (\"exitCode\" in result && typeof result.exitCode === \"number\") return result.exitCode;\n\tif (\"code\" in result && typeof result.code === \"number\") return result.code;\n\n\treturn null;\n}\n\n/**\n * Type guard to narrow AgentSessionEvent to the AgentEvent subset\n * (the variants we handle). Session-specific events like auto_compaction\n * are ignored.\n */\nfunction isAgentEvent(\n\tev: AgentSessionEvent,\n): ev is Extract<\n\tAgentEvent,\n\t| { type: \"message_update\" }\n\t| { type: \"message_end\" }\n\t| { type: \"tool_execution_start\" }\n\t| { type: \"tool_execution_update\" }\n\t| { type: \"tool_execution_end\" }\n\t| { type: \"agent_end\" }\n> {\n\treturn (\n\t\tev.type === \"message_update\" ||\n\t\tev.type === \"message_end\" ||\n\t\tev.type === \"tool_execution_start\" ||\n\t\tev.type === \"tool_execution_update\" ||\n\t\tev.type === \"tool_execution_end\" ||\n\t\tev.type === \"agent_end\"\n\t);\n}\n","/**\n * Extract plain text from pi message content.\n *\n * Pi messages store content as either a string or an array of typed blocks.\n * These helpers extract the text portions for ACP session replay.\n */\n\ninterface TextBlock {\n\ttype: \"text\";\n\ttext: string;\n}\n\nfunction isTextBlock(block: unknown): block is TextBlock {\n\tif (typeof block !== \"object\" || block === null) return false;\n\treturn (\n\t\t\"type\" in block && block.type === \"text\" && \"text\" in block && typeof block.text === \"string\"\n\t);\n}\n\nexport function extractUserMessageText(content: unknown): string {\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter(isTextBlock)\n\t\t.map((b) => b.text)\n\t\t.join(\"\");\n}\n\nexport function extractAssistantText(content: unknown): string {\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter(isTextBlock)\n\t\t.map((b) => b.text)\n\t\t.join(\"\");\n}\n","/**\n * Convert ACP prompt ContentBlocks to a pi-compatible message string and image array.\n */\n\nimport type { ContentBlock } from \"@agentclientprotocol/sdk\";\n\nexport interface PiImage {\n\ttype: \"image\";\n\tmimeType: string;\n\tdata: string;\n}\n\nexport function acpPromptToPiMessage(blocks: ContentBlock[]): {\n\tmessage: string;\n\timages: PiImage[];\n} {\n\tlet message = \"\";\n\tconst images: PiImage[] = [];\n\n\tfor (const block of blocks) {\n\t\tswitch (block.type) {\n\t\t\tcase \"text\":\n\t\t\t\tmessage += block.text;\n\t\t\t\tbreak;\n\n\t\t\tcase \"resource_link\":\n\t\t\t\tmessage += `\\n[Context] ${block.uri}`;\n\t\t\t\tbreak;\n\n\t\t\tcase \"image\":\n\t\t\t\timages.push({\n\t\t\t\t\ttype: \"image\",\n\t\t\t\t\tmimeType: block.mimeType,\n\t\t\t\t\tdata: block.data,\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase \"resource\": {\n\t\t\t\tconst resource = block.resource;\n\t\t\t\tconst uri = resource.uri;\n\t\t\t\tconst mime = resource.mimeType ?? null;\n\n\t\t\t\tif (\"text\" in resource) {\n\t\t\t\t\tmessage += `\\n[Embedded Context] ${uri} (${mime ?? \"text/plain\"})\\n${resource.text}`;\n\t\t\t\t} else if (\"blob\" in resource) {\n\t\t\t\t\tconst bytes = Buffer.byteLength(resource.blob, \"base64\");\n\t\t\t\t\tmessage += `\\n[Embedded Context] ${uri} (${mime ?? \"application/octet-stream\"}, ${bytes} bytes)`;\n\t\t\t\t} else {\n\t\t\t\t\tmessage += `\\n[Embedded Context] ${uri}`;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"audio\": {\n\t\t\t\tconst bytes = Buffer.byteLength(block.data, \"base64\");\n\t\t\t\tmessage += `\\n[Audio] (${block.mimeType}, ${bytes} bytes) not supported`;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn { message, images };\n}\n","","import { spawnSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport {\n\ttype Agent as ACPAgent,\n\ttype AgentSideConnection,\n\ttype AuthenticateRequest,\n\ttype AvailableCommand,\n\ttype CancelNotification,\n\ttype CloseSessionRequest,\n\ttype CloseSessionResponse,\n\ttype ForkSessionRequest,\n\ttype ForkSessionResponse,\n\ttype InitializeRequest,\n\ttype InitializeResponse,\n\ttype ListSessionsRequest,\n\ttype ListSessionsResponse,\n\ttype LoadSessionRequest,\n\ttype LoadSessionResponse,\n\ttype ModelInfo,\n\ttype NewSessionRequest,\n\ttype PromptRequest,\n\ttype PromptResponse,\n\tRequestError,\n\ttype ResumeSessionRequest,\n\ttype ResumeSessionResponse,\n\ttype SessionConfigOption,\n\ttype SessionInfo,\n\ttype SessionModelState,\n\ttype SessionModeState,\n\ttype SetSessionConfigOptionRequest,\n\ttype SetSessionConfigOptionResponse,\n\ttype SetSessionModelRequest,\n\ttype SetSessionModelResponse,\n\ttype SetSessionModeRequest,\n\ttype SetSessionModeResponse,\n\ttype StopReason,\n} from \"@agentclientprotocol/sdk\";\nimport type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, ToolResultMessage, UserMessage } from \"@earendil-works/pi-ai\";\nimport {\n\ttype AgentSession,\n\ttype CreateAgentSessionResult,\n\tcreateAgentSession,\n\tSessionManager as PiSessionManager,\n} from \"@earendil-works/pi-coding-agent\";\nimport { buildAuthMethods } from \"@pi-acp/acp/auth\";\nimport { detectAuthError } from \"@pi-acp/acp/auth-required\";\nimport {\n\ttype ClientCapabilityFlags,\n\tparseClientCapabilities,\n} from \"@pi-acp/acp/client-capabilities\";\nimport { resolveModelPreference } from \"@pi-acp/acp/model-alias\";\nimport { skillCommandsEnabled } from \"@pi-acp/acp/pi-settings\";\nimport {\n\tbuildToolTitle,\n\tPiAcpSession,\n\tresolveToolPath,\n\tSessionManager,\n\ttype ToolArgs,\n\ttoToolArgs,\n\ttoToolKind,\n} from \"@pi-acp/acp/session\";\nimport { extractUserMessageText } from \"@pi-acp/acp/translate/pi-messages\";\nimport { acpPromptToPiMessage } from \"@pi-acp/acp/translate/prompt\";\nimport { formatToolContent } from \"@pi-acp/acp/translate/tool-content\";\n\nimport pkgJson from \"../../package.json\" with { type: \"json\" };\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n/** Builtin ACP slash commands handled directly by the adapter. */\nconst BUILTIN_COMMANDS: readonly AvailableCommand[] = [\n\t{\n\t\tname: \"compact\",\n\t\tdescription: \"Manually compact the session context\",\n\t\tinput: { hint: \"optional custom instructions\" },\n\t},\n\t{\n\t\tname: \"autocompact\",\n\t\tdescription: \"Toggle automatic context compaction\",\n\t\tinput: { hint: \"on|off|toggle\" },\n\t},\n\t{ name: \"export\", description: \"Export session to an HTML file in the session cwd\" },\n\t{ name: \"session\", description: \"Show session stats (messages, tokens, cost, session file)\" },\n\t{ name: \"name\", description: \"Set session display name\", input: { hint: \"<name>\" } },\n\t{\n\t\tname: \"steering\",\n\t\tdescription: \"Get/set pi steering message delivery mode\",\n\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t},\n\t{\n\t\tname: \"follow-up\",\n\t\tdescription: \"Get/set pi follow-up message delivery mode\",\n\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t},\n\t{ name: \"changelog\", description: \"Show pi changelog\" },\n] as const;\n\n/**\n * Deduplicate commands by name. First occurrence wins.\n */\nfunction deduplicateCommands(commands: AvailableCommand[]): AvailableCommand[] {\n\tconst seen = new Set<string>();\n\tconst out: AvailableCommand[] = [];\n\tfor (const c of commands) {\n\t\tif (seen.has(c.name)) continue;\n\t\tseen.add(c.name);\n\t\tout.push(c);\n\t}\n\treturn out;\n}\n\nfunction parseArgs(input: string): string[] {\n\tconst args: string[] = [];\n\tlet current = \"\";\n\tlet quote: string | null = null;\n\n\tfor (const ch of input) {\n\t\tif (quote !== null) {\n\t\t\tif (ch === quote) quote = null;\n\t\t\telse current += ch;\n\t\t} else if (ch === '\"' || ch === \"'\") {\n\t\t\tquote = ch;\n\t\t} else if (ch === \" \" || ch === \"\\t\") {\n\t\t\tif (current !== \"\") {\n\t\t\t\targs.push(current);\n\t\t\t\tcurrent = \"\";\n\t\t\t}\n\t\t} else {\n\t\t\tcurrent += ch;\n\t\t}\n\t}\n\n\tif (current !== \"\") args.push(current);\n\treturn args;\n}\n\nconst SESSION_TITLE_MAX = 100;\n\nfunction truncateSessionTitle(text: string): string | null {\n\tconst trimmed = text.trim();\n\tif (trimmed === \"\") return null;\n\tconst oneLine = trimmed.replace(/\\n/g, \" \");\n\tif (oneLine.length <= SESSION_TITLE_MAX) return oneLine;\n\treturn `${oneLine.slice(0, SESSION_TITLE_MAX - 1)}…`;\n}\n\nexport class PiAcpAgent implements ACPAgent {\n\tprivate readonly conn: AgentSideConnection;\n\tprivate readonly sessions = new SessionManager();\n\t/** Cache of sessionId → file path, populated by listSessions and newSession. */\n\tprivate readonly sessionPaths = new Map<string, string>();\n\t/** Parsed client capability flags from initialize(). */\n\tprivate clientCapabilities: ClientCapabilityFlags = {\n\t\tterminalOutput: false,\n\t\tterminalAuth: false,\n\t\tgatewayAuth: false,\n\t};\n\n\tprivate readonly daemonContext: import(\"@pi-acp/daemon/context\").DaemonContext | undefined;\n\t/** Unique ID for this ACP connection. Used as the ownership key in the daemon SessionRegistry. */\n\tprivate readonly connectionId = randomUUID();\n\n\tdispose(): void {\n\t\t// On connection close, release every session this connection owned or\n\t\t// resumed from the daemon registry. Sessions another client still holds\n\t\t// stay live; sessions only this connection held get disposed by release().\n\t\tif (this.daemonContext !== undefined) {\n\t\t\tconst registry = this.daemonContext.sessionRegistry;\n\t\t\tfor (const entry of registry.listOwnedBy(this.connectionId)) {\n\t\t\t\tconst result = registry.release(entry.sessionId, this.connectionId);\n\t\t\t\tif (result.kind === \"disposed\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tentry.piSession.dispose();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* best-effort */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.sessions.disposeAll();\n\t}\n\n\tconstructor(\n\t\tconn: AgentSideConnection,\n\t\tdaemonContext?: import(\"@pi-acp/daemon/context\").DaemonContext,\n\t) {\n\t\tthis.conn = conn;\n\t\tthis.daemonContext = daemonContext;\n\t}\n\n\tprivate registerWithDaemon(input: {\n\t\tsessionId: string;\n\t\tpiSession: AgentSession;\n\t\tcwd: string;\n\t\tsessionFile: string | undefined;\n\t}): void {\n\t\tif (this.daemonContext === undefined) return;\n\t\tthis.daemonContext.sessionRegistry.register({\n\t\t\tsessionId: input.sessionId,\n\t\t\tpiSession: input.piSession,\n\t\t\townerConnectionId: this.connectionId,\n\t\t\tcwd: input.cwd,\n\t\t\tsessionFile: input.sessionFile,\n\t\t});\n\t}\n\n\tprivate releaseFromDaemon(sessionId: string): { disposed: boolean } {\n\t\tif (this.daemonContext === undefined) return { disposed: true };\n\t\tconst result = this.daemonContext.sessionRegistry.release(sessionId, this.connectionId);\n\t\treturn { disposed: result.kind === \"disposed\" };\n\t}\n\n\tasync initialize(params: InitializeRequest): Promise<InitializeResponse> {\n\t\tconst supportedVersion = 1;\n\t\tconst requested = params.protocolVersion;\n\n\t\tthis.clientCapabilities = parseClientCapabilities(params.clientCapabilities);\n\n\t\treturn {\n\t\t\tprotocolVersion: requested === supportedVersion ? requested : supportedVersion,\n\t\t\tagentInfo: {\n\t\t\t\tname: pkgJson.name,\n\t\t\t\ttitle: \"pi ACP adapter\",\n\t\t\t\tversion: pkgJson.version,\n\t\t\t},\n\t\t\tauthMethods: buildAuthMethods({\n\t\t\t\tsupportsTerminalAuthMeta: this.clientCapabilities.terminalAuth,\n\t\t\t}),\n\t\t\tagentCapabilities: {\n\t\t\t\tloadSession: true,\n\t\t\t\tmcpCapabilities: { http: false, sse: false },\n\t\t\t\tpromptCapabilities: {\n\t\t\t\t\timage: true,\n\t\t\t\t\taudio: false,\n\t\t\t\t\tembeddedContext: true,\n\t\t\t\t},\n\t\t\t\tsessionCapabilities: {\n\t\t\t\t\tlist: {},\n\t\t\t\t\tclose: {},\n\t\t\t\t\tresume: {},\n\t\t\t\t\tfork: {},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\tasync newSession(params: NewSessionRequest) {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tresult = await createAgentSession({ cwd: params.cwd });\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to create pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\n\t\tconst availableModels = piSession.modelRegistry.getAvailable();\n\t\tif (availableModels.length === 0) {\n\t\t\tpiSession.dispose();\n\t\t\tthrow RequestError.authRequired(\n\t\t\t\t{ authMethods: buildAuthMethods() },\n\t\t\t\t\"Configure an API key or log in with an OAuth provider.\",\n\t\t\t);\n\t\t}\n\n\t\tconst sessionId = piSession.sessionManager.getSessionId();\n\t\tconst sessionFile = piSession.sessionManager.getSessionFile();\n\t\tif (sessionFile !== undefined) {\n\t\t\tthis.sessionPaths.set(sessionId, sessionFile);\n\t\t}\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers,\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.registerWithDaemon({ sessionId, piSession, cwd: params.cwd, sessionFile });\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\treturn {\n\t\t\tsessionId: session.sessionId,\n\t\t\tconfigOptions,\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync authenticate(_params: AuthenticateRequest) {\n\t\treturn {};\n\t}\n\n\tasync prompt(params: PromptRequest): Promise<PromptResponse> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst { message, images } = acpPromptToPiMessage(params.prompt);\n\n\t\tif (images.length === 0 && message.trimStart().startsWith(\"/\")) {\n\t\t\tconst trimmed = message.trim();\n\t\t\tconst space = trimmed.indexOf(\" \");\n\t\t\tconst cmd = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space);\n\t\t\tconst argsString = space === -1 ? \"\" : trimmed.slice(space + 1);\n\t\t\tconst args = parseArgs(argsString);\n\n\t\t\tconst handled = await this.handleBuiltinCommand(session, cmd, args);\n\t\t\tif (handled) return handled;\n\t\t}\n\n\t\tconst result = await session.prompt(message, images);\n\n\t\tconst stopReason: StopReason = result === \"error\" ? \"end_turn\" : result;\n\t\tconst usage = session.getUsage();\n\t\tconst cost = session.getCost();\n\n\t\treturn {\n\t\t\tstopReason,\n\t\t\tusage: {\n\t\t\t\tinputTokens: usage.inputTokens,\n\t\t\t\toutputTokens: usage.outputTokens,\n\t\t\t\tcachedReadTokens: usage.cachedReadTokens,\n\t\t\t\tcachedWriteTokens: usage.cachedWriteTokens,\n\t\t\t\ttotalTokens: usage.inputTokens + usage.outputTokens,\n\t\t\t},\n\t\t\t_meta: cost > 0 ? { cost: { amount: cost, currency: \"USD\" } } : {},\n\t\t};\n\t}\n\n\tasync cancel(params: CancelNotification): Promise<void> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tawait session.cancel();\n\t}\n\n\t/**\n\t * Resolve a session ID to a file path.\n\t * Checks the local cache first (populated by listSessions/newSession),\n\t * falls back to a full listAll() scan on cache miss.\n\t */\n\tprivate async resolveSessionFile(sessionId: string): Promise<string | null> {\n\t\tconst cached = this.sessionPaths.get(sessionId);\n\t\tif (cached !== undefined) return cached;\n\n\t\tconst all = await PiSessionManager.listAll();\n\t\tfor (const s of all) {\n\t\t\tthis.sessionPaths.set(s.id, s.path);\n\t\t}\n\n\t\treturn this.sessionPaths.get(sessionId) ?? null;\n\t}\n\n\t/**\n\t * Replay persisted session messages as ACP session updates.\n\t *\n\t * Iterates through the message history, emitting structured updates for each\n\t * content block type: text, thinking, tool calls, and tool results. A map of\n\t * tool call IDs to their invocation data (from assistant messages) is built\n\t * to enrich subsequent tool result updates with rawInput and locations.\n\t */\n\tprivate async replaySessionHistory(\n\t\tsession: PiAcpSession,\n\t\tmessages: AgentMessage[],\n\t): Promise<void> {\n\t\tconst toolCallMap = new Map<string, { name: string; args: ToolArgs }>();\n\n\t\tfor (const m of messages) {\n\t\t\tif (!(\"role\" in m)) continue;\n\n\t\t\tif (m.role === \"user\") {\n\t\t\t\tconst text = extractUserMessageText((m satisfies UserMessage).content);\n\t\t\t\tif (text) {\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: { sessionUpdate: \"user_message_chunk\", content: { type: \"text\", text } },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (m.role === \"assistant\") {\n\t\t\t\tconst am = m satisfies AssistantMessage;\n\t\t\t\tfor (const block of am.content) {\n\t\t\t\t\tif (block.type === \"text\" && block.text) {\n\t\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\t\t\tcontent: { type: \"text\", text: block.text },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (block.type === \"thinking\" && block.thinking) {\n\t\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tsessionUpdate: \"agent_thought_chunk\",\n\t\t\t\t\t\t\t\tcontent: { type: \"text\", text: block.thinking },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (block.type === \"toolCall\") {\n\t\t\t\t\t\tconst args = toToolArgs(block.arguments);\n\t\t\t\t\t\ttoolCallMap.set(block.id, { name: block.name, args });\n\t\t\t\t\t\tconst locations = resolveToolPath(args, session.cwd);\n\n\t\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\t\t\t\ttoolCallId: block.id,\n\t\t\t\t\t\t\t\ttitle: buildToolTitle(block.name, args),\n\t\t\t\t\t\t\t\tkind: toToolKind(block.name),\n\t\t\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\t\t\trawInput: args,\n\t\t\t\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\t\t\t\t_meta: { piAcp: { toolName: block.name } },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (m.role === \"toolResult\") {\n\t\t\t\tconst tr = m satisfies ToolResultMessage;\n\t\t\t\tconst toolName = tr.toolName;\n\t\t\t\tconst toolCallId = tr.toolCallId;\n\t\t\t\tconst isError = tr.isError;\n\n\t\t\t\t// Enrich from the preceding assistant tool call if available.\n\t\t\t\tconst invocation = toolCallMap.get(toolCallId);\n\t\t\t\tconst args = invocation?.args;\n\t\t\t\tconst locations = args !== undefined ? resolveToolPath(args, session.cwd) : undefined;\n\n\t\t\t\t// If no tool_call was emitted from the assistant message (e.g. older\n\t\t\t\t// session format without structured assistant content), emit one now.\n\t\t\t\tif (invocation === undefined) {\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\ttitle: buildToolTitle(toolName, {}),\n\t\t\t\t\t\t\tkind: toToolKind(toolName),\n\t\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\t\trawInput: null,\n\t\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t\t\t_meta: { piAcp: { toolName } },\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst content = formatToolContent(toolName, m, isError);\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\tstatus: isError ? \"failed\" : \"completed\",\n\t\t\t\t\t\tcontent: content.length > 0 ? content : null,\n\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\t\t\t_meta: { piAcp: { toolName } },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tasync listSessions(params: ListSessionsRequest): Promise<ListSessionsResponse> {\n\t\tconst cwd = params.cwd;\n\n\t\tconst raw =\n\t\t\tcwd !== undefined && cwd !== null\n\t\t\t\t? await PiSessionManager.list(cwd)\n\t\t\t\t: await PiSessionManager.listAll();\n\n\t\tfor (const s of raw) {\n\t\t\tthis.sessionPaths.set(s.id, s.path);\n\t\t}\n\n\t\tconst sessions = raw.map((s) => ({\n\t\t\tid: s.id,\n\t\t\tcwd: s.cwd,\n\t\t\tname: s.name,\n\t\t\tfirstMessage: s.firstMessage,\n\t\t\tmodified: s.modified,\n\t\t\tmessageCount: s.messageCount,\n\t\t}));\n\n\t\tif (params.cursor !== undefined && params.cursor !== null) {\n\t\t\tconst parsed = Number.parseInt(params.cursor, 10);\n\t\t\tif (!Number.isFinite(parsed) || parsed < 0) {\n\t\t\t\tthrow RequestError.invalidParams(`Invalid cursor: ${params.cursor}`);\n\t\t\t}\n\t\t}\n\n\t\tconst start =\n\t\t\tparams.cursor !== undefined && params.cursor !== null\n\t\t\t\t? Number.parseInt(params.cursor, 10)\n\t\t\t\t: 0;\n\n\t\tconst PAGE_SIZE = 50;\n\t\tconst page = sessions.slice(start, start + PAGE_SIZE);\n\n\t\tconst liveSessions =\n\t\t\tthis.daemonContext !== undefined ? this.daemonContext.sessionRegistry.listAll() : [];\n\t\tconst liveById = new Map(liveSessions.map((e) => [e.sessionId, e]));\n\n\t\tconst acpSessions: SessionInfo[] = page.map((s) => {\n\t\t\tconst live = liveById.get(s.id);\n\t\t\tconst isOwnedByThisConnection =\n\t\t\t\tlive !== undefined &&\n\t\t\t\t(live.ownerConnectionId === this.connectionId || live.alsoHeldBy.has(this.connectionId));\n\t\t\treturn {\n\t\t\t\tsessionId: s.id,\n\t\t\t\tcwd: s.cwd,\n\t\t\t\ttitle:\n\t\t\t\t\t(s.name !== undefined && s.name !== \"\" ? s.name : null) ??\n\t\t\t\t\ttruncateSessionTitle(s.firstMessage) ??\n\t\t\t\t\tnull,\n\t\t\t\tupdatedAt: s.modified.toISOString(),\n\t\t\t\t...(live !== undefined\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t_meta: {\n\t\t\t\t\t\t\t\tpiAcp: {\n\t\t\t\t\t\t\t\t\tlive: true,\n\t\t\t\t\t\t\t\t\townedByThisConnection: isOwnedByThisConnection,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t};\n\t\t});\n\n\t\t// Surface daemon-live sessions that are NOT on disk yet (e.g., newSession\n\t\t// called but not yet persisted by pi). Insert at the front so the most\n\t\t// recently-active live ones bubble up.\n\t\tconst seen = new Set(page.map((s) => s.id));\n\t\tconst liveOnly = liveSessions\n\t\t\t.filter((e) => !seen.has(e.sessionId))\n\t\t\t.map<SessionInfo>((e) => ({\n\t\t\t\tsessionId: e.sessionId,\n\t\t\t\tcwd: e.cwd,\n\t\t\t\ttitle: null,\n\t\t\t\tupdatedAt: e.updatedAt.toISOString(),\n\t\t\t\t_meta: {\n\t\t\t\t\tpiAcp: {\n\t\t\t\t\t\tlive: true,\n\t\t\t\t\t\townedByThisConnection:\n\t\t\t\t\t\t\te.ownerConnectionId === this.connectionId || e.alsoHeldBy.has(this.connectionId),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}));\n\n\t\tconst merged = [...liveOnly, ...acpSessions];\n\t\tconst nextCursor = start + PAGE_SIZE < sessions.length ? String(start + PAGE_SIZE) : null;\n\n\t\treturn { sessions: merged, nextCursor, _meta: {} };\n\t}\n\n\tasync loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\tthis.sessions.close(params.sessionId);\n\n\t\tconst sessionFile = await this.resolveSessionFile(params.sessionId);\n\t\tif (sessionFile === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tconst sm = PiSessionManager.open(sessionFile);\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: params.cwd,\n\t\t\t\tsessionManager: sm,\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to load pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId: params.sessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers,\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.registerWithDaemon({\n\t\t\tsessionId: params.sessionId,\n\t\t\tpiSession,\n\t\t\tcwd: params.cwd,\n\t\t\tsessionFile,\n\t\t});\n\n\t\tawait this.replaySessionHistory(session, piSession.messages);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\treturn {\n\t\t\tconfigOptions,\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse> {\n\t\tconst local = this.sessions.maybeGet(params.sessionId);\n\t\t// Check daemon registry too: another client may have created the session\n\t\t// and this connection only resumed it; the local PiAcpSession wrapper\n\t\t// existed but the underlying piSession is shared.\n\t\tconst inRegistry = this.daemonContext?.sessionRegistry.get(params.sessionId);\n\t\tif (local === undefined && inRegistry === undefined) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\t// Release from registry first to decide whether to dispose pi runtime.\n\t\tconst release = this.releaseFromDaemon(params.sessionId);\n\t\tif (release.disposed) {\n\t\t\t// Last holder — full close including pi dispose via SessionManager.\n\t\t\tthis.sessions.close(params.sessionId);\n\t\t} else if (local !== undefined) {\n\t\t\t// Other clients still hold the session. Drop only this connection's\n\t\t\t// PiAcpSession wrapper (which holds our own event subscription).\n\t\t\t// SessionManager.detach removes the entry without disposing the\n\t\t\t// underlying piSession.\n\t\t\tthis.sessions.detach(params.sessionId);\n\t\t}\n\t\treturn {};\n\t}\n\n\tasync resumeSession(params: ResumeSessionRequest): Promise<ResumeSessionResponse> {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\t// If the session is already live in THIS connection, reuse it.\n\t\tconst existing = this.sessions.maybeGet(params.sessionId);\n\t\tif (existing !== undefined) {\n\t\t\tconst modes = buildThinkingModes(existing.piSession);\n\t\t\tconst models = buildModelState(existing.piSession);\n\t\t\treturn {\n\t\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\t\tmodes,\n\t\t\t\tmodels,\n\t\t\t};\n\t\t}\n\n\t\t// If another connection in the same daemon already holds the session,\n\t\t// attach to it and create a local PiAcpSession wrapping the shared\n\t\t// piSession with this connection's own event subscription + conn.\n\t\tif (this.daemonContext !== undefined) {\n\t\t\tconst registry = this.daemonContext.sessionRegistry;\n\t\t\tconst attached = registry.attach(params.sessionId, this.connectionId);\n\t\t\tif (attached !== undefined) {\n\t\t\t\tconst session = new PiAcpSession({\n\t\t\t\t\tsessionId: params.sessionId,\n\t\t\t\t\tcwd: params.cwd,\n\t\t\t\t\tmcpServers: params.mcpServers ?? [],\n\t\t\t\t\tpiSession: attached.piSession,\n\t\t\t\t\tconn: this.conn,\n\t\t\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t\t\t});\n\t\t\t\tthis.sessions.register(session);\n\t\t\t\tif (attached.sessionFile !== undefined) {\n\t\t\t\t\tthis.sessionPaths.set(params.sessionId, attached.sessionFile);\n\t\t\t\t}\n\t\t\t\tconst modes = buildThinkingModes(attached.piSession);\n\t\t\t\tconst models = buildModelState(attached.piSession);\n\t\t\t\treturn {\n\t\t\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\t\t\tmodes,\n\t\t\t\t\tmodels,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise, load from disk (same path as loadSession but without replay).\n\t\tconst sessionFile = await this.resolveSessionFile(params.sessionId);\n\t\tif (sessionFile === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tconst sm = PiSessionManager.open(sessionFile);\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: params.cwd,\n\t\t\t\tsessionManager: sm,\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to resume pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId: params.sessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers ?? [],\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.sessionPaths.set(params.sessionId, sessionFile);\n\t\tthis.registerWithDaemon({\n\t\t\tsessionId: params.sessionId,\n\t\t\tpiSession,\n\t\t\tcwd: params.cwd,\n\t\t\tsessionFile,\n\t\t});\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\treturn {\n\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync unstable_forkSession(params: ForkSessionRequest): Promise<ForkSessionResponse> {\n\t\tif (!isAbsolute(params.cwd)) {\n\t\t\tthrow RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);\n\t\t}\n\n\t\tconst sourceFile = await this.resolveSessionFile(params.sessionId);\n\t\tif (sourceFile === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\n\t\tlet result: CreateAgentSessionResult;\n\t\ttry {\n\t\t\tconst sm = PiSessionManager.forkFrom(sourceFile, params.cwd);\n\t\t\tresult = await createAgentSession({\n\t\t\t\tcwd: params.cwd,\n\t\t\t\tsessionManager: sm,\n\t\t\t});\n\t\t} catch (e: unknown) {\n\t\t\tconst authErr = detectAuthError(e);\n\t\t\tif (authErr !== null) throw authErr;\n\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\tthrow RequestError.internalError({}, `Failed to fork pi session: ${msg}`);\n\t\t}\n\n\t\tconst piSession = result.session;\n\n\t\tconst newSessionId = piSession.sessionManager.getSessionId();\n\t\tconst newSessionFile = piSession.sessionManager.getSessionFile();\n\t\tif (newSessionFile !== undefined) {\n\t\t\tthis.sessionPaths.set(newSessionId, newSessionFile);\n\t\t}\n\n\t\tconst session = new PiAcpSession({\n\t\t\tsessionId: newSessionId,\n\t\t\tcwd: params.cwd,\n\t\t\tmcpServers: params.mcpServers ?? [],\n\t\t\tpiSession,\n\t\t\tconn: this.conn,\n\t\t\tsupportsTerminalOutput: this.clientCapabilities.terminalOutput,\n\t\t});\n\n\t\tthis.sessions.register(session);\n\t\tthis.registerWithDaemon({\n\t\t\tsessionId: newSessionId,\n\t\t\tpiSession,\n\t\t\tcwd: params.cwd,\n\t\t\tsessionFile: newSessionFile,\n\t\t});\n\n\t\tconst enableSkillCommands = skillCommandsEnabled(params.cwd);\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst commands = buildCommandList(piSession, enableSkillCommands);\n\t\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tsessionUpdate: \"available_commands_update\",\n\t\t\t\t\t\t\tavailableCommands: deduplicateCommands([...commands, ...BUILTIN_COMMANDS]),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t})();\n\t\t}, 0);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\treturn {\n\t\t\tsessionId: newSessionId,\n\t\t\tconfigOptions: buildConfigOptions(modes, models),\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t};\n\t}\n\n\tasync setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst mode = String(params.modeId);\n\t\tif (!isThinkingLevel(mode)) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modeId: ${mode}`);\n\t\t}\n\n\t\tsession.piSession.setThinkingLevel(mode);\n\n\t\tvoid this.conn.sessionUpdate({\n\t\t\tsessionId: session.sessionId,\n\t\t\tupdate: { sessionUpdate: \"current_mode_update\", currentModeId: mode },\n\t\t});\n\n\t\tthis.emitConfigOptionUpdate(session);\n\n\t\treturn {};\n\t}\n\n\tasync unstable_setSessionModel(\n\t\tparams: SetSessionModelRequest,\n\t): Promise<SetSessionModelResponse | void> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\n\t\tconst resolved = resolveModelPreference(available, params.modelId);\n\t\tif (resolved === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modelId: ${params.modelId}`);\n\t\t}\n\n\t\tconst model = available.find((m) => m.provider === resolved.provider && m.id === resolved.id);\n\t\tif (!model) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modelId: ${params.modelId}`);\n\t\t}\n\n\t\tawait session.piSession.setModel(model);\n\t\tthis.emitConfigOptionUpdate(session);\n\t}\n\n\tasync setSessionConfigOption(\n\t\tparams: SetSessionConfigOptionRequest,\n\t): Promise<SetSessionConfigOptionResponse> {\n\t\tconst session = this.sessions.get(params.sessionId);\n\t\tconst configId = String(params.configId);\n\t\tconst value = String(params.value);\n\n\t\tif (configId === \"model\") {\n\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\tconst resolved = resolveModelPreference(available, value);\n\t\t\tif (resolved === null) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t}\n\n\t\t\tconst model = available.find((m) => m.provider === resolved.provider && m.id === resolved.id);\n\t\t\tif (!model) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t}\n\n\t\t\tawait session.piSession.setModel(model);\n\t\t} else if (configId === \"thought_level\") {\n\t\t\tif (!isThinkingLevel(value)) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown thinking level: ${value}`);\n\t\t\t}\n\t\t\tsession.piSession.setThinkingLevel(value);\n\t\t} else {\n\t\t\tthrow RequestError.invalidParams(`Unknown config option: ${configId}`);\n\t\t}\n\n\t\tconst modes = buildThinkingModes(session.piSession);\n\t\tconst models = buildModelState(session.piSession);\n\t\treturn { configOptions: buildConfigOptions(modes, models) };\n\t}\n\n\tprivate emitConfigOptionUpdate(session: PiAcpSession): void {\n\t\tconst modes = buildThinkingModes(session.piSession);\n\t\tconst models = buildModelState(session.piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tvoid this.conn.sessionUpdate({\n\t\t\tsessionId: session.sessionId,\n\t\t\tupdate: {\n\t\t\t\tsessionUpdate: \"config_option_update\",\n\t\t\t\tconfigOptions,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async handleBuiltinCommand(\n\t\tsession: PiAcpSession,\n\t\tcmd: string,\n\t\targs: string[],\n\t): Promise<PromptResponse | null> {\n\t\tconst piSession = session.piSession;\n\n\t\tif (cmd === \"compact\") {\n\t\t\tconst customInstructions = args.join(\" \").trim() || undefined;\n\t\t\tconst res = await piSession.compact(customInstructions);\n\n\t\t\tconst headerLines = [\n\t\t\t\t`Compaction completed.${customInstructions !== undefined && customInstructions !== \"\" ? \" (custom instructions applied)\" : \"\"}`,\n\t\t\t\ttypeof res?.tokensBefore === \"number\" ? `Tokens before: ${res.tokensBefore}` : null,\n\t\t\t].filter(Boolean);\n\n\t\t\tconst text = headerLines.join(\"\\n\") + (res?.summary ? `\\n\\n${res.summary}` : \"\");\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"session\") {\n\t\t\tconst stats = piSession.getSessionStats();\n\t\t\tconst lines: string[] = [];\n\t\t\tif (stats.sessionId !== undefined && stats.sessionId !== \"\")\n\t\t\t\tlines.push(`Session: ${stats.sessionId}`);\n\t\t\tif (stats.sessionFile !== undefined && stats.sessionFile !== \"\")\n\t\t\t\tlines.push(`Session file: ${stats.sessionFile}`);\n\t\t\tlines.push(`Messages: ${stats.totalMessages}`);\n\t\t\tlines.push(`Cost: ${stats.cost}`);\n\t\t\tconst t = stats.tokens;\n\t\t\tconst parts: string[] = [];\n\t\t\tif (t.input) parts.push(`in ${t.input}`);\n\t\t\tif (t.output) parts.push(`out ${t.output}`);\n\t\t\tif (t.cacheRead) parts.push(`cache read ${t.cacheRead}`);\n\t\t\tif (t.cacheWrite) parts.push(`cache write ${t.cacheWrite}`);\n\t\t\tif (t.total) parts.push(`total ${t.total}`);\n\t\t\tif (parts.length > 0) lines.push(`Tokens: ${parts.join(\", \")}`);\n\n\t\t\tconst text = lines.join(\"\\n\");\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"name\") {\n\t\t\tconst name = args.join(\" \").trim();\n\t\t\tif (!name) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Usage: /name <name>\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\tpiSession.setSessionName(name);\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"session_info_update\",\n\t\t\t\t\ttitle: name,\n\t\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Session name set: ${name}` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"steering\") {\n\t\t\tconst modeRaw = String(args[0] ?? \"\").toLowerCase();\n\t\t\tif (!modeRaw) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Steering mode: ${piSession.steeringMode}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tif (modeRaw !== \"all\" && modeRaw !== \"one-at-a-time\") {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Usage: /steering all | /steering one-at-a-time\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tpiSession.setSteeringMode(modeRaw);\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Steering mode set to: ${modeRaw}` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"follow-up\") {\n\t\t\tconst modeRaw = String(args[0] ?? \"\").toLowerCase();\n\t\t\tif (!modeRaw) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Follow-up mode: ${piSession.followUpMode}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tif (modeRaw !== \"all\" && modeRaw !== \"one-at-a-time\") {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Usage: /follow-up all | /follow-up one-at-a-time\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\t\t\tpiSession.setFollowUpMode(modeRaw);\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Follow-up mode set to: ${modeRaw}` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"autocompact\") {\n\t\t\tconst mode = (args[0] ?? \"toggle\").toLowerCase();\n\t\t\tlet enabled: boolean | null = null;\n\t\t\tif (mode === \"on\" || mode === \"true\" || mode === \"enable\") enabled = true;\n\t\t\telse if (mode === \"off\" || mode === \"false\" || mode === \"disable\") enabled = false;\n\n\t\t\tif (enabled === null) {\n\t\t\t\tenabled = !piSession.autoCompactionEnabled;\n\t\t\t}\n\n\t\t\tpiSession.setAutoCompactionEnabled(enabled);\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: {\n\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\tcontent: { type: \"text\", text: `Auto-compaction ${enabled ? \"enabled\" : \"disabled\"}.` },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"changelog\") {\n\t\t\tconst changelogPath = findChangelog();\n\t\t\tif (changelogPath === null) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Changelog not found.\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\tlet text = \"\";\n\t\t\ttry {\n\t\t\t\ttext = readFileSync(changelogPath, \"utf-8\");\n\t\t\t} catch (e: unknown) {\n\t\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Failed to read changelog: ${msg}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\tconst maxChars = 20_000;\n\t\t\tif (text.length > maxChars) text = `${text.slice(0, maxChars)}\\n\\n...(truncated)...`;\n\n\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\tsessionId: session.sessionId,\n\t\t\t\tupdate: { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t});\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\tif (cmd === \"export\") {\n\t\t\tconst messageCount = piSession.messages.length;\n\t\t\tif (messageCount === 0) {\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Nothing to export yet. Send a prompt first.\" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\treturn { stopReason: \"end_turn\" };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst safeSessionId = session.sessionId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\t\t\t\tconst outputPath = join(session.cwd, `pi-session-${safeSessionId}.html`);\n\t\t\t\tconst resultPath = await piSession.exportToHtml(outputPath);\n\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: \"Session exported: \" },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\ttype: \"resource_link\",\n\t\t\t\t\t\t\tname: `pi-session-${safeSessionId}.html`,\n\t\t\t\t\t\t\turi: `file://${resultPath}`,\n\t\t\t\t\t\t\tmimeType: \"text/html\",\n\t\t\t\t\t\t\ttitle: \"Session exported\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (e: unknown) {\n\t\t\t\tconst msg = e instanceof Error ? e.message : String(e);\n\t\t\t\tawait this.conn.sessionUpdate({\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"text\", text: `Export failed: ${msg}` },\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { stopReason: \"end_turn\" };\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\nfunction isThinkingLevel(x: string): x is ThinkingLevel {\n\treturn (\n\t\tx === \"off\" || x === \"minimal\" || x === \"low\" || x === \"medium\" || x === \"high\" || x === \"xhigh\"\n\t);\n}\n\nfunction buildThinkingModes(piSession: AgentSession): {\n\tavailableModes: Array<{ id: string; name: string; description?: string | null }>;\n\tcurrentModeId: string;\n} {\n\tconst levels = piSession.getAvailableThinkingLevels();\n\treturn {\n\t\tcurrentModeId: piSession.thinkingLevel,\n\t\tavailableModes: levels.map((id) => ({\n\t\t\tid,\n\t\t\tname: `Thinking: ${id}`,\n\t\t\tdescription: null,\n\t\t})),\n\t};\n}\n\nfunction buildModelState(piSession: AgentSession): SessionModelState {\n\tconst available = piSession.modelRegistry.getAvailable();\n\tconst current = piSession.model;\n\n\tconst availableModels: ModelInfo[] = available.map((m) => ({\n\t\tmodelId: `${m.provider}/${m.id}`,\n\t\tname: `${m.provider}/${m.name ?? m.id}`,\n\t\tdescription: null,\n\t}));\n\n\tlet currentModelId = \"default\";\n\tif (current !== undefined) {\n\t\tcurrentModelId = `${current.provider}/${current.id}`;\n\t} else if (availableModels.length > 0 && availableModels[0] !== undefined) {\n\t\tcurrentModelId = availableModels[0].modelId;\n\t}\n\n\treturn { availableModels, currentModelId };\n}\n\nfunction buildConfigOptions(\n\tmodes: SessionModeState,\n\tmodels: SessionModelState,\n): SessionConfigOption[] {\n\treturn [\n\t\t{\n\t\t\tid: \"model\",\n\t\t\tname: \"Model\",\n\t\t\tdescription: \"AI model to use\",\n\t\t\tcategory: \"model\",\n\t\t\ttype: \"select\" as const,\n\t\t\tcurrentValue: models.currentModelId,\n\t\t\toptions: models.availableModels.map((m) => ({\n\t\t\t\tvalue: m.modelId,\n\t\t\t\tname: m.name,\n\t\t\t\tdescription: m.description ?? null,\n\t\t\t})),\n\t\t},\n\t\t{\n\t\t\tid: \"thought_level\",\n\t\t\tname: \"Thinking Level\",\n\t\t\tdescription: \"Reasoning depth for models that support it\",\n\t\t\tcategory: \"thought_level\",\n\t\t\ttype: \"select\" as const,\n\t\t\tcurrentValue: modes.currentModeId,\n\t\t\toptions: modes.availableModes.map((m) => ({\n\t\t\t\tvalue: m.id,\n\t\t\t\tname: m.name,\n\t\t\t\tdescription: m.description ?? null,\n\t\t\t})),\n\t\t},\n\t];\n}\n\nfunction buildCommandList(\n\tpiSession: AgentSession,\n\tenableSkillCommands: boolean,\n): AvailableCommand[] {\n\tconst commands: AvailableCommand[] = [];\n\n\tfor (const template of piSession.promptTemplates) {\n\t\tcommands.push({\n\t\t\tname: template.name,\n\t\t\tdescription: template.description ?? `(prompt)`,\n\t\t});\n\t}\n\n\tif (enableSkillCommands) {\n\t\tconst skills = piSession.resourceLoader.getSkills();\n\t\tfor (const skill of skills.skills) {\n\t\t\tcommands.push({\n\t\t\t\tname: `skill:${skill.name}`,\n\t\t\t\tdescription: skill.description ?? `(skill)`,\n\t\t\t});\n\t\t}\n\t}\n\n\tfor (const cmd of piSession.extensionRunner.getRegisteredCommands()) {\n\t\tcommands.push({\n\t\t\tname: cmd.name,\n\t\t\tdescription: cmd.description ?? \"(extension)\",\n\t\t});\n\t}\n\n\treturn commands;\n}\n\nfunction findChangelog(): string | null {\n\ttry {\n\t\tconst whichCmd = process.platform === \"win32\" ? \"where\" : \"which\";\n\t\tconst which = spawnSync(whichCmd, [\"pi\"], { encoding: \"utf-8\" });\n\t\tconst piPath = String(which.stdout ?? \"\")\n\t\t\t.split(/\\r?\\n/)[0]\n\t\t\t?.trim();\n\t\tif (piPath !== undefined && piPath !== \"\") {\n\t\t\tconst resolved = realpathSync(piPath);\n\t\t\tconst pkgRoot = dirname(dirname(resolved));\n\t\t\tconst p = join(pkgRoot, \"CHANGELOG.md\");\n\t\t\tif (existsSync(p)) return p;\n\t\t}\n\t} catch {}\n\n\ttry {\n\t\tconst npmRoot = spawnSync(\"npm\", [\"root\", \"-g\"], { encoding: \"utf-8\" });\n\t\tconst root = String(npmRoot.stdout ?? \"\").trim();\n\t\tif (root) {\n\t\t\tconst p = join(root, \"@mariozechner\", \"pi-coding-agent\", \"CHANGELOG.md\");\n\t\t\tif (existsSync(p)) return p;\n\t\t}\n\t} catch {}\n\n\treturn null;\n}\n","/**\n * Shared ACP-over-stream wiring used by both the in-process v0.5 fallback and\n * the daemon's per-connection accept path.\n *\n * Owns nothing global. Returns the constructed AgentSideConnection plus a\n * shutdown helper. Caller decides what process / signal handlers to attach.\n */\n\nimport type { Duplex } from \"node:stream\";\nimport { AgentSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\";\nimport { PiAcpAgent } from \"@pi-acp/acp/agent\";\nimport type { DaemonContext } from \"@pi-acp/daemon/context\";\n\nexport interface ServeOptions {\n\t/** Reads from the client. */\n\tinput: Duplex;\n\t/** Writes to the client. */\n\toutput: Duplex;\n\t/** Optional daemon context. Absent in `PI_ACP_NO_DAEMON=1` fallback path. */\n\tdaemonContext?: DaemonContext;\n}\n\nexport interface ServeHandle {\n\tconnection: AgentSideConnection;\n\t/** Best-effort dispose of the PiAcpAgent. */\n\tdispose: () => void;\n}\n\nexport function serveAcp(opts: ServeOptions): ServeHandle {\n\t// Build the NDJSON framing layer. `input` is the client-bound stream we\n\t// read FROM (client → agent). `output` is the stream we write TO\n\t// (agent → client). ndJsonStream(writable, readable): first arg is where\n\t// the agent writes responses, second is where it reads requests.\n\tconst stream = ndJsonStream(toWebWritable(opts.output), toWebReadable(opts.input));\n\tconst connection = new AgentSideConnection(\n\t\t(conn) => new PiAcpAgent(conn, opts.daemonContext),\n\t\tstream,\n\t);\n\treturn {\n\t\tconnection,\n\t\tdispose() {\n\t\t\ttry {\n\t\t\t\tconst inner = readUnknownProp(connection, \"agent\");\n\t\t\t\tconst dispose = readUnknownProp(inner, \"dispose\");\n\t\t\t\tif (typeof dispose === \"function\") {\n\t\t\t\t\tReflect.apply(dispose, inner, []);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t/* best-effort */\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction readUnknownProp(target: unknown, key: string): unknown {\n\tif (typeof target !== \"object\" || target === null) return undefined;\n\treturn Reflect.get(target, key);\n}\n\nfunction toWebReadable(src: Duplex): ReadableStream<Uint8Array> {\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tsrc.on(\"data\", (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)));\n\t\t\tsrc.on(\"end\", () => {\n\t\t\t\ttry {\n\t\t\t\t\tcontroller.close();\n\t\t\t\t} catch {\n\t\t\t\t\t/* already closed */\n\t\t\t\t}\n\t\t\t});\n\t\t\tsrc.on(\"error\", (err) => {\n\t\t\t\ttry {\n\t\t\t\t\tcontroller.error(err);\n\t\t\t\t} catch {\n\t\t\t\t\t/* already terminated */\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t});\n}\n\nfunction toWebWritable(dst: Duplex): WritableStream<Uint8Array> {\n\treturn new WritableStream<Uint8Array>({\n\t\twrite(chunk) {\n\t\t\treturn new Promise<void>((resolve) => {\n\t\t\t\tif (dst.destroyed || !dst.writable) {\n\t\t\t\t\tresolve();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tdst.write(chunk, () => resolve());\n\t\t\t\t} catch {\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t});\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"socket-BUNWxnAN.mjs","names":["fsConstants"],"sources":["../src/daemon/socket.ts"],"sourcesContent":["import {\n\tcloseSync,\n\tconstants as fsConstants,\n\topenSync,\n\treadFileSync,\n\tstatSync,\n\tunlinkSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { tmpdir, userInfo } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * Per-UID socket path. Unix family: under XDG_RUNTIME_DIR (or TMPDIR) so the\n * file is bounded to the user. Windows: named pipe in the per-user namespace.\n */\nexport function socketPath(): string {\n\tif (process.platform === \"win32\") {\n\t\tconst user = process.env[\"USERNAME\"] ?? userInfo().username;\n\t\treturn `\\\\\\\\.\\\\pipe\\\\pi-acp-${user}`;\n\t}\n\tconst baseDir =\n\t\tprocess.env[\"PI_ACP_SOCKET_DIR\"] ??\n\t\tprocess.env[\"XDG_RUNTIME_DIR\"] ??\n\t\tprocess.env[\"TMPDIR\"] ??\n\t\ttmpdir();\n\tconst uid =\n\t\ttypeof process.getuid === \"function\"\n\t\t\t? process.getuid()\n\t\t\t: userInfo().uid !== -1\n\t\t\t\t? userInfo().uid\n\t\t\t\t: 0;\n\treturn join(baseDir, `pi-acp-${uid}.sock`);\n}\n\nexport function lockfilePath(): string {\n\tif (process.platform === \"win32\") {\n\t\t// Named pipes aren't files — use a regular lockfile in TMPDIR.\n\t\tconst baseDir = process.env[\"TMPDIR\"] ?? tmpdir();\n\t\tconst user = process.env[\"USERNAME\"] ?? userInfo().username;\n\t\treturn join(baseDir, `pi-acp-${user}.lock`);\n\t}\n\treturn `${socketPath()}.lock`;\n}\n\nfunction errnoCode(err: unknown): string | undefined {\n\tif (typeof err === \"object\" && err !== null && \"code\" in err) {\n\t\tconst code = (err as { code: unknown }).code;\n\t\treturn typeof code === \"string\" ? code : undefined;\n\t}\n\treturn undefined;\n}\n\nfunction pidIsAlive(pid: number): boolean {\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (err) {\n\t\tconst code = errnoCode(err);\n\t\tif (code === \"EPERM\") return true;\n\t\treturn false;\n\t}\n}\n\nexport interface LockAcquireResult {\n\tok: boolean;\n\theldByPid?: number;\n}\n\n/**\n * Acquire the daemon lockfile by writing our PID. If a lockfile already exists\n * and its PID is alive, refuse. If the PID is dead, reclaim.\n */\nexport function acquireLock(): LockAcquireResult {\n\tconst path = lockfilePath();\n\tfor (let attempt = 0; attempt < 2; attempt++) {\n\t\ttry {\n\t\t\tconst fd = openSync(\n\t\t\t\tpath,\n\t\t\t\tfsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY,\n\t\t\t\t0o600,\n\t\t\t);\n\t\t\ttry {\n\t\t\t\twriteFileSync(fd, String(process.pid));\n\t\t\t} finally {\n\t\t\t\tcloseSync(fd);\n\t\t\t}\n\t\t\treturn { ok: true };\n\t\t} catch (err) {\n\t\t\tconst code = errnoCode(err);\n\t\t\tif (code !== \"EEXIST\") throw err;\n\t\t\tconst existing = readPidFromLockfile(path);\n\t\t\tif (existing !== undefined && pidIsAlive(existing)) {\n\t\t\t\treturn { ok: false, heldByPid: existing };\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tunlinkSync(path);\n\t\t\t} catch {\n\t\t\t\t/* ignore — next attempt */\n\t\t\t}\n\t\t}\n\t}\n\treturn { ok: false };\n}\n\nexport function releaseLock(): void {\n\ttry {\n\t\tunlinkSync(lockfilePath());\n\t} catch {\n\t\t/* ignore */\n\t}\n}\n\nfunction readPidFromLockfile(path: string): number | undefined {\n\ttry {\n\t\tconst raw = readFileSync(path, \"utf8\").trim();\n\t\tconst n = Number.parseInt(raw, 10);\n\t\treturn Number.isFinite(n) ? n : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Remove a socket file left behind by a dead daemon. Safe no-op on Windows\n * (named pipes have no filesystem residue) or if the path doesn't exist.\n */\nexport function removeStaleSocketIfAny(): void {\n\tif (process.platform === \"win32\") return;\n\tconst path = socketPath();\n\ttry {\n\t\tstatSync(path);\n\t\tunlinkSync(path);\n\t} catch {\n\t\t/* not present — fine */\n\t}\n}\n\n/**\n * Ensure the directory the socket lives in exists. Skip on Windows (the\n * named-pipe namespace is provided by the OS).\n */\nexport function ensureSocketParentDir(): void {\n\tif (process.platform === \"win32\") return;\n\tconst dir = dirname(socketPath());\n\ttry {\n\t\tstatSync(dir);\n\t} catch {\n\t\t// Defer mkdir to the OS-default; if the parent is missing we surface\n\t\t// the error later at bind() rather than guessing at mode bits here.\n\t}\n}\n"],"mappings":";;;;;;;;;AAgBA,SAAgB,aAAqB;AACpC,KAAI,QAAQ,aAAa,QAExB,QAAO,uBADM,QAAQ,IAAI,eAAe,UAAU,CAAC;AAcpD,QAAO,KAVN,QAAQ,IAAI,wBACZ,QAAQ,IAAI,sBACZ,QAAQ,IAAI,aACZ,QAAQ,EAOY,UALpB,OAAO,QAAQ,WAAW,aACvB,QAAQ,QAAQ,GAChB,UAAU,CAAC,QAAQ,KAClB,UAAU,CAAC,MACX,EAC8B,OAAO;;AAG3C,SAAgB,eAAuB;AACtC,KAAI,QAAQ,aAAa,QAIxB,QAAO,KAFS,QAAQ,IAAI,aAAa,QAAQ,EAE5B,UADR,QAAQ,IAAI,eAAe,UAAU,CAAC,SACf,OAAO;AAE5C,QAAO,GAAG,YAAY,CAAC;;AAGxB,SAAS,UAAU,KAAkC;AACpD,KAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,UAAU,KAAK;EAC7D,MAAM,OAAQ,IAA0B;AACxC,SAAO,OAAO,SAAS,WAAW,OAAO,KAAA;;;AAK3C,SAAS,WAAW,KAAsB;AACzC,KAAI;AACH,UAAQ,KAAK,KAAK,EAAE;AACpB,SAAO;UACC,KAAK;AAEb,MADa,UAAU,IACf,KAAK,QAAS,QAAO;AAC7B,SAAO;;;;;;;AAaT,SAAgB,cAAiC;CAChD,MAAM,OAAO,cAAc;AAC3B,MAAK,IAAI,UAAU,GAAG,UAAU,GAAG,UAClC,KAAI;EACH,MAAM,KAAK,SACV,MACAA,UAAY,UAAUA,UAAY,SAASA,UAAY,UACvD,IACA;AACD,MAAI;AACH,iBAAc,IAAI,OAAO,QAAQ,IAAI,CAAC;YAC7B;AACT,aAAU,GAAG;;AAEd,SAAO,EAAE,IAAI,MAAM;UACX,KAAK;AAEb,MADa,UAAU,IACf,KAAK,SAAU,OAAM;EAC7B,MAAM,WAAW,oBAAoB,KAAK;AAC1C,MAAI,aAAa,KAAA,KAAa,WAAW,SAAS,CACjD,QAAO;GAAE,IAAI;GAAO,WAAW;GAAU;AAE1C,MAAI;AACH,cAAW,KAAK;UACT;;AAKV,QAAO,EAAE,IAAI,OAAO;;AAGrB,SAAgB,cAAoB;AACnC,KAAI;AACH,aAAW,cAAc,CAAC;SACnB;;AAKT,SAAS,oBAAoB,MAAkC;AAC9D,KAAI;EACH,MAAM,MAAM,aAAa,MAAM,OAAO,CAAC,MAAM;EAC7C,MAAM,IAAI,OAAO,SAAS,KAAK,GAAG;AAClC,SAAO,OAAO,SAAS,EAAE,GAAG,IAAI,KAAA;SACzB;AACP;;;;;;;AAQF,SAAgB,yBAA+B;AAC9C,KAAI,QAAQ,aAAa,QAAS;CAClC,MAAM,OAAO,YAAY;AACzB,KAAI;AACH,WAAS,KAAK;AACd,aAAW,KAAK;SACT;;;;;;AAST,SAAgB,wBAA8B;AAC7C,KAAI,QAAQ,aAAa,QAAS;CAClC,MAAM,MAAM,QAAQ,YAAY,CAAC;AACjC,KAAI;AACH,WAAS,IAAI;SACN"}
|