@victor-software-house/pi-acp 0.1.2 → 0.2.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/README.md +14 -8
- package/dist/index.mjs +376 -80
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,8 +13,9 @@ Active development. ACP compliance is improving steadily. Development is centere
|
|
|
13
13
|
- Streams assistant output as ACP `agent_message_chunk`
|
|
14
14
|
- Streams thinking output as ACP `agent_thought_chunk`
|
|
15
15
|
- Maps pi tool execution to ACP `tool_call` / `tool_call_update`
|
|
16
|
+
- Descriptive tool titles (`Read src/index.ts`, `Run ls -la`, `Edit config.ts`)
|
|
16
17
|
- Tool call locations surfaced for follow-along features in clients like Zed
|
|
17
|
-
- For `edit`, emits ACP structured diffs (`oldText`/`newText`)
|
|
18
|
+
- For `edit` and `write`, emits ACP structured diffs (`oldText`/`newText`)
|
|
18
19
|
- Tool kinds: `read`, `edit`, `execute` (bash), `other`
|
|
19
20
|
- Session configuration via ACP `configOptions`
|
|
20
21
|
- Model selector (category: `model`)
|
|
@@ -22,11 +23,16 @@ Active development. ACP compliance is improving steadily. Development is centere
|
|
|
22
23
|
- Also advertises `modes` and `models` for backward compatibility
|
|
23
24
|
- `session/set_config_option` for changing model or thinking level
|
|
24
25
|
- `config_option_update` emitted when configuration changes
|
|
25
|
-
- Session persistence and
|
|
26
|
+
- Session persistence and lifecycle
|
|
27
|
+
- Multiple concurrent sessions supported
|
|
26
28
|
- pi manages sessions in `~/.pi/agent/sessions/...`
|
|
27
|
-
- `session/list`
|
|
28
|
-
- `session/load` replays
|
|
29
|
+
- `session/list` with title fallback from first user message
|
|
30
|
+
- `session/load` replays structured history (text, thinking, tool calls)
|
|
31
|
+
- `unstable_closeSession`, `unstable_resumeSession`, `unstable_forkSession`
|
|
29
32
|
- Sessions can be resumed in both `pi` CLI and ACP clients
|
|
33
|
+
- Usage and cost tracking
|
|
34
|
+
- `usage_update` emitted after each agent turn with context size and cost
|
|
35
|
+
- `PromptResponse.usage` includes per-turn token counts
|
|
30
36
|
- Slash commands
|
|
31
37
|
- File-based prompt templates from `~/.pi/agent/prompts/` and `<cwd>/.pi/prompts/`
|
|
32
38
|
- Extension commands from pi extensions
|
|
@@ -163,7 +169,7 @@ test/
|
|
|
163
169
|
|
|
164
170
|
### MUST-level gaps
|
|
165
171
|
|
|
166
|
-
- **MCP servers** -- accepted in `session/new` and `session/load` params but not wired through to pi. ACP requires agents to connect to all provided MCP servers. This is the main compliance gap.
|
|
172
|
+
- **MCP servers** -- accepted in `session/new` and `session/load` params but not wired through to pi. ACP requires agents to connect to all provided MCP servers. This is the main compliance gap (upstream pi SDK limitation).
|
|
167
173
|
|
|
168
174
|
### SHOULD-level gaps
|
|
169
175
|
|
|
@@ -171,8 +177,7 @@ test/
|
|
|
171
177
|
|
|
172
178
|
### Not implemented (MAY / client capabilities)
|
|
173
179
|
|
|
174
|
-
- **`
|
|
175
|
-
- **`agent_plan`** -- plan updates not emitted before tool execution.
|
|
180
|
+
- **`agent_plan`** -- plan updates not emitted before tool execution. pi has no equivalent planning surface.
|
|
176
181
|
- **ACP filesystem delegation** (`fs/read_text_file`, `fs/write_text_file`) -- pi reads/writes locally. Not advertised.
|
|
177
182
|
- **ACP terminal delegation** (`terminal/*`) -- pi executes commands locally. Not advertised.
|
|
178
183
|
|
|
@@ -180,8 +185,9 @@ test/
|
|
|
180
185
|
|
|
181
186
|
- pi does not have real session modes (ask/architect/code). The `modes` field exposes thinking levels for backward compatibility with clients that do not support `configOptions`.
|
|
182
187
|
- `configOptions` is the preferred configuration mechanism. Zed uses it exclusively when present.
|
|
188
|
+
- pi-acp uses direct filesystem access rather than delegating reads/writes to the ACP client. This means pi reads on-disk file versions, not unsaved editor buffers.
|
|
183
189
|
|
|
184
|
-
See [
|
|
190
|
+
See [docs/engineering/acp-conformance.md](docs/engineering/acp-conformance.md) for detailed conformance status.
|
|
185
191
|
|
|
186
192
|
## Release
|
|
187
193
|
|
package/dist/index.mjs
CHANGED
|
@@ -41,6 +41,29 @@ function resolveTerminalLaunchCommand() {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
//#endregion
|
|
44
|
+
//#region src/acp/auth-required.ts
|
|
45
|
+
/**
|
|
46
|
+
* Detect common auth/credential errors from pi and surface them as ACP AUTH_REQUIRED.
|
|
47
|
+
*/
|
|
48
|
+
const AUTH_ERROR_PATTERNS = [
|
|
49
|
+
"api key",
|
|
50
|
+
"apikey",
|
|
51
|
+
"missing key",
|
|
52
|
+
"no key",
|
|
53
|
+
"not configured",
|
|
54
|
+
"unauthorized",
|
|
55
|
+
"authentication",
|
|
56
|
+
"permission denied",
|
|
57
|
+
"forbidden",
|
|
58
|
+
"401",
|
|
59
|
+
"403"
|
|
60
|
+
];
|
|
61
|
+
function detectAuthError(err) {
|
|
62
|
+
const lower = (err instanceof Error ? err.message : String(err ?? "")).toLowerCase();
|
|
63
|
+
if (!AUTH_ERROR_PATTERNS.some((p) => lower.includes(p))) return null;
|
|
64
|
+
return RequestError.authRequired({ authMethods: buildAuthMethods() }, "Configure an API key or log in with an OAuth provider.");
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
44
67
|
//#region src/acp/pi-settings.ts
|
|
45
68
|
/**
|
|
46
69
|
* Read pi settings from global and project config files.
|
|
@@ -191,6 +214,30 @@ function toToolKind(toolName) {
|
|
|
191
214
|
default: return "other";
|
|
192
215
|
}
|
|
193
216
|
}
|
|
217
|
+
const MAX_TITLE_LEN = 80;
|
|
218
|
+
function truncateTitle(text) {
|
|
219
|
+
const oneLine = text.replace(/\n/g, " ").trim();
|
|
220
|
+
if (oneLine.length <= MAX_TITLE_LEN) return oneLine;
|
|
221
|
+
return `${oneLine.slice(0, MAX_TITLE_LEN - 1)}…`;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Build a descriptive tool title from tool name and args.
|
|
225
|
+
*
|
|
226
|
+
* Returns a short human-readable label like "Read src/index.ts" or "Run ls -la".
|
|
227
|
+
*/
|
|
228
|
+
function buildToolTitle(toolName, args) {
|
|
229
|
+
const p = args.path;
|
|
230
|
+
switch (toolName) {
|
|
231
|
+
case "read": return p !== void 0 ? `Read ${p}` : "Read";
|
|
232
|
+
case "write": return p !== void 0 ? `Write ${p}` : "Write";
|
|
233
|
+
case "edit": return p !== void 0 ? `Edit ${p}` : "Edit";
|
|
234
|
+
case "bash": {
|
|
235
|
+
const command = typeof args["command"] === "string" ? args["command"] : typeof args["cmd"] === "string" ? args["cmd"] : void 0;
|
|
236
|
+
return command !== void 0 ? truncateTitle(`Run ${command}`) : "bash";
|
|
237
|
+
}
|
|
238
|
+
default: return toolName;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
194
241
|
/**
|
|
195
242
|
* Map pi assistant stopReason to ACP StopReason.
|
|
196
243
|
* pi: "stop" | "length" | "toolUse" | "error" | "aborted"
|
|
@@ -382,7 +429,7 @@ var PiAcpSession = class {
|
|
|
382
429
|
this.emit({
|
|
383
430
|
sessionUpdate: "tool_call",
|
|
384
431
|
toolCallId: toolCall.id,
|
|
385
|
-
title: toolCall.name,
|
|
432
|
+
title: buildToolTitle(toolCall.name, rawInput),
|
|
386
433
|
kind: toToolKind(toolCall.name),
|
|
387
434
|
status,
|
|
388
435
|
...locations ? { locations } : {},
|
|
@@ -402,14 +449,17 @@ var PiAcpSession = class {
|
|
|
402
449
|
}
|
|
403
450
|
handleToolStart(toolCallId, toolName, args) {
|
|
404
451
|
let line;
|
|
405
|
-
if (toolName === "edit" && args.path !== void 0) try {
|
|
452
|
+
if ((toolName === "edit" || toolName === "write") && args.path !== void 0) try {
|
|
406
453
|
const abs = isAbsolute(args.path) ? args.path : resolve(this.cwd, args.path);
|
|
407
|
-
|
|
454
|
+
let oldText = "";
|
|
455
|
+
try {
|
|
456
|
+
oldText = readFileSync(abs, "utf8");
|
|
457
|
+
} catch {}
|
|
408
458
|
this.editSnapshots.set(toolCallId, {
|
|
409
459
|
path: abs,
|
|
410
460
|
oldText
|
|
411
461
|
});
|
|
412
|
-
line = findUniqueLineNumber(oldText, args.oldText ?? "");
|
|
462
|
+
if (toolName === "edit") line = findUniqueLineNumber(oldText, args.oldText ?? "");
|
|
413
463
|
} catch {}
|
|
414
464
|
const locations = resolveToolPath(args, this.cwd, line);
|
|
415
465
|
if (!this.currentToolCalls.has(toolCallId)) {
|
|
@@ -417,7 +467,7 @@ var PiAcpSession = class {
|
|
|
417
467
|
this.emit({
|
|
418
468
|
sessionUpdate: "tool_call",
|
|
419
469
|
toolCallId,
|
|
420
|
-
title: toolName,
|
|
470
|
+
title: buildToolTitle(toolName, args),
|
|
421
471
|
kind: toToolKind(toolName),
|
|
422
472
|
status: "in_progress",
|
|
423
473
|
...locations ? { locations } : {},
|
|
@@ -428,6 +478,7 @@ var PiAcpSession = class {
|
|
|
428
478
|
this.emit({
|
|
429
479
|
sessionUpdate: "tool_call_update",
|
|
430
480
|
toolCallId,
|
|
481
|
+
title: buildToolTitle(toolName, args),
|
|
431
482
|
status: "in_progress",
|
|
432
483
|
...locations ? { locations } : {},
|
|
433
484
|
rawInput: args
|
|
@@ -487,6 +538,7 @@ var PiAcpSession = class {
|
|
|
487
538
|
this.editSnapshots.delete(toolCallId);
|
|
488
539
|
}
|
|
489
540
|
handleAgentEnd() {
|
|
541
|
+
this.emitUsageUpdate();
|
|
490
542
|
this.flushEmits().finally(() => {
|
|
491
543
|
const reason = this.cancelRequested ? "cancelled" : mapPiStopReason(this.lastAssistantStopReason);
|
|
492
544
|
this.lastAssistantStopReason = null;
|
|
@@ -494,6 +546,42 @@ var PiAcpSession = class {
|
|
|
494
546
|
this.pendingTurn = null;
|
|
495
547
|
});
|
|
496
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Emit a usage_update notification with current context and cost data.
|
|
551
|
+
*/
|
|
552
|
+
emitUsageUpdate() {
|
|
553
|
+
const contextUsage = this.piSession.getContextUsage?.();
|
|
554
|
+
const stats = this.piSession.getSessionStats();
|
|
555
|
+
const used = contextUsage?.tokens ?? 0;
|
|
556
|
+
const size = contextUsage?.contextWindow ?? 0;
|
|
557
|
+
this.emit({
|
|
558
|
+
sessionUpdate: "usage_update",
|
|
559
|
+
used,
|
|
560
|
+
size,
|
|
561
|
+
cost: stats.cost > 0 ? {
|
|
562
|
+
amount: stats.cost,
|
|
563
|
+
currency: "USD"
|
|
564
|
+
} : null
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Build ACP Usage data from pi session stats for prompt response.
|
|
569
|
+
*/
|
|
570
|
+
getUsage() {
|
|
571
|
+
const stats = this.piSession.getSessionStats();
|
|
572
|
+
return {
|
|
573
|
+
inputTokens: stats.tokens.input,
|
|
574
|
+
outputTokens: stats.tokens.output,
|
|
575
|
+
cachedReadTokens: stats.tokens.cacheRead,
|
|
576
|
+
cachedWriteTokens: stats.tokens.cacheWrite
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Get cumulative session cost.
|
|
581
|
+
*/
|
|
582
|
+
getCost() {
|
|
583
|
+
return this.piSession.getSessionStats().cost;
|
|
584
|
+
}
|
|
497
585
|
};
|
|
498
586
|
/**
|
|
499
587
|
* Type guard to narrow AgentSessionEvent to the AgentEvent subset
|
|
@@ -514,10 +602,6 @@ function extractUserMessageText(content) {
|
|
|
514
602
|
if (!Array.isArray(content)) return "";
|
|
515
603
|
return content.filter(isTextBlock).map((b) => b.text).join("");
|
|
516
604
|
}
|
|
517
|
-
function extractAssistantText(content) {
|
|
518
|
-
if (!Array.isArray(content)) return "";
|
|
519
|
-
return content.filter(isTextBlock).map((b) => b.text).join("");
|
|
520
|
-
}
|
|
521
605
|
//#endregion
|
|
522
606
|
//#region src/acp/translate/prompt.ts
|
|
523
607
|
function acpPromptToPiMessage(blocks) {
|
|
@@ -699,6 +783,14 @@ function parseArgs(input) {
|
|
|
699
783
|
if (current !== "") args.push(current);
|
|
700
784
|
return args;
|
|
701
785
|
}
|
|
786
|
+
const SESSION_TITLE_MAX = 100;
|
|
787
|
+
function truncateSessionTitle(text) {
|
|
788
|
+
const trimmed = text.trim();
|
|
789
|
+
if (trimmed === "") return null;
|
|
790
|
+
const oneLine = trimmed.replace(/\n/g, " ");
|
|
791
|
+
if (oneLine.length <= SESSION_TITLE_MAX) return oneLine;
|
|
792
|
+
return `${oneLine.slice(0, SESSION_TITLE_MAX - 1)}…`;
|
|
793
|
+
}
|
|
702
794
|
const pkg = readNearestPackageJson(import.meta.url);
|
|
703
795
|
var PiAcpAgent = class {
|
|
704
796
|
conn;
|
|
@@ -731,9 +823,14 @@ var PiAcpAgent = class {
|
|
|
731
823
|
promptCapabilities: {
|
|
732
824
|
image: true,
|
|
733
825
|
audio: false,
|
|
734
|
-
embeddedContext:
|
|
826
|
+
embeddedContext: true
|
|
735
827
|
},
|
|
736
|
-
sessionCapabilities: {
|
|
828
|
+
sessionCapabilities: {
|
|
829
|
+
list: {},
|
|
830
|
+
close: {},
|
|
831
|
+
resume: {},
|
|
832
|
+
fork: {}
|
|
833
|
+
}
|
|
737
834
|
}
|
|
738
835
|
};
|
|
739
836
|
}
|
|
@@ -744,6 +841,8 @@ var PiAcpAgent = class {
|
|
|
744
841
|
try {
|
|
745
842
|
result = await createAgentSession({ cwd: params.cwd });
|
|
746
843
|
} catch (e) {
|
|
844
|
+
const authErr = detectAuthError(e);
|
|
845
|
+
if (authErr !== null) throw authErr;
|
|
747
846
|
const msg = e instanceof Error ? e.message : String(e);
|
|
748
847
|
throw RequestError.internalError({}, `Failed to create pi session: ${msg}`);
|
|
749
848
|
}
|
|
@@ -770,7 +869,6 @@ var PiAcpAgent = class {
|
|
|
770
869
|
updateNotice
|
|
771
870
|
});
|
|
772
871
|
if (preludeText) session.setStartupInfo(preludeText);
|
|
773
|
-
this.sessions.closeAllExcept(session.sessionId);
|
|
774
872
|
const modes = buildThinkingModes(piSession);
|
|
775
873
|
const models = buildModelState(piSession);
|
|
776
874
|
const configOptions = buildConfigOptions(modes, models);
|
|
@@ -799,7 +897,9 @@ var PiAcpAgent = class {
|
|
|
799
897
|
}, 0);
|
|
800
898
|
return response;
|
|
801
899
|
}
|
|
802
|
-
async authenticate(_params) {
|
|
900
|
+
async authenticate(_params) {
|
|
901
|
+
return {};
|
|
902
|
+
}
|
|
803
903
|
async prompt(params) {
|
|
804
904
|
const session = this.sessions.get(params.sessionId);
|
|
805
905
|
const { message, images } = acpPromptToPiMessage(params.prompt);
|
|
@@ -812,7 +912,23 @@ var PiAcpAgent = class {
|
|
|
812
912
|
if (handled) return handled;
|
|
813
913
|
}
|
|
814
914
|
const result = await session.prompt(message, images);
|
|
815
|
-
|
|
915
|
+
const stopReason = result === "error" ? "end_turn" : result;
|
|
916
|
+
const usage = session.getUsage();
|
|
917
|
+
const cost = session.getCost();
|
|
918
|
+
return {
|
|
919
|
+
stopReason,
|
|
920
|
+
usage: {
|
|
921
|
+
inputTokens: usage.inputTokens,
|
|
922
|
+
outputTokens: usage.outputTokens,
|
|
923
|
+
cachedReadTokens: usage.cachedReadTokens,
|
|
924
|
+
cachedWriteTokens: usage.cachedWriteTokens,
|
|
925
|
+
totalTokens: usage.inputTokens + usage.outputTokens
|
|
926
|
+
},
|
|
927
|
+
_meta: cost > 0 ? { cost: {
|
|
928
|
+
amount: cost,
|
|
929
|
+
currency: "USD"
|
|
930
|
+
} } : {}
|
|
931
|
+
};
|
|
816
932
|
}
|
|
817
933
|
async cancel(params) {
|
|
818
934
|
await this.sessions.get(params.sessionId).cancel();
|
|
@@ -829,61 +945,16 @@ var PiAcpAgent = class {
|
|
|
829
945
|
for (const s of all) this.sessionPaths.set(s.id, s.path);
|
|
830
946
|
return this.sessionPaths.get(sessionId) ?? null;
|
|
831
947
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}));
|
|
843
|
-
if (params.cursor !== void 0 && params.cursor !== null) {
|
|
844
|
-
const parsed = Number.parseInt(params.cursor, 10);
|
|
845
|
-
if (!Number.isFinite(parsed) || parsed < 0) throw RequestError.invalidParams(`Invalid cursor: ${params.cursor}`);
|
|
846
|
-
}
|
|
847
|
-
const start = params.cursor !== void 0 && params.cursor !== null ? Number.parseInt(params.cursor, 10) : 0;
|
|
848
|
-
const PAGE_SIZE = 50;
|
|
849
|
-
return {
|
|
850
|
-
sessions: sessions.slice(start, start + PAGE_SIZE).map((s) => ({
|
|
851
|
-
sessionId: s.id,
|
|
852
|
-
cwd: s.cwd,
|
|
853
|
-
title: s.name ?? null,
|
|
854
|
-
updatedAt: s.modified.toISOString()
|
|
855
|
-
})),
|
|
856
|
-
nextCursor: start + PAGE_SIZE < sessions.length ? String(start + PAGE_SIZE) : null,
|
|
857
|
-
_meta: {}
|
|
858
|
-
};
|
|
859
|
-
}
|
|
860
|
-
async loadSession(params) {
|
|
861
|
-
if (!isAbsolute(params.cwd)) throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
|
|
862
|
-
this.sessions.close(params.sessionId);
|
|
863
|
-
const sessionFile = await this.resolveSessionFile(params.sessionId);
|
|
864
|
-
if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
865
|
-
let result;
|
|
866
|
-
try {
|
|
867
|
-
const sm = SessionManager.open(sessionFile);
|
|
868
|
-
result = await createAgentSession({
|
|
869
|
-
cwd: params.cwd,
|
|
870
|
-
sessionManager: sm
|
|
871
|
-
});
|
|
872
|
-
} catch (e) {
|
|
873
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
874
|
-
throw RequestError.internalError({}, `Failed to load pi session: ${msg}`);
|
|
875
|
-
}
|
|
876
|
-
const piSession = result.session;
|
|
877
|
-
const session = new PiAcpSession({
|
|
878
|
-
sessionId: params.sessionId,
|
|
879
|
-
cwd: params.cwd,
|
|
880
|
-
mcpServers: params.mcpServers,
|
|
881
|
-
piSession,
|
|
882
|
-
conn: this.conn
|
|
883
|
-
});
|
|
884
|
-
this.sessions.register(session);
|
|
885
|
-
this.sessions.closeAllExcept(session.sessionId);
|
|
886
|
-
const messages = piSession.messages;
|
|
948
|
+
/**
|
|
949
|
+
* Replay persisted session messages as ACP session updates.
|
|
950
|
+
*
|
|
951
|
+
* Iterates through the message history, emitting structured updates for each
|
|
952
|
+
* content block type: text, thinking, tool calls, and tool results. A map of
|
|
953
|
+
* tool call IDs to their invocation data (from assistant messages) is built
|
|
954
|
+
* to enrich subsequent tool result updates with rawInput and locations.
|
|
955
|
+
*/
|
|
956
|
+
async replaySessionHistory(session, messages) {
|
|
957
|
+
const toolCallMap = /* @__PURE__ */ new Map();
|
|
887
958
|
for (const m of messages) {
|
|
888
959
|
if (!("role" in m)) continue;
|
|
889
960
|
if (m.role === "user") {
|
|
@@ -898,32 +969,67 @@ var PiAcpAgent = class {
|
|
|
898
969
|
}
|
|
899
970
|
}
|
|
900
971
|
});
|
|
972
|
+
continue;
|
|
901
973
|
}
|
|
902
974
|
if (m.role === "assistant") {
|
|
903
|
-
const
|
|
904
|
-
if (text) await this.conn.sessionUpdate({
|
|
975
|
+
const am = m;
|
|
976
|
+
for (const block of am.content) if (block.type === "text" && block.text) await this.conn.sessionUpdate({
|
|
905
977
|
sessionId: session.sessionId,
|
|
906
978
|
update: {
|
|
907
979
|
sessionUpdate: "agent_message_chunk",
|
|
908
980
|
content: {
|
|
909
981
|
type: "text",
|
|
910
|
-
text
|
|
982
|
+
text: block.text
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
else if (block.type === "thinking" && block.thinking) await this.conn.sessionUpdate({
|
|
987
|
+
sessionId: session.sessionId,
|
|
988
|
+
update: {
|
|
989
|
+
sessionUpdate: "agent_thought_chunk",
|
|
990
|
+
content: {
|
|
991
|
+
type: "text",
|
|
992
|
+
text: block.thinking
|
|
911
993
|
}
|
|
912
994
|
}
|
|
913
995
|
});
|
|
996
|
+
else if (block.type === "toolCall") {
|
|
997
|
+
const args = toToolArgs(block.arguments);
|
|
998
|
+
toolCallMap.set(block.id, {
|
|
999
|
+
name: block.name,
|
|
1000
|
+
args
|
|
1001
|
+
});
|
|
1002
|
+
const locations = resolveToolPath(args, session.cwd);
|
|
1003
|
+
await this.conn.sessionUpdate({
|
|
1004
|
+
sessionId: session.sessionId,
|
|
1005
|
+
update: {
|
|
1006
|
+
sessionUpdate: "tool_call",
|
|
1007
|
+
toolCallId: block.id,
|
|
1008
|
+
title: buildToolTitle(block.name, args),
|
|
1009
|
+
kind: toToolKind(block.name),
|
|
1010
|
+
status: "completed",
|
|
1011
|
+
rawInput: args,
|
|
1012
|
+
...locations ? { locations } : {}
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
continue;
|
|
914
1017
|
}
|
|
915
1018
|
if (m.role === "toolResult") {
|
|
916
1019
|
const tr = m;
|
|
917
1020
|
const toolName = tr.toolName;
|
|
918
1021
|
const toolCallId = tr.toolCallId;
|
|
919
1022
|
const isError = tr.isError;
|
|
920
|
-
|
|
1023
|
+
const invocation = toolCallMap.get(toolCallId);
|
|
1024
|
+
const args = invocation?.args;
|
|
1025
|
+
const locations = args !== void 0 ? resolveToolPath(args, session.cwd) : void 0;
|
|
1026
|
+
if (invocation === void 0) await this.conn.sessionUpdate({
|
|
921
1027
|
sessionId: session.sessionId,
|
|
922
1028
|
update: {
|
|
923
1029
|
sessionUpdate: "tool_call",
|
|
924
1030
|
toolCallId,
|
|
925
|
-
title: toolName,
|
|
926
|
-
kind: toolName
|
|
1031
|
+
title: buildToolTitle(toolName, {}),
|
|
1032
|
+
kind: toToolKind(toolName),
|
|
927
1033
|
status: "completed",
|
|
928
1034
|
rawInput: null,
|
|
929
1035
|
rawOutput: m
|
|
@@ -943,11 +1049,70 @@ var PiAcpAgent = class {
|
|
|
943
1049
|
text
|
|
944
1050
|
}
|
|
945
1051
|
}] : null,
|
|
946
|
-
rawOutput: m
|
|
1052
|
+
rawOutput: m,
|
|
1053
|
+
...locations ? { locations } : {}
|
|
947
1054
|
}
|
|
948
1055
|
});
|
|
949
1056
|
}
|
|
950
1057
|
}
|
|
1058
|
+
}
|
|
1059
|
+
async listSessions(params) {
|
|
1060
|
+
const cwd = params.cwd;
|
|
1061
|
+
const raw = cwd !== void 0 && cwd !== null ? await SessionManager.list(cwd) : await SessionManager.listAll();
|
|
1062
|
+
for (const s of raw) this.sessionPaths.set(s.id, s.path);
|
|
1063
|
+
const sessions = raw.map((s) => ({
|
|
1064
|
+
id: s.id,
|
|
1065
|
+
cwd: s.cwd,
|
|
1066
|
+
name: s.name,
|
|
1067
|
+
firstMessage: s.firstMessage,
|
|
1068
|
+
modified: s.modified,
|
|
1069
|
+
messageCount: s.messageCount
|
|
1070
|
+
}));
|
|
1071
|
+
if (params.cursor !== void 0 && params.cursor !== null) {
|
|
1072
|
+
const parsed = Number.parseInt(params.cursor, 10);
|
|
1073
|
+
if (!Number.isFinite(parsed) || parsed < 0) throw RequestError.invalidParams(`Invalid cursor: ${params.cursor}`);
|
|
1074
|
+
}
|
|
1075
|
+
const start = params.cursor !== void 0 && params.cursor !== null ? Number.parseInt(params.cursor, 10) : 0;
|
|
1076
|
+
const PAGE_SIZE = 50;
|
|
1077
|
+
return {
|
|
1078
|
+
sessions: sessions.slice(start, start + PAGE_SIZE).map((s) => ({
|
|
1079
|
+
sessionId: s.id,
|
|
1080
|
+
cwd: s.cwd,
|
|
1081
|
+
title: (s.name !== void 0 && s.name !== "" ? s.name : null) ?? truncateSessionTitle(s.firstMessage) ?? null,
|
|
1082
|
+
updatedAt: s.modified.toISOString()
|
|
1083
|
+
})),
|
|
1084
|
+
nextCursor: start + PAGE_SIZE < sessions.length ? String(start + PAGE_SIZE) : null,
|
|
1085
|
+
_meta: {}
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
async loadSession(params) {
|
|
1089
|
+
if (!isAbsolute(params.cwd)) throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
|
|
1090
|
+
this.sessions.close(params.sessionId);
|
|
1091
|
+
const sessionFile = await this.resolveSessionFile(params.sessionId);
|
|
1092
|
+
if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
1093
|
+
let result;
|
|
1094
|
+
try {
|
|
1095
|
+
const sm = SessionManager.open(sessionFile);
|
|
1096
|
+
result = await createAgentSession({
|
|
1097
|
+
cwd: params.cwd,
|
|
1098
|
+
sessionManager: sm
|
|
1099
|
+
});
|
|
1100
|
+
} catch (e) {
|
|
1101
|
+
const authErr = detectAuthError(e);
|
|
1102
|
+
if (authErr !== null) throw authErr;
|
|
1103
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1104
|
+
throw RequestError.internalError({}, `Failed to load pi session: ${msg}`);
|
|
1105
|
+
}
|
|
1106
|
+
const piSession = result.session;
|
|
1107
|
+
const session = new PiAcpSession({
|
|
1108
|
+
sessionId: params.sessionId,
|
|
1109
|
+
cwd: params.cwd,
|
|
1110
|
+
mcpServers: params.mcpServers,
|
|
1111
|
+
piSession,
|
|
1112
|
+
conn: this.conn
|
|
1113
|
+
});
|
|
1114
|
+
this.sessions.register(session);
|
|
1115
|
+
await this.replaySessionHistory(session, piSession.messages);
|
|
951
1116
|
const modes = buildThinkingModes(piSession);
|
|
952
1117
|
const models = buildModelState(piSession);
|
|
953
1118
|
const configOptions = buildConfigOptions(modes, models);
|
|
@@ -973,6 +1138,124 @@ var PiAcpAgent = class {
|
|
|
973
1138
|
_meta: { piAcp: { startupInfo: null } }
|
|
974
1139
|
};
|
|
975
1140
|
}
|
|
1141
|
+
async unstable_closeSession(params) {
|
|
1142
|
+
if (this.sessions.maybeGet(params.sessionId) === void 0) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
1143
|
+
this.sessions.close(params.sessionId);
|
|
1144
|
+
return {};
|
|
1145
|
+
}
|
|
1146
|
+
async unstable_resumeSession(params) {
|
|
1147
|
+
if (!isAbsolute(params.cwd)) throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
|
|
1148
|
+
const existing = this.sessions.maybeGet(params.sessionId);
|
|
1149
|
+
if (existing !== void 0) {
|
|
1150
|
+
const modes = buildThinkingModes(existing.piSession);
|
|
1151
|
+
const models = buildModelState(existing.piSession);
|
|
1152
|
+
return {
|
|
1153
|
+
configOptions: buildConfigOptions(modes, models),
|
|
1154
|
+
modes,
|
|
1155
|
+
models
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
const sessionFile = await this.resolveSessionFile(params.sessionId);
|
|
1159
|
+
if (sessionFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
1160
|
+
let result;
|
|
1161
|
+
try {
|
|
1162
|
+
const sm = SessionManager.open(sessionFile);
|
|
1163
|
+
result = await createAgentSession({
|
|
1164
|
+
cwd: params.cwd,
|
|
1165
|
+
sessionManager: sm
|
|
1166
|
+
});
|
|
1167
|
+
} catch (e) {
|
|
1168
|
+
const authErr = detectAuthError(e);
|
|
1169
|
+
if (authErr !== null) throw authErr;
|
|
1170
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1171
|
+
throw RequestError.internalError({}, `Failed to resume pi session: ${msg}`);
|
|
1172
|
+
}
|
|
1173
|
+
const piSession = result.session;
|
|
1174
|
+
const session = new PiAcpSession({
|
|
1175
|
+
sessionId: params.sessionId,
|
|
1176
|
+
cwd: params.cwd,
|
|
1177
|
+
mcpServers: params.mcpServers ?? [],
|
|
1178
|
+
piSession,
|
|
1179
|
+
conn: this.conn
|
|
1180
|
+
});
|
|
1181
|
+
this.sessions.register(session);
|
|
1182
|
+
this.sessionPaths.set(params.sessionId, sessionFile);
|
|
1183
|
+
const enableSkillCommands = skillCommandsEnabled(params.cwd);
|
|
1184
|
+
setTimeout(() => {
|
|
1185
|
+
(async () => {
|
|
1186
|
+
try {
|
|
1187
|
+
const commands = buildCommandList(piSession, enableSkillCommands);
|
|
1188
|
+
await this.conn.sessionUpdate({
|
|
1189
|
+
sessionId: session.sessionId,
|
|
1190
|
+
update: {
|
|
1191
|
+
sessionUpdate: "available_commands_update",
|
|
1192
|
+
availableCommands: mergeCommands(commands, builtinAvailableCommands())
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
} catch {}
|
|
1196
|
+
})();
|
|
1197
|
+
}, 0);
|
|
1198
|
+
const modes = buildThinkingModes(piSession);
|
|
1199
|
+
const models = buildModelState(piSession);
|
|
1200
|
+
return {
|
|
1201
|
+
configOptions: buildConfigOptions(modes, models),
|
|
1202
|
+
modes,
|
|
1203
|
+
models
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
async unstable_forkSession(params) {
|
|
1207
|
+
if (!isAbsolute(params.cwd)) throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
|
|
1208
|
+
const sourceFile = await this.resolveSessionFile(params.sessionId);
|
|
1209
|
+
if (sourceFile === null) throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);
|
|
1210
|
+
let result;
|
|
1211
|
+
try {
|
|
1212
|
+
const sm = SessionManager.forkFrom(sourceFile, params.cwd);
|
|
1213
|
+
result = await createAgentSession({
|
|
1214
|
+
cwd: params.cwd,
|
|
1215
|
+
sessionManager: sm
|
|
1216
|
+
});
|
|
1217
|
+
} catch (e) {
|
|
1218
|
+
const authErr = detectAuthError(e);
|
|
1219
|
+
if (authErr !== null) throw authErr;
|
|
1220
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1221
|
+
throw RequestError.internalError({}, `Failed to fork pi session: ${msg}`);
|
|
1222
|
+
}
|
|
1223
|
+
const piSession = result.session;
|
|
1224
|
+
const newSessionId = piSession.sessionManager.getSessionId();
|
|
1225
|
+
const newSessionFile = piSession.sessionManager.getSessionFile();
|
|
1226
|
+
if (newSessionFile !== void 0) this.sessionPaths.set(newSessionId, newSessionFile);
|
|
1227
|
+
const session = new PiAcpSession({
|
|
1228
|
+
sessionId: newSessionId,
|
|
1229
|
+
cwd: params.cwd,
|
|
1230
|
+
mcpServers: params.mcpServers ?? [],
|
|
1231
|
+
piSession,
|
|
1232
|
+
conn: this.conn
|
|
1233
|
+
});
|
|
1234
|
+
this.sessions.register(session);
|
|
1235
|
+
const enableSkillCommands = skillCommandsEnabled(params.cwd);
|
|
1236
|
+
setTimeout(() => {
|
|
1237
|
+
(async () => {
|
|
1238
|
+
try {
|
|
1239
|
+
const commands = buildCommandList(piSession, enableSkillCommands);
|
|
1240
|
+
await this.conn.sessionUpdate({
|
|
1241
|
+
sessionId: session.sessionId,
|
|
1242
|
+
update: {
|
|
1243
|
+
sessionUpdate: "available_commands_update",
|
|
1244
|
+
availableCommands: mergeCommands(commands, builtinAvailableCommands())
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
} catch {}
|
|
1248
|
+
})();
|
|
1249
|
+
}, 0);
|
|
1250
|
+
const modes = buildThinkingModes(piSession);
|
|
1251
|
+
const models = buildModelState(piSession);
|
|
1252
|
+
return {
|
|
1253
|
+
sessionId: newSessionId,
|
|
1254
|
+
configOptions: buildConfigOptions(modes, models),
|
|
1255
|
+
modes,
|
|
1256
|
+
models
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
976
1259
|
async setSessionMode(params) {
|
|
977
1260
|
const session = this.sessions.get(params.sessionId);
|
|
978
1261
|
const mode = String(params.modeId);
|
|
@@ -1414,10 +1697,15 @@ function buildCommandList(piSession, enableSkillCommands) {
|
|
|
1414
1697
|
});
|
|
1415
1698
|
return commands;
|
|
1416
1699
|
}
|
|
1700
|
+
let cachedUpdateNotice;
|
|
1417
1701
|
function buildUpdateNotice() {
|
|
1702
|
+
if (cachedUpdateNotice !== void 0) return cachedUpdateNotice;
|
|
1418
1703
|
try {
|
|
1419
1704
|
const installed = VERSION;
|
|
1420
|
-
if (!installed || !isSemver(installed))
|
|
1705
|
+
if (!installed || !isSemver(installed)) {
|
|
1706
|
+
cachedUpdateNotice = null;
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1421
1709
|
const latestRes = spawnSync("npm", [
|
|
1422
1710
|
"view",
|
|
1423
1711
|
"@mariozechner/pi-coding-agent",
|
|
@@ -1427,10 +1715,18 @@ function buildUpdateNotice() {
|
|
|
1427
1715
|
timeout: 800
|
|
1428
1716
|
});
|
|
1429
1717
|
const latest = String(latestRes.stdout ?? "").trim().replace(/^v/i, "");
|
|
1430
|
-
if (!latest || !isSemver(latest))
|
|
1431
|
-
|
|
1432
|
-
|
|
1718
|
+
if (!latest || !isSemver(latest)) {
|
|
1719
|
+
cachedUpdateNotice = null;
|
|
1720
|
+
return null;
|
|
1721
|
+
}
|
|
1722
|
+
if (compareSemver(latest, installed) <= 0) {
|
|
1723
|
+
cachedUpdateNotice = null;
|
|
1724
|
+
return null;
|
|
1725
|
+
}
|
|
1726
|
+
cachedUpdateNotice = `New version available: v${latest} (installed v${installed}). Run: \`npm i -g @mariozechner/pi-coding-agent\``;
|
|
1727
|
+
return cachedUpdateNotice;
|
|
1433
1728
|
} catch {
|
|
1729
|
+
cachedUpdateNotice = null;
|
|
1434
1730
|
return null;
|
|
1435
1731
|
}
|
|
1436
1732
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["resolvePath","SessionManager","SessionManager","PiSessionManager","PI_VERSION"],"sources":["../src/acp/auth.ts","../src/acp/pi-settings.ts","../src/acp/translate/pi-tools.ts","../src/acp/session.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts","../src/pi-auth/status.ts","../src/acp/agent.ts","../src/index.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 * 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\nexport function quietStartupEnabled(cwd: string): boolean {\n\tconst settings = resolvedSettings(cwd);\n\n\tif (typeof settings.quietStartup === \"boolean\") {\n\t\treturn settings.quietStartup;\n\t}\n\n\tif (typeof settings.quietStart === \"boolean\") {\n\t\treturn settings.quietStart;\n\t}\n\n\treturn false;\n}\n","/**\n * Extract displayable text from a pi tool result.\n *\n * Pi tool results have varying shapes depending on the tool. This function\n * tries content blocks first, then falls back to details fields (diff, stdout/stderr),\n * and finally JSON serialization as a last resort.\n */\n\nimport * as z from \"zod\";\n\nconst textBlockSchema = z.object({\n\ttype: z.literal(\"text\"),\n\ttext: z.string(),\n});\n\nconst toolDetailsSchema = z.object({\n\tdiff: z.string().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\nconst toolResultSchema = z.object({\n\tcontent: z.array(z.unknown()).optional(),\n\tdetails: toolDetailsSchema.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\nexport function toolResultToText(result: unknown): string {\n\tif (result === null || result === undefined || typeof result !== \"object\") return \"\";\n\n\tconst parsed = toolResultSchema.safeParse(result);\n\tif (!parsed.success) {\n\t\ttry {\n\t\t\treturn JSON.stringify(result, null, 2);\n\t\t} catch {\n\t\t\treturn String(result);\n\t\t}\n\t}\n\n\tconst r = parsed.data;\n\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) return texts.join(\"\");\n\t}\n\n\tconst d = r.details;\n\n\tconst diff = d?.diff;\n\tif (diff !== undefined && diff.trim() !== \"\") return diff;\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 hasStdout = stdout !== undefined && stdout.trim() !== \"\";\n\tconst hasStderr = stderr !== undefined && stderr.trim() !== \"\";\n\n\tif (hasStdout || hasStderr) {\n\t\tconst parts: string[] = [];\n\t\tif (hasStdout) parts.push(stdout);\n\t\tif (hasStderr) parts.push(`stderr:\\n${stderr}`);\n\t\tif (exitCode !== undefined) parts.push(`exit code: ${exitCode}`);\n\t\treturn parts.join(\"\\n\\n\").trimEnd();\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","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 \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessageEvent, ToolCall } from \"@mariozechner/pi-ai\";\nimport type { AgentSession, AgentSessionEvent } from \"@mariozechner/pi-coding-agent\";\nimport { toolResultToText } from \"@pi-acp/acp/translate/pi-tools\";\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\ninterface ToolArgs {\n\tpath?: string | undefined;\n\toldText?: string | undefined;\n\t[key: string]: unknown;\n}\n\nfunction 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\nfunction 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\t\treturn \"execute\";\n\t\tdefault:\n\t\t\treturn \"other\";\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\nfunction toToolArgs(raw: unknown): ToolArgs {\n\tconst result = toolArgsSchema.safeParse(raw);\n\treturn result.success ? result.data : {};\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\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\ninterface PiAcpSessionOpts {\n\tsessionId: string;\n\tcwd: string;\n\tmcpServers: McpServer[];\n\tpiSession: AgentSession;\n\tconn: AgentSideConnection;\n}\n\nexport class PiAcpSession {\n\treadonly sessionId: string;\n\treadonly cwd: string;\n\treadonly mcpServers: McpServer[];\n\treadonly piSession: AgentSession;\n\n\tprivate startupInfo: string | null = null;\n\tprivate startupInfoSent = false;\n\tprivate readonly conn: AgentSideConnection;\n\n\tprivate cancelRequested = false;\n\tprivate pendingTurn: { resolve: (r: StopReason) => void; reject: (e: unknown) => void } | null =\n\t\tnull;\n\n\tprivate currentToolCalls = new Map<string, \"pending\" | \"in_progress\">();\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.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\tsetStartupInfo(text: string): void {\n\t\tthis.startupInfo = text;\n\t}\n\n\tsendStartupInfoIfPending(): void {\n\t\tif (this.startupInfoSent || this.startupInfo === null) return;\n\t\tthis.startupInfoSent = true;\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\tcontent: { type: \"text\", text: this.startupInfo },\n\t\t});\n\t}\n\n\tasync prompt(message: string, images: unknown[] = []): Promise<StopReason> {\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\tasync cancel(): Promise<void> {\n\t\tthis.cancelRequested = true;\n\t\tawait this.piSession.abort();\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.partialResult);\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_end\":\n\t\t\t\tthis.handleToolEnd(ev.toolCallId, 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\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: toolCall.name,\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});\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});\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\tlet line: number | undefined;\n\n\t\tif (toolName === \"edit\" && 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\tconst oldText = readFileSync(abs, \"utf8\");\n\t\t\t\tthis.editSnapshots.set(toolCallId, { path: abs, oldText });\n\t\t\t\tline = findUniqueLineNumber(oldText, args.oldText ?? \"\");\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\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: toolName,\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\trawInput: args,\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\tstatus: \"in_progress\",\n\t\t\t\t...(locations ? { locations } : {}),\n\t\t\t\trawInput: args,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate handleToolUpdate(toolCallId: string, partialResult: unknown): void {\n\t\tconst text = toolResultToText(partialResult);\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\ttoolCallId,\n\t\t\tstatus: \"in_progress\",\n\t\t\tcontent: text\n\t\t\t\t? ([{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[])\n\t\t\t\t: null,\n\t\t\trawOutput: partialResult,\n\t\t});\n\t}\n\n\tprivate handleToolEnd(toolCallId: string, result: unknown, isError: boolean): void {\n\t\tconst text = toolResultToText(result);\n\t\tconst snapshot = this.editSnapshots.get(toolCallId);\n\t\tlet content: ToolCallContent[] | null = null;\n\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\tcontent = [\n\t\t\t\t\t\t{ type: \"diff\", path: snapshot.path, oldText: snapshot.oldText, newText },\n\t\t\t\t\t\t...(text\n\t\t\t\t\t\t\t? ([{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[])\n\t\t\t\t\t\t\t: []),\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// fall back to text\n\t\t\t}\n\t\t}\n\n\t\tif (!content && text) {\n\t\t\tcontent = [{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[];\n\t\t}\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\trawOutput: result,\n\t\t});\n\n\t\tthis.currentToolCalls.delete(toolCallId);\n\t\tthis.editSnapshots.delete(toolCallId);\n\t}\n\n\tprivate handleAgentEnd(): void {\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});\n\t}\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","/**\n * Detect whether the user has any pi authentication configured.\n *\n * Checks three sources:\n * 1. auth.json (API keys, OAuth credentials)\n * 2. models.json custom provider apiKey entries\n * 3. Known provider environment variables\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as z from \"zod\";\n\nconst modelsConfigSchema = z.object({\n\tproviders: z\n\t\t.record(\n\t\t\tz.string().trim(),\n\t\t\tz.object({\n\t\t\t\tapiKey: z.string().trim().optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\nfunction agentDir(): string {\n\tconst env = process.env.PI_CODING_AGENT_DIR;\n\tif (env === undefined) return join(homedir(), \".pi\", \"agent\");\n\tif (env === \"~\") return homedir();\n\tif (env.startsWith(\"~/\")) return homedir() + env.slice(1);\n\treturn env;\n}\n\nfunction readJsonFile(path: string): unknown {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\tconst raw = readFileSync(path, \"utf-8\").trim();\n\t\tif (!raw) return null;\n\t\treturn JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction hasAuthJson(): boolean {\n\tconst data = readJsonFile(join(agentDir(), \"auth.json\"));\n\treturn typeof data === \"object\" && data !== null && Object.keys(data).length > 0;\n}\n\nfunction hasCustomProviderKey(): boolean {\n\tconst raw = readJsonFile(join(agentDir(), \"models.json\"));\n\tconst result = modelsConfigSchema.safeParse(raw);\n\tif (!result.success || !result.data.providers) return false;\n\n\treturn Object.values(result.data.providers).some(\n\t\t(provider) => typeof provider.apiKey === \"string\" && provider.apiKey.trim().length > 0,\n\t);\n}\n\n/** Environment variables that indicate a configured provider API key. */\nconst PROVIDER_ENV_VARS = [\n\t\"ANTHROPIC_API_KEY\",\n\t\"ANTHROPIC_OAUTH_TOKEN\",\n\t\"OPENAI_API_KEY\",\n\t\"AZURE_OPENAI_API_KEY\",\n\t\"GEMINI_API_KEY\",\n\t\"GROQ_API_KEY\",\n\t\"CEREBRAS_API_KEY\",\n\t\"XAI_API_KEY\",\n\t\"OPENROUTER_API_KEY\",\n\t\"AI_GATEWAY_API_KEY\",\n\t\"ZAI_API_KEY\",\n\t\"MISTRAL_API_KEY\",\n\t\"MINIMAX_API_KEY\",\n\t\"MINIMAX_CN_API_KEY\",\n\t\"HF_TOKEN\",\n\t\"OPENCODE_API_KEY\",\n\t\"KIMI_API_KEY\",\n\t\"COPILOT_GITHUB_TOKEN\",\n\t\"GH_TOKEN\",\n\t\"GITHUB_TOKEN\",\n];\n\nfunction hasProviderEnvVar(): boolean {\n\treturn PROVIDER_ENV_VARS.some((key) => {\n\t\tconst val = process.env[key];\n\t\treturn typeof val === \"string\" && val.trim().length > 0;\n\t});\n}\n\nexport function hasPiAuthConfigured(): boolean {\n\treturn hasAuthJson() || hasCustomProviderKey() || hasProviderEnvVar();\n}\n","import { spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n\ttype Agent as ACPAgent,\n\ttype AgentSideConnection,\n\ttype AuthenticateRequest,\n\ttype AvailableCommand,\n\ttype CancelNotification,\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 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 \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessage, ToolResultMessage, UserMessage } from \"@mariozechner/pi-ai\";\nimport {\n\ttype AgentSession,\n\ttype CreateAgentSessionResult,\n\tcreateAgentSession,\n\tVERSION as PI_VERSION,\n\tSessionManager as PiSessionManager,\n} from \"@mariozechner/pi-coding-agent\";\nimport { buildAuthMethods } from \"@pi-acp/acp/auth\";\nimport { quietStartupEnabled, skillCommandsEnabled } from \"@pi-acp/acp/pi-settings\";\nimport { PiAcpSession, SessionManager } from \"@pi-acp/acp/session\";\nimport { extractAssistantText, extractUserMessageText } from \"@pi-acp/acp/translate/pi-messages\";\nimport { toolResultToText } from \"@pi-acp/acp/translate/pi-tools\";\nimport { acpPromptToPiMessage } from \"@pi-acp/acp/translate/prompt\";\nimport { hasPiAuthConfigured } from \"@pi-acp/pi-auth/status\";\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\nfunction builtinAvailableCommands(): AvailableCommand[] {\n\treturn [\n\t\t{\n\t\t\tname: \"compact\",\n\t\t\tdescription: \"Manually compact the session context\",\n\t\t\tinput: { hint: \"optional custom instructions\" },\n\t\t},\n\t\t{\n\t\t\tname: \"autocompact\",\n\t\t\tdescription: \"Toggle automatic context compaction\",\n\t\t\tinput: { hint: \"on|off|toggle\" },\n\t\t},\n\t\t{ name: \"export\", description: \"Export session to an HTML file in the session cwd\" },\n\t\t{ name: \"session\", description: \"Show session stats (messages, tokens, cost, session file)\" },\n\t\t{ name: \"name\", description: \"Set session display name\", input: { hint: \"<name>\" } },\n\t\t{\n\t\t\tname: \"steering\",\n\t\t\tdescription: \"Get/set pi steering message delivery mode\",\n\t\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t\t},\n\t\t{\n\t\t\tname: \"follow-up\",\n\t\t\tdescription: \"Get/set pi follow-up message delivery mode\",\n\t\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t\t},\n\t\t{ name: \"changelog\", description: \"Show pi changelog\" },\n\t];\n}\n\nfunction mergeCommands(a: AvailableCommand[], b: AvailableCommand[]): AvailableCommand[] {\n\tconst out: AvailableCommand[] = [];\n\tconst seen = new Set<string>();\n\tfor (const c of [...a, ...b]) {\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 pkg = readNearestPackageJson(import.meta.url);\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\n\tdispose(): void {\n\t\tthis.sessions.disposeAll();\n\t}\n\n\tconstructor(conn: AgentSideConnection, _config?: unknown) {\n\t\tthis.conn = conn;\n\t\tvoid _config;\n\t}\n\n\tasync initialize(params: InitializeRequest): Promise<InitializeResponse> {\n\t\tconst supportedVersion = 1;\n\t\tconst requested = params.protocolVersion;\n\n\t\treturn {\n\t\t\tprotocolVersion: requested === supportedVersion ? requested : supportedVersion,\n\t\t\tagentInfo: {\n\t\t\t\tname: pkg.name,\n\t\t\t\ttitle: \"pi ACP adapter\",\n\t\t\t\tversion: pkg.version,\n\t\t\t},\n\t\t\tauthMethods: buildAuthMethods({\n\t\t\t\tsupportsTerminalAuthMeta: params.clientCapabilities?._meta?.[\"terminal-auth\"] === true,\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: false,\n\t\t\t\t},\n\t\t\t\tsessionCapabilities: {\n\t\t\t\t\tlist: {},\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\tif (!hasPiAuthConfigured()) {\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\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 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});\n\n\t\tthis.sessions.register(session);\n\n\t\tconst quietStartup = quietStartupEnabled(params.cwd);\n\t\tconst updateNotice = buildUpdateNotice();\n\n\t\tconst preludeText = quietStartup\n\t\t\t? updateNotice !== null\n\t\t\t\t? `${updateNotice}\\n`\n\t\t\t\t: \"\"\n\t\t\t: buildStartupInfo({ cwd: params.cwd, updateNotice });\n\n\t\tif (preludeText) session.setStartupInfo(preludeText);\n\n\t\tthis.sessions.closeAllExcept(session.sessionId);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tconst response = {\n\t\t\tsessionId: session.sessionId,\n\t\t\tconfigOptions,\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t\t_meta: {\n\t\t\t\tpiAcp: { startupInfo: preludeText || null },\n\t\t\t},\n\t\t};\n\n\t\tif (preludeText) setTimeout(() => session.sendStartupInfoIfPending(), 0);\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: mergeCommands(commands, builtinAvailableCommands()),\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 response;\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\n\t\treturn { stopReason };\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\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\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 acpSessions: SessionInfo[] = page.map((s) => ({\n\t\t\tsessionId: s.id,\n\t\t\tcwd: s.cwd,\n\t\t\ttitle: s.name ?? null,\n\t\t\tupdatedAt: s.modified.toISOString(),\n\t\t}));\n\n\t\tconst nextCursor = start + PAGE_SIZE < sessions.length ? String(start + PAGE_SIZE) : null;\n\n\t\treturn { sessions: acpSessions, 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 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});\n\n\t\tthis.sessions.register(session);\n\t\tthis.sessions.closeAllExcept(session.sessionId);\n\n\t\tconst messages: AgentMessage[] = piSession.messages;\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}\n\n\t\t\tif (m.role === \"assistant\") {\n\t\t\t\tconst text = extractAssistantText((m satisfies AssistantMessage).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: \"agent_message_chunk\", content: { type: \"text\", text } },\n\t\t\t\t\t});\n\t\t\t\t}\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\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\",\n\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\ttitle: toolName,\n\t\t\t\t\t\tkind:\n\t\t\t\t\t\t\ttoolName === \"read\"\n\t\t\t\t\t\t\t\t? \"read\"\n\t\t\t\t\t\t\t\t: toolName === \"write\" || toolName === \"edit\"\n\t\t\t\t\t\t\t\t\t? \"edit\"\n\t\t\t\t\t\t\t\t\t: \"other\",\n\t\t\t\t\t\tstatus: \"completed\",\n\t\t\t\t\t\trawInput: null,\n\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tconst text = toolResultToText(m);\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: text ? [{ type: \"content\", content: { type: \"text\", text } }] : null,\n\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\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: mergeCommands(commands, builtinAvailableCommands()),\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\t_meta: { piAcp: { startupInfo: null } },\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\n\t\tlet provider: string | null = null;\n\t\tlet modelId: string | null = null;\n\n\t\tif (params.modelId.includes(\"/\")) {\n\t\t\tconst [p, ...rest] = params.modelId.split(\"/\");\n\t\t\tprovider = p ?? null;\n\t\t\tmodelId = rest.join(\"/\");\n\t\t} else {\n\t\t\tmodelId = params.modelId;\n\t\t}\n\n\t\tif (provider === null) {\n\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\tconst found = available.find((m) => m.id === modelId);\n\t\t\tif (found) {\n\t\t\t\tprovider = found.provider;\n\t\t\t\tmodelId = found.id;\n\t\t\t}\n\t\t}\n\n\t\tif (provider === null || modelId === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modelId: ${params.modelId}`);\n\t\t}\n\n\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\tconst model = available.find((m) => m.provider === provider && m.id === modelId);\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\tlet provider: string | null = null;\n\t\t\tlet modelId: string | null = null;\n\n\t\t\tif (value.includes(\"/\")) {\n\t\t\t\tconst [p, ...rest] = value.split(\"/\");\n\t\t\t\tprovider = p ?? null;\n\t\t\t\tmodelId = rest.join(\"/\");\n\t\t\t} else {\n\t\t\t\tmodelId = value;\n\t\t\t}\n\n\t\t\tif (provider === null) {\n\t\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\t\tconst found = available.find((m) => m.id === modelId);\n\t\t\t\tif (found) {\n\t\t\t\t\tprovider = found.provider;\n\t\t\t\t\tmodelId = found.id;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (provider === null || modelId === null) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t}\n\n\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\tconst model = available.find((m) => m.provider === provider && m.id === modelId);\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\tconst runner = piSession.extensionRunner;\n\tif (runner) {\n\t\tfor (const cmd of runner.getRegisteredCommands()) {\n\t\t\tcommands.push({\n\t\t\t\tname: cmd.name,\n\t\t\t\tdescription: cmd.description ?? \"(extension)\",\n\t\t\t});\n\t\t}\n\t}\n\n\treturn commands;\n}\n\nfunction buildUpdateNotice(): string | null {\n\ttry {\n\t\tconst installed = PI_VERSION;\n\t\tif (!installed || !isSemver(installed)) return null;\n\n\t\tconst latestRes = spawnSync(\"npm\", [\"view\", \"@mariozechner/pi-coding-agent\", \"version\"], {\n\t\t\tencoding: \"utf-8\",\n\t\t\ttimeout: 800,\n\t\t});\n\t\tconst latest = String(latestRes.stdout ?? \"\")\n\t\t\t.trim()\n\t\t\t.replace(/^v/i, \"\");\n\t\tif (!latest || !isSemver(latest)) return null;\n\t\tif (compareSemver(latest, installed) <= 0) return null;\n\n\t\treturn `New version available: v${latest} (installed v${installed}). Run: \\`npm i -g @mariozechner/pi-coding-agent\\``;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction buildStartupInfo(opts: { cwd: string; updateNotice: string | null }): string {\n\tconst md: string[] = [];\n\n\tif (PI_VERSION) {\n\t\tmd.push(`pi v${PI_VERSION}`);\n\t\tmd.push(\"---\");\n\t\tmd.push(\"\");\n\t}\n\n\tconst addSection = (title: string, items: string[]) => {\n\t\tconst cleaned = items.map((s) => s.trim()).filter(Boolean);\n\t\tif (cleaned.length === 0) return;\n\t\tmd.push(`## ${title}`);\n\t\tfor (const item of cleaned) md.push(`- ${item}`);\n\t\tmd.push(\"\");\n\t};\n\n\tconst contextItems: string[] = [];\n\tconst contextPath = join(opts.cwd, \"AGENTS.md\");\n\tif (existsSync(contextPath)) contextItems.push(contextPath);\n\taddSection(\"Context\", contextItems);\n\n\tif (opts.updateNotice !== undefined && opts.updateNotice !== null) {\n\t\tmd.push(\"---\");\n\t\tmd.push(opts.updateNotice);\n\t\tmd.push(\"\");\n\t}\n\n\treturn `${md.join(\"\\n\").trim()}\\n`;\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\nfunction isSemver(v: string): boolean {\n\treturn /^\\d+\\.\\d+\\.\\d+(?:[-+].+)?$/.test(v);\n}\n\nfunction compareSemver(a: string, b: string): number {\n\tconst pa = a\n\t\t.split(/[.-]/)\n\t\t.slice(0, 3)\n\t\t.map((n) => Number(n));\n\tconst pb = b\n\t\t.split(/[.-]/)\n\t\t.slice(0, 3)\n\t\t.map((n) => Number(n));\n\tfor (let i = 0; i < 3; i++) {\n\t\tconst da = pa[i] ?? 0;\n\t\tconst db = pb[i] ?? 0;\n\t\tif (da > db) return 1;\n\t\tif (da < db) return -1;\n\t}\n\treturn 0;\n}\n\nfunction readNearestPackageJson(metaUrl: string): { name: string; version: string } {\n\tconst fallback = { name: \"pi-acp\", version: \"0.0.0\" };\n\ttry {\n\t\tlet dir = dirname(fileURLToPath(metaUrl));\n\t\tfor (let i = 0; i < 6; i++) {\n\t\t\tconst p = join(dir, \"package.json\");\n\t\t\tif (existsSync(p)) {\n\t\t\t\tconst raw: unknown = JSON.parse(readFileSync(p, \"utf-8\"));\n\t\t\t\tif (typeof raw !== \"object\" || raw === null) return fallback;\n\t\t\t\tconst name = \"name\" in raw && typeof raw.name === \"string\" ? raw.name : fallback.name;\n\t\t\t\tconst version =\n\t\t\t\t\t\"version\" in raw && typeof raw.version === \"string\" ? raw.version : fallback.version;\n\t\t\t\treturn { name, version };\n\t\t\t}\n\t\t\tdir = dirname(dir);\n\t\t}\n\t} catch {\n\t\t// fall through\n\t}\n\treturn fallback;\n}\n","import { platform } from \"node:os\";\nimport { AgentSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\";\nimport { PiAcpAgent } from \"@pi-acp/acp/agent\";\n\n// Terminal Auth entrypoint: ACP client launches with `--terminal-login`.\nif (process.argv.includes(\"--terminal-login\")) {\n\tconst { spawnSync } = await import(\"node:child_process\");\n\tconst isWindows = platform() === \"win32\";\n\tconst cmd = process.env.PI_ACP_PI_COMMAND ?? (isWindows ? \"pi.cmd\" : \"pi\");\n\tconst res = spawnSync(cmd, [], { stdio: \"inherit\", env: process.env });\n\n\tif (res.error && \"code\" in res.error && res.error.code === \"ENOENT\") {\n\t\tprocess.stderr.write(\n\t\t\t`pi-acp: could not start pi (command not found: ${cmd}). ` +\n\t\t\t\t\"Install via `npm install -g @mariozechner/pi-coding-agent` \" +\n\t\t\t\t\"or ensure `pi` is on your PATH.\\n\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tprocess.exit(typeof res.status === \"number\" ? res.status : 1);\n}\n\nconst input = new WritableStream<Uint8Array>({\n\twrite(chunk) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tif (process.stdout.destroyed || !process.stdout.writable) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tprocess.stdout.write(chunk, () => resolve());\n\t\t\t} catch {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t},\n});\n\nconst output = new ReadableStream<Uint8Array>({\n\tstart(controller) {\n\t\tprocess.stdin.on(\"data\", (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)));\n\t\tprocess.stdin.on(\"end\", () => controller.close());\n\t\tprocess.stdin.on(\"error\", (err) => controller.error(err));\n\t},\n});\n\nconst stream = ndJsonStream(input, output);\nconst agent = new AgentSideConnection((conn) => new PiAcpAgent(conn), stream);\n\nfunction shutdown() {\n\ttry {\n\t\t// AgentSideConnection stores the agent instance internally;\n\t\t// call dispose() on it if available for clean shutdown.\n\t\tif (\"agent\" in agent) {\n\t\t\tconst inner: unknown = agent.agent;\n\t\t\tif (\n\t\t\t\ttypeof inner === \"object\" &&\n\t\t\t\tinner !== null &&\n\t\t\t\t\"dispose\" in inner &&\n\t\t\t\ttypeof inner.dispose === \"function\"\n\t\t\t) {\n\t\t\t\t// eslint-disable-next-line typescript-eslint/no-unsafe-call -- runtime-guarded\n\t\t\t\tinner.dispose();\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// best-effort cleanup\n\t}\n\tprocess.exit(0);\n}\n\nprocess.stdin.on(\"end\", shutdown);\nprocess.stdin.on(\"close\", shutdown);\nprocess.stdin.resume();\nprocess.on(\"SIGINT\", shutdown);\nprocess.on(\"SIGTERM\", shutdown);\nprocess.stdout.on(\"error\", () => process.exit(0));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["resolvePath","SessionManager","SessionManager","PiSessionManager","PI_VERSION"],"sources":["../src/acp/auth.ts","../src/acp/auth-required.ts","../src/acp/pi-settings.ts","../src/acp/translate/pi-tools.ts","../src/acp/session.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts","../src/pi-auth/status.ts","../src/acp/agent.ts","../src/index.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 * 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\nexport function quietStartupEnabled(cwd: string): boolean {\n\tconst settings = resolvedSettings(cwd);\n\n\tif (typeof settings.quietStartup === \"boolean\") {\n\t\treturn settings.quietStartup;\n\t}\n\n\tif (typeof settings.quietStart === \"boolean\") {\n\t\treturn settings.quietStart;\n\t}\n\n\treturn false;\n}\n","/**\n * Extract displayable text from a pi tool result.\n *\n * Pi tool results have varying shapes depending on the tool. This function\n * tries content blocks first, then falls back to details fields (diff, stdout/stderr),\n * and finally JSON serialization as a last resort.\n */\n\nimport * as z from \"zod\";\n\nconst textBlockSchema = z.object({\n\ttype: z.literal(\"text\"),\n\ttext: z.string(),\n});\n\nconst toolDetailsSchema = z.object({\n\tdiff: z.string().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\nconst toolResultSchema = z.object({\n\tcontent: z.array(z.unknown()).optional(),\n\tdetails: toolDetailsSchema.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\nexport function toolResultToText(result: unknown): string {\n\tif (result === null || result === undefined || typeof result !== \"object\") return \"\";\n\n\tconst parsed = toolResultSchema.safeParse(result);\n\tif (!parsed.success) {\n\t\ttry {\n\t\t\treturn JSON.stringify(result, null, 2);\n\t\t} catch {\n\t\t\treturn String(result);\n\t\t}\n\t}\n\n\tconst r = parsed.data;\n\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) return texts.join(\"\");\n\t}\n\n\tconst d = r.details;\n\n\tconst diff = d?.diff;\n\tif (diff !== undefined && diff.trim() !== \"\") return diff;\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 hasStdout = stdout !== undefined && stdout.trim() !== \"\";\n\tconst hasStderr = stderr !== undefined && stderr.trim() !== \"\";\n\n\tif (hasStdout || hasStderr) {\n\t\tconst parts: string[] = [];\n\t\tif (hasStdout) parts.push(stdout);\n\t\tif (hasStderr) parts.push(`stderr:\\n${stderr}`);\n\t\tif (exitCode !== undefined) parts.push(`exit code: ${exitCode}`);\n\t\treturn parts.join(\"\\n\\n\").trimEnd();\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","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 \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessageEvent, ToolCall } from \"@mariozechner/pi-ai\";\nimport type { AgentSession, AgentSessionEvent } from \"@mariozechner/pi-coding-agent\";\nimport { toolResultToText } from \"@pi-acp/acp/translate/pi-tools\";\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\t\treturn \"execute\";\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\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\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// 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\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\ninterface PiAcpSessionOpts {\n\tsessionId: string;\n\tcwd: string;\n\tmcpServers: McpServer[];\n\tpiSession: AgentSession;\n\tconn: AgentSideConnection;\n}\n\nexport class PiAcpSession {\n\treadonly sessionId: string;\n\treadonly cwd: string;\n\treadonly mcpServers: McpServer[];\n\treadonly piSession: AgentSession;\n\n\tprivate startupInfo: string | null = null;\n\tprivate startupInfoSent = false;\n\tprivate readonly conn: AgentSideConnection;\n\n\tprivate cancelRequested = false;\n\tprivate pendingTurn: { resolve: (r: StopReason) => void; reject: (e: unknown) => void } | null =\n\t\tnull;\n\n\tprivate currentToolCalls = new Map<string, \"pending\" | \"in_progress\">();\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.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\tsetStartupInfo(text: string): void {\n\t\tthis.startupInfo = text;\n\t}\n\n\tsendStartupInfoIfPending(): void {\n\t\tif (this.startupInfoSent || this.startupInfo === null) return;\n\t\tthis.startupInfoSent = true;\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"agent_message_chunk\",\n\t\t\tcontent: { type: \"text\", text: this.startupInfo },\n\t\t});\n\t}\n\n\tasync prompt(message: string, images: unknown[] = []): Promise<StopReason> {\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\tasync cancel(): Promise<void> {\n\t\tthis.cancelRequested = true;\n\t\tawait this.piSession.abort();\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.partialResult);\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_end\":\n\t\t\t\tthis.handleToolEnd(ev.toolCallId, 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\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});\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});\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\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\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\trawInput: args,\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\trawInput: args,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate handleToolUpdate(toolCallId: string, partialResult: unknown): void {\n\t\tconst text = toolResultToText(partialResult);\n\t\tthis.emit({\n\t\t\tsessionUpdate: \"tool_call_update\",\n\t\t\ttoolCallId,\n\t\t\tstatus: \"in_progress\",\n\t\t\tcontent: text\n\t\t\t\t? ([{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[])\n\t\t\t\t: null,\n\t\t\trawOutput: partialResult,\n\t\t});\n\t}\n\n\tprivate handleToolEnd(toolCallId: string, result: unknown, isError: boolean): void {\n\t\tconst text = toolResultToText(result);\n\t\tconst snapshot = this.editSnapshots.get(toolCallId);\n\t\tlet content: ToolCallContent[] | null = null;\n\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\tcontent = [\n\t\t\t\t\t\t{ type: \"diff\", path: snapshot.path, oldText: snapshot.oldText, newText },\n\t\t\t\t\t\t...(text\n\t\t\t\t\t\t\t? ([{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[])\n\t\t\t\t\t\t\t: []),\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// fall back to text\n\t\t\t}\n\t\t}\n\n\t\tif (!content && text) {\n\t\t\tcontent = [{ type: \"content\", content: { type: \"text\", text } }] satisfies ToolCallContent[];\n\t\t}\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\trawOutput: result,\n\t\t});\n\n\t\tthis.currentToolCalls.delete(toolCallId);\n\t\tthis.editSnapshots.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});\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 * 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","/**\n * Detect whether the user has any pi authentication configured.\n *\n * Checks three sources:\n * 1. auth.json (API keys, OAuth credentials)\n * 2. models.json custom provider apiKey entries\n * 3. Known provider environment variables\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport * as z from \"zod\";\n\nconst modelsConfigSchema = z.object({\n\tproviders: z\n\t\t.record(\n\t\t\tz.string().trim(),\n\t\t\tz.object({\n\t\t\t\tapiKey: z.string().trim().optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\nfunction agentDir(): string {\n\tconst env = process.env.PI_CODING_AGENT_DIR;\n\tif (env === undefined) return join(homedir(), \".pi\", \"agent\");\n\tif (env === \"~\") return homedir();\n\tif (env.startsWith(\"~/\")) return homedir() + env.slice(1);\n\treturn env;\n}\n\nfunction readJsonFile(path: string): unknown {\n\ttry {\n\t\tif (!existsSync(path)) return null;\n\t\tconst raw = readFileSync(path, \"utf-8\").trim();\n\t\tif (!raw) return null;\n\t\treturn JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction hasAuthJson(): boolean {\n\tconst data = readJsonFile(join(agentDir(), \"auth.json\"));\n\treturn typeof data === \"object\" && data !== null && Object.keys(data).length > 0;\n}\n\nfunction hasCustomProviderKey(): boolean {\n\tconst raw = readJsonFile(join(agentDir(), \"models.json\"));\n\tconst result = modelsConfigSchema.safeParse(raw);\n\tif (!result.success || !result.data.providers) return false;\n\n\treturn Object.values(result.data.providers).some(\n\t\t(provider) => typeof provider.apiKey === \"string\" && provider.apiKey.trim().length > 0,\n\t);\n}\n\n/** Environment variables that indicate a configured provider API key. */\nconst PROVIDER_ENV_VARS = [\n\t\"ANTHROPIC_API_KEY\",\n\t\"ANTHROPIC_OAUTH_TOKEN\",\n\t\"OPENAI_API_KEY\",\n\t\"AZURE_OPENAI_API_KEY\",\n\t\"GEMINI_API_KEY\",\n\t\"GROQ_API_KEY\",\n\t\"CEREBRAS_API_KEY\",\n\t\"XAI_API_KEY\",\n\t\"OPENROUTER_API_KEY\",\n\t\"AI_GATEWAY_API_KEY\",\n\t\"ZAI_API_KEY\",\n\t\"MISTRAL_API_KEY\",\n\t\"MINIMAX_API_KEY\",\n\t\"MINIMAX_CN_API_KEY\",\n\t\"HF_TOKEN\",\n\t\"OPENCODE_API_KEY\",\n\t\"KIMI_API_KEY\",\n\t\"COPILOT_GITHUB_TOKEN\",\n\t\"GH_TOKEN\",\n\t\"GITHUB_TOKEN\",\n];\n\nfunction hasProviderEnvVar(): boolean {\n\treturn PROVIDER_ENV_VARS.some((key) => {\n\t\tconst val = process.env[key];\n\t\treturn typeof val === \"string\" && val.trim().length > 0;\n\t});\n}\n\nexport function hasPiAuthConfigured(): boolean {\n\treturn hasAuthJson() || hasCustomProviderKey() || hasProviderEnvVar();\n}\n","import { spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\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 \"@mariozechner/pi-agent-core\";\nimport type { AssistantMessage, ToolResultMessage, UserMessage } from \"@mariozechner/pi-ai\";\nimport {\n\ttype AgentSession,\n\ttype CreateAgentSessionResult,\n\tcreateAgentSession,\n\tVERSION as PI_VERSION,\n\tSessionManager as PiSessionManager,\n} from \"@mariozechner/pi-coding-agent\";\nimport { buildAuthMethods } from \"@pi-acp/acp/auth\";\nimport { detectAuthError } from \"@pi-acp/acp/auth-required\";\nimport { quietStartupEnabled, 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 { toolResultToText } from \"@pi-acp/acp/translate/pi-tools\";\nimport { acpPromptToPiMessage } from \"@pi-acp/acp/translate/prompt\";\nimport { hasPiAuthConfigured } from \"@pi-acp/pi-auth/status\";\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\nfunction builtinAvailableCommands(): AvailableCommand[] {\n\treturn [\n\t\t{\n\t\t\tname: \"compact\",\n\t\t\tdescription: \"Manually compact the session context\",\n\t\t\tinput: { hint: \"optional custom instructions\" },\n\t\t},\n\t\t{\n\t\t\tname: \"autocompact\",\n\t\t\tdescription: \"Toggle automatic context compaction\",\n\t\t\tinput: { hint: \"on|off|toggle\" },\n\t\t},\n\t\t{ name: \"export\", description: \"Export session to an HTML file in the session cwd\" },\n\t\t{ name: \"session\", description: \"Show session stats (messages, tokens, cost, session file)\" },\n\t\t{ name: \"name\", description: \"Set session display name\", input: { hint: \"<name>\" } },\n\t\t{\n\t\t\tname: \"steering\",\n\t\t\tdescription: \"Get/set pi steering message delivery mode\",\n\t\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t\t},\n\t\t{\n\t\t\tname: \"follow-up\",\n\t\t\tdescription: \"Get/set pi follow-up message delivery mode\",\n\t\t\tinput: { hint: \"(no args to show) all | one-at-a-time\" },\n\t\t},\n\t\t{ name: \"changelog\", description: \"Show pi changelog\" },\n\t];\n}\n\nfunction mergeCommands(a: AvailableCommand[], b: AvailableCommand[]): AvailableCommand[] {\n\tconst out: AvailableCommand[] = [];\n\tconst seen = new Set<string>();\n\tfor (const c of [...a, ...b]) {\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\nconst pkg = readNearestPackageJson(import.meta.url);\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\n\tdispose(): void {\n\t\tthis.sessions.disposeAll();\n\t}\n\n\tconstructor(conn: AgentSideConnection, _config?: unknown) {\n\t\tthis.conn = conn;\n\t\tvoid _config;\n\t}\n\n\tasync initialize(params: InitializeRequest): Promise<InitializeResponse> {\n\t\tconst supportedVersion = 1;\n\t\tconst requested = params.protocolVersion;\n\n\t\treturn {\n\t\t\tprotocolVersion: requested === supportedVersion ? requested : supportedVersion,\n\t\t\tagentInfo: {\n\t\t\t\tname: pkg.name,\n\t\t\t\ttitle: \"pi ACP adapter\",\n\t\t\t\tversion: pkg.version,\n\t\t\t},\n\t\t\tauthMethods: buildAuthMethods({\n\t\t\t\tsupportsTerminalAuthMeta: params.clientCapabilities?._meta?.[\"terminal-auth\"] === true,\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\tif (!hasPiAuthConfigured()) {\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\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});\n\n\t\tthis.sessions.register(session);\n\n\t\tconst quietStartup = quietStartupEnabled(params.cwd);\n\t\tconst updateNotice = buildUpdateNotice();\n\n\t\tconst preludeText = quietStartup\n\t\t\t? updateNotice !== null\n\t\t\t\t? `${updateNotice}\\n`\n\t\t\t\t: \"\"\n\t\t\t: buildStartupInfo({ cwd: params.cwd, updateNotice });\n\n\t\tif (preludeText) session.setStartupInfo(preludeText);\n\n\t\tconst modes = buildThinkingModes(piSession);\n\t\tconst models = buildModelState(piSession);\n\t\tconst configOptions = buildConfigOptions(modes, models);\n\n\t\tconst response = {\n\t\t\tsessionId: session.sessionId,\n\t\t\tconfigOptions,\n\t\t\tmodes,\n\t\t\tmodels,\n\t\t\t_meta: {\n\t\t\t\tpiAcp: { startupInfo: preludeText || null },\n\t\t\t},\n\t\t};\n\n\t\tif (preludeText) setTimeout(() => session.sendStartupInfoIfPending(), 0);\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: mergeCommands(commands, builtinAvailableCommands()),\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 response;\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},\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},\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst text = toolResultToText(m);\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: text ? [{ type: \"content\", content: { type: \"text\", text } }] : null,\n\t\t\t\t\t\trawOutput: m,\n\t\t\t\t\t\t...(locations ? { locations } : {}),\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 acpSessions: SessionInfo[] = page.map((s) => ({\n\t\t\tsessionId: s.id,\n\t\t\tcwd: s.cwd,\n\t\t\ttitle:\n\t\t\t\t(s.name !== undefined && s.name !== \"\" ? s.name : null) ??\n\t\t\t\ttruncateSessionTitle(s.firstMessage) ??\n\t\t\t\tnull,\n\t\t\tupdatedAt: s.modified.toISOString(),\n\t\t}));\n\n\t\tconst nextCursor = start + PAGE_SIZE < sessions.length ? String(start + PAGE_SIZE) : null;\n\n\t\treturn { sessions: acpSessions, 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});\n\n\t\tthis.sessions.register(session);\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: mergeCommands(commands, builtinAvailableCommands()),\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\t_meta: { piAcp: { startupInfo: null } },\n\t\t};\n\t}\n\n\tasync unstable_closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse> {\n\t\tconst session = this.sessions.maybeGet(params.sessionId);\n\t\tif (session === undefined) {\n\t\t\tthrow RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`);\n\t\t}\n\t\tthis.sessions.close(params.sessionId);\n\t\treturn {};\n\t}\n\n\tasync unstable_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, 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// 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});\n\n\t\tthis.sessions.register(session);\n\t\tthis.sessionPaths.set(params.sessionId, sessionFile);\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: mergeCommands(commands, builtinAvailableCommands()),\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});\n\n\t\tthis.sessions.register(session);\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: mergeCommands(commands, builtinAvailableCommands()),\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\n\t\tlet provider: string | null = null;\n\t\tlet modelId: string | null = null;\n\n\t\tif (params.modelId.includes(\"/\")) {\n\t\t\tconst [p, ...rest] = params.modelId.split(\"/\");\n\t\t\tprovider = p ?? null;\n\t\t\tmodelId = rest.join(\"/\");\n\t\t} else {\n\t\t\tmodelId = params.modelId;\n\t\t}\n\n\t\tif (provider === null) {\n\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\tconst found = available.find((m) => m.id === modelId);\n\t\t\tif (found) {\n\t\t\t\tprovider = found.provider;\n\t\t\t\tmodelId = found.id;\n\t\t\t}\n\t\t}\n\n\t\tif (provider === null || modelId === null) {\n\t\t\tthrow RequestError.invalidParams(`Unknown modelId: ${params.modelId}`);\n\t\t}\n\n\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\tconst model = available.find((m) => m.provider === provider && m.id === modelId);\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\tlet provider: string | null = null;\n\t\t\tlet modelId: string | null = null;\n\n\t\t\tif (value.includes(\"/\")) {\n\t\t\t\tconst [p, ...rest] = value.split(\"/\");\n\t\t\t\tprovider = p ?? null;\n\t\t\t\tmodelId = rest.join(\"/\");\n\t\t\t} else {\n\t\t\t\tmodelId = value;\n\t\t\t}\n\n\t\t\tif (provider === null) {\n\t\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\t\tconst found = available.find((m) => m.id === modelId);\n\t\t\t\tif (found) {\n\t\t\t\t\tprovider = found.provider;\n\t\t\t\t\tmodelId = found.id;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (provider === null || modelId === null) {\n\t\t\t\tthrow RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t}\n\n\t\t\tconst available = session.piSession.modelRegistry.getAvailable();\n\t\t\tconst model = available.find((m) => m.provider === provider && m.id === modelId);\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\tconst runner = piSession.extensionRunner;\n\tif (runner) {\n\t\tfor (const cmd of runner.getRegisteredCommands()) {\n\t\t\tcommands.push({\n\t\t\t\tname: cmd.name,\n\t\t\t\tdescription: cmd.description ?? \"(extension)\",\n\t\t\t});\n\t\t}\n\t}\n\n\treturn commands;\n}\n\nlet cachedUpdateNotice: string | null | undefined;\n\nfunction buildUpdateNotice(): string | null {\n\tif (cachedUpdateNotice !== undefined) return cachedUpdateNotice;\n\ttry {\n\t\tconst installed = PI_VERSION;\n\t\tif (!installed || !isSemver(installed)) {\n\t\t\tcachedUpdateNotice = null;\n\t\t\treturn null;\n\t\t}\n\n\t\tconst latestRes = spawnSync(\"npm\", [\"view\", \"@mariozechner/pi-coding-agent\", \"version\"], {\n\t\t\tencoding: \"utf-8\",\n\t\t\ttimeout: 800,\n\t\t});\n\t\tconst latest = String(latestRes.stdout ?? \"\")\n\t\t\t.trim()\n\t\t\t.replace(/^v/i, \"\");\n\t\tif (!latest || !isSemver(latest)) {\n\t\t\tcachedUpdateNotice = null;\n\t\t\treturn null;\n\t\t}\n\t\tif (compareSemver(latest, installed) <= 0) {\n\t\t\tcachedUpdateNotice = null;\n\t\t\treturn null;\n\t\t}\n\n\t\tcachedUpdateNotice = `New version available: v${latest} (installed v${installed}). Run: \\`npm i -g @mariozechner/pi-coding-agent\\``;\n\t\treturn cachedUpdateNotice;\n\t} catch {\n\t\tcachedUpdateNotice = null;\n\t\treturn null;\n\t}\n}\n\nfunction buildStartupInfo(opts: { cwd: string; updateNotice: string | null }): string {\n\tconst md: string[] = [];\n\n\tif (PI_VERSION) {\n\t\tmd.push(`pi v${PI_VERSION}`);\n\t\tmd.push(\"---\");\n\t\tmd.push(\"\");\n\t}\n\n\tconst addSection = (title: string, items: string[]) => {\n\t\tconst cleaned = items.map((s) => s.trim()).filter(Boolean);\n\t\tif (cleaned.length === 0) return;\n\t\tmd.push(`## ${title}`);\n\t\tfor (const item of cleaned) md.push(`- ${item}`);\n\t\tmd.push(\"\");\n\t};\n\n\tconst contextItems: string[] = [];\n\tconst contextPath = join(opts.cwd, \"AGENTS.md\");\n\tif (existsSync(contextPath)) contextItems.push(contextPath);\n\taddSection(\"Context\", contextItems);\n\n\tif (opts.updateNotice !== undefined && opts.updateNotice !== null) {\n\t\tmd.push(\"---\");\n\t\tmd.push(opts.updateNotice);\n\t\tmd.push(\"\");\n\t}\n\n\treturn `${md.join(\"\\n\").trim()}\\n`;\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\nfunction isSemver(v: string): boolean {\n\treturn /^\\d+\\.\\d+\\.\\d+(?:[-+].+)?$/.test(v);\n}\n\nfunction compareSemver(a: string, b: string): number {\n\tconst pa = a\n\t\t.split(/[.-]/)\n\t\t.slice(0, 3)\n\t\t.map((n) => Number(n));\n\tconst pb = b\n\t\t.split(/[.-]/)\n\t\t.slice(0, 3)\n\t\t.map((n) => Number(n));\n\tfor (let i = 0; i < 3; i++) {\n\t\tconst da = pa[i] ?? 0;\n\t\tconst db = pb[i] ?? 0;\n\t\tif (da > db) return 1;\n\t\tif (da < db) return -1;\n\t}\n\treturn 0;\n}\n\nfunction readNearestPackageJson(metaUrl: string): { name: string; version: string } {\n\tconst fallback = { name: \"pi-acp\", version: \"0.0.0\" };\n\ttry {\n\t\tlet dir = dirname(fileURLToPath(metaUrl));\n\t\tfor (let i = 0; i < 6; i++) {\n\t\t\tconst p = join(dir, \"package.json\");\n\t\t\tif (existsSync(p)) {\n\t\t\t\tconst raw: unknown = JSON.parse(readFileSync(p, \"utf-8\"));\n\t\t\t\tif (typeof raw !== \"object\" || raw === null) return fallback;\n\t\t\t\tconst name = \"name\" in raw && typeof raw.name === \"string\" ? raw.name : fallback.name;\n\t\t\t\tconst version =\n\t\t\t\t\t\"version\" in raw && typeof raw.version === \"string\" ? raw.version : fallback.version;\n\t\t\t\treturn { name, version };\n\t\t\t}\n\t\t\tdir = dirname(dir);\n\t\t}\n\t} catch {\n\t\t// fall through\n\t}\n\treturn fallback;\n}\n","import { platform } from \"node:os\";\nimport { AgentSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\";\nimport { PiAcpAgent } from \"@pi-acp/acp/agent\";\n\n// Terminal Auth entrypoint: ACP client launches with `--terminal-login`.\nif (process.argv.includes(\"--terminal-login\")) {\n\tconst { spawnSync } = await import(\"node:child_process\");\n\tconst isWindows = platform() === \"win32\";\n\tconst cmd = process.env.PI_ACP_PI_COMMAND ?? (isWindows ? \"pi.cmd\" : \"pi\");\n\tconst res = spawnSync(cmd, [], { stdio: \"inherit\", env: process.env });\n\n\tif (res.error && \"code\" in res.error && res.error.code === \"ENOENT\") {\n\t\tprocess.stderr.write(\n\t\t\t`pi-acp: could not start pi (command not found: ${cmd}). ` +\n\t\t\t\t\"Install via `npm install -g @mariozechner/pi-coding-agent` \" +\n\t\t\t\t\"or ensure `pi` is on your PATH.\\n\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tprocess.exit(typeof res.status === \"number\" ? res.status : 1);\n}\n\nconst input = new WritableStream<Uint8Array>({\n\twrite(chunk) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tif (process.stdout.destroyed || !process.stdout.writable) {\n\t\t\t\tresolve();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tprocess.stdout.write(chunk, () => resolve());\n\t\t\t} catch {\n\t\t\t\tresolve();\n\t\t\t}\n\t\t});\n\t},\n});\n\nconst output = new ReadableStream<Uint8Array>({\n\tstart(controller) {\n\t\tprocess.stdin.on(\"data\", (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)));\n\t\tprocess.stdin.on(\"end\", () => controller.close());\n\t\tprocess.stdin.on(\"error\", (err) => controller.error(err));\n\t},\n});\n\nconst stream = ndJsonStream(input, output);\nconst agent = new AgentSideConnection((conn) => new PiAcpAgent(conn), stream);\n\nfunction shutdown() {\n\ttry {\n\t\t// AgentSideConnection stores the agent instance internally;\n\t\t// call dispose() on it if available for clean shutdown.\n\t\tif (\"agent\" in agent) {\n\t\t\tconst inner: unknown = agent.agent;\n\t\t\tif (\n\t\t\t\ttypeof inner === \"object\" &&\n\t\t\t\tinner !== null &&\n\t\t\t\t\"dispose\" in inner &&\n\t\t\t\ttypeof inner.dispose === \"function\"\n\t\t\t) {\n\t\t\t\t// eslint-disable-next-line typescript-eslint/no-unsafe-call -- runtime-guarded\n\t\t\t\tinner.dispose();\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// best-effort cleanup\n\t}\n\tprocess.exit(0);\n}\n\nprocess.stdin.on(\"end\", shutdown);\nprocess.stdin.on(\"close\", shutdown);\nprocess.stdin.resume();\nprocess.on(\"SIGINT\", shutdown);\nprocess.on(\"SIGTERM\", shutdown);\nprocess.stdout.on(\"error\", () => process.exit(0));\n"],"mappings":"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"}
|