pi-acp 0.0.26 → 0.0.27

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # pi-acp
2
2
 
3
- ACP ([Agent Client Protocol](https://agentclientprotocol.com/overview/introduction)) adapter for [`pi`](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent) coding agent (fka shitty coding agent).
3
+ ACP ([Agent Client Protocol](https://agentclientprotocol.com/overview/introduction)) adapter for [`pi`](https://github.com/earendil-works/pi) coding agent (fka shitty coding agent).
4
4
 
5
5
  `pi-acp` communicates **ACP JSON-RPC 2.0 over stdio** to an ACP client (e.g. Zed editor) and spawns `pi --mode rpc`, bridging requests/events between the two.
6
6
 
@@ -34,7 +34,7 @@ Expect some minor breaking changes.
34
34
  Make sure pi is installed
35
35
 
36
36
  ```bash
37
- npm install -g @mariozechner/pi-coding-agent
37
+ npm install -g @earendil-works/pi-coding-agent
38
38
  ```
39
39
 
40
40
  - Node.js 22+
@@ -195,7 +195,7 @@ Project layout:
195
195
  ## Limitations
196
196
 
197
197
  - No ACP filesystem delegation (`fs/*`) and no ACP terminal delegation (`terminal/*`). pi reads/writes and executes locally.
198
- - MCP servers are accepted in ACP params and stored in session state, but not wired through to pi (see [why](https://mariozechner.at/posts/2025-11-02-what-if-you-dont-need-mcp/)). If you use [pi MCP adapter](https://github.com/nicobailon/pi-mcp-adapter) it will be available in the ACP client.
198
+ - MCP servers are accepted in ACP params and stored in session state, but not wired through to pi in this adapter. If you use [pi MCP adapter](https://github.com/nicobailon/pi-mcp-adapter) it will be available in the ACP client.
199
199
  - Assistant streaming is currently sent as `agent_message_chunk` (no separate thought stream).
200
200
  - Queue is implemented client-side and should work like pi's `one-at-a-time`
201
201
  - ~~ACP clients don't yet suport session history, but ACP sessions from `pi-acp` can be `/resume`d in pi directly~~
package/dist/index.js CHANGED
@@ -171,10 +171,10 @@ var PiRpcProcess = class _PiRpcProcess {
171
171
  shell: shouldUseShellForPiCommand(cmd)
172
172
  });
173
173
  try {
174
- await new Promise((resolve3, reject) => {
174
+ await new Promise((resolve4, reject) => {
175
175
  const onSpawn = () => {
176
176
  cleanup();
177
- resolve3();
177
+ resolve4();
178
178
  };
179
179
  const onError = (err) => {
180
180
  cleanup();
@@ -191,7 +191,7 @@ var PiRpcProcess = class _PiRpcProcess {
191
191
  const code = typeof e?.code === "string" ? e.code : void 0;
192
192
  if (code === "ENOENT") {
193
193
  throw new PiRpcSpawnError(
194
- `Could not start pi: executable not found (command: ${cmd}). Pi needs to be installed before it can run in ACP clients. Install it via \`npm install -g @mariozechner/pi-coding-agent\` or ensure \`pi\` is on your PATH. Then try again.`,
194
+ `Could not start pi: executable not found (command: ${cmd}). Pi needs to be installed before it can run in ACP clients. Install it via \`npm install -g @earendil-works/pi-coding-agent\` or ensure \`pi\` is on your PATH. Then try again.`,
195
195
  { code, cause: e }
196
196
  );
197
197
  }
@@ -313,8 +313,8 @@ var PiRpcProcess = class _PiRpcProcess {
313
313
  const id = crypto.randomUUID();
314
314
  const withId = { ...cmd, id };
315
315
  const line = JSON.stringify(withId) + "\n";
316
- return new Promise((resolve3, reject) => {
317
- this.pending.set(id, { resolve: resolve3, reject });
316
+ return new Promise((resolve4, reject) => {
317
+ this.pending.set(id, { resolve: resolve4, reject });
318
318
  try {
319
319
  this.child.stdin.write(line, (err) => {
320
320
  if (err) {
@@ -383,6 +383,12 @@ var SessionStore = class {
383
383
  };
384
384
  saveFile(this.path, db);
385
385
  }
386
+ delete(sessionId) {
387
+ const db = loadFile(this.path);
388
+ if (!db.sessions[sessionId]) return;
389
+ delete db.sessions[sessionId];
390
+ saveFile(this.path, db);
391
+ }
386
392
  };
387
393
 
388
394
  // src/acp/translate/pi-tools.ts
@@ -654,7 +660,8 @@ var PiAcpSession = class {
654
660
  cwd;
655
661
  mcpServers;
656
662
  startupInfo = null;
657
- startupInfoSent = false;
663
+ startupInfoSentOutOfTurn = false;
664
+ startupInfoSentInPrompt = false;
658
665
  proc;
659
666
  conn;
660
667
  fileCommands;
@@ -689,6 +696,8 @@ var PiAcpSession = class {
689
696
  }
690
697
  setStartupInfo(text) {
691
698
  this.startupInfo = text;
699
+ this.startupInfoSentOutOfTurn = false;
700
+ this.startupInfoSentInPrompt = false;
692
701
  }
693
702
  /**
694
703
  * Best-effort attempt to send startup info outside of a prompt turn.
@@ -696,17 +705,26 @@ var PiAcpSession = class {
696
705
  * callers can invoke this shortly after session/new returns.
697
706
  */
698
707
  sendStartupInfoIfPending() {
699
- if (this.startupInfoSent || !this.startupInfo) return;
700
- this.startupInfoSent = true;
708
+ if (this.startupInfoSentOutOfTurn || !this.startupInfo) return;
709
+ this.startupInfoSentOutOfTurn = true;
710
+ this.emit({
711
+ sessionUpdate: "agent_message_chunk",
712
+ content: { type: "text", text: this.startupInfo }
713
+ });
714
+ }
715
+ sendStartupInfoOnFirstPromptIfPending() {
716
+ if (this.startupInfoSentInPrompt || !this.startupInfo) return;
717
+ this.startupInfoSentInPrompt = true;
701
718
  this.emit({
702
719
  sessionUpdate: "agent_message_chunk",
703
720
  content: { type: "text", text: this.startupInfo }
704
721
  });
705
722
  }
706
723
  async prompt(message, images = []) {
724
+ this.sendStartupInfoOnFirstPromptIfPending();
707
725
  const expandedMessage = expandSlashCommand(message, this.fileCommands);
708
- const turnPromise = new Promise((resolve3, reject) => {
709
- const queued = { message: expandedMessage, images, resolve: resolve3, reject };
726
+ const turnPromise = new Promise((resolve4, reject) => {
727
+ const queued = { message: expandedMessage, images, resolve: resolve4, reject };
710
728
  if (this.pendingTurn) {
711
729
  this.turnQueue.push(queued);
712
730
  this.emit({
@@ -962,7 +980,10 @@ var PiAcpSession = class {
962
980
  case "auto_compaction_start": {
963
981
  this.emit({
964
982
  sessionUpdate: "agent_message_chunk",
965
- content: { type: "text", text: "Context nearing limit, running automatic compaction..." }
983
+ content: {
984
+ type: "text",
985
+ text: "Context nearing limit, running automatic compaction..."
986
+ }
966
987
  });
967
988
  break;
968
989
  }
@@ -1036,16 +1057,31 @@ function toToolKind(toolName) {
1036
1057
  }
1037
1058
 
1038
1059
  // src/acp/pi-sessions.ts
1039
- import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync, openSync, readSync, closeSync } from "fs";
1060
+ import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync, openSync, readSync, closeSync, existsSync as existsSync2 } from "fs";
1040
1061
  import { homedir as homedir3 } from "os";
1041
- import { join as join3 } from "path";
1062
+ import { join as join3, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
1042
1063
  var DEFAULT_TAIL_BYTES = 256 * 1024;
1043
1064
  var DEFAULT_HEAD_BYTES = 64 * 1024;
1044
1065
  function getPiAgentDir() {
1045
- return process.env.PI_CODING_AGENT_DIR ?? join3(homedir3(), ".pi", "agent");
1066
+ return process.env.PI_CODING_AGENT_DIR ? resolve2(process.env.PI_CODING_AGENT_DIR) : join3(homedir3(), ".pi", "agent");
1067
+ }
1068
+ function readSessionDirFromSettings(agentDir) {
1069
+ const settingsPath = join3(agentDir, "settings.json");
1070
+ try {
1071
+ if (!existsSync2(settingsPath)) return null;
1072
+ const raw = readFileSync4(settingsPath, "utf8");
1073
+ const data = JSON.parse(raw);
1074
+ if (!data || typeof data !== "object" || Array.isArray(data)) return null;
1075
+ const sessionDir = data.sessionDir;
1076
+ if (typeof sessionDir !== "string" || !sessionDir.trim()) return null;
1077
+ return isAbsolute2(sessionDir) ? sessionDir : resolve2(agentDir, sessionDir);
1078
+ } catch {
1079
+ return null;
1080
+ }
1046
1081
  }
1047
1082
  function getPiSessionsDir() {
1048
- return join3(getPiAgentDir(), "sessions");
1083
+ const agentDir = getPiAgentDir();
1084
+ return readSessionDirFromSettings(agentDir) ?? join3(agentDir, "sessions");
1049
1085
  }
1050
1086
  function walkJsonlFiles(dir, out) {
1051
1087
  let entries;
@@ -1339,9 +1375,9 @@ ${r.text}`;
1339
1375
  }
1340
1376
 
1341
1377
  // src/acp/pi-settings.ts
1342
- import { existsSync as existsSync2, readFileSync as readFileSync5 } from "fs";
1378
+ import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
1343
1379
  import { homedir as homedir4 } from "os";
1344
- import { join as join4, resolve as resolve2 } from "path";
1380
+ import { join as join4, resolve as resolve3 } from "path";
1345
1381
  function isObject(x) {
1346
1382
  return Boolean(x) && typeof x === "object" && !Array.isArray(x);
1347
1383
  }
@@ -1356,7 +1392,7 @@ function deepMerge(a, b) {
1356
1392
  }
1357
1393
  function readJsonFile(path) {
1358
1394
  try {
1359
- if (!existsSync2(path)) return {};
1395
+ if (!existsSync3(path)) return {};
1360
1396
  const raw = readFileSync5(path, "utf-8");
1361
1397
  const data = JSON.parse(raw);
1362
1398
  return isObject(data) ? data : {};
@@ -1366,13 +1402,13 @@ function readJsonFile(path) {
1366
1402
  }
1367
1403
  function getMergedSettings(cwd) {
1368
1404
  const globalSettingsPath = join4(getAgentDir(), "settings.json");
1369
- const projectSettingsPath = resolve2(cwd, ".pi", "settings.json");
1405
+ const projectSettingsPath = resolve3(cwd, ".pi", "settings.json");
1370
1406
  const global = readJsonFile(globalSettingsPath);
1371
1407
  const project = readJsonFile(projectSettingsPath);
1372
1408
  return deepMerge(global, project);
1373
1409
  }
1374
1410
  function getAgentDir() {
1375
- return process.env.PI_CODING_AGENT_DIR ? resolve2(process.env.PI_CODING_AGENT_DIR) : join4(homedir4(), ".pi", "agent");
1411
+ return process.env.PI_CODING_AGENT_DIR ? resolve3(process.env.PI_CODING_AGENT_DIR) : join4(homedir4(), ".pi", "agent");
1376
1412
  }
1377
1413
  function getEnableSkillCommands(cwd) {
1378
1414
  const merged = getMergedSettings(cwd);
@@ -1422,81 +1458,10 @@ function toAvailableCommandsFromPiGetCommands(data, opts) {
1422
1458
  }
1423
1459
 
1424
1460
  // src/acp/agent.ts
1425
- import { isAbsolute as isAbsolute2 } from "path";
1426
- import { existsSync as existsSync4, readFileSync as readFileSync7, realpathSync, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
1427
- import { join as join6, dirname as dirname2, basename } from "path";
1461
+ import { isAbsolute as isAbsolute3 } from "path";
1462
+ import { existsSync as existsSync4, readFileSync as readFileSync6, realpathSync, readdirSync as readdirSync3, statSync as statSync2, unlinkSync } from "fs";
1463
+ import { join as join5, dirname as dirname2, basename } from "path";
1428
1464
  import { spawnSync } from "child_process";
1429
-
1430
- // src/pi-auth/status.ts
1431
- import { existsSync as existsSync3, readFileSync as readFileSync6 } from "fs";
1432
- import { homedir as homedir5 } from "os";
1433
- import { join as join5 } from "path";
1434
- function safeReadJson(path) {
1435
- try {
1436
- if (!existsSync3(path)) return null;
1437
- const raw = readFileSync6(path, "utf-8");
1438
- if (!raw.trim()) return null;
1439
- return JSON.parse(raw);
1440
- } catch {
1441
- return null;
1442
- }
1443
- }
1444
- function getPiAgentDir2() {
1445
- const envDir = process.env.PI_CODING_AGENT_DIR;
1446
- if (envDir) {
1447
- if (envDir === "~") return homedir5();
1448
- if (envDir.startsWith("~/")) return homedir5() + envDir.slice(1);
1449
- return envDir;
1450
- }
1451
- return join5(homedir5(), ".pi", "agent");
1452
- }
1453
- function hasAnyPiAuthConfigured() {
1454
- const agentDir = getPiAgentDir2();
1455
- const authPath = join5(agentDir, "auth.json");
1456
- const auth = safeReadJson(authPath);
1457
- if (auth && typeof auth === "object" && Object.keys(auth).length > 0) return true;
1458
- const modelsPath = join5(agentDir, "models.json");
1459
- const models = safeReadJson(modelsPath);
1460
- const providers = models?.providers;
1461
- if (providers && typeof providers === "object") {
1462
- for (const p of Object.values(providers)) {
1463
- if (p && typeof p === "object" && typeof p.apiKey === "string" && p.apiKey.trim()) {
1464
- return true;
1465
- }
1466
- }
1467
- }
1468
- const envVars = [
1469
- "OPENAI_API_KEY",
1470
- "AZURE_OPENAI_API_KEY",
1471
- "GEMINI_API_KEY",
1472
- "GROQ_API_KEY",
1473
- "CEREBRAS_API_KEY",
1474
- "XAI_API_KEY",
1475
- "OPENROUTER_API_KEY",
1476
- "AI_GATEWAY_API_KEY",
1477
- "ZAI_API_KEY",
1478
- "MISTRAL_API_KEY",
1479
- "MINIMAX_API_KEY",
1480
- "MINIMAX_CN_API_KEY",
1481
- "HF_TOKEN",
1482
- "OPENCODE_API_KEY",
1483
- "KIMI_API_KEY",
1484
- // Copilot/github
1485
- "COPILOT_GITHUB_TOKEN",
1486
- "GH_TOKEN",
1487
- "GITHUB_TOKEN",
1488
- // Anthropic oauth
1489
- "ANTHROPIC_OAUTH_TOKEN",
1490
- "ANTHROPIC_API_KEY"
1491
- ];
1492
- for (const k of envVars) {
1493
- const v = process.env[k];
1494
- if (typeof v === "string" && v.trim()) return true;
1495
- }
1496
- return false;
1497
- }
1498
-
1499
- // src/acp/agent.ts
1500
1465
  import { fileURLToPath } from "url";
1501
1466
  function builtinAvailableCommands() {
1502
1467
  return [
@@ -1563,6 +1528,17 @@ var PiAcpAgent = class {
1563
1528
  this.conn = conn;
1564
1529
  void _config;
1565
1530
  }
1531
+ cleanupFailedNewSession(sessionId, state) {
1532
+ this.sessions.close(sessionId);
1533
+ const sessionFile = typeof state?.sessionFile === "string" && state.sessionFile.trim() ? state.sessionFile : this.store.get(sessionId)?.sessionFile;
1534
+ if (typeof sessionFile === "string" && sessionFile.trim()) {
1535
+ try {
1536
+ if (existsSync4(sessionFile)) unlinkSync(sessionFile);
1537
+ } catch {
1538
+ }
1539
+ }
1540
+ this.store.delete(sessionId);
1541
+ }
1566
1542
  async initialize(params) {
1567
1543
  const supportedVersion = 1;
1568
1544
  const requested = params.protocolVersion;
@@ -1595,16 +1571,10 @@ var PiAcpAgent = class {
1595
1571
  };
1596
1572
  }
1597
1573
  async newSession(params) {
1598
- if (!isAbsolute2(params.cwd)) {
1574
+ if (!isAbsolute3(params.cwd)) {
1599
1575
  throw RequestError3.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
1600
1576
  }
1601
1577
  this.lastSessionCwd = params.cwd;
1602
- if (!hasAnyPiAuthConfigured()) {
1603
- throw RequestError3.authRequired(
1604
- { authMethods: getAuthMethods() },
1605
- "Configure an API key or log in with an OAuth provider."
1606
- );
1607
- }
1608
1578
  const fileCommands = loadSlashCommands(params.cwd);
1609
1579
  const enableSkillCommands = getEnableSkillCommands(params.cwd);
1610
1580
  const session = await this.sessions.create({
@@ -1616,24 +1586,41 @@ var PiAcpAgent = class {
1616
1586
  });
1617
1587
  let state = null;
1618
1588
  let availableModels = null;
1589
+ let stateErr = null;
1590
+ let availableModelsErr = null;
1619
1591
  await Promise.all([
1620
1592
  session.proc.getState().then((s) => {
1621
1593
  state = s;
1622
- }).catch(() => {
1594
+ }).catch((err) => {
1595
+ stateErr = err;
1623
1596
  state = null;
1624
1597
  }),
1625
1598
  session.proc.getAvailableModels().then((m) => {
1626
1599
  availableModels = m;
1627
- }).catch(() => {
1600
+ }).catch((err) => {
1601
+ availableModelsErr = err;
1628
1602
  availableModels = null;
1629
1603
  })
1630
1604
  ]);
1605
+ const availableModelsAuthErr = maybeAuthRequiredError(availableModelsErr);
1606
+ if (availableModelsAuthErr) {
1607
+ this.cleanupFailedNewSession(session.sessionId, state);
1608
+ throw availableModelsAuthErr;
1609
+ }
1610
+ if (availableModelsErr) {
1611
+ this.cleanupFailedNewSession(session.sessionId, state);
1612
+ throw RequestError3.internalError({}, String(availableModelsErr?.message ?? availableModelsErr));
1613
+ }
1631
1614
  const rawModelsCount = Array.isArray(availableModels?.models) ? availableModels.models.length : 0;
1632
1615
  if (rawModelsCount === 0) {
1633
- try {
1634
- session.proc.dispose?.();
1635
- } catch {
1636
- }
1616
+ this.cleanupFailedNewSession(session.sessionId, state);
1617
+ throw RequestError3.authRequired(
1618
+ { authMethods: getAuthMethods() },
1619
+ "Configure an API key or log in with an OAuth provider."
1620
+ );
1621
+ }
1622
+ if (stateErr && maybeAuthRequiredError(stateErr)) {
1623
+ this.cleanupFailedNewSession(session.sessionId, state);
1637
1624
  throw RequestError3.authRequired(
1638
1625
  { authMethods: getAuthMethods() },
1639
1626
  "Configure an API key or log in with an OAuth provider."
@@ -1885,7 +1872,7 @@ ${JSON.stringify(stats, null, 2)}`;
1885
1872
  if (piPath) {
1886
1873
  const resolved = realpathSync(piPath);
1887
1874
  const pkgRoot = dirname2(dirname2(resolved));
1888
- const p = join6(pkgRoot, "CHANGELOG.md");
1875
+ const p = join5(pkgRoot, "CHANGELOG.md");
1889
1876
  if (existsSync4(p)) return p;
1890
1877
  }
1891
1878
  } catch {
@@ -1894,7 +1881,7 @@ ${JSON.stringify(stats, null, 2)}`;
1894
1881
  const npmRoot = spawnSync("npm", ["root", "-g"], { encoding: "utf-8" });
1895
1882
  const root = String(npmRoot.stdout ?? "").trim();
1896
1883
  if (root) {
1897
- const p = join6(root, "@mariozechner", "pi-coding-agent", "CHANGELOG.md");
1884
+ const p = join5(root, "@earendil-works", "pi-coding-agent", "CHANGELOG.md");
1898
1885
  if (existsSync4(p)) return p;
1899
1886
  }
1900
1887
  } catch {
@@ -1914,7 +1901,7 @@ ${JSON.stringify(stats, null, 2)}`;
1914
1901
  }
1915
1902
  let text = "";
1916
1903
  try {
1917
- text = readFileSync7(changelogPath, "utf-8");
1904
+ text = readFileSync6(changelogPath, "utf-8");
1918
1905
  } catch (e) {
1919
1906
  await this.conn.sessionUpdate({
1920
1907
  sessionId: session.sessionId,
@@ -1954,7 +1941,7 @@ ${JSON.stringify(stats, null, 2)}`;
1954
1941
  return { stopReason: "end_turn" };
1955
1942
  }
1956
1943
  try {
1957
- const raw = readFileSync7(sessionFile, "utf-8");
1944
+ const raw = readFileSync6(sessionFile, "utf-8");
1958
1945
  if (raw.trim().length === 0) {
1959
1946
  await this.conn.sessionUpdate({
1960
1947
  sessionId: session.sessionId,
@@ -1982,7 +1969,7 @@ ${JSON.stringify(stats, null, 2)}`;
1982
1969
  return { stopReason: "end_turn" };
1983
1970
  }
1984
1971
  const safeSessionId = session.sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
1985
- const outputPath = join6(session.cwd, `pi-session-${safeSessionId}.html`);
1972
+ const outputPath = join5(session.cwd, `pi-session-${safeSessionId}.html`);
1986
1973
  let resultPath = "";
1987
1974
  try {
1988
1975
  const result2 = await session.proc.exportHtml(outputPath);
@@ -2089,7 +2076,7 @@ ${JSON.stringify(stats, null, 2)}`;
2089
2076
  return { sessions, nextCursor, _meta: {} };
2090
2077
  }
2091
2078
  async loadSession(params) {
2092
- if (!isAbsolute2(params.cwd)) {
2079
+ if (!isAbsolute3(params.cwd)) {
2093
2080
  throw RequestError3.invalidParams(`cwd must be an absolute path: ${params.cwd}`);
2094
2081
  }
2095
2082
  this.sessions.close(params.sessionId);
@@ -2354,14 +2341,14 @@ function buildUpdateNotice() {
2354
2341
  ""
2355
2342
  );
2356
2343
  if (!installed || !isSemver(installed)) return null;
2357
- const latestRes = spawnSync("npm", ["view", "@mariozechner/pi-coding-agent", "version"], {
2344
+ const latestRes = spawnSync("npm", ["view", "@earendil-works/pi-coding-agent", "version"], {
2358
2345
  encoding: "utf-8",
2359
2346
  timeout: 800
2360
2347
  });
2361
2348
  const latest = String(latestRes.stdout ?? "").trim().replace(/^v/i, "");
2362
2349
  if (!latest || !isSemver(latest)) return null;
2363
2350
  if (compareSemver(latest, installed) <= 0) return null;
2364
- return `New version available: v${latest} (installed v${installed}). Run: \`npm i -g @mariozechner/pi-coding-agent\``;
2351
+ return `New version available: v${latest} (installed v${installed}). Run: \`npm i -g @earendil-works/pi-coding-agent\``;
2365
2352
  } catch {
2366
2353
  return null;
2367
2354
  }
@@ -2390,14 +2377,14 @@ function buildStartupInfo(opts) {
2390
2377
  md.push("");
2391
2378
  };
2392
2379
  const contextItems = [];
2393
- const contextPath = join6(opts.cwd, "AGENTS.md");
2380
+ const contextPath = join5(opts.cwd, "AGENTS.md");
2394
2381
  if (existsSync4(contextPath)) contextItems.push(contextPath);
2395
2382
  addSection("Context", contextItems);
2396
2383
  const skillsItems = [];
2397
2384
  const pushSkillFromRoot = (root) => {
2398
2385
  try {
2399
2386
  for (const e of readdirSync3(root)) {
2400
- const p = join6(root, e);
2387
+ const p = join5(root, e);
2401
2388
  try {
2402
2389
  const st = statSync2(p);
2403
2390
  if (st.isFile() && e.toLowerCase().endsWith(".md")) {
@@ -2417,7 +2404,7 @@ function buildStartupInfo(opts) {
2417
2404
  }
2418
2405
  for (const name of entries) {
2419
2406
  if (name === "node_modules" || name === ".git") continue;
2420
- const p = join6(dir, name);
2407
+ const p = join5(dir, name);
2421
2408
  let st;
2422
2409
  try {
2423
2410
  st = statSync2(p);
@@ -2434,15 +2421,15 @@ function buildStartupInfo(opts) {
2434
2421
  } catch {
2435
2422
  }
2436
2423
  };
2437
- const globalSkillsDir = join6(getAgentDir(), "skills");
2424
+ const globalSkillsDir = join5(getAgentDir(), "skills");
2438
2425
  pushSkillFromRoot(globalSkillsDir);
2439
- const legacyAgentsSkillsDir = join6(process.env.HOME ?? "", ".agents", "skills");
2426
+ const legacyAgentsSkillsDir = join5(process.env.HOME ?? "", ".agents", "skills");
2440
2427
  pushSkillFromRoot(legacyAgentsSkillsDir);
2441
- const projectSkillsDir = join6(opts.cwd, ".pi", "skills");
2428
+ const projectSkillsDir = join5(opts.cwd, ".pi", "skills");
2442
2429
  pushSkillFromRoot(projectSkillsDir);
2443
2430
  addSection("Skills", skillsItems);
2444
2431
  const promptsItems = [];
2445
- const promptsDir = join6(process.env.HOME ?? "", ".pi", "agent", "prompts");
2432
+ const promptsDir = join5(process.env.HOME ?? "", ".pi", "agent", "prompts");
2446
2433
  try {
2447
2434
  const prompts = readdirSync3(promptsDir).filter((f) => f.endsWith(".md"));
2448
2435
  for (const f of prompts) promptsItems.push(`/${basename(f, ".md")}`);
@@ -2450,15 +2437,15 @@ function buildStartupInfo(opts) {
2450
2437
  }
2451
2438
  addSection("Prompts", promptsItems);
2452
2439
  const extItems = [];
2453
- const extDir = join6(process.env.HOME ?? "", ".pi", "agent", "extensions");
2440
+ const extDir = join5(process.env.HOME ?? "", ".pi", "agent", "extensions");
2454
2441
  try {
2455
2442
  const exts = readdirSync3(extDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
2456
- for (const f of exts) extItems.push(join6(extDir, f));
2443
+ for (const f of exts) extItems.push(join5(extDir, f));
2457
2444
  } catch {
2458
2445
  }
2459
2446
  try {
2460
- const settingsPath = join6(process.env.HOME ?? "", ".pi", "agent", "settings.json");
2461
- const settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
2447
+ const settingsPath = join5(process.env.HOME ?? "", ".pi", "agent", "settings.json");
2448
+ const settings = JSON.parse(readFileSync6(settingsPath, "utf-8"));
2462
2449
  const pkgs = Array.isArray(settings?.packages) ? settings.packages : [];
2463
2450
  for (const pkg2 of pkgs) {
2464
2451
  const s = String(pkg2);
@@ -2483,9 +2470,9 @@ function readNearestPackageJson(metaUrl) {
2483
2470
  try {
2484
2471
  let dir = dirname2(fileURLToPath(metaUrl));
2485
2472
  for (let i = 0; i < 6; i++) {
2486
- const p = join6(dir, "package.json");
2473
+ const p = join5(dir, "package.json");
2487
2474
  if (existsSync4(p)) {
2488
- const json = JSON.parse(readFileSync7(p, "utf-8"));
2475
+ const json = JSON.parse(readFileSync6(p, "utf-8"));
2489
2476
  return { name: json?.name, version: json?.version };
2490
2477
  }
2491
2478
  dir = dirname2(dir);
@@ -2506,7 +2493,7 @@ if (process.argv.includes("--terminal-login")) {
2506
2493
  });
2507
2494
  if (res.error && res.error.code === "ENOENT") {
2508
2495
  process.stderr.write(
2509
- `pi-acp: could not start pi (command not found: ${cmd}). Install it via \`npm install -g @mariozechner/pi-coding-agent\` or ensure \`pi\` is on your PATH.
2496
+ `pi-acp: could not start pi (command not found: ${cmd}). Install it via \`npm install -g @earendil-works/pi-coding-agent\` or ensure \`pi\` is on your PATH.
2510
2497
  `
2511
2498
  );
2512
2499
  process.exit(1);
@@ -2515,15 +2502,15 @@ if (process.argv.includes("--terminal-login")) {
2515
2502
  }
2516
2503
  var input = new WritableStream({
2517
2504
  write(chunk) {
2518
- return new Promise((resolve3) => {
2519
- if (process.stdout.destroyed || !process.stdout.writable) return resolve3();
2505
+ return new Promise((resolve4) => {
2506
+ if (process.stdout.destroyed || !process.stdout.writable) return resolve4();
2520
2507
  try {
2521
2508
  process.stdout.write(chunk, (err) => {
2522
2509
  void err;
2523
- resolve3();
2510
+ resolve4();
2524
2511
  });
2525
2512
  } catch {
2526
- resolve3();
2513
+ resolve4();
2527
2514
  }
2528
2515
  });
2529
2516
  }