pi-acp 0.0.15 → 0.0.17
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 +27 -29
- package/dist/index.js +5 -203
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ ACP ([Agent Client Protocol](https://agentclientprotocol.com/overview/introducti
|
|
|
6
6
|
|
|
7
7
|
## Status
|
|
8
8
|
|
|
9
|
-
This is an MVP-style adapter intended to be useful today and easy to iterate on.
|
|
9
|
+
This is an MVP-style adapter intended to be useful today and easy to iterate on. Some ACP features may be not implemented or are not supported (see [Limitations](#limitations)). Development is centered around Zed editor support, other clients may have varying levels of compatibility.
|
|
10
10
|
|
|
11
11
|
## How it works
|
|
12
12
|
|
|
@@ -33,6 +33,8 @@ High-level mapping:
|
|
|
33
33
|
- Adds a small set of built-in commands for headless/editor usage
|
|
34
34
|
- Skills are loaded by pi directly and are available in ACP sessions
|
|
35
35
|
- (Zed) On session start, `pi-acp` posts a markdown “startup info” block (pi version, context file, skills, prompts, extensions)
|
|
36
|
+
- (Zed) By default, `pi-acp` emits a short markdown “startup info” block into the session (pi version, context, skills, prompts, extensions - similar to `pi` in the terminal). You can disable it by setting: `PI_ACP_STARTUP_INFO=false` (see below)
|
|
37
|
+
- (Zed) Session history is supported in Zed starting with [`v0.225.0`](https://zed.dev/releases/preview/0.225.0). Session loading / history maps to pi's session files. Sessions can be resumed both in `pi` and in the ACP client.
|
|
36
38
|
|
|
37
39
|
## Prerequisites
|
|
38
40
|
|
|
@@ -52,7 +54,7 @@ npm install -g @mariozechner/pi-coding-agent
|
|
|
52
54
|
|
|
53
55
|
Add the following to your Zed `settngs.json`:
|
|
54
56
|
|
|
55
|
-
#### Using with `npx` (no global install needed):
|
|
57
|
+
#### Using with `npx` (no global install needed, always loads the latest version):
|
|
56
58
|
|
|
57
59
|
```json
|
|
58
60
|
"agent_servers": {
|
|
@@ -61,7 +63,7 @@ Add the following to your Zed `settngs.json`:
|
|
|
61
63
|
"command": "npx",
|
|
62
64
|
"args": ["-y", "pi-acp"],
|
|
63
65
|
"env": {
|
|
64
|
-
"PI_ACP_STARTUP_INFO": "true"
|
|
66
|
+
"PI_ACP_STARTUP_INFO": "true" // optional, "true" by default
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
}
|
|
@@ -79,9 +81,7 @@ npm install -g pi-acp
|
|
|
79
81
|
"type": "custom",
|
|
80
82
|
"command": "pi-acp",
|
|
81
83
|
"args": [],
|
|
82
|
-
"env": {
|
|
83
|
-
"PI_ACP_STARTUP_INFO": "true"
|
|
84
|
-
}
|
|
84
|
+
"env": {}
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
```
|
|
@@ -101,31 +101,11 @@ Point your ACP client to the built `dist/index.js`:
|
|
|
101
101
|
"type": "custom",
|
|
102
102
|
"command": "node",
|
|
103
103
|
"args": ["/path/to/pi-acp/dist/index.js"],
|
|
104
|
-
"env": {
|
|
105
|
-
"PI_ACP_STARTUP_INFO": "true"
|
|
106
|
-
}
|
|
104
|
+
"env": {}
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
107
|
```
|
|
110
108
|
|
|
111
|
-
## Features
|
|
112
|
-
|
|
113
|
-
### Startup info message (Zed)
|
|
114
|
-
|
|
115
|
-
By default, `pi-acp` emits a short markdown “startup info” block into the session (pi version, context, skills, prompts, extensions).
|
|
116
|
-
|
|
117
|
-
Disable it by setting:
|
|
118
|
-
|
|
119
|
-
- `PI_ACP_STARTUP_INFO=false`
|
|
120
|
-
|
|
121
|
-
In Zed:
|
|
122
|
-
|
|
123
|
-
```json
|
|
124
|
-
"env": {
|
|
125
|
-
"PI_ACP_STARTUP_INFO": "false"
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
109
|
### Slash commands
|
|
130
110
|
|
|
131
111
|
`pi-acp` supports slash commands:
|
|
@@ -156,7 +136,25 @@ Other built-in commands:
|
|
|
156
136
|
- `/thinking` - maps to 'mode' selector in Zed
|
|
157
137
|
- `/clear` - not implemented (use ACP client 'new' command)
|
|
158
138
|
|
|
159
|
-
|
|
139
|
+
#### 3) Skill commands
|
|
140
|
+
|
|
141
|
+
- Skill commands can be enabled in pi settings and will appear in the slash command list in ACP host as `/skill:skill-name`.
|
|
142
|
+
|
|
143
|
+
**Note**: Slash commands provided by pi extensions are not currently supported.
|
|
144
|
+
|
|
145
|
+
## Authentication / Setup (ACP Registry)
|
|
146
|
+
|
|
147
|
+
This agent supports **Terminal Auth** for the ACP Registry.
|
|
148
|
+
|
|
149
|
+
In Zed, this will show an **Authenticate** banner that launches pi in a terminal.
|
|
150
|
+
|
|
151
|
+
Launch pi in a terminal for interactive login/setup:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pi-acp --terminal-login
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Your ACP client can also invoke this automatically based on the agent's advertised `authMethods`.
|
|
160
158
|
|
|
161
159
|
## Development
|
|
162
160
|
|
|
@@ -179,7 +177,7 @@ Project layout:
|
|
|
179
177
|
- MCP servers are accepted in ACP params and stored in session state, but not wired through to pi.
|
|
180
178
|
- Assistant streaming is currently sent as `agent_message_chunk` (no separate thought stream).
|
|
181
179
|
- Queue is implemented client-side and should work like pi's `one-at-a-time`
|
|
182
|
-
- ACP clients don't yet suport session history, but ACP sessions from `pi-acp` can be `/resume`d in pi directly
|
|
180
|
+
- ~~ACP clients don't yet suport session history, but ACP sessions from `pi-acp` can be `/resume`d in pi directly~~
|
|
183
181
|
|
|
184
182
|
## License
|
|
185
183
|
|
package/dist/index.js
CHANGED
|
@@ -16,14 +16,10 @@ import { isAbsolute, resolve as resolvePath } from "path";
|
|
|
16
16
|
// src/pi-rpc/process.ts
|
|
17
17
|
import { spawn } from "child_process";
|
|
18
18
|
import * as readline from "readline";
|
|
19
|
-
function stripAnsi(s) {
|
|
20
|
-
return s.replace(/[\u001B\u009B][[\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
|
|
21
|
-
}
|
|
22
19
|
var PiRpcProcess = class _PiRpcProcess {
|
|
23
20
|
child;
|
|
24
21
|
pending = /* @__PURE__ */ new Map();
|
|
25
22
|
eventHandlers = [];
|
|
26
|
-
preludeLines = [];
|
|
27
23
|
constructor(child) {
|
|
28
24
|
this.child = child;
|
|
29
25
|
const rl = readline.createInterface({ input: child.stdout });
|
|
@@ -33,8 +29,6 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
33
29
|
try {
|
|
34
30
|
msg = JSON.parse(line);
|
|
35
31
|
} catch {
|
|
36
|
-
const cleaned = stripAnsi(String(line)).trimEnd();
|
|
37
|
-
if (cleaned) this.preludeLines.push(cleaned);
|
|
38
32
|
return;
|
|
39
33
|
}
|
|
40
34
|
if (msg?.type === "response") {
|
|
@@ -86,14 +80,6 @@ var PiRpcProcess = class _PiRpcProcess {
|
|
|
86
80
|
this.eventHandlers = this.eventHandlers.filter((h) => h !== handler);
|
|
87
81
|
};
|
|
88
82
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Human-readable stdout lines emitted before RPC NDJSON begins (e.g. Context/Skills/Extensions info).
|
|
91
|
-
* Themes are typically noisy/less useful for ACP, so callers can filter as needed.
|
|
92
|
-
*/
|
|
93
|
-
consumePreludeLines() {
|
|
94
|
-
const lines = this.preludeLines.splice(0, this.preludeLines.length);
|
|
95
|
-
return lines;
|
|
96
|
-
}
|
|
97
83
|
async prompt(message, attachments = []) {
|
|
98
84
|
const res = await this.request({ type: "prompt", message, attachments });
|
|
99
85
|
if (!res.success) throw new Error(`pi prompt failed: ${res.error ?? JSON.stringify(res.data)}`);
|
|
@@ -441,8 +427,6 @@ var PiAcpSession = class {
|
|
|
441
427
|
sessionId;
|
|
442
428
|
cwd;
|
|
443
429
|
mcpServers;
|
|
444
|
-
startupInfo = null;
|
|
445
|
-
startupInfoSent = false;
|
|
446
430
|
proc;
|
|
447
431
|
conn;
|
|
448
432
|
fileCommands;
|
|
@@ -475,30 +459,7 @@ var PiAcpSession = class {
|
|
|
475
459
|
this.fileCommands = opts.fileCommands ?? [];
|
|
476
460
|
this.proc.onEvent((ev) => this.handlePiEvent(ev));
|
|
477
461
|
}
|
|
478
|
-
setStartupInfo(text) {
|
|
479
|
-
this.startupInfo = text;
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Best-effort attempt to send startup info outside of a prompt turn.
|
|
483
|
-
* Some clients (e.g. Zed) may only render agent messages once the UI is ready;
|
|
484
|
-
* callers can invoke this shortly after session/new returns.
|
|
485
|
-
*/
|
|
486
|
-
sendStartupInfoIfPending() {
|
|
487
|
-
if (this.startupInfoSent || !this.startupInfo) return;
|
|
488
|
-
this.startupInfoSent = true;
|
|
489
|
-
this.emit({
|
|
490
|
-
sessionUpdate: "agent_message_chunk",
|
|
491
|
-
content: { type: "text", text: this.startupInfo }
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
462
|
async prompt(message, attachments = []) {
|
|
495
|
-
if (!this.startupInfoSent && this.startupInfo) {
|
|
496
|
-
this.startupInfoSent = true;
|
|
497
|
-
this.emit({
|
|
498
|
-
sessionUpdate: "agent_message_chunk",
|
|
499
|
-
content: { type: "text", text: this.startupInfo }
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
463
|
const expandedMessage = expandSlashCommand(message, this.fileCommands);
|
|
503
464
|
const turnPromise = new Promise((resolve2, reject) => {
|
|
504
465
|
const queued = { message: expandedMessage, attachments, resolve: resolve2, reject };
|
|
@@ -842,18 +803,10 @@ ${r.text}`;
|
|
|
842
803
|
|
|
843
804
|
// src/acp/agent.ts
|
|
844
805
|
import { isAbsolute as isAbsolute2 } from "path";
|
|
845
|
-
import { existsSync as existsSync2, readFileSync as readFileSync4, realpathSync
|
|
846
|
-
import { join as join3, dirname as dirname2
|
|
806
|
+
import { existsSync as existsSync2, readFileSync as readFileSync4, realpathSync } from "fs";
|
|
807
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
847
808
|
import { spawnSync } from "child_process";
|
|
848
809
|
import { fileURLToPath } from "url";
|
|
849
|
-
function booleanEnv(name, defaultValue) {
|
|
850
|
-
const raw = process.env[name];
|
|
851
|
-
if (raw == null) return defaultValue;
|
|
852
|
-
const v = String(raw).trim().toLowerCase();
|
|
853
|
-
if (v === "true") return true;
|
|
854
|
-
if (v === "false") return false;
|
|
855
|
-
return defaultValue;
|
|
856
|
-
}
|
|
857
810
|
function builtinAvailableCommands() {
|
|
858
811
|
return [
|
|
859
812
|
{
|
|
@@ -905,9 +858,8 @@ var PiAcpAgent = class {
|
|
|
905
858
|
conn;
|
|
906
859
|
sessions = new SessionManager();
|
|
907
860
|
store = new SessionStore();
|
|
908
|
-
constructor(conn
|
|
861
|
+
constructor(conn) {
|
|
909
862
|
this.conn = conn;
|
|
910
|
-
void _config;
|
|
911
863
|
}
|
|
912
864
|
async initialize(params) {
|
|
913
865
|
const supportedVersion = 1;
|
|
@@ -945,20 +897,12 @@ var PiAcpAgent = class {
|
|
|
945
897
|
});
|
|
946
898
|
const models = await getModelState(session.proc);
|
|
947
899
|
const thinking = await getThinkingState(session.proc);
|
|
948
|
-
const showStartupInfo = booleanEnv("PI_ACP_STARTUP_INFO", true);
|
|
949
|
-
const preludeText = showStartupInfo ? buildStartupInfo({ cwd: params.cwd, fileCommands }) : "";
|
|
950
|
-
if (preludeText) session.setStartupInfo(preludeText);
|
|
951
900
|
const response = {
|
|
952
901
|
sessionId: session.sessionId,
|
|
953
902
|
models,
|
|
954
903
|
modes: thinking,
|
|
955
|
-
_meta: {
|
|
956
|
-
piAcp: {
|
|
957
|
-
startupInfo: preludeText || null
|
|
958
|
-
}
|
|
959
|
-
}
|
|
904
|
+
_meta: {}
|
|
960
905
|
};
|
|
961
|
-
if (showStartupInfo) setTimeout(() => session.sendStartupInfoIfPending(), 0);
|
|
962
906
|
setTimeout(() => {
|
|
963
907
|
void this.conn.sessionUpdate({
|
|
964
908
|
sessionId: session.sessionId,
|
|
@@ -1363,19 +1307,11 @@ ${JSON.stringify(stats, null, 2)}`;
|
|
|
1363
1307
|
}
|
|
1364
1308
|
const models = await getModelState(proc);
|
|
1365
1309
|
const thinking = await getThinkingState(proc);
|
|
1366
|
-
const showStartupInfo = booleanEnv("PI_ACP_STARTUP_INFO", true);
|
|
1367
|
-
const preludeText = showStartupInfo ? buildStartupInfo({ cwd: params.cwd, fileCommands }) : "";
|
|
1368
|
-
if (preludeText) session.setStartupInfo(preludeText);
|
|
1369
1310
|
const response = {
|
|
1370
1311
|
models,
|
|
1371
1312
|
modes: thinking,
|
|
1372
|
-
_meta: {
|
|
1373
|
-
piAcp: {
|
|
1374
|
-
startupInfo: preludeText || null
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1313
|
+
_meta: {}
|
|
1377
1314
|
};
|
|
1378
|
-
if (showStartupInfo) setTimeout(() => session.sendStartupInfoIfPending(), 0);
|
|
1379
1315
|
setTimeout(() => {
|
|
1380
1316
|
void this.conn.sessionUpdate({
|
|
1381
1317
|
sessionId: session.sessionId,
|
|
@@ -1486,140 +1422,6 @@ async function getModelState(proc) {
|
|
|
1486
1422
|
currentModelId
|
|
1487
1423
|
};
|
|
1488
1424
|
}
|
|
1489
|
-
function isSemver(v) {
|
|
1490
|
-
return /^\d+\.\d+\.\d+(?:[-+].+)?$/.test(v);
|
|
1491
|
-
}
|
|
1492
|
-
function compareSemver(a, b) {
|
|
1493
|
-
const pa = a.split(/[.-]/).slice(0, 3).map((n) => Number(n));
|
|
1494
|
-
const pb = b.split(/[.-]/).slice(0, 3).map((n) => Number(n));
|
|
1495
|
-
for (let i = 0; i < 3; i++) {
|
|
1496
|
-
const da = pa[i] ?? 0;
|
|
1497
|
-
const db = pb[i] ?? 0;
|
|
1498
|
-
if (da > db) return 1;
|
|
1499
|
-
if (da < db) return -1;
|
|
1500
|
-
}
|
|
1501
|
-
return 0;
|
|
1502
|
-
}
|
|
1503
|
-
function buildStartupInfo(opts) {
|
|
1504
|
-
void opts.fileCommands;
|
|
1505
|
-
const md = [];
|
|
1506
|
-
let updateNotice = null;
|
|
1507
|
-
try {
|
|
1508
|
-
const piVersion = spawnSync("pi", ["--version"], { encoding: "utf-8" });
|
|
1509
|
-
const installed = String(piVersion.stdout ?? "").trim().replace(/^v/i, "");
|
|
1510
|
-
if (installed) {
|
|
1511
|
-
md.push(`pi v${installed}`);
|
|
1512
|
-
md.push("---");
|
|
1513
|
-
md.push("");
|
|
1514
|
-
try {
|
|
1515
|
-
const latestRes = spawnSync("npm", ["view", "@mariozechner/pi-coding-agent", "version"], {
|
|
1516
|
-
encoding: "utf-8",
|
|
1517
|
-
timeout: 800
|
|
1518
|
-
});
|
|
1519
|
-
const latest = String(latestRes.stdout ?? "").trim().replace(/^v/i, "");
|
|
1520
|
-
if (latest && isSemver(latest) && isSemver(installed) && compareSemver(latest, installed) > 0) {
|
|
1521
|
-
updateNotice = `New version available: v${latest} (installed v${installed}). Run: \`npm i -g @mariozechner/pi-coding-agent\``;
|
|
1522
|
-
}
|
|
1523
|
-
} catch {
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
} catch {
|
|
1527
|
-
}
|
|
1528
|
-
const addSection = (title, items) => {
|
|
1529
|
-
const cleaned = items.map((s) => s.trim()).filter(Boolean);
|
|
1530
|
-
if (!cleaned.length) return;
|
|
1531
|
-
md.push(`## ${title}`);
|
|
1532
|
-
for (const item of cleaned) md.push(`- ${item}`);
|
|
1533
|
-
md.push("");
|
|
1534
|
-
};
|
|
1535
|
-
const contextItems = [];
|
|
1536
|
-
const contextPath = join3(opts.cwd, "AGENTS.md");
|
|
1537
|
-
if (existsSync2(contextPath)) contextItems.push(contextPath);
|
|
1538
|
-
addSection("Context", contextItems);
|
|
1539
|
-
const skillsItems = [];
|
|
1540
|
-
const pushSkillFromRoot = (root) => {
|
|
1541
|
-
try {
|
|
1542
|
-
for (const e of readdirSync2(root)) {
|
|
1543
|
-
const p = join3(root, e);
|
|
1544
|
-
try {
|
|
1545
|
-
const st = statSync(p);
|
|
1546
|
-
if (st.isFile() && e.toLowerCase().endsWith(".md")) {
|
|
1547
|
-
skillsItems.push(p);
|
|
1548
|
-
}
|
|
1549
|
-
} catch {
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
const stack = [root];
|
|
1553
|
-
while (stack.length) {
|
|
1554
|
-
const dir = stack.pop();
|
|
1555
|
-
let entries = [];
|
|
1556
|
-
try {
|
|
1557
|
-
entries = readdirSync2(dir);
|
|
1558
|
-
} catch {
|
|
1559
|
-
continue;
|
|
1560
|
-
}
|
|
1561
|
-
for (const name of entries) {
|
|
1562
|
-
if (name === "node_modules" || name === ".git") continue;
|
|
1563
|
-
const p = join3(dir, name);
|
|
1564
|
-
let st;
|
|
1565
|
-
try {
|
|
1566
|
-
st = statSync(p);
|
|
1567
|
-
} catch {
|
|
1568
|
-
continue;
|
|
1569
|
-
}
|
|
1570
|
-
if (st.isDirectory()) {
|
|
1571
|
-
stack.push(p);
|
|
1572
|
-
} else if (st.isFile() && name === "SKILL.md") {
|
|
1573
|
-
skillsItems.push(p);
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
} catch {
|
|
1578
|
-
}
|
|
1579
|
-
};
|
|
1580
|
-
const globalSkillsDir = join3(process.env.HOME ?? "", ".pi", "agent", "skills");
|
|
1581
|
-
pushSkillFromRoot(globalSkillsDir);
|
|
1582
|
-
const projectSkillsDir = join3(opts.cwd, ".pi", "skills");
|
|
1583
|
-
pushSkillFromRoot(projectSkillsDir);
|
|
1584
|
-
addSection("Skills", skillsItems);
|
|
1585
|
-
const promptsItems = [];
|
|
1586
|
-
const promptsDir = join3(process.env.HOME ?? "", ".pi", "agent", "prompts");
|
|
1587
|
-
try {
|
|
1588
|
-
const prompts = readdirSync2(promptsDir).filter((f) => f.endsWith(".md"));
|
|
1589
|
-
for (const f of prompts) promptsItems.push(`/${basename(f, ".md")}`);
|
|
1590
|
-
} catch {
|
|
1591
|
-
}
|
|
1592
|
-
addSection("Prompts", promptsItems);
|
|
1593
|
-
const extItems = [];
|
|
1594
|
-
const extDir = join3(process.env.HOME ?? "", ".pi", "agent", "extensions");
|
|
1595
|
-
try {
|
|
1596
|
-
const exts = readdirSync2(extDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
1597
|
-
for (const f of exts) extItems.push(join3(extDir, f));
|
|
1598
|
-
} catch {
|
|
1599
|
-
}
|
|
1600
|
-
try {
|
|
1601
|
-
const settingsPath = join3(process.env.HOME ?? "", ".pi", "agent", "settings.json");
|
|
1602
|
-
const settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
|
|
1603
|
-
const pkgs = Array.isArray(settings?.packages) ? settings.packages : [];
|
|
1604
|
-
for (const pkg2 of pkgs) {
|
|
1605
|
-
const s = String(pkg2);
|
|
1606
|
-
if (s.startsWith("npm:")) {
|
|
1607
|
-
extItems.push(`${s}
|
|
1608
|
-
- index.ts`);
|
|
1609
|
-
} else {
|
|
1610
|
-
extItems.push(s);
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
} catch {
|
|
1614
|
-
}
|
|
1615
|
-
addSection("Extensions", extItems);
|
|
1616
|
-
if (updateNotice) {
|
|
1617
|
-
md.push("---");
|
|
1618
|
-
md.push(updateNotice);
|
|
1619
|
-
md.push("");
|
|
1620
|
-
}
|
|
1621
|
-
return md.join("\n").trim() + "\n";
|
|
1622
|
-
}
|
|
1623
1425
|
function readNearestPackageJson(metaUrl) {
|
|
1624
1426
|
try {
|
|
1625
1427
|
let dir = dirname2(fileURLToPath(metaUrl));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/acp/agent.ts","../src/acp/session.ts","../src/pi-rpc/process.ts","../src/acp/session-store.ts","../src/acp/paths.ts","../src/acp/translate/pi-tools.ts","../src/acp/slash-commands.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts"],"sourcesContent":["import { AgentSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'\nimport { PiAcpAgent } from './acp/agent.js'\n\n\nconst input = new WritableStream<Uint8Array>({\n write(chunk) {\n return new Promise<void>((resolve, reject) => {\n process.stdout.write(chunk, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n})\n\nconst output = new ReadableStream<Uint8Array>({\n start(controller) {\n process.stdin.on('data', (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)))\n process.stdin.on('end', () => controller.close())\n process.stdin.on('error', err => controller.error(err))\n }\n})\n\nconst stream = ndJsonStream(input, output)\n\nnew AgentSideConnection(conn => new PiAcpAgent(conn), stream)\n\nprocess.stdin.resume()\nprocess.on('SIGINT', () => process.exit(0))\nprocess.on('SIGTERM', () => process.exit(0))\n","import {\n RequestError,\n type Agent as ACPAgent,\n type AgentSideConnection,\n type AuthenticateRequest,\n type CancelNotification,\n type InitializeRequest,\n type InitializeResponse,\n type LoadSessionRequest,\n type LoadSessionResponse,\n type ModelInfo,\n type NewSessionRequest,\n type PromptRequest,\n type PromptResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n type StopReason\n} from '@agentclientprotocol/sdk'\nimport { SessionManager } from './session.js'\nimport { SessionStore } from './session-store.js'\nimport { PiRpcProcess } from '../pi-rpc/process.js'\nimport { normalizePiAssistantText, normalizePiMessageText } from './translate/pi-messages.js'\nimport { promptToPiMessage } from './translate/prompt.js'\nimport { loadSlashCommands, parseCommandArgs, toAvailableCommands } from './slash-commands.js'\nimport { isAbsolute } from 'node:path'\nimport { existsSync, readFileSync, realpathSync, readdirSync, statSync } from 'node:fs'\nimport type { AvailableCommand } from '@agentclientprotocol/sdk'\nimport { join, dirname, basename } from 'node:path'\nimport { spawnSync } from 'node:child_process'\n\ntype ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'\n\nfunction booleanEnv(name: string, defaultValue: boolean): boolean {\n const raw = process.env[name]\n if (raw == null) return defaultValue\n const v = String(raw).trim().toLowerCase()\n if (v === 'true') return true\n if (v === 'false') return false\n return defaultValue\n}\n\nfunction builtinAvailableCommands(): AvailableCommand[] {\n return [\n {\n name: 'compact',\n description: 'Manually compact the session context',\n input: { hint: 'optional custom instructions' }\n },\n {\n name: 'autocompact',\n description: 'Toggle automatic context compaction',\n input: { hint: 'on|off|toggle' }\n },\n {\n name: 'export',\n description: 'Export session to an HTML file in the session cwd'\n },\n {\n name: 'session',\n description: 'Show session stats (messages, tokens, cost, session file)'\n },\n {\n name: 'steering',\n description: 'Get/set pi steering message delivery mode (how queued steering messages are delivered)',\n input: { hint: '(no args to show) all | one-at-a-time' }\n },\n {\n name: 'follow-up',\n description: 'Get/set pi follow-up message delivery mode (how queued follow-up messages are delivered)',\n input: { hint: '(no args to show) all | one-at-a-time' }\n },\n {\n name: 'changelog',\n description: 'Show pi changelog'\n }\n ]\n}\n\nfunction mergeCommands(a: AvailableCommand[], b: AvailableCommand[]): AvailableCommand[] {\n // Preserve order, de-dupe by name (first wins).\n const out: AvailableCommand[] = []\n const seen = new Set<string>()\n\n for (const c of [...a, ...b]) {\n if (seen.has(c.name)) continue\n seen.add(c.name)\n out.push(c)\n }\n\n return out\n}\nimport { fileURLToPath } from 'node:url'\n\nconst pkg = readNearestPackageJson(import.meta.url)\n\nexport class PiAcpAgent implements ACPAgent {\n private readonly conn: AgentSideConnection\n private readonly sessions = new SessionManager()\n private readonly store = new SessionStore()\n\n constructor(conn: AgentSideConnection, _config?: unknown) {\n this.conn = conn\n void _config\n }\n\n async initialize(params: InitializeRequest): Promise<InitializeResponse> {\n // We currently only support ACP protocol version 1.\n const supportedVersion = 1\n const requested = params.protocolVersion\n\n return {\n protocolVersion: requested === supportedVersion ? requested : supportedVersion,\n agentInfo: {\n name: pkg.name ?? 'pi-acp',\n title: 'pi ACP adapter',\n version: pkg.version ?? '0.0.0'\n },\n authMethods: [],\n agentCapabilities: {\n loadSession: true,\n mcpCapabilities: { http: false, sse: false },\n promptCapabilities: {\n image: true,\n audio: false,\n embeddedContext: false\n },\n sessionCapabilities: {}\n }\n }\n }\n\n async newSession(params: NewSessionRequest) {\n if (!isAbsolute(params.cwd)) {\n throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`)\n }\n\n const fileCommands = loadSlashCommands(params.cwd)\n\n // Pi doesn't support mcpServers, but we accept and store.\n const session = await this.sessions.create({\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n conn: this.conn,\n fileCommands\n })\n\n const models = await getModelState(session.proc)\n const thinking = await getThinkingState(session.proc)\n\n const showStartupInfo = booleanEnv('PI_ACP_STARTUP_INFO', true)\n\n // In pi --mode rpc there typically is no human-readable prelude on stdout.\n // So we synthesize a similar \"startup info\" block from local data and emit it.\n const preludeText = showStartupInfo ? buildStartupInfo({ cwd: params.cwd, fileCommands }) : ''\n if (preludeText) session.setStartupInfo(preludeText)\n\n const response = {\n sessionId: session.sessionId,\n models,\n modes: thinking,\n _meta: {\n piAcp: {\n startupInfo: preludeText || null\n }\n }\n }\n\n // Try to send it immediately after session/new returns; if the client ignores it,\n // it will still be emitted as the first chunk of the first prompt.\n if (showStartupInfo) setTimeout(() => session.sendStartupInfoIfPending(), 0)\n\n // Advertise slash commands (ACP: available_commands_update)\n // Important: some clients (e.g. Zed) will ignore notifications for an unknown sessionId.\n // So we must send this *after* the session/new response has been delivered.\n setTimeout(() => {\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'available_commands_update',\n availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())\n }\n })\n }, 0)\n\n return response\n }\n\n async authenticate(_params: AuthenticateRequest) {\n // MVP: no auth.\n return\n }\n\n async prompt(params: PromptRequest): Promise<PromptResponse> {\n const session = this.sessions.get(params.sessionId)\n\n const { message, attachments } = promptToPiMessage(params.prompt)\n\n // Built-in ACP slash command handling (headless-friendly subset).\n // Note: file-based slash commands are expanded inside session.prompt().\n if (attachments.length === 0 && message.trimStart().startsWith('/')) {\n const trimmed = message.trim()\n const space = trimmed.indexOf(' ')\n const cmd = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space)\n const argsString = space === -1 ? '' : trimmed.slice(space + 1)\n const args = parseCommandArgs(argsString)\n\n if (cmd === 'compact') {\n const customInstructions = args.join(' ').trim() || undefined\n const res = await session.proc.compact(customInstructions)\n\n const r: any = res && typeof res === 'object' ? (res as any) : null\n const tokensBefore = typeof r?.tokensBefore === 'number' ? r.tokensBefore : null\n const summary = typeof r?.summary === 'string' ? r.summary : null\n\n const headerLines = [\n `Compaction completed.${customInstructions ? ' (custom instructions applied)' : ''}`,\n tokensBefore !== null ? `Tokens before: ${tokensBefore}` : null\n ].filter(Boolean)\n\n const text = headerLines.join('\\n') + (summary ? `\\n\\n${summary}` : '')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'session') {\n const stats = (await session.proc.getSessionStats()) as any\n\n const lines: string[] = []\n if (stats?.sessionId) lines.push(`Session: ${stats.sessionId}`)\n if (stats?.sessionFile) lines.push(`Session file: ${stats.sessionFile}`)\n if (typeof stats?.totalMessages === 'number') lines.push(`Messages: ${stats.totalMessages}`)\n\n if (typeof stats?.cost === 'number') lines.push(`Cost: ${stats.cost}`)\n\n const t = stats?.tokens\n if (t && typeof t === 'object') {\n const parts: string[] = []\n if (typeof t.input === 'number') parts.push(`in ${t.input}`)\n if (typeof t.output === 'number') parts.push(`out ${t.output}`)\n if (typeof t.cacheRead === 'number') parts.push(`cache read ${t.cacheRead}`)\n if (typeof t.cacheWrite === 'number') parts.push(`cache write ${t.cacheWrite}`)\n if (typeof t.total === 'number') parts.push(`total ${t.total}`)\n if (parts.length) lines.push(`Tokens: ${parts.join(', ')}`)\n }\n\n // Fallback if stats shape changes.\n const text = lines.length ? lines.join('\\n') : `Session stats:\\n${JSON.stringify(stats, null, 2)}`\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'steering') {\n const modeRaw = String(args[0] ?? '').toLowerCase()\n const state = (await session.proc.getState()) as any\n const current = String(state?.steeringMode ?? '')\n\n // If no arg, just report current.\n if (!modeRaw) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Steering mode: ${current || 'unknown'}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (modeRaw !== 'all' && modeRaw !== 'one-at-a-time') {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Usage: /steering all | /steering one-at-a-time'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n await session.proc.setSteeringMode(modeRaw as 'all' | 'one-at-a-time')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Steering mode set to: ${modeRaw}` }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'follow-up') {\n const modeRaw = String(args[0] ?? '').toLowerCase()\n const state = (await session.proc.getState()) as any\n const current = String(state?.followUpMode ?? '')\n\n // If no arg, just report current.\n if (!modeRaw) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Follow-up mode: ${current || 'unknown'}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (modeRaw !== 'all' && modeRaw !== 'one-at-a-time') {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Usage: /follow-up all | /follow-up one-at-a-time'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n await session.proc.setFollowUpMode(modeRaw as 'all' | 'one-at-a-time')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Follow-up mode set to: ${modeRaw}` }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'changelog') {\n // Read pi's installed CHANGELOG.md. Adapter-side, no model call.\n const findChangelog = (): string | null => {\n // 1) Locate the installed pi package by resolving the `pi` executable.\n // On Node installs, `pi` typically resolves to .../@mariozechner/pi-coding-agent/dist/cli.js\n try {\n const whichCmd = process.platform === 'win32' ? 'where' : 'which'\n const which = spawnSync(whichCmd, ['pi'], { encoding: 'utf-8' })\n const piPath = String(which.stdout ?? '')\n .split(/\\r?\\n/)[0]\n ?.trim()\n\n if (piPath) {\n const resolved = realpathSync(piPath)\n const pkgRoot = dirname(dirname(resolved))\n const p = join(pkgRoot, 'CHANGELOG.md')\n if (existsSync(p)) return p\n }\n } catch {\n // ignore\n }\n\n // 2) Fallback: ask npm where global modules live.\n try {\n const npmRoot = spawnSync('npm', ['root', '-g'], { encoding: 'utf-8' })\n const root = String(npmRoot.stdout ?? '').trim()\n if (root) {\n const p = join(root, '@mariozechner', 'pi-coding-agent', 'CHANGELOG.md')\n if (existsSync(p)) return p\n }\n } catch {\n // ignore\n }\n\n return null\n }\n\n const changelogPath = findChangelog()\n if (!changelogPath) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: \"Changelog not found (couldn't locate pi installation).\" }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n let text = ''\n try {\n text = readFileSync(changelogPath, 'utf-8')\n } catch (e: any) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Failed to read changelog: ${String(e?.message ?? e)}` }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n // Keep it reasonably sized in chat.\n const maxChars = 20_000\n if (text.length > maxChars) text = text.slice(0, maxChars) + '\\n\\n...(truncated)...'\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'export') {\n // For now we always export into the session cwd and do not accept a user-provided path.\n // IMPORTANT: pi's export_html reads the session JSONL file. If it doesn't exist yet\n // (no messages) or is empty, pi throws and RPC mode emits an uncorrelated parse error\n // (no id), which would otherwise hang our request. So we guard here.\n const state = (await session.proc.getState()) as any\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n const messageCount = typeof state?.messageCount === 'number' ? state.messageCount : 0\n\n if (!sessionFile || messageCount === 0 || !existsSync(sessionFile)) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Nothing to export yet (no session messages). Send a prompt first.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n try {\n const raw = readFileSync(sessionFile, 'utf-8')\n if (raw.trim().length === 0) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Nothing to export yet (empty session file). Send a prompt first.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n } catch {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: \"Couldn't read session file for export. Try sending a prompt first.\"\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n const safeSessionId = session.sessionId.replace(/[^a-zA-Z0-9_-]/g, '_')\n const outputPath = join(session.cwd, `pi-session-${safeSessionId}.html`)\n\n let resultPath = ''\n try {\n const result = await session.proc.exportHtml(outputPath)\n resultPath = result.path\n } catch (e: any) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Export failed: ${String(e?.message ?? e)}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (!resultPath) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Export failed: no output path returned by pi.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n const uri = `file://${resultPath}`\n\n // Emit a short prefix + a resource link. Many clients concatenate chunks into a single\n // assistant message, so this avoids the \"link + duplicate plain text\" look.\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Session exported: '\n }\n }\n })\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'resource_link',\n name: `pi-session-${safeSessionId}.html`,\n uri,\n mimeType: 'text/html',\n title: 'Session exported'\n }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'autocompact') {\n const mode = (args[0] ?? 'toggle').toLowerCase()\n let enabled: boolean | null = null\n if (mode === 'on' || mode === 'true' || mode === 'enable' || mode === 'enabled') enabled = true\n else if (mode === 'off' || mode === 'false' || mode === 'disable' || mode === 'disabled') enabled = false\n\n if (enabled === null) {\n // toggle: read current state and invert.\n const state = (await session.proc.getState()) as any\n const current = Boolean(state?.autoCompactionEnabled)\n enabled = !current\n }\n\n await session.proc.setAutoCompaction(enabled)\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Auto-compaction ${enabled ? 'enabled' : 'disabled'}.`\n }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n }\n\n const result = await session.prompt(message, attachments)\n\n // ACP StopReason does not include \"error\"; if pi fails we map to end_turn for now,\n // unless we know this was a cancellation.\n const stopReason: StopReason =\n result === 'error' ? (session.wasCancelRequested() ? 'cancelled' : 'end_turn') : result\n\n return { stopReason }\n }\n\n async cancel(params: CancelNotification): Promise<void> {\n const session = this.sessions.get(params.sessionId)\n await session.cancel()\n }\n\n async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {\n if (!isAbsolute(params.cwd)) {\n throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`)\n }\n\n // MVP: ignore mcpServers.\n const stored = this.store.get(params.sessionId)\n if (!stored) {\n throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`)\n }\n\n // Spawn pi and point it directly at the stored session file.\n const proc = await PiRpcProcess.spawn({\n cwd: params.cwd,\n sessionPath: stored.sessionFile\n })\n\n const fileCommands = loadSlashCommands(params.cwd)\n\n const session = this.sessions.getOrCreate(params.sessionId, {\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n conn: this.conn,\n proc,\n fileCommands\n })\n\n // (Optional) ensure mapping stays fresh.\n this.store.upsert({\n sessionId: params.sessionId,\n cwd: params.cwd,\n sessionFile: stored.sessionFile\n })\n\n // Replay full conversation history.\n const data = (await proc.getMessages()) as any\n const messages = Array.isArray(data?.messages) ? data.messages : []\n\n for (const m of messages) {\n const role = String(m?.role ?? '')\n\n if (role === 'user') {\n const text = normalizePiMessageText(m?.content)\n if (text) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'user_message_chunk',\n content: { type: 'text', text }\n }\n })\n }\n }\n\n if (role === 'assistant') {\n const text = normalizePiAssistantText(m?.content)\n if (text) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n }\n }\n }\n\n const models = await getModelState(proc)\n const thinking = await getThinkingState(proc)\n\n const showStartupInfo = booleanEnv('PI_ACP_STARTUP_INFO', true)\n\n // Emit a synthesized startup info block for loaded sessions too.\n const preludeText = showStartupInfo ? buildStartupInfo({ cwd: params.cwd, fileCommands }) : ''\n if (preludeText) session.setStartupInfo(preludeText)\n\n const response = {\n models,\n modes: thinking,\n _meta: {\n piAcp: {\n startupInfo: preludeText || null\n }\n }\n }\n\n if (showStartupInfo) setTimeout(() => session.sendStartupInfoIfPending(), 0)\n\n // Advertise slash commands after the response so the client knows the session exists.\n setTimeout(() => {\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'available_commands_update',\n availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())\n }\n })\n }, 0)\n\n return response\n }\n\n async unstable_setSessionModel(params: { sessionId: string; modelId: string }): Promise<void> {\n const session = this.sessions.get(params.sessionId)\n\n // Accept either:\n // - \"provider/model\" (preferred, matches how we advertise)\n // - \"model\" (fallback, we try to resolve via available models)\n let provider: string | null = null\n let modelId: string | null = null\n\n if (params.modelId.includes('/')) {\n const [p, ...rest] = params.modelId.split('/')\n provider = p\n modelId = rest.join('/')\n } else {\n modelId = params.modelId\n }\n\n if (!provider) {\n const data = (await session.proc.getAvailableModels()) as any\n const models: any[] = Array.isArray(data?.models) ? data.models : []\n const found = models.find(m => String(m?.id) === modelId)\n if (found) {\n provider = String(found.provider)\n modelId = String(found.id)\n }\n }\n\n if (!provider || !modelId) {\n throw RequestError.invalidParams(`Unknown modelId: ${params.modelId}`)\n }\n\n await session.proc.setModel(provider, modelId)\n }\n\n async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n const session = this.sessions.get(params.sessionId)\n\n const mode = String(params.modeId)\n if (!isThinkingLevel(mode)) {\n throw RequestError.invalidParams(`Unknown modeId: ${mode}`)\n }\n\n await session.proc.setThinkingLevel(mode)\n\n // Let the client know the current mode changed (keeps the dropdown in sync).\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'current_mode_update',\n currentModeId: mode\n }\n })\n\n return {}\n }\n}\n\nfunction isThinkingLevel(x: string): x is ThinkingLevel {\n return x === 'off' || x === 'minimal' || x === 'low' || x === 'medium' || x === 'high' || x === 'xhigh'\n}\n\nasync function getThinkingState(proc: PiRpcProcess): Promise<{\n availableModes: Array<{\n id: string\n name: string\n description?: string | null\n }>\n currentModeId: string\n}> {\n // Ask pi for current thinking level.\n let current: ThinkingLevel = 'medium'\n try {\n const state = (await proc.getState()) as any\n const tl = typeof state?.thinkingLevel === 'string' ? state.thinkingLevel : null\n if (tl && isThinkingLevel(tl)) current = tl\n } catch {\n // ignore\n }\n\n const available: ThinkingLevel[] = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh']\n\n return {\n currentModeId: current,\n availableModes: available.map(id => ({\n id,\n name: `Thinking: ${id}`,\n description: null\n }))\n }\n}\n\nasync function getModelState(proc: PiRpcProcess): Promise<{\n availableModels: ModelInfo[]\n currentModelId: string\n} | null> {\n // Ask pi for available models.\n let availableModels: ModelInfo[] = []\n try {\n const data = (await proc.getAvailableModels()) as any\n const models: any[] = Array.isArray(data?.models) ? data.models : []\n availableModels = models\n .map(m => {\n const provider = String(m?.provider ?? '').trim()\n const id = String(m?.id ?? '').trim()\n if (!provider || !id) return null\n\n const name = String(m?.name ?? id)\n return {\n modelId: `${provider}/${id}`,\n name: `${provider}/${name}`,\n description: null\n } satisfies ModelInfo\n })\n .filter(Boolean) as ModelInfo[]\n } catch {\n // ignore\n }\n\n // Ask pi what model is currently active.\n let currentModelId: string | null = null\n try {\n const state = (await proc.getState()) as any\n const model = state?.model\n if (model && typeof model === 'object') {\n const provider = String((model as any).provider ?? '').trim()\n const id = String((model as any).id ?? '').trim()\n if (provider && id) currentModelId = `${provider}/${id}`\n }\n } catch {\n // ignore\n }\n\n if (!availableModels.length && !currentModelId) return null\n\n // Fallback if current model is unknown: use first in list.\n if (!currentModelId) currentModelId = availableModels[0]?.modelId ?? 'default'\n\n return {\n availableModels,\n currentModelId\n }\n}\n\nfunction isSemver(v: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(?:[-+].+)?$/.test(v)\n}\n\nfunction compareSemver(a: string, b: string): number {\n // Very small comparator for x.y.z (ignores pre-release/build beyond making them \"not greater\" unless base differs)\n const pa = a.split(/[.-]/).slice(0, 3).map(n => Number(n))\n const pb = b.split(/[.-]/).slice(0, 3).map(n => Number(n))\n for (let i = 0; i < 3; i++) {\n const da = pa[i] ?? 0\n const db = pb[i] ?? 0\n if (da > db) return 1\n if (da < db) return -1\n }\n return 0\n}\n\nfunction buildStartupInfo(opts: {\n cwd: string\n fileCommands: ReturnType<typeof loadSlashCommands>\n}): string {\n void opts.fileCommands\n\n const md: string[] = []\n\n let updateNotice: string | null = null\n\n // pi version header + update notice (best-effort, matches what users see in terminal startup)\n try {\n // No timeout here; in some environments process startup can be slow and we'd rather show the version.\n const piVersion = spawnSync('pi', ['--version'], { encoding: 'utf-8' })\n const installed = String(piVersion.stdout ?? '').trim().replace(/^v/i, '')\n if (installed) {\n md.push(`pi v${installed}`)\n md.push('---')\n md.push('')\n\n // Best-effort update check against npm registry.\n // Important: keep it fast to not slow down session/new.\n try {\n const latestRes = spawnSync('npm', ['view', '@mariozechner/pi-coding-agent', 'version'], {\n encoding: 'utf-8',\n timeout: 800\n })\n const latest = String(latestRes.stdout ?? '').trim().replace(/^v/i, '')\n\n if (latest && isSemver(latest) && isSemver(installed) && compareSemver(latest, installed) > 0) {\n updateNotice = `New version available: v${latest} (installed v${installed}). Run: \\`npm i -g @mariozechner/pi-coding-agent\\``\n }\n } catch {\n // ignore\n }\n }\n } catch {\n // ignore\n }\n\n const addSection = (title: string, items: string[]) => {\n const cleaned = items.map(s => s.trim()).filter(Boolean)\n if (!cleaned.length) return\n\n md.push(`## ${title}`)\n for (const item of cleaned) md.push(`- ${item}`)\n md.push('')\n }\n\n // Context\n const contextItems: string[] = []\n const contextPath = join(opts.cwd, 'AGENTS.md')\n if (existsSync(contextPath)) contextItems.push(contextPath)\n addSection('Context', contextItems)\n\n // Skills\n const skillsItems: string[] = []\n\n const pushSkillFromRoot = (root: string) => {\n try {\n // Direct .md files in root\n for (const e of readdirSync(root)) {\n const p = join(root, e)\n try {\n const st = statSync(p)\n if (st.isFile() && e.toLowerCase().endsWith('.md')) {\n skillsItems.push(p)\n }\n } catch {\n // ignore\n }\n }\n\n // Recursive SKILL.md under subdirectories\n const stack: string[] = [root]\n while (stack.length) {\n const dir = stack.pop()!\n let entries: string[] = []\n try {\n entries = readdirSync(dir)\n } catch {\n continue\n }\n\n for (const name of entries) {\n // Skip obvious noise\n if (name === 'node_modules' || name === '.git') continue\n const p = join(dir, name)\n let st\n try {\n st = statSync(p)\n } catch {\n continue\n }\n if (st.isDirectory()) {\n stack.push(p)\n } else if (st.isFile() && name === 'SKILL.md') {\n skillsItems.push(p)\n }\n }\n }\n } catch {\n // ignore\n }\n }\n\n // Global skills\n const globalSkillsDir = join(process.env.HOME ?? '', '.pi', 'agent', 'skills')\n pushSkillFromRoot(globalSkillsDir)\n\n // Project skills (.pi/skills)\n const projectSkillsDir = join(opts.cwd, '.pi', 'skills')\n pushSkillFromRoot(projectSkillsDir)\n\n addSection('Skills', skillsItems)\n\n // Prompts\n const promptsItems: string[] = []\n const promptsDir = join(process.env.HOME ?? '', '.pi', 'agent', 'prompts')\n try {\n const prompts = readdirSync(promptsDir).filter(f => f.endsWith('.md'))\n for (const f of prompts) promptsItems.push(`/${basename(f, '.md')}`)\n } catch {\n // ignore\n }\n addSection('Prompts', promptsItems)\n\n // Extensions\n const extItems: string[] = []\n const extDir = join(process.env.HOME ?? '', '.pi', 'agent', 'extensions')\n try {\n const exts = readdirSync(extDir).filter(f => f.endsWith('.ts') || f.endsWith('.js'))\n for (const f of exts) extItems.push(join(extDir, f))\n } catch {\n // ignore\n }\n\n // Also show npm packages from pi settings (best-effort)\n try {\n const settingsPath = join(process.env.HOME ?? '', '.pi', 'agent', 'settings.json')\n const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')) as any\n const pkgs: string[] = Array.isArray(settings?.packages) ? settings.packages : []\n for (const pkg of pkgs) {\n const s = String(pkg)\n if (s.startsWith('npm:')) {\n // Render a two-line bullet structure using markdown indentation.\n extItems.push(`${s}\\n - index.ts`)\n } else {\n extItems.push(s)\n }\n }\n } catch {\n // ignore\n }\n\n addSection('Extensions', extItems)\n\n if (updateNotice) {\n md.push('---')\n md.push(updateNotice)\n md.push('')\n }\n\n // Do NOT include themes (per request).\n return md.join('\\n').trim() + '\\n'\n}\n\nfunction readNearestPackageJson(metaUrl: string): {\n name?: string\n version?: string\n} {\n try {\n let dir = dirname(fileURLToPath(metaUrl))\n\n // Walk upwards a few levels to find the nearest package.json\n for (let i = 0; i < 6; i++) {\n const p = join(dir, 'package.json')\n if (existsSync(p)) {\n const json = JSON.parse(readFileSync(p, 'utf-8')) as any\n return { name: json?.name, version: json?.version }\n }\n dir = dirname(dir)\n }\n } catch {\n // ignore\n }\n return { name: 'pi-acp', version: '0.0.0' }\n}\n","import type {\n AgentSideConnection,\n ContentBlock,\n McpServer,\n SessionUpdate,\n ToolCallContent,\n ToolKind\n} from '@agentclientprotocol/sdk'\nimport { RequestError } from '@agentclientprotocol/sdk'\nimport { readFileSync } from 'node:fs'\nimport { isAbsolute, resolve as resolvePath } from 'node:path'\nimport { PiRpcProcess, type PiRpcEvent } from '../pi-rpc/process.js'\nimport { SessionStore } from './session-store.js'\nimport { toolResultToText } from './translate/pi-tools.js'\nimport { expandSlashCommand, type FileSlashCommand } from './slash-commands.js'\n\ntype SessionCreateParams = {\n cwd: string\n mcpServers: McpServer[]\n conn: AgentSideConnection\n fileCommands?: import('./slash-commands.js').FileSlashCommand[]\n}\n\nexport type StopReason = 'end_turn' | 'cancelled' | 'error'\n\ntype PendingTurn = {\n resolve: (reason: StopReason) => void\n reject: (err: unknown) => void\n}\n\ntype QueuedTurn = {\n message: string\n attachments: unknown[]\n resolve: (reason: StopReason) => void\n reject: (err: unknown) => void\n}\n\nexport class SessionManager {\n private sessions = new Map<string, PiAcpSession>()\n private readonly store = new SessionStore()\n\n /** Get a registered session if it exists (no throw). */\n maybeGet(sessionId: string): PiAcpSession | undefined {\n return this.sessions.get(sessionId)\n }\n\n async create(params: SessionCreateParams): Promise<PiAcpSession> {\n // Let pi manage session persistence in its default location (~/.pi/agent/sessions/...)\n // so sessions are visible to the regular `pi` CLI.\n const proc = await PiRpcProcess.spawn({\n cwd: params.cwd\n })\n\n const state = (await proc.getState()) as any\n const sessionId = typeof state?.sessionId === 'string' ? state.sessionId : crypto.randomUUID()\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n\n if (sessionFile) {\n this.store.upsert({ sessionId, cwd: params.cwd, sessionFile })\n }\n\n const session = new PiAcpSession({\n sessionId,\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n proc,\n conn: params.conn,\n fileCommands: params.fileCommands ?? []\n })\n\n this.sessions.set(sessionId, session)\n return session\n }\n\n get(sessionId: string): PiAcpSession {\n const s = this.sessions.get(sessionId)\n if (!s) throw RequestError.invalidParams(`Unknown sessionId: ${sessionId}`)\n return s\n }\n\n /**\n * Used by session/load: create a session object bound to an existing sessionId/proc\n * if it isn't already registered.\n */\n getOrCreate(sessionId: string, params: SessionCreateParams & { proc: PiRpcProcess }): PiAcpSession {\n const existing = this.sessions.get(sessionId)\n if (existing) return existing\n\n const session = new PiAcpSession({\n sessionId,\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n proc: params.proc,\n conn: params.conn,\n fileCommands: params.fileCommands ?? []\n })\n\n this.sessions.set(sessionId, session)\n return session\n }\n}\n\nexport class PiAcpSession {\n readonly sessionId: string\n readonly cwd: string\n readonly mcpServers: McpServer[]\n\n private startupInfo: string | null = null\n private startupInfoSent = false\n\n readonly proc: PiRpcProcess\n private readonly conn: AgentSideConnection\n private readonly fileCommands: FileSlashCommand[]\n\n // Used to map abort semantics to ACP stopReason.\n // Applies to the currently running turn.\n private cancelRequested = false\n\n // Current in-flight turn (if any). Additional prompts are queued.\n private pendingTurn: PendingTurn | null = null\n private readonly turnQueue: QueuedTurn[] = []\n // Track tool call statuses and ensure they are monotonic (pending -> in_progress -> completed).\n // Some pi events can arrive out of order (e.g. late toolcall_* deltas after execution starts),\n // and clients may hide progress if we ever downgrade back to `pending`.\n private currentToolCalls = new Map<string, 'pending' | 'in_progress'>()\n\n // pi can emit multiple `turn_end` events for a single user prompt (e.g. after tool_use).\n // The overall agent loop completes when `agent_end` is emitted.\n private inAgentLoop = false\n\n // For ACP diff support: capture file contents before edits, then emit ToolCallContent {type:\"diff\"}.\n // This is due to pi sending diff as a string as opposed to ACP expected diff format.\n // Compatible format may need to be implemented in pi in the future.\n private editSnapshots = new Map<string, { path: string; oldText: string }>()\n\n // Ensure `session/update` notifications are sent in order and can be awaited\n // before completing a `session/prompt` request.\n private lastEmit: Promise<void> = Promise.resolve()\n\n constructor(opts: {\n sessionId: string\n cwd: string\n mcpServers: McpServer[]\n proc: PiRpcProcess\n conn: AgentSideConnection\n fileCommands?: FileSlashCommand[]\n }) {\n this.sessionId = opts.sessionId\n this.cwd = opts.cwd\n this.mcpServers = opts.mcpServers\n this.proc = opts.proc\n this.conn = opts.conn\n this.fileCommands = opts.fileCommands ?? []\n\n this.proc.onEvent(ev => this.handlePiEvent(ev))\n }\n\n setStartupInfo(text: string) {\n this.startupInfo = text\n }\n\n /**\n * Best-effort attempt to send startup info outside of a prompt turn.\n * Some clients (e.g. Zed) may only render agent messages once the UI is ready;\n * callers can invoke this shortly after session/new returns.\n */\n sendStartupInfoIfPending(): void {\n if (this.startupInfoSent || !this.startupInfo) return\n this.startupInfoSent = true\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: this.startupInfo }\n })\n }\n\n async prompt(message: string, attachments: unknown[] = []): Promise<StopReason> {\n // If we have startup info pending, emit it as the first chunk of the first turn.\n // This is more reliable than sending a standalone sessionUpdate right after session/new,\n // because some clients won't render agent messages until a prompt occurs.\n if (!this.startupInfoSent && this.startupInfo) {\n this.startupInfoSent = true\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: this.startupInfo }\n })\n }\n\n // pi RPC mode disables slash command expansion, so we do it here.\n const expandedMessage = expandSlashCommand(message, this.fileCommands)\n\n const turnPromise = new Promise<StopReason>((resolve, reject) => {\n const queued: QueuedTurn = { message: expandedMessage, attachments, resolve, reject }\n\n // If a turn is already running, enqueue.\n if (this.pendingTurn) {\n this.turnQueue.push(queued)\n\n // Best-effort: notify client that a prompt was queued.\n // This doesn't work in Zed yet, needs to be revisited\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Queued message (position ${this.turnQueue.length}).`\n }\n })\n\n // Also publish queue depth via session info metadata.\n // This also not visible in the client\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: true } }\n })\n\n return\n }\n\n // No turn is running; start immediately.\n this.startTurn(queued)\n })\n\n return turnPromise\n }\n\n async cancel(): Promise<void> {\n // Cancel current and clear any queued prompts.\n this.cancelRequested = true\n\n if (this.turnQueue.length) {\n const queued = this.turnQueue.splice(0, this.turnQueue.length)\n for (const t of queued) t.resolve('cancelled')\n\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: 'Cleared queued prompts.' }\n })\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: 0, running: Boolean(this.pendingTurn) } }\n })\n }\n\n // Abort the currently running turn (if any). If nothing is running, this is a no-op.\n await this.proc.abort()\n }\n\n wasCancelRequested(): boolean {\n return this.cancelRequested\n }\n\n private emit(update: SessionUpdate): void {\n // Serialize update delivery.\n this.lastEmit = this.lastEmit\n .then(() =>\n this.conn.sessionUpdate({\n sessionId: this.sessionId,\n update\n })\n )\n .catch(() => {\n // Ignore notification errors (client may have gone away). We still want\n // prompt completion.\n })\n }\n\n private async flushEmits(): Promise<void> {\n await this.lastEmit\n }\n\n private startTurn(t: QueuedTurn): void {\n this.cancelRequested = false\n this.inAgentLoop = false\n\n this.pendingTurn = { resolve: t.resolve, reject: t.reject }\n\n // Publish queue depth (0 because we're starting the turn now).\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: true } }\n })\n\n // Kick off pi, but completion is determined by pi events, not the RPC response.\n // Important: pi may emit multiple `turn_end` events (e.g. when the model requests tools).\n // The full prompt is finished when we see `agent_end`.\n this.proc.prompt(t.message, t.attachments).catch(err => {\n // If the subprocess errors before we get an `agent_end`, treat as error unless cancelled.\n // Also ensure we flush any already-enqueued updates first.\n void this.flushEmits().finally(() => {\n const reason: StopReason = this.cancelRequested ? 'cancelled' : 'error'\n this.pendingTurn?.resolve(reason)\n this.pendingTurn = null\n this.inAgentLoop = false\n\n // If the prompt failed, do not automatically proceed—pi may be unhealthy.\n // But we still clear the queueDepth metadata.\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: false } }\n })\n })\n void err\n })\n }\n\n private handlePiEvent(ev: PiRpcEvent) {\n const type = String((ev as any).type ?? '')\n\n switch (type) {\n case 'message_update': {\n const ame = (ev as any).assistantMessageEvent\n\n // Stream assistant text.\n if (ame?.type === 'text_delta' && typeof ame.delta === 'string') {\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: ame.delta } satisfies ContentBlock\n })\n break\n }\n\n // Surface tool calls ASAP so clients (e.g. Zed) can show a tool-in-use/loading UI\n // while the model is still streaming tool call args.\n if (ame?.type === 'toolcall_start' || ame?.type === 'toolcall_delta' || ame?.type === 'toolcall_end') {\n const toolCall =\n // pi sometimes includes the tool call directly on the event\n (ame as any)?.toolCall ??\n // ...and always includes it in the partial assistant message at contentIndex\n (ame as any)?.partial?.content?.[(ame as any)?.contentIndex ?? 0]\n\n const toolCallId = String((toolCall as any)?.id ?? '')\n const toolName = String((toolCall as any)?.name ?? 'tool')\n\n if (toolCallId) {\n const rawInput =\n (toolCall as any)?.arguments && typeof (toolCall as any).arguments === 'object'\n ? (toolCall as any).arguments\n : (() => {\n const s = String((toolCall as any)?.partialArgs ?? '')\n if (!s) return undefined\n try {\n return JSON.parse(s)\n } catch {\n return { partialArgs: s }\n }\n })()\n\n const existingStatus = this.currentToolCalls.get(toolCallId)\n // IMPORTANT: never downgrade status (e.g. if we already marked in_progress via tool_execution_start).\n const status = existingStatus ?? 'pending'\n\n if (!existingStatus) {\n this.currentToolCalls.set(toolCallId, 'pending')\n this.emit({\n sessionUpdate: 'tool_call',\n toolCallId,\n title: toolName,\n kind: toToolKind(toolName),\n status,\n rawInput\n })\n } else {\n // Best-effort: keep rawInput updated while args are streaming.\n // Keep the existing status (pending or in_progress).\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status,\n rawInput\n })\n }\n }\n\n break\n }\n\n // (MVP) ignore other delta types (thinking, etc.) for now.\n break\n }\n\n case 'tool_execution_start': {\n const toolCallId = String((ev as any).toolCallId ?? crypto.randomUUID())\n const toolName = String((ev as any).toolName ?? 'tool')\n const args = (ev as any).args\n\n // Capture pre-edit file contents so we can emit a structured ACP diff on completion.\n if (toolName === 'edit') {\n const p = typeof args?.path === 'string' ? args.path : undefined\n if (p) {\n try {\n const abs = isAbsolute(p) ? p : resolvePath(this.cwd, p)\n const oldText = readFileSync(abs, 'utf8')\n this.editSnapshots.set(toolCallId, { path: p, oldText })\n } catch {\n // Ignore snapshot failures; we'll fall back to plain text output.\n }\n }\n }\n\n // If we already surfaced the tool call while the model streamed it, just transition.\n if (!this.currentToolCalls.has(toolCallId)) {\n this.currentToolCalls.set(toolCallId, 'in_progress')\n this.emit({\n sessionUpdate: 'tool_call',\n toolCallId,\n title: toolName,\n kind: toToolKind(toolName),\n status: 'in_progress',\n rawInput: args\n })\n } else {\n this.currentToolCalls.set(toolCallId, 'in_progress')\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: 'in_progress',\n rawInput: args\n })\n }\n\n break\n }\n\n case 'tool_execution_update': {\n const toolCallId = String((ev as any).toolCallId ?? '')\n if (!toolCallId) break\n\n const partial = (ev as any).partialResult\n const text = toolResultToText(partial)\n\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: 'in_progress',\n content: text\n ? ([{ type: 'content', content: { type: 'text', text } }] satisfies ToolCallContent[])\n : undefined,\n rawOutput: partial\n })\n break\n }\n\n case 'tool_execution_end': {\n const toolCallId = String((ev as any).toolCallId ?? '')\n if (!toolCallId) break\n\n const result = (ev as any).result\n const isError = Boolean((ev as any).isError)\n const text = toolResultToText(result)\n\n // If this was an edit and we captured a snapshot, emit a structured ACP diff.\n // This enables clients like Zed to render an actual diff UI.\n const snapshot = this.editSnapshots.get(toolCallId)\n let content: ToolCallContent[] | undefined\n\n if (!isError && snapshot) {\n try {\n const abs = isAbsolute(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path)\n const newText = readFileSync(abs, 'utf8')\n if (newText !== snapshot.oldText) {\n content = [\n {\n type: 'diff',\n path: snapshot.path,\n oldText: snapshot.oldText,\n newText\n },\n ...(text ? ([{ type: 'content', content: { type: 'text', text } }] as ToolCallContent[]) : [])\n ]\n }\n } catch {\n // ignore; fall back to text only\n }\n }\n\n // Fallback: just text content.\n if (!content && text) {\n content = [{ type: 'content', content: { type: 'text', text } }] satisfies ToolCallContent[]\n }\n\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: isError ? 'failed' : 'completed',\n content,\n rawOutput: result\n })\n\n this.currentToolCalls.delete(toolCallId)\n this.editSnapshots.delete(toolCallId)\n break\n }\n\n case 'agent_start': {\n this.inAgentLoop = true\n break\n }\n\n case 'turn_end': {\n // pi uses `turn_end` for sub-steps (e.g. tool_use) and will often start another turn.\n // Do NOT resolve the ACP `session/prompt` here; wait for `agent_end`.\n break\n }\n\n case 'agent_end': {\n // Ensure all updates derived from pi events are delivered before we resolve\n // the ACP `session/prompt` request.\n void this.flushEmits().finally(() => {\n const reason: StopReason = this.cancelRequested ? 'cancelled' : 'end_turn'\n this.pendingTurn?.resolve(reason)\n this.pendingTurn = null\n this.inAgentLoop = false\n\n // Start next queued prompt, if any.\n const next = this.turnQueue.shift()\n if (next) {\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Starting queued message. (${this.turnQueue.length} remaining)` }\n })\n this.startTurn(next)\n } else {\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: 0, running: false } }\n })\n }\n })\n break\n }\n\n default:\n break\n }\n }\n}\n\nfunction toToolKind(toolName: string): ToolKind {\n switch (toolName) {\n case 'read':\n return 'read'\n case 'write':\n case 'edit':\n return 'edit'\n case 'bash':\n // Many ACP clients render `execute` tool calls only via the terminal APIs.\n // Since this adapter lets pi execute locally (no client terminal delegation),\n // we report bash as `other` so clients show inline text output blocks.\n return 'other'\n default:\n return 'other'\n }\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport * as readline from 'node:readline'\n\nfunction stripAnsi(s: string): string {\n // Basic ANSI escape stripping (colors, cursor movement, etc.)\n return s.replace(/[\\u001B\\u009B][[\\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')\n}\n\ntype PiRpcCommand =\n | { type: 'prompt'; id?: string; message: string; attachments?: unknown[] }\n | { type: 'abort'; id?: string }\n | { type: 'get_state'; id?: string }\n // Model\n | { type: 'get_available_models'; id?: string }\n | { type: 'set_model'; id?: string; provider: string; modelId: string }\n // Thinking\n | { type: 'set_thinking_level'; id?: string; level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' }\n // Modes\n | { type: 'set_follow_up_mode'; id?: string; mode: 'all' | 'one-at-a-time' }\n | { type: 'set_steering_mode'; id?: string; mode: 'all' | 'one-at-a-time' }\n // Compaction\n | { type: 'compact'; id?: string; customInstructions?: string }\n | { type: 'set_auto_compaction'; id?: string; enabled: boolean }\n // Session\n | { type: 'get_session_stats'; id?: string }\n | { type: 'export_html'; id?: string; outputPath?: string }\n | { type: 'switch_session'; id?: string; sessionPath: string }\n // Messages\n | { type: 'get_messages'; id?: string }\n\ntype PiRpcResponse = {\n type: 'response'\n id?: string\n command: string\n success: boolean\n data?: unknown\n error?: string\n}\n\nexport type PiRpcEvent = Record<string, unknown>\n\ntype SpawnParams = {\n cwd: string\n /** Optional override for `pi` executable name/path */\n piCommand?: string\n /** If set, pi will persist the session to this exact file (via `--session <path>`). */\n sessionPath?: string\n}\n\nexport class PiRpcProcess {\n private readonly child: ChildProcessWithoutNullStreams\n private readonly pending = new Map<string, { resolve: (v: PiRpcResponse) => void; reject: (e: unknown) => void }>()\n private eventHandlers: Array<(ev: PiRpcEvent) => void> = []\n private readonly preludeLines: string[] = []\n\n private constructor(child: ChildProcessWithoutNullStreams) {\n this.child = child\n\n const rl = readline.createInterface({ input: child.stdout })\n rl.on('line', line => {\n if (!line.trim()) return\n let msg: any\n try {\n msg = JSON.parse(line)\n } catch {\n // pi may emit a human-readable prelude on stdout before NDJSON starts.\n // Capture it so the ACP adapter can surface it on session start.\n const cleaned = stripAnsi(String(line)).trimEnd()\n if (cleaned) this.preludeLines.push(cleaned)\n return\n }\n\n if (msg?.type === 'response') {\n const id = typeof msg.id === 'string' ? msg.id : undefined\n if (id) {\n const pending = this.pending.get(id)\n if (pending) {\n this.pending.delete(id)\n pending.resolve(msg as PiRpcResponse)\n return\n }\n }\n }\n\n for (const h of this.eventHandlers) h(msg as PiRpcEvent)\n })\n\n child.on('exit', (code, signal) => {\n const err = new Error(`pi process exited (code=${code}, signal=${signal})`)\n for (const [, p] of this.pending) p.reject(err)\n this.pending.clear()\n })\n }\n\n static async spawn(params: SpawnParams): Promise<PiRpcProcess> {\n const cmd = params.piCommand ?? 'pi'\n\n const args = ['--mode', 'rpc']\n if (params.sessionPath) args.push('--session', params.sessionPath)\n\n const child = spawn(cmd, args, {\n cwd: params.cwd,\n stdio: 'pipe',\n env: process.env\n })\n\n child.stderr.on('data', () => {\n // leave stderr untouched; ACP clients may capture it.\n })\n\n const proc = new PiRpcProcess(child)\n\n // Best-effort handshake.\n // Important: pi may emit a get_state response pointing at a sessionFile in a directory\n // that is created lazily. Create the parent dir up-front to avoid later parse errors\n // when we call commands like export_html.\n try {\n const state = (await proc.getState()) as any\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n if (sessionFile) {\n const { mkdirSync } = await import('node:fs')\n const { dirname } = await import('node:path')\n mkdirSync(dirname(sessionFile), { recursive: true })\n }\n } catch {\n // ignore for now\n }\n\n return proc\n }\n\n onEvent(handler: (ev: PiRpcEvent) => void): () => void {\n this.eventHandlers.push(handler)\n return () => {\n this.eventHandlers = this.eventHandlers.filter(h => h !== handler)\n }\n }\n\n /**\n * Human-readable stdout lines emitted before RPC NDJSON begins (e.g. Context/Skills/Extensions info).\n * Themes are typically noisy/less useful for ACP, so callers can filter as needed.\n */\n consumePreludeLines(): string[] {\n const lines = this.preludeLines.splice(0, this.preludeLines.length)\n return lines\n }\n\n async prompt(message: string, attachments: unknown[] = []): Promise<void> {\n const res = await this.request({ type: 'prompt', message, attachments })\n if (!res.success) throw new Error(`pi prompt failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async abort(): Promise<void> {\n const res = await this.request({ type: 'abort' })\n if (!res.success) throw new Error(`pi abort failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getState(): Promise<unknown> {\n const res = await this.request({ type: 'get_state' })\n if (!res.success) throw new Error(`pi get_state failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async getAvailableModels(): Promise<unknown> {\n const res = await this.request({ type: 'get_available_models' })\n if (!res.success) throw new Error(`pi get_available_models failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setModel(provider: string, modelId: string): Promise<unknown> {\n const res = await this.request({ type: 'set_model', provider, modelId })\n if (!res.success) throw new Error(`pi set_model failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setThinkingLevel(level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'): Promise<void> {\n const res = await this.request({ type: 'set_thinking_level', level })\n if (!res.success) throw new Error(`pi set_thinking_level failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async setFollowUpMode(mode: 'all' | 'one-at-a-time'): Promise<void> {\n const res = await this.request({ type: 'set_follow_up_mode', mode })\n if (!res.success) throw new Error(`pi set_follow_up_mode failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async setSteeringMode(mode: 'all' | 'one-at-a-time'): Promise<void> {\n const res = await this.request({ type: 'set_steering_mode', mode })\n if (!res.success) throw new Error(`pi set_steering_mode failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async compact(customInstructions?: string): Promise<unknown> {\n const res = await this.request({ type: 'compact', customInstructions })\n if (!res.success) throw new Error(`pi compact failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setAutoCompaction(enabled: boolean): Promise<void> {\n const res = await this.request({ type: 'set_auto_compaction', enabled })\n if (!res.success) throw new Error(`pi set_auto_compaction failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getSessionStats(): Promise<unknown> {\n const res = await this.request({ type: 'get_session_stats' })\n if (!res.success) throw new Error(`pi get_session_stats failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async exportHtml(outputPath?: string): Promise<{ path: string }> {\n const res = await this.request({ type: 'export_html', outputPath })\n if (!res.success) throw new Error(`pi export_html failed: ${res.error ?? JSON.stringify(res.data)}`)\n const data: any = res.data\n return { path: String(data?.path ?? '') }\n }\n\n async switchSession(sessionPath: string): Promise<void> {\n const res = await this.request({ type: 'switch_session', sessionPath })\n if (!res.success) throw new Error(`pi switch_session failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getMessages(): Promise<unknown> {\n const res = await this.request({ type: 'get_messages' })\n if (!res.success) throw new Error(`pi get_messages failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n private request(cmd: PiRpcCommand): Promise<PiRpcResponse> {\n const id = crypto.randomUUID()\n const withId = { ...cmd, id }\n\n const line = JSON.stringify(withId) + '\\n'\n\n return new Promise<PiRpcResponse>((resolve, reject) => {\n this.pending.set(id, { resolve, reject })\n this.child.stdin.write(line, err => {\n if (err) {\n this.pending.delete(id)\n reject(err)\n }\n })\n })\n }\n}\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { getPiAcpSessionMapPath } from './paths.js'\n\nexport type StoredSession = {\n sessionId: string\n cwd: string\n sessionFile: string\n updatedAt: string\n}\n\ntype SessionMapFile = {\n version: 1\n sessions: Record<string, StoredSession>\n}\n\nfunction ensureParentDir(path: string) {\n mkdirSync(dirname(path), { recursive: true })\n}\n\nfunction loadFile(path: string): SessionMapFile {\n try {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as SessionMapFile\n if (parsed?.version !== 1 || typeof parsed.sessions !== 'object' || !parsed.sessions) {\n return { version: 1, sessions: {} }\n }\n return parsed\n } catch {\n return { version: 1, sessions: {} }\n }\n}\n\nfunction saveFile(path: string, data: SessionMapFile): void {\n ensureParentDir(path)\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n', 'utf-8')\n}\n\nexport class SessionStore {\n private readonly path: string\n\n constructor(path = getPiAcpSessionMapPath()) {\n this.path = path\n }\n\n get(sessionId: string): StoredSession | null {\n const db = loadFile(this.path)\n return db.sessions[sessionId] ?? null\n }\n\n upsert(entry: { sessionId: string; cwd: string; sessionFile: string }): void {\n const db = loadFile(this.path)\n db.sessions[entry.sessionId] = {\n sessionId: entry.sessionId,\n cwd: entry.cwd,\n sessionFile: entry.sessionFile,\n updatedAt: new Date().toISOString()\n }\n saveFile(this.path, db)\n }\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n/**\n * Storage owned by the ACP adapter.\n *\n * We intentionally keep this separate from pi's own ~/.pi/agent/* directory.\n */\nexport function getPiAcpDir(): string {\n return join(homedir(), '.pi', 'pi-acp')\n}\n\nexport function getPiAcpSessionMapPath(): string {\n return join(getPiAcpDir(), 'session-map.json')\n}\n","export function toolResultToText(result: unknown): string {\n if (!result) return ''\n\n // pi tool results generally look like: { content: [{type:\"text\", text:\"...\"}], details: {...} }\n const content = (result as any).content\n if (Array.isArray(content)) {\n const texts = content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n if (texts.length) return texts.join('')\n }\n\n const details = (result as any)?.details\n\n // Some pi tools return a unified diff in `details.diff`.\n const diff = details?.diff\n if (typeof diff === 'string' && diff.trim()) {\n return diff\n }\n\n // The bash tool frequently returns stdout/stderr in `details` rather than content blocks.\n const stdout =\n (typeof details?.stdout === 'string' ? details.stdout : undefined) ??\n (typeof (result as any)?.stdout === 'string' ? (result as any).stdout : undefined) ??\n (typeof details?.output === 'string' ? details.output : undefined) ??\n (typeof (result as any)?.output === 'string' ? (result as any).output : undefined)\n\n const stderr =\n (typeof details?.stderr === 'string' ? details.stderr : undefined) ??\n (typeof (result as any)?.stderr === 'string' ? (result as any).stderr : undefined)\n\n const exitCode =\n (typeof details?.exitCode === 'number' ? details.exitCode : undefined) ??\n (typeof (result as any)?.exitCode === 'number' ? (result as any).exitCode : undefined) ??\n (typeof details?.code === 'number' ? details.code : undefined) ??\n (typeof (result as any)?.code === 'number' ? (result as any).code : undefined)\n\n if ((typeof stdout === 'string' && stdout.trim()) || (typeof stderr === 'string' && stderr.trim())) {\n const parts: string[] = []\n if (typeof stdout === 'string' && stdout.trim()) parts.push(stdout)\n if (typeof stderr === 'string' && stderr.trim()) parts.push(`stderr:\\n${stderr}`)\n if (typeof exitCode === 'number') parts.push(`exit code: ${exitCode}`)\n return parts.join('\\n\\n').trimEnd()\n }\n\n try {\n return JSON.stringify(result, null, 2)\n } catch {\n return String(result)\n }\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join, resolve } from 'node:path'\nimport type { AvailableCommand } from '@agentclientprotocol/sdk'\n\n/**\n * File-based slash command (mirrors pi-coding-agent semantics).\n */\nexport type FileSlashCommand = {\n name: string\n description: string\n content: string\n source: string // e.g. \"(user)\", \"(project)\", \"(project:frontend)\"\n}\n\nfunction parseFrontmatter(content: string): {\n frontmatter: Record<string, string>\n content: string\n} {\n const frontmatter: Record<string, string> = {}\n\n if (!content.startsWith('---')) return { frontmatter, content }\n\n const endIndex = content.indexOf('\\n---', 3)\n if (endIndex === -1) return { frontmatter, content }\n\n const frontmatterBlock = content.slice(4, endIndex)\n const remaining = content.slice(endIndex + 4).trim()\n\n for (const line of frontmatterBlock.split('\\n')) {\n const match = line.match(/^(\\w+):\\s*(.*)$/)\n if (match) frontmatter[match[1]] = match[2].trim()\n }\n\n return { frontmatter, content: remaining }\n}\n\nfunction loadCommandsFromDir(dir: string, source: 'user' | 'project', subdir = ''): FileSlashCommand[] {\n const commands: FileSlashCommand[] = []\n if (!existsSync(dir)) return commands\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n\n if (entry.isDirectory()) {\n const newSubdir = subdir ? `${subdir}:${entry.name}` : entry.name\n commands.push(...loadCommandsFromDir(fullPath, source, newSubdir))\n continue\n }\n\n if (!entry.isFile() || !entry.name.endsWith('.md')) continue\n\n try {\n const rawContent = readFileSync(fullPath, 'utf-8')\n const { frontmatter, content } = parseFrontmatter(rawContent)\n\n const name = entry.name.slice(0, -3)\n\n const sourceStr =\n source === 'user' ? (subdir ? `(user:${subdir})` : '(user)') : subdir ? `(project:${subdir})` : '(project)'\n\n let description = frontmatter.description || ''\n if (!description) {\n const firstLine = content.split('\\n').find(l => l.trim())\n if (firstLine) {\n description = firstLine.slice(0, 60)\n if (firstLine.length > 60) description += '...'\n }\n }\n\n description = description ? `${description} ${sourceStr}` : sourceStr\n\n commands.push({\n name,\n description,\n content,\n source: sourceStr\n })\n } catch {\n // Silently skip unreadable files.\n }\n }\n } catch {\n // Silently skip unreadable dirs.\n }\n\n return commands\n}\n\n/**\n * Load prompt templates from pi's prompt directories (formerly \"commands\").\n * - user: ~/.pi/agent/prompts/**\\/*.md\n * - project: <cwd>/.pi/prompts/**\\/*.md\n */\nexport function loadSlashCommands(cwd: string): FileSlashCommand[] {\n const commands: FileSlashCommand[] = []\n\n const userDir = join(homedir(), '.pi', 'agent', 'prompts')\n const projectDir = resolve(cwd, '.pi', 'prompts')\n\n // Match pi ordering: user first, then project.\n commands.push(...loadCommandsFromDir(userDir, 'user'))\n commands.push(...loadCommandsFromDir(projectDir, 'project'))\n\n return commands\n}\n\n/**\n * Convert file-based commands to ACP AvailableCommand objects.\n * De-dupes by name (first wins).\n */\nexport function toAvailableCommands(fileCommands: FileSlashCommand[]): AvailableCommand[] {\n const seen = new Set<string>()\n const out: AvailableCommand[] = []\n\n for (const c of fileCommands) {\n if (seen.has(c.name)) continue\n seen.add(c.name)\n\n out.push({\n name: c.name,\n description: c.description\n // input: omitted for now (pi commands don't specify this)\n })\n }\n\n return out\n}\n\n/**\n * Parse command args (bash-style quotes).\n */\nexport function parseCommandArgs(argsString: string): string[] {\n const args: string[] = []\n let current = ''\n let inQuote: string | null = null\n\n for (let i = 0; i < argsString.length; i++) {\n const ch = argsString[i]\n\n if (inQuote) {\n if (ch === inQuote) inQuote = null\n else current += ch\n continue\n }\n\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch\n } else if (ch === ' ' || ch === '\\t') {\n if (current) {\n args.push(current)\n current = ''\n }\n } else {\n current += ch\n }\n }\n\n if (current) args.push(current)\n return args\n}\n\n/**\n * Substitute $1, $2, ... and $@.\n */\nexport function substituteArgs(content: string, args: string[]): string {\n let result = content\n\n result = result.replace(/\\$@/g, args.join(' '))\n result = result.replace(/\\$(\\d+)/g, (_m, num) => {\n const idx = Number.parseInt(String(num), 10) - 1\n return args[idx] ?? ''\n })\n\n return result\n}\n\n/**\n * Expand a leading /command using the loaded file commands.\n * Returns original text if it's not a known slash command.\n */\nexport function expandSlashCommand(text: string, fileCommands: FileSlashCommand[]): string {\n if (!text.startsWith('/')) return text\n\n const spaceIndex = text.indexOf(' ')\n const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex)\n const argsString = spaceIndex === -1 ? '' : text.slice(spaceIndex + 1)\n\n const cmd = fileCommands.find(c => c.name === commandName)\n if (!cmd) return text\n\n const args = parseCommandArgs(argsString)\n return substituteArgs(cmd.content, args)\n}\n","export function normalizePiMessageText(content: unknown): string {\n if (typeof content === 'string') return content\n if (!Array.isArray(content)) return ''\n return content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n .join('')\n}\n\nexport function normalizePiAssistantText(content: unknown): string {\n // Assistant content is typically an array of blocks; only replay text blocks for MVP.\n if (!Array.isArray(content)) return ''\n return content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n .join('')\n}\n","import type { ContentBlock } from '@agentclientprotocol/sdk'\n\nexport type PiAttachment = {\n id: string\n type: 'image' | 'document'\n fileName: string\n mimeType: string\n size: number\n content: string\n extractedText?: string\n preview?: string\n}\n\nexport function guessFileNameFromMime(mimeType: string): string {\n const ext =\n mimeType === 'image/png' ? 'png' : mimeType === 'image/jpeg' ? 'jpg' : mimeType === 'image/webp' ? 'webp' : 'bin'\n return `attachment.${ext}`\n}\n\nexport function promptToPiMessage(blocks: ContentBlock[]): {\n message: string\n attachments: PiAttachment[]\n} {\n let message = ''\n const attachments: PiAttachment[] = []\n\n for (const b of blocks) {\n switch (b.type) {\n case 'text':\n message += b.text\n break\n\n case 'resource_link':\n // A lightweight, human-readable hint for the LLM.\n message += `\\n[Context] ${b.uri}`\n break\n\n case 'image': {\n const id = b.uri ?? crypto.randomUUID()\n // pi expects base64 without data-url prefix.\n const size = Buffer.byteLength(b.data, 'base64')\n attachments.push({\n id,\n type: 'image',\n fileName: guessFileNameFromMime(b.mimeType),\n mimeType: b.mimeType,\n size,\n content: b.data\n })\n break\n }\n\n case 'resource': {\n // Clients should not send this if embeddedContext=false, but be resilient.\n const r: any = (b as any).resource\n const uri = typeof r?.uri === 'string' ? r.uri : '(unknown)'\n\n if (typeof r?.text === 'string') {\n // TextResourceContents\n const mime = typeof r?.mimeType === 'string' ? r.mimeType : 'text/plain'\n message += `\\n[Embedded Context] ${uri} (${mime})\\n${r.text}`\n } else if (typeof r?.blob === 'string') {\n // BlobResourceContents\n const mime = typeof r?.mimeType === 'string' ? r.mimeType : 'application/octet-stream'\n const bytes = Buffer.byteLength(r.blob, 'base64')\n message += `\\n[Embedded Context] ${uri} (${mime}, ${bytes} bytes)`\n } else {\n message += `\\n[Embedded Context] ${uri}`\n }\n break\n }\n\n case 'audio': {\n // Not supported by pi. Provide a marker so we don't silently drop context.\n const bytes = Buffer.byteLength(b.data, 'base64')\n message += `\\n[Audio] (${b.mimeType}, ${bytes} bytes) not supported by pi-acp`\n break\n }\n\n default:\n // Ignore unknown block types for now.\n break\n }\n }\n\n return { message, attachments }\n}\n"],"mappings":"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","names":["RequestError","readFileSync","mkdirSync","dirname","resolve","readFileSync","homedir","join","resolve","readFileSync","isAbsolute","existsSync","readFileSync","readdirSync","join","dirname","RequestError","result","pkg","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/acp/agent.ts","../src/acp/session.ts","../src/pi-rpc/process.ts","../src/acp/session-store.ts","../src/acp/paths.ts","../src/acp/translate/pi-tools.ts","../src/acp/slash-commands.ts","../src/acp/translate/pi-messages.ts","../src/acp/translate/prompt.ts"],"sourcesContent":["import { AgentSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'\nimport { PiAcpAgent } from './acp/agent.js'\n\n\nconst input = new WritableStream<Uint8Array>({\n write(chunk) {\n return new Promise<void>((resolve, reject) => {\n process.stdout.write(chunk, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n})\n\nconst output = new ReadableStream<Uint8Array>({\n start(controller) {\n process.stdin.on('data', (chunk: Buffer) => controller.enqueue(new Uint8Array(chunk)))\n process.stdin.on('end', () => controller.close())\n process.stdin.on('error', err => controller.error(err))\n }\n})\n\nconst stream = ndJsonStream(input, output)\n\nnew AgentSideConnection(conn => new PiAcpAgent(conn), stream)\n\nprocess.stdin.resume()\nprocess.on('SIGINT', () => process.exit(0))\nprocess.on('SIGTERM', () => process.exit(0))\n","import {\n RequestError,\n type Agent as ACPAgent,\n type AgentSideConnection,\n type AuthenticateRequest,\n type CancelNotification,\n type InitializeRequest,\n type InitializeResponse,\n type LoadSessionRequest,\n type LoadSessionResponse,\n type ModelInfo,\n type NewSessionRequest,\n type PromptRequest,\n type PromptResponse,\n type SetSessionModeRequest,\n type SetSessionModeResponse,\n type StopReason\n} from '@agentclientprotocol/sdk'\nimport { SessionManager } from './session.js'\nimport { SessionStore } from './session-store.js'\nimport { PiRpcProcess } from '../pi-rpc/process.js'\nimport { normalizePiAssistantText, normalizePiMessageText } from './translate/pi-messages.js'\nimport { promptToPiMessage } from './translate/prompt.js'\nimport { loadSlashCommands, parseCommandArgs, toAvailableCommands } from './slash-commands.js'\nimport { isAbsolute } from 'node:path'\nimport { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport type { AvailableCommand } from '@agentclientprotocol/sdk'\nimport { join, dirname } from 'node:path'\nimport { spawnSync } from 'node:child_process'\n\ntype ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'\n\nfunction builtinAvailableCommands(): AvailableCommand[] {\n return [\n {\n name: 'compact',\n description: 'Manually compact the session context',\n input: { hint: 'optional custom instructions' }\n },\n {\n name: 'autocompact',\n description: 'Toggle automatic context compaction',\n input: { hint: 'on|off|toggle' }\n },\n {\n name: 'export',\n description: 'Export session to an HTML file in the session cwd'\n },\n {\n name: 'session',\n description: 'Show session stats (messages, tokens, cost, session file)'\n },\n {\n name: 'steering',\n description: 'Get/set pi steering message delivery mode (how queued steering messages are delivered)',\n input: { hint: '(no args to show) all | one-at-a-time' }\n },\n {\n name: 'follow-up',\n description: 'Get/set pi follow-up message delivery mode (how queued follow-up messages are delivered)',\n input: { hint: '(no args to show) all | one-at-a-time' }\n },\n {\n name: 'changelog',\n description: 'Show pi changelog'\n }\n ]\n}\n\nfunction mergeCommands(a: AvailableCommand[], b: AvailableCommand[]): AvailableCommand[] {\n // Preserve order, de-dupe by name (first wins).\n const out: AvailableCommand[] = []\n const seen = new Set<string>()\n\n for (const c of [...a, ...b]) {\n if (seen.has(c.name)) continue\n seen.add(c.name)\n out.push(c)\n }\n\n return out\n}\nimport { fileURLToPath } from 'node:url'\n\nconst pkg = readNearestPackageJson(import.meta.url)\n\nexport class PiAcpAgent implements ACPAgent {\n private readonly conn: AgentSideConnection\n private readonly sessions = new SessionManager()\n private readonly store = new SessionStore()\n\n constructor(conn: AgentSideConnection) {\n this.conn = conn\n }\n\n async initialize(params: InitializeRequest): Promise<InitializeResponse> {\n // We currently only support ACP protocol version 1.\n const supportedVersion = 1\n const requested = params.protocolVersion\n\n return {\n protocolVersion: requested === supportedVersion ? requested : supportedVersion,\n agentInfo: {\n name: pkg.name ?? 'pi-acp',\n title: 'pi ACP adapter',\n version: pkg.version ?? '0.0.0'\n },\n authMethods: [],\n agentCapabilities: {\n loadSession: true,\n mcpCapabilities: { http: false, sse: false },\n promptCapabilities: {\n image: true,\n audio: false,\n embeddedContext: false\n },\n sessionCapabilities: {}\n }\n }\n }\n\n async newSession(params: NewSessionRequest) {\n if (!isAbsolute(params.cwd)) {\n throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`)\n }\n\n const fileCommands = loadSlashCommands(params.cwd)\n\n // Pi doesn't support mcpServers, but we accept and store.\n const session = await this.sessions.create({\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n conn: this.conn,\n fileCommands\n })\n\n const models = await getModelState(session.proc)\n const thinking = await getThinkingState(session.proc)\n\n const response = {\n sessionId: session.sessionId,\n models,\n modes: thinking,\n _meta: {}\n }\n\n // Advertise slash commands (ACP: available_commands_update)\n // Important: some clients (e.g. Zed) will ignore notifications for an unknown sessionId.\n // So we must send this *after* the session/new response has been delivered.\n setTimeout(() => {\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'available_commands_update',\n availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())\n }\n })\n }, 0)\n\n return response\n }\n\n async authenticate(_params: AuthenticateRequest) {\n // MVP: no auth.\n return\n }\n\n async prompt(params: PromptRequest): Promise<PromptResponse> {\n const session = this.sessions.get(params.sessionId)\n\n const { message, attachments } = promptToPiMessage(params.prompt)\n\n // Built-in ACP slash command handling (headless-friendly subset).\n // Note: file-based slash commands are expanded inside session.prompt().\n if (attachments.length === 0 && message.trimStart().startsWith('/')) {\n const trimmed = message.trim()\n const space = trimmed.indexOf(' ')\n const cmd = space === -1 ? trimmed.slice(1) : trimmed.slice(1, space)\n const argsString = space === -1 ? '' : trimmed.slice(space + 1)\n const args = parseCommandArgs(argsString)\n\n if (cmd === 'compact') {\n const customInstructions = args.join(' ').trim() || undefined\n const res = await session.proc.compact(customInstructions)\n\n const r: any = res && typeof res === 'object' ? (res as any) : null\n const tokensBefore = typeof r?.tokensBefore === 'number' ? r.tokensBefore : null\n const summary = typeof r?.summary === 'string' ? r.summary : null\n\n const headerLines = [\n `Compaction completed.${customInstructions ? ' (custom instructions applied)' : ''}`,\n tokensBefore !== null ? `Tokens before: ${tokensBefore}` : null\n ].filter(Boolean)\n\n const text = headerLines.join('\\n') + (summary ? `\\n\\n${summary}` : '')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'session') {\n const stats = (await session.proc.getSessionStats()) as any\n\n const lines: string[] = []\n if (stats?.sessionId) lines.push(`Session: ${stats.sessionId}`)\n if (stats?.sessionFile) lines.push(`Session file: ${stats.sessionFile}`)\n if (typeof stats?.totalMessages === 'number') lines.push(`Messages: ${stats.totalMessages}`)\n\n if (typeof stats?.cost === 'number') lines.push(`Cost: ${stats.cost}`)\n\n const t = stats?.tokens\n if (t && typeof t === 'object') {\n const parts: string[] = []\n if (typeof t.input === 'number') parts.push(`in ${t.input}`)\n if (typeof t.output === 'number') parts.push(`out ${t.output}`)\n if (typeof t.cacheRead === 'number') parts.push(`cache read ${t.cacheRead}`)\n if (typeof t.cacheWrite === 'number') parts.push(`cache write ${t.cacheWrite}`)\n if (typeof t.total === 'number') parts.push(`total ${t.total}`)\n if (parts.length) lines.push(`Tokens: ${parts.join(', ')}`)\n }\n\n // Fallback if stats shape changes.\n const text = lines.length ? lines.join('\\n') : `Session stats:\\n${JSON.stringify(stats, null, 2)}`\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'steering') {\n const modeRaw = String(args[0] ?? '').toLowerCase()\n const state = (await session.proc.getState()) as any\n const current = String(state?.steeringMode ?? '')\n\n // If no arg, just report current.\n if (!modeRaw) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Steering mode: ${current || 'unknown'}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (modeRaw !== 'all' && modeRaw !== 'one-at-a-time') {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Usage: /steering all | /steering one-at-a-time'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n await session.proc.setSteeringMode(modeRaw as 'all' | 'one-at-a-time')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Steering mode set to: ${modeRaw}` }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'follow-up') {\n const modeRaw = String(args[0] ?? '').toLowerCase()\n const state = (await session.proc.getState()) as any\n const current = String(state?.followUpMode ?? '')\n\n // If no arg, just report current.\n if (!modeRaw) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Follow-up mode: ${current || 'unknown'}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (modeRaw !== 'all' && modeRaw !== 'one-at-a-time') {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Usage: /follow-up all | /follow-up one-at-a-time'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n await session.proc.setFollowUpMode(modeRaw as 'all' | 'one-at-a-time')\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Follow-up mode set to: ${modeRaw}` }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'changelog') {\n // Read pi's installed CHANGELOG.md. Adapter-side, no model call.\n const findChangelog = (): string | null => {\n // 1) Locate the installed pi package by resolving the `pi` executable.\n // On Node installs, `pi` typically resolves to .../@mariozechner/pi-coding-agent/dist/cli.js\n try {\n const whichCmd = process.platform === 'win32' ? 'where' : 'which'\n const which = spawnSync(whichCmd, ['pi'], { encoding: 'utf-8' })\n const piPath = String(which.stdout ?? '')\n .split(/\\r?\\n/)[0]\n ?.trim()\n\n if (piPath) {\n const resolved = realpathSync(piPath)\n const pkgRoot = dirname(dirname(resolved))\n const p = join(pkgRoot, 'CHANGELOG.md')\n if (existsSync(p)) return p\n }\n } catch {\n // ignore\n }\n\n // 2) Fallback: ask npm where global modules live.\n try {\n const npmRoot = spawnSync('npm', ['root', '-g'], { encoding: 'utf-8' })\n const root = String(npmRoot.stdout ?? '').trim()\n if (root) {\n const p = join(root, '@mariozechner', 'pi-coding-agent', 'CHANGELOG.md')\n if (existsSync(p)) return p\n }\n } catch {\n // ignore\n }\n\n return null\n }\n\n const changelogPath = findChangelog()\n if (!changelogPath) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: \"Changelog not found (couldn't locate pi installation).\" }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n let text = ''\n try {\n text = readFileSync(changelogPath, 'utf-8')\n } catch (e: any) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Failed to read changelog: ${String(e?.message ?? e)}` }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n // Keep it reasonably sized in chat.\n const maxChars = 20_000\n if (text.length > maxChars) text = text.slice(0, maxChars) + '\\n\\n...(truncated)...'\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'export') {\n // For now we always export into the session cwd and do not accept a user-provided path.\n // IMPORTANT: pi's export_html reads the session JSONL file. If it doesn't exist yet\n // (no messages) or is empty, pi throws and RPC mode emits an uncorrelated parse error\n // (no id), which would otherwise hang our request. So we guard here.\n const state = (await session.proc.getState()) as any\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n const messageCount = typeof state?.messageCount === 'number' ? state.messageCount : 0\n\n if (!sessionFile || messageCount === 0 || !existsSync(sessionFile)) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Nothing to export yet (no session messages). Send a prompt first.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n try {\n const raw = readFileSync(sessionFile, 'utf-8')\n if (raw.trim().length === 0) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Nothing to export yet (empty session file). Send a prompt first.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n } catch {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: \"Couldn't read session file for export. Try sending a prompt first.\"\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n const safeSessionId = session.sessionId.replace(/[^a-zA-Z0-9_-]/g, '_')\n const outputPath = join(session.cwd, `pi-session-${safeSessionId}.html`)\n\n let resultPath = ''\n try {\n const result = await session.proc.exportHtml(outputPath)\n resultPath = result.path\n } catch (e: any) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Export failed: ${String(e?.message ?? e)}`\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n if (!resultPath) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Export failed: no output path returned by pi.'\n }\n }\n })\n return { stopReason: 'end_turn' }\n }\n\n const uri = `file://${resultPath}`\n\n // Emit a short prefix + a resource link. Many clients concatenate chunks into a single\n // assistant message, so this avoids the \"link + duplicate plain text\" look.\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: 'Session exported: '\n }\n }\n })\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'resource_link',\n name: `pi-session-${safeSessionId}.html`,\n uri,\n mimeType: 'text/html',\n title: 'Session exported'\n }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n\n if (cmd === 'autocompact') {\n const mode = (args[0] ?? 'toggle').toLowerCase()\n let enabled: boolean | null = null\n if (mode === 'on' || mode === 'true' || mode === 'enable' || mode === 'enabled') enabled = true\n else if (mode === 'off' || mode === 'false' || mode === 'disable' || mode === 'disabled') enabled = false\n\n if (enabled === null) {\n // toggle: read current state and invert.\n const state = (await session.proc.getState()) as any\n const current = Boolean(state?.autoCompactionEnabled)\n enabled = !current\n }\n\n await session.proc.setAutoCompaction(enabled)\n\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Auto-compaction ${enabled ? 'enabled' : 'disabled'}.`\n }\n }\n })\n\n return { stopReason: 'end_turn' }\n }\n }\n\n const result = await session.prompt(message, attachments)\n\n // ACP StopReason does not include \"error\"; if pi fails we map to end_turn for now,\n // unless we know this was a cancellation.\n const stopReason: StopReason =\n result === 'error' ? (session.wasCancelRequested() ? 'cancelled' : 'end_turn') : result\n\n return { stopReason }\n }\n\n async cancel(params: CancelNotification): Promise<void> {\n const session = this.sessions.get(params.sessionId)\n await session.cancel()\n }\n\n async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {\n if (!isAbsolute(params.cwd)) {\n throw RequestError.invalidParams(`cwd must be an absolute path: ${params.cwd}`)\n }\n\n // MVP: ignore mcpServers.\n const stored = this.store.get(params.sessionId)\n if (!stored) {\n throw RequestError.invalidParams(`Unknown sessionId: ${params.sessionId}`)\n }\n\n // Spawn pi and point it directly at the stored session file.\n const proc = await PiRpcProcess.spawn({\n cwd: params.cwd,\n sessionPath: stored.sessionFile\n })\n\n const fileCommands = loadSlashCommands(params.cwd)\n\n const session = this.sessions.getOrCreate(params.sessionId, {\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n conn: this.conn,\n proc,\n fileCommands\n })\n\n // (Optional) ensure mapping stays fresh.\n this.store.upsert({\n sessionId: params.sessionId,\n cwd: params.cwd,\n sessionFile: stored.sessionFile\n })\n\n // Replay full conversation history.\n const data = (await proc.getMessages()) as any\n const messages = Array.isArray(data?.messages) ? data.messages : []\n\n for (const m of messages) {\n const role = String(m?.role ?? '')\n\n if (role === 'user') {\n const text = normalizePiMessageText(m?.content)\n if (text) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'user_message_chunk',\n content: { type: 'text', text }\n }\n })\n }\n }\n\n if (role === 'assistant') {\n const text = normalizePiAssistantText(m?.content)\n if (text) {\n await this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text }\n }\n })\n }\n }\n }\n\n const models = await getModelState(proc)\n const thinking = await getThinkingState(proc)\n\n const response = {\n models,\n modes: thinking,\n _meta: {}\n }\n\n // Advertise slash commands after the response so the client knows the session exists.\n setTimeout(() => {\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'available_commands_update',\n availableCommands: mergeCommands(toAvailableCommands(fileCommands), builtinAvailableCommands())\n }\n })\n }, 0)\n\n return response\n }\n\n async unstable_setSessionModel(params: { sessionId: string; modelId: string }): Promise<void> {\n const session = this.sessions.get(params.sessionId)\n\n // Accept either:\n // - \"provider/model\" (preferred, matches how we advertise)\n // - \"model\" (fallback, we try to resolve via available models)\n let provider: string | null = null\n let modelId: string | null = null\n\n if (params.modelId.includes('/')) {\n const [p, ...rest] = params.modelId.split('/')\n provider = p\n modelId = rest.join('/')\n } else {\n modelId = params.modelId\n }\n\n if (!provider) {\n const data = (await session.proc.getAvailableModels()) as any\n const models: any[] = Array.isArray(data?.models) ? data.models : []\n const found = models.find(m => String(m?.id) === modelId)\n if (found) {\n provider = String(found.provider)\n modelId = String(found.id)\n }\n }\n\n if (!provider || !modelId) {\n throw RequestError.invalidParams(`Unknown modelId: ${params.modelId}`)\n }\n\n await session.proc.setModel(provider, modelId)\n }\n\n async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {\n const session = this.sessions.get(params.sessionId)\n\n const mode = String(params.modeId)\n if (!isThinkingLevel(mode)) {\n throw RequestError.invalidParams(`Unknown modeId: ${mode}`)\n }\n\n await session.proc.setThinkingLevel(mode)\n\n // Let the client know the current mode changed (keeps the dropdown in sync).\n void this.conn.sessionUpdate({\n sessionId: session.sessionId,\n update: {\n sessionUpdate: 'current_mode_update',\n currentModeId: mode\n }\n })\n\n return {}\n }\n}\n\nfunction isThinkingLevel(x: string): x is ThinkingLevel {\n return x === 'off' || x === 'minimal' || x === 'low' || x === 'medium' || x === 'high' || x === 'xhigh'\n}\n\nasync function getThinkingState(proc: PiRpcProcess): Promise<{\n availableModes: Array<{\n id: string\n name: string\n description?: string | null\n }>\n currentModeId: string\n}> {\n // Ask pi for current thinking level.\n let current: ThinkingLevel = 'medium'\n try {\n const state = (await proc.getState()) as any\n const tl = typeof state?.thinkingLevel === 'string' ? state.thinkingLevel : null\n if (tl && isThinkingLevel(tl)) current = tl\n } catch {\n // ignore\n }\n\n const available: ThinkingLevel[] = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh']\n\n return {\n currentModeId: current,\n availableModes: available.map(id => ({\n id,\n name: `Thinking: ${id}`,\n description: null\n }))\n }\n}\n\nasync function getModelState(proc: PiRpcProcess): Promise<{\n availableModels: ModelInfo[]\n currentModelId: string\n} | null> {\n // Ask pi for available models.\n let availableModels: ModelInfo[] = []\n try {\n const data = (await proc.getAvailableModels()) as any\n const models: any[] = Array.isArray(data?.models) ? data.models : []\n availableModels = models\n .map(m => {\n const provider = String(m?.provider ?? '').trim()\n const id = String(m?.id ?? '').trim()\n if (!provider || !id) return null\n\n const name = String(m?.name ?? id)\n return {\n modelId: `${provider}/${id}`,\n name: `${provider}/${name}`,\n description: null\n } satisfies ModelInfo\n })\n .filter(Boolean) as ModelInfo[]\n } catch {\n // ignore\n }\n\n // Ask pi what model is currently active.\n let currentModelId: string | null = null\n try {\n const state = (await proc.getState()) as any\n const model = state?.model\n if (model && typeof model === 'object') {\n const provider = String((model as any).provider ?? '').trim()\n const id = String((model as any).id ?? '').trim()\n if (provider && id) currentModelId = `${provider}/${id}`\n }\n } catch {\n // ignore\n }\n\n if (!availableModels.length && !currentModelId) return null\n\n // Fallback if current model is unknown: use first in list.\n if (!currentModelId) currentModelId = availableModels[0]?.modelId ?? 'default'\n\n return {\n availableModels,\n currentModelId\n }\n}\n\nfunction readNearestPackageJson(metaUrl: string): {\n name?: string\n version?: string\n} {\n try {\n let dir = dirname(fileURLToPath(metaUrl))\n\n // Walk upwards a few levels to find the nearest package.json\n for (let i = 0; i < 6; i++) {\n const p = join(dir, 'package.json')\n if (existsSync(p)) {\n const json = JSON.parse(readFileSync(p, 'utf-8')) as any\n return { name: json?.name, version: json?.version }\n }\n dir = dirname(dir)\n }\n } catch {\n // ignore\n }\n return { name: 'pi-acp', version: '0.0.0' }\n}\n","import type {\n AgentSideConnection,\n ContentBlock,\n McpServer,\n SessionUpdate,\n ToolCallContent,\n ToolKind\n} from '@agentclientprotocol/sdk'\nimport { RequestError } from '@agentclientprotocol/sdk'\nimport { readFileSync } from 'node:fs'\nimport { isAbsolute, resolve as resolvePath } from 'node:path'\nimport { PiRpcProcess, type PiRpcEvent } from '../pi-rpc/process.js'\nimport { SessionStore } from './session-store.js'\nimport { toolResultToText } from './translate/pi-tools.js'\nimport { expandSlashCommand, type FileSlashCommand } from './slash-commands.js'\n\ntype SessionCreateParams = {\n cwd: string\n mcpServers: McpServer[]\n conn: AgentSideConnection\n fileCommands?: import('./slash-commands.js').FileSlashCommand[]\n}\n\nexport type StopReason = 'end_turn' | 'cancelled' | 'error'\n\ntype PendingTurn = {\n resolve: (reason: StopReason) => void\n reject: (err: unknown) => void\n}\n\ntype QueuedTurn = {\n message: string\n attachments: unknown[]\n resolve: (reason: StopReason) => void\n reject: (err: unknown) => void\n}\n\nexport class SessionManager {\n private sessions = new Map<string, PiAcpSession>()\n private readonly store = new SessionStore()\n\n /** Get a registered session if it exists (no throw). */\n maybeGet(sessionId: string): PiAcpSession | undefined {\n return this.sessions.get(sessionId)\n }\n\n async create(params: SessionCreateParams): Promise<PiAcpSession> {\n // Let pi manage session persistence in its default location (~/.pi/agent/sessions/...)\n // so sessions are visible to the regular `pi` CLI.\n const proc = await PiRpcProcess.spawn({\n cwd: params.cwd\n })\n\n const state = (await proc.getState()) as any\n const sessionId = typeof state?.sessionId === 'string' ? state.sessionId : crypto.randomUUID()\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n\n if (sessionFile) {\n this.store.upsert({ sessionId, cwd: params.cwd, sessionFile })\n }\n\n const session = new PiAcpSession({\n sessionId,\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n proc,\n conn: params.conn,\n fileCommands: params.fileCommands ?? []\n })\n\n this.sessions.set(sessionId, session)\n return session\n }\n\n get(sessionId: string): PiAcpSession {\n const s = this.sessions.get(sessionId)\n if (!s) throw RequestError.invalidParams(`Unknown sessionId: ${sessionId}`)\n return s\n }\n\n /**\n * Used by session/load: create a session object bound to an existing sessionId/proc\n * if it isn't already registered.\n */\n getOrCreate(sessionId: string, params: SessionCreateParams & { proc: PiRpcProcess }): PiAcpSession {\n const existing = this.sessions.get(sessionId)\n if (existing) return existing\n\n const session = new PiAcpSession({\n sessionId,\n cwd: params.cwd,\n mcpServers: params.mcpServers,\n proc: params.proc,\n conn: params.conn,\n fileCommands: params.fileCommands ?? []\n })\n\n this.sessions.set(sessionId, session)\n return session\n }\n}\n\nexport class PiAcpSession {\n readonly sessionId: string\n readonly cwd: string\n readonly mcpServers: McpServer[]\n\n readonly proc: PiRpcProcess\n private readonly conn: AgentSideConnection\n private readonly fileCommands: FileSlashCommand[]\n\n // Used to map abort semantics to ACP stopReason.\n // Applies to the currently running turn.\n private cancelRequested = false\n\n // Current in-flight turn (if any). Additional prompts are queued.\n private pendingTurn: PendingTurn | null = null\n private readonly turnQueue: QueuedTurn[] = []\n // Track tool call statuses and ensure they are monotonic (pending -> in_progress -> completed).\n // Some pi events can arrive out of order (e.g. late toolcall_* deltas after execution starts),\n // and clients may hide progress if we ever downgrade back to `pending`.\n private currentToolCalls = new Map<string, 'pending' | 'in_progress'>()\n\n // pi can emit multiple `turn_end` events for a single user prompt (e.g. after tool_use).\n // The overall agent loop completes when `agent_end` is emitted.\n private inAgentLoop = false\n\n // For ACP diff support: capture file contents before edits, then emit ToolCallContent {type:\"diff\"}.\n // This is due to pi sending diff as a string as opposed to ACP expected diff format.\n // Compatible format may need to be implemented in pi in the future.\n private editSnapshots = new Map<string, { path: string; oldText: string }>()\n\n // Ensure `session/update` notifications are sent in order and can be awaited\n // before completing a `session/prompt` request.\n private lastEmit: Promise<void> = Promise.resolve()\n\n constructor(opts: {\n sessionId: string\n cwd: string\n mcpServers: McpServer[]\n proc: PiRpcProcess\n conn: AgentSideConnection\n fileCommands?: FileSlashCommand[]\n }) {\n this.sessionId = opts.sessionId\n this.cwd = opts.cwd\n this.mcpServers = opts.mcpServers\n this.proc = opts.proc\n this.conn = opts.conn\n this.fileCommands = opts.fileCommands ?? []\n\n this.proc.onEvent(ev => this.handlePiEvent(ev))\n }\n\n async prompt(message: string, attachments: unknown[] = []): Promise<StopReason> {\n // pi RPC mode disables slash command expansion, so we do it here.\n const expandedMessage = expandSlashCommand(message, this.fileCommands)\n\n const turnPromise = new Promise<StopReason>((resolve, reject) => {\n const queued: QueuedTurn = { message: expandedMessage, attachments, resolve, reject }\n\n // If a turn is already running, enqueue.\n if (this.pendingTurn) {\n this.turnQueue.push(queued)\n\n // Best-effort: notify client that a prompt was queued.\n // This doesn't work in Zed yet, needs to be revisited\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: {\n type: 'text',\n text: `Queued message (position ${this.turnQueue.length}).`\n }\n })\n\n // Also publish queue depth via session info metadata.\n // This also not visible in the client\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: true } }\n })\n\n return\n }\n\n // No turn is running; start immediately.\n this.startTurn(queued)\n })\n\n return turnPromise\n }\n\n async cancel(): Promise<void> {\n // Cancel current and clear any queued prompts.\n this.cancelRequested = true\n\n if (this.turnQueue.length) {\n const queued = this.turnQueue.splice(0, this.turnQueue.length)\n for (const t of queued) t.resolve('cancelled')\n\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: 'Cleared queued prompts.' }\n })\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: 0, running: Boolean(this.pendingTurn) } }\n })\n }\n\n // Abort the currently running turn (if any). If nothing is running, this is a no-op.\n await this.proc.abort()\n }\n\n wasCancelRequested(): boolean {\n return this.cancelRequested\n }\n\n private emit(update: SessionUpdate): void {\n // Serialize update delivery.\n this.lastEmit = this.lastEmit\n .then(() =>\n this.conn.sessionUpdate({\n sessionId: this.sessionId,\n update\n })\n )\n .catch(() => {\n // Ignore notification errors (client may have gone away). We still want\n // prompt completion.\n })\n }\n\n private async flushEmits(): Promise<void> {\n await this.lastEmit\n }\n\n private startTurn(t: QueuedTurn): void {\n this.cancelRequested = false\n this.inAgentLoop = false\n\n this.pendingTurn = { resolve: t.resolve, reject: t.reject }\n\n // Publish queue depth (0 because we're starting the turn now).\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: true } }\n })\n\n // Kick off pi, but completion is determined by pi events, not the RPC response.\n // Important: pi may emit multiple `turn_end` events (e.g. when the model requests tools).\n // The full prompt is finished when we see `agent_end`.\n this.proc.prompt(t.message, t.attachments).catch(err => {\n // If the subprocess errors before we get an `agent_end`, treat as error unless cancelled.\n // Also ensure we flush any already-enqueued updates first.\n void this.flushEmits().finally(() => {\n const reason: StopReason = this.cancelRequested ? 'cancelled' : 'error'\n this.pendingTurn?.resolve(reason)\n this.pendingTurn = null\n this.inAgentLoop = false\n\n // If the prompt failed, do not automatically proceed—pi may be unhealthy.\n // But we still clear the queueDepth metadata.\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: this.turnQueue.length, running: false } }\n })\n })\n void err\n })\n }\n\n private handlePiEvent(ev: PiRpcEvent) {\n const type = String((ev as any).type ?? '')\n\n switch (type) {\n case 'message_update': {\n const ame = (ev as any).assistantMessageEvent\n\n // Stream assistant text.\n if (ame?.type === 'text_delta' && typeof ame.delta === 'string') {\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: ame.delta } satisfies ContentBlock\n })\n break\n }\n\n // Surface tool calls ASAP so clients (e.g. Zed) can show a tool-in-use/loading UI\n // while the model is still streaming tool call args.\n if (ame?.type === 'toolcall_start' || ame?.type === 'toolcall_delta' || ame?.type === 'toolcall_end') {\n const toolCall =\n // pi sometimes includes the tool call directly on the event\n (ame as any)?.toolCall ??\n // ...and always includes it in the partial assistant message at contentIndex\n (ame as any)?.partial?.content?.[(ame as any)?.contentIndex ?? 0]\n\n const toolCallId = String((toolCall as any)?.id ?? '')\n const toolName = String((toolCall as any)?.name ?? 'tool')\n\n if (toolCallId) {\n const rawInput =\n (toolCall as any)?.arguments && typeof (toolCall as any).arguments === 'object'\n ? (toolCall as any).arguments\n : (() => {\n const s = String((toolCall as any)?.partialArgs ?? '')\n if (!s) return undefined\n try {\n return JSON.parse(s)\n } catch {\n return { partialArgs: s }\n }\n })()\n\n const existingStatus = this.currentToolCalls.get(toolCallId)\n // IMPORTANT: never downgrade status (e.g. if we already marked in_progress via tool_execution_start).\n const status = existingStatus ?? 'pending'\n\n if (!existingStatus) {\n this.currentToolCalls.set(toolCallId, 'pending')\n this.emit({\n sessionUpdate: 'tool_call',\n toolCallId,\n title: toolName,\n kind: toToolKind(toolName),\n status,\n rawInput\n })\n } else {\n // Best-effort: keep rawInput updated while args are streaming.\n // Keep the existing status (pending or in_progress).\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status,\n rawInput\n })\n }\n }\n\n break\n }\n\n // (MVP) ignore other delta types (thinking, etc.) for now.\n break\n }\n\n case 'tool_execution_start': {\n const toolCallId = String((ev as any).toolCallId ?? crypto.randomUUID())\n const toolName = String((ev as any).toolName ?? 'tool')\n const args = (ev as any).args\n\n // Capture pre-edit file contents so we can emit a structured ACP diff on completion.\n if (toolName === 'edit') {\n const p = typeof args?.path === 'string' ? args.path : undefined\n if (p) {\n try {\n const abs = isAbsolute(p) ? p : resolvePath(this.cwd, p)\n const oldText = readFileSync(abs, 'utf8')\n this.editSnapshots.set(toolCallId, { path: p, oldText })\n } catch {\n // Ignore snapshot failures; we'll fall back to plain text output.\n }\n }\n }\n\n // If we already surfaced the tool call while the model streamed it, just transition.\n if (!this.currentToolCalls.has(toolCallId)) {\n this.currentToolCalls.set(toolCallId, 'in_progress')\n this.emit({\n sessionUpdate: 'tool_call',\n toolCallId,\n title: toolName,\n kind: toToolKind(toolName),\n status: 'in_progress',\n rawInput: args\n })\n } else {\n this.currentToolCalls.set(toolCallId, 'in_progress')\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: 'in_progress',\n rawInput: args\n })\n }\n\n break\n }\n\n case 'tool_execution_update': {\n const toolCallId = String((ev as any).toolCallId ?? '')\n if (!toolCallId) break\n\n const partial = (ev as any).partialResult\n const text = toolResultToText(partial)\n\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: 'in_progress',\n content: text\n ? ([{ type: 'content', content: { type: 'text', text } }] satisfies ToolCallContent[])\n : undefined,\n rawOutput: partial\n })\n break\n }\n\n case 'tool_execution_end': {\n const toolCallId = String((ev as any).toolCallId ?? '')\n if (!toolCallId) break\n\n const result = (ev as any).result\n const isError = Boolean((ev as any).isError)\n const text = toolResultToText(result)\n\n // If this was an edit and we captured a snapshot, emit a structured ACP diff.\n // This enables clients like Zed to render an actual diff UI.\n const snapshot = this.editSnapshots.get(toolCallId)\n let content: ToolCallContent[] | undefined\n\n if (!isError && snapshot) {\n try {\n const abs = isAbsolute(snapshot.path) ? snapshot.path : resolvePath(this.cwd, snapshot.path)\n const newText = readFileSync(abs, 'utf8')\n if (newText !== snapshot.oldText) {\n content = [\n {\n type: 'diff',\n path: snapshot.path,\n oldText: snapshot.oldText,\n newText\n },\n ...(text ? ([{ type: 'content', content: { type: 'text', text } }] as ToolCallContent[]) : [])\n ]\n }\n } catch {\n // ignore; fall back to text only\n }\n }\n\n // Fallback: just text content.\n if (!content && text) {\n content = [{ type: 'content', content: { type: 'text', text } }] satisfies ToolCallContent[]\n }\n\n this.emit({\n sessionUpdate: 'tool_call_update',\n toolCallId,\n status: isError ? 'failed' : 'completed',\n content,\n rawOutput: result\n })\n\n this.currentToolCalls.delete(toolCallId)\n this.editSnapshots.delete(toolCallId)\n break\n }\n\n case 'agent_start': {\n this.inAgentLoop = true\n break\n }\n\n case 'turn_end': {\n // pi uses `turn_end` for sub-steps (e.g. tool_use) and will often start another turn.\n // Do NOT resolve the ACP `session/prompt` here; wait for `agent_end`.\n break\n }\n\n case 'agent_end': {\n // Ensure all updates derived from pi events are delivered before we resolve\n // the ACP `session/prompt` request.\n void this.flushEmits().finally(() => {\n const reason: StopReason = this.cancelRequested ? 'cancelled' : 'end_turn'\n this.pendingTurn?.resolve(reason)\n this.pendingTurn = null\n this.inAgentLoop = false\n\n // Start next queued prompt, if any.\n const next = this.turnQueue.shift()\n if (next) {\n this.emit({\n sessionUpdate: 'agent_message_chunk',\n content: { type: 'text', text: `Starting queued message. (${this.turnQueue.length} remaining)` }\n })\n this.startTurn(next)\n } else {\n this.emit({\n sessionUpdate: 'session_info_update',\n _meta: { piAcp: { queueDepth: 0, running: false } }\n })\n }\n })\n break\n }\n\n default:\n break\n }\n }\n}\n\nfunction toToolKind(toolName: string): ToolKind {\n switch (toolName) {\n case 'read':\n return 'read'\n case 'write':\n case 'edit':\n return 'edit'\n case 'bash':\n // Many ACP clients render `execute` tool calls only via the terminal APIs.\n // Since this adapter lets pi execute locally (no client terminal delegation),\n // we report bash as `other` so clients show inline text output blocks.\n return 'other'\n default:\n return 'other'\n }\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport * as readline from 'node:readline'\n\ntype PiRpcCommand =\n | { type: 'prompt'; id?: string; message: string; attachments?: unknown[] }\n | { type: 'abort'; id?: string }\n | { type: 'get_state'; id?: string }\n // Model\n | { type: 'get_available_models'; id?: string }\n | { type: 'set_model'; id?: string; provider: string; modelId: string }\n // Thinking\n | { type: 'set_thinking_level'; id?: string; level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' }\n // Modes\n | { type: 'set_follow_up_mode'; id?: string; mode: 'all' | 'one-at-a-time' }\n | { type: 'set_steering_mode'; id?: string; mode: 'all' | 'one-at-a-time' }\n // Compaction\n | { type: 'compact'; id?: string; customInstructions?: string }\n | { type: 'set_auto_compaction'; id?: string; enabled: boolean }\n // Session\n | { type: 'get_session_stats'; id?: string }\n | { type: 'export_html'; id?: string; outputPath?: string }\n | { type: 'switch_session'; id?: string; sessionPath: string }\n // Messages\n | { type: 'get_messages'; id?: string }\n\ntype PiRpcResponse = {\n type: 'response'\n id?: string\n command: string\n success: boolean\n data?: unknown\n error?: string\n}\n\nexport type PiRpcEvent = Record<string, unknown>\n\ntype SpawnParams = {\n cwd: string\n /** Optional override for `pi` executable name/path */\n piCommand?: string\n /** If set, pi will persist the session to this exact file (via `--session <path>`). */\n sessionPath?: string\n}\n\nexport class PiRpcProcess {\n private readonly child: ChildProcessWithoutNullStreams\n private readonly pending = new Map<string, { resolve: (v: PiRpcResponse) => void; reject: (e: unknown) => void }>()\n private eventHandlers: Array<(ev: PiRpcEvent) => void> = []\n\n private constructor(child: ChildProcessWithoutNullStreams) {\n this.child = child\n\n const rl = readline.createInterface({ input: child.stdout })\n rl.on('line', line => {\n if (!line.trim()) return\n let msg: any\n try {\n msg = JSON.parse(line)\n } catch {\n // ignore malformed lines for now\n return\n }\n\n if (msg?.type === 'response') {\n const id = typeof msg.id === 'string' ? msg.id : undefined\n if (id) {\n const pending = this.pending.get(id)\n if (pending) {\n this.pending.delete(id)\n pending.resolve(msg as PiRpcResponse)\n return\n }\n }\n }\n\n for (const h of this.eventHandlers) h(msg as PiRpcEvent)\n })\n\n child.on('exit', (code, signal) => {\n const err = new Error(`pi process exited (code=${code}, signal=${signal})`)\n for (const [, p] of this.pending) p.reject(err)\n this.pending.clear()\n })\n }\n\n static async spawn(params: SpawnParams): Promise<PiRpcProcess> {\n const cmd = params.piCommand ?? 'pi'\n\n const args = ['--mode', 'rpc']\n if (params.sessionPath) args.push('--session', params.sessionPath)\n\n const child = spawn(cmd, args, {\n cwd: params.cwd,\n stdio: 'pipe',\n env: process.env\n })\n\n child.stderr.on('data', () => {\n // leave stderr untouched; ACP clients may capture it.\n })\n\n const proc = new PiRpcProcess(child)\n\n // Best-effort handshake.\n // Important: pi may emit a get_state response pointing at a sessionFile in a directory\n // that is created lazily. Create the parent dir up-front to avoid later parse errors\n // when we call commands like export_html.\n try {\n const state = (await proc.getState()) as any\n const sessionFile = typeof state?.sessionFile === 'string' ? state.sessionFile : null\n if (sessionFile) {\n const { mkdirSync } = await import('node:fs')\n const { dirname } = await import('node:path')\n mkdirSync(dirname(sessionFile), { recursive: true })\n }\n } catch {\n // ignore for now\n }\n\n return proc\n }\n\n onEvent(handler: (ev: PiRpcEvent) => void): () => void {\n this.eventHandlers.push(handler)\n return () => {\n this.eventHandlers = this.eventHandlers.filter(h => h !== handler)\n }\n }\n\n async prompt(message: string, attachments: unknown[] = []): Promise<void> {\n const res = await this.request({ type: 'prompt', message, attachments })\n if (!res.success) throw new Error(`pi prompt failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async abort(): Promise<void> {\n const res = await this.request({ type: 'abort' })\n if (!res.success) throw new Error(`pi abort failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getState(): Promise<unknown> {\n const res = await this.request({ type: 'get_state' })\n if (!res.success) throw new Error(`pi get_state failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async getAvailableModels(): Promise<unknown> {\n const res = await this.request({ type: 'get_available_models' })\n if (!res.success) throw new Error(`pi get_available_models failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setModel(provider: string, modelId: string): Promise<unknown> {\n const res = await this.request({ type: 'set_model', provider, modelId })\n if (!res.success) throw new Error(`pi set_model failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setThinkingLevel(level: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'): Promise<void> {\n const res = await this.request({ type: 'set_thinking_level', level })\n if (!res.success) throw new Error(`pi set_thinking_level failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async setFollowUpMode(mode: 'all' | 'one-at-a-time'): Promise<void> {\n const res = await this.request({ type: 'set_follow_up_mode', mode })\n if (!res.success) throw new Error(`pi set_follow_up_mode failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async setSteeringMode(mode: 'all' | 'one-at-a-time'): Promise<void> {\n const res = await this.request({ type: 'set_steering_mode', mode })\n if (!res.success) throw new Error(`pi set_steering_mode failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async compact(customInstructions?: string): Promise<unknown> {\n const res = await this.request({ type: 'compact', customInstructions })\n if (!res.success) throw new Error(`pi compact failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async setAutoCompaction(enabled: boolean): Promise<void> {\n const res = await this.request({ type: 'set_auto_compaction', enabled })\n if (!res.success) throw new Error(`pi set_auto_compaction failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getSessionStats(): Promise<unknown> {\n const res = await this.request({ type: 'get_session_stats' })\n if (!res.success) throw new Error(`pi get_session_stats failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n async exportHtml(outputPath?: string): Promise<{ path: string }> {\n const res = await this.request({ type: 'export_html', outputPath })\n if (!res.success) throw new Error(`pi export_html failed: ${res.error ?? JSON.stringify(res.data)}`)\n const data: any = res.data\n return { path: String(data?.path ?? '') }\n }\n\n async switchSession(sessionPath: string): Promise<void> {\n const res = await this.request({ type: 'switch_session', sessionPath })\n if (!res.success) throw new Error(`pi switch_session failed: ${res.error ?? JSON.stringify(res.data)}`)\n }\n\n async getMessages(): Promise<unknown> {\n const res = await this.request({ type: 'get_messages' })\n if (!res.success) throw new Error(`pi get_messages failed: ${res.error ?? JSON.stringify(res.data)}`)\n return res.data\n }\n\n private request(cmd: PiRpcCommand): Promise<PiRpcResponse> {\n const id = crypto.randomUUID()\n const withId = { ...cmd, id }\n\n const line = JSON.stringify(withId) + '\\n'\n\n return new Promise<PiRpcResponse>((resolve, reject) => {\n this.pending.set(id, { resolve, reject })\n this.child.stdin.write(line, err => {\n if (err) {\n this.pending.delete(id)\n reject(err)\n }\n })\n })\n }\n}\n","import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { getPiAcpSessionMapPath } from './paths.js'\n\nexport type StoredSession = {\n sessionId: string\n cwd: string\n sessionFile: string\n updatedAt: string\n}\n\ntype SessionMapFile = {\n version: 1\n sessions: Record<string, StoredSession>\n}\n\nfunction ensureParentDir(path: string) {\n mkdirSync(dirname(path), { recursive: true })\n}\n\nfunction loadFile(path: string): SessionMapFile {\n try {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as SessionMapFile\n if (parsed?.version !== 1 || typeof parsed.sessions !== 'object' || !parsed.sessions) {\n return { version: 1, sessions: {} }\n }\n return parsed\n } catch {\n return { version: 1, sessions: {} }\n }\n}\n\nfunction saveFile(path: string, data: SessionMapFile): void {\n ensureParentDir(path)\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n', 'utf-8')\n}\n\nexport class SessionStore {\n private readonly path: string\n\n constructor(path = getPiAcpSessionMapPath()) {\n this.path = path\n }\n\n get(sessionId: string): StoredSession | null {\n const db = loadFile(this.path)\n return db.sessions[sessionId] ?? null\n }\n\n upsert(entry: { sessionId: string; cwd: string; sessionFile: string }): void {\n const db = loadFile(this.path)\n db.sessions[entry.sessionId] = {\n sessionId: entry.sessionId,\n cwd: entry.cwd,\n sessionFile: entry.sessionFile,\n updatedAt: new Date().toISOString()\n }\n saveFile(this.path, db)\n }\n}\n","import { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n/**\n * Storage owned by the ACP adapter.\n *\n * We intentionally keep this separate from pi's own ~/.pi/agent/* directory.\n */\nexport function getPiAcpDir(): string {\n return join(homedir(), '.pi', 'pi-acp')\n}\n\nexport function getPiAcpSessionMapPath(): string {\n return join(getPiAcpDir(), 'session-map.json')\n}\n","export function toolResultToText(result: unknown): string {\n if (!result) return ''\n\n // pi tool results generally look like: { content: [{type:\"text\", text:\"...\"}], details: {...} }\n const content = (result as any).content\n if (Array.isArray(content)) {\n const texts = content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n if (texts.length) return texts.join('')\n }\n\n const details = (result as any)?.details\n\n // Some pi tools return a unified diff in `details.diff`.\n const diff = details?.diff\n if (typeof diff === 'string' && diff.trim()) {\n return diff\n }\n\n // The bash tool frequently returns stdout/stderr in `details` rather than content blocks.\n const stdout =\n (typeof details?.stdout === 'string' ? details.stdout : undefined) ??\n (typeof (result as any)?.stdout === 'string' ? (result as any).stdout : undefined) ??\n (typeof details?.output === 'string' ? details.output : undefined) ??\n (typeof (result as any)?.output === 'string' ? (result as any).output : undefined)\n\n const stderr =\n (typeof details?.stderr === 'string' ? details.stderr : undefined) ??\n (typeof (result as any)?.stderr === 'string' ? (result as any).stderr : undefined)\n\n const exitCode =\n (typeof details?.exitCode === 'number' ? details.exitCode : undefined) ??\n (typeof (result as any)?.exitCode === 'number' ? (result as any).exitCode : undefined) ??\n (typeof details?.code === 'number' ? details.code : undefined) ??\n (typeof (result as any)?.code === 'number' ? (result as any).code : undefined)\n\n if ((typeof stdout === 'string' && stdout.trim()) || (typeof stderr === 'string' && stderr.trim())) {\n const parts: string[] = []\n if (typeof stdout === 'string' && stdout.trim()) parts.push(stdout)\n if (typeof stderr === 'string' && stderr.trim()) parts.push(`stderr:\\n${stderr}`)\n if (typeof exitCode === 'number') parts.push(`exit code: ${exitCode}`)\n return parts.join('\\n\\n').trimEnd()\n }\n\n try {\n return JSON.stringify(result, null, 2)\n } catch {\n return String(result)\n }\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join, resolve } from 'node:path'\nimport type { AvailableCommand } from '@agentclientprotocol/sdk'\n\n/**\n * File-based slash command (mirrors pi-coding-agent semantics).\n */\nexport type FileSlashCommand = {\n name: string\n description: string\n content: string\n source: string // e.g. \"(user)\", \"(project)\", \"(project:frontend)\"\n}\n\nfunction parseFrontmatter(content: string): {\n frontmatter: Record<string, string>\n content: string\n} {\n const frontmatter: Record<string, string> = {}\n\n if (!content.startsWith('---')) return { frontmatter, content }\n\n const endIndex = content.indexOf('\\n---', 3)\n if (endIndex === -1) return { frontmatter, content }\n\n const frontmatterBlock = content.slice(4, endIndex)\n const remaining = content.slice(endIndex + 4).trim()\n\n for (const line of frontmatterBlock.split('\\n')) {\n const match = line.match(/^(\\w+):\\s*(.*)$/)\n if (match) frontmatter[match[1]] = match[2].trim()\n }\n\n return { frontmatter, content: remaining }\n}\n\nfunction loadCommandsFromDir(dir: string, source: 'user' | 'project', subdir = ''): FileSlashCommand[] {\n const commands: FileSlashCommand[] = []\n if (!existsSync(dir)) return commands\n\n try {\n const entries = readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n\n if (entry.isDirectory()) {\n const newSubdir = subdir ? `${subdir}:${entry.name}` : entry.name\n commands.push(...loadCommandsFromDir(fullPath, source, newSubdir))\n continue\n }\n\n if (!entry.isFile() || !entry.name.endsWith('.md')) continue\n\n try {\n const rawContent = readFileSync(fullPath, 'utf-8')\n const { frontmatter, content } = parseFrontmatter(rawContent)\n\n const name = entry.name.slice(0, -3)\n\n const sourceStr =\n source === 'user' ? (subdir ? `(user:${subdir})` : '(user)') : subdir ? `(project:${subdir})` : '(project)'\n\n let description = frontmatter.description || ''\n if (!description) {\n const firstLine = content.split('\\n').find(l => l.trim())\n if (firstLine) {\n description = firstLine.slice(0, 60)\n if (firstLine.length > 60) description += '...'\n }\n }\n\n description = description ? `${description} ${sourceStr}` : sourceStr\n\n commands.push({\n name,\n description,\n content,\n source: sourceStr\n })\n } catch {\n // Silently skip unreadable files.\n }\n }\n } catch {\n // Silently skip unreadable dirs.\n }\n\n return commands\n}\n\n/**\n * Load prompt templates from pi's prompt directories (formerly \"commands\").\n * - user: ~/.pi/agent/prompts/**\\/*.md\n * - project: <cwd>/.pi/prompts/**\\/*.md\n */\nexport function loadSlashCommands(cwd: string): FileSlashCommand[] {\n const commands: FileSlashCommand[] = []\n\n const userDir = join(homedir(), '.pi', 'agent', 'prompts')\n const projectDir = resolve(cwd, '.pi', 'prompts')\n\n // Match pi ordering: user first, then project.\n commands.push(...loadCommandsFromDir(userDir, 'user'))\n commands.push(...loadCommandsFromDir(projectDir, 'project'))\n\n return commands\n}\n\n/**\n * Convert file-based commands to ACP AvailableCommand objects.\n * De-dupes by name (first wins).\n */\nexport function toAvailableCommands(fileCommands: FileSlashCommand[]): AvailableCommand[] {\n const seen = new Set<string>()\n const out: AvailableCommand[] = []\n\n for (const c of fileCommands) {\n if (seen.has(c.name)) continue\n seen.add(c.name)\n\n out.push({\n name: c.name,\n description: c.description\n // input: omitted for now (pi commands don't specify this)\n })\n }\n\n return out\n}\n\n/**\n * Parse command args (bash-style quotes).\n */\nexport function parseCommandArgs(argsString: string): string[] {\n const args: string[] = []\n let current = ''\n let inQuote: string | null = null\n\n for (let i = 0; i < argsString.length; i++) {\n const ch = argsString[i]\n\n if (inQuote) {\n if (ch === inQuote) inQuote = null\n else current += ch\n continue\n }\n\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch\n } else if (ch === ' ' || ch === '\\t') {\n if (current) {\n args.push(current)\n current = ''\n }\n } else {\n current += ch\n }\n }\n\n if (current) args.push(current)\n return args\n}\n\n/**\n * Substitute $1, $2, ... and $@.\n */\nexport function substituteArgs(content: string, args: string[]): string {\n let result = content\n\n result = result.replace(/\\$@/g, args.join(' '))\n result = result.replace(/\\$(\\d+)/g, (_m, num) => {\n const idx = Number.parseInt(String(num), 10) - 1\n return args[idx] ?? ''\n })\n\n return result\n}\n\n/**\n * Expand a leading /command using the loaded file commands.\n * Returns original text if it's not a known slash command.\n */\nexport function expandSlashCommand(text: string, fileCommands: FileSlashCommand[]): string {\n if (!text.startsWith('/')) return text\n\n const spaceIndex = text.indexOf(' ')\n const commandName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex)\n const argsString = spaceIndex === -1 ? '' : text.slice(spaceIndex + 1)\n\n const cmd = fileCommands.find(c => c.name === commandName)\n if (!cmd) return text\n\n const args = parseCommandArgs(argsString)\n return substituteArgs(cmd.content, args)\n}\n","export function normalizePiMessageText(content: unknown): string {\n if (typeof content === 'string') return content\n if (!Array.isArray(content)) return ''\n return content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n .join('')\n}\n\nexport function normalizePiAssistantText(content: unknown): string {\n // Assistant content is typically an array of blocks; only replay text blocks for MVP.\n if (!Array.isArray(content)) return ''\n return content\n .map((c: any) => (c?.type === 'text' && typeof c.text === 'string' ? c.text : ''))\n .filter(Boolean)\n .join('')\n}\n","import type { ContentBlock } from '@agentclientprotocol/sdk'\n\nexport type PiAttachment = {\n id: string\n type: 'image' | 'document'\n fileName: string\n mimeType: string\n size: number\n content: string\n extractedText?: string\n preview?: string\n}\n\nexport function guessFileNameFromMime(mimeType: string): string {\n const ext =\n mimeType === 'image/png' ? 'png' : mimeType === 'image/jpeg' ? 'jpg' : mimeType === 'image/webp' ? 'webp' : 'bin'\n return `attachment.${ext}`\n}\n\nexport function promptToPiMessage(blocks: ContentBlock[]): {\n message: string\n attachments: PiAttachment[]\n} {\n let message = ''\n const attachments: PiAttachment[] = []\n\n for (const b of blocks) {\n switch (b.type) {\n case 'text':\n message += b.text\n break\n\n case 'resource_link':\n // A lightweight, human-readable hint for the LLM.\n message += `\\n[Context] ${b.uri}`\n break\n\n case 'image': {\n const id = b.uri ?? crypto.randomUUID()\n // pi expects base64 without data-url prefix.\n const size = Buffer.byteLength(b.data, 'base64')\n attachments.push({\n id,\n type: 'image',\n fileName: guessFileNameFromMime(b.mimeType),\n mimeType: b.mimeType,\n size,\n content: b.data\n })\n break\n }\n\n case 'resource': {\n // Clients should not send this if embeddedContext=false, but be resilient.\n const r: any = (b as any).resource\n const uri = typeof r?.uri === 'string' ? r.uri : '(unknown)'\n\n if (typeof r?.text === 'string') {\n // TextResourceContents\n const mime = typeof r?.mimeType === 'string' ? r.mimeType : 'text/plain'\n message += `\\n[Embedded Context] ${uri} (${mime})\\n${r.text}`\n } else if (typeof r?.blob === 'string') {\n // BlobResourceContents\n const mime = typeof r?.mimeType === 'string' ? r.mimeType : 'application/octet-stream'\n const bytes = Buffer.byteLength(r.blob, 'base64')\n message += `\\n[Embedded Context] ${uri} (${mime}, ${bytes} bytes)`\n } else {\n message += `\\n[Embedded Context] ${uri}`\n }\n break\n }\n\n case 'audio': {\n // Not supported by pi. Provide a marker so we don't silently drop context.\n const bytes = Buffer.byteLength(b.data, 'base64')\n message += `\\n[Audio] (${b.mimeType}, ${bytes} bytes) not supported by pi-acp`\n break\n }\n\n default:\n // Ignore unknown block types for now.\n break\n }\n }\n\n return { message, attachments }\n}\n"],"mappings":"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","names":["RequestError","readFileSync","mkdirSync","dirname","resolve","readFileSync","homedir","join","resolve","readFileSync","isAbsolute","existsSync","readFileSync","join","dirname","RequestError","result","resolve"]}
|