acpx 0.5.3 → 0.6.1

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.
Files changed (47) hide show
  1. package/README.md +12 -4
  2. package/dist/{cli-ChWsO-bb.js → cli-Ddxpnz9X.js} +4 -4
  3. package/dist/{cli-ChWsO-bb.js.map → cli-Ddxpnz9X.js.map} +1 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +147 -75
  7. package/dist/cli.js.map +1 -1
  8. package/dist/{client-D-4_aZf2.d.ts → client-2fTFutRH.d.ts} +4 -2
  9. package/dist/client-2fTFutRH.d.ts.map +1 -0
  10. package/dist/{flags-ceSqz2T6.js → flags-yXzUm7Aq.js} +25 -6
  11. package/dist/flags-yXzUm7Aq.js.map +1 -0
  12. package/dist/{flows-_KmnuUXd.js → flows-CDsfbaA2.js} +13 -6
  13. package/dist/flows-CDsfbaA2.js.map +1 -0
  14. package/dist/flows.d.ts +2 -8
  15. package/dist/flows.d.ts.map +1 -1
  16. package/dist/flows.js +1 -1
  17. package/dist/{ipc-BM335WFg.js → ipc-BruTG5Fb.js} +50 -19
  18. package/dist/ipc-BruTG5Fb.js.map +1 -0
  19. package/dist/{output-C4QhjpM6.js → output-DmHvT8vm.js} +141 -12
  20. package/dist/output-DmHvT8vm.js.map +1 -0
  21. package/dist/{perf-metrics-D0um6IR6.js → perf-metrics-C2pXfxvR.js} +12 -2
  22. package/dist/perf-metrics-C2pXfxvR.js.map +1 -0
  23. package/dist/{prompt-turn-CXMtXBl-.js → prompt-turn-BY5SwU1F.js} +256 -80
  24. package/dist/prompt-turn-BY5SwU1F.js.map +1 -0
  25. package/dist/{render-Br-kVPK_.js → render-yqwtaOX4.js} +35 -3
  26. package/dist/{render-Br-kVPK_.js.map → render-yqwtaOX4.js.map} +1 -1
  27. package/dist/runtime.d.ts +84 -10
  28. package/dist/runtime.d.ts.map +1 -1
  29. package/dist/runtime.js +425 -190
  30. package/dist/runtime.js.map +1 -1
  31. package/dist/{session-BtwAKtJ3.js → session-BwgaPK8-.js} +119 -81
  32. package/dist/session-BwgaPK8-.js.map +1 -0
  33. package/dist/session-options-pCbHn_n7.d.ts +13 -0
  34. package/dist/session-options-pCbHn_n7.d.ts.map +1 -0
  35. package/dist/{types-yxf-gcOE.d.ts → types-CVBeQyi3.d.ts} +9 -1
  36. package/dist/types-CVBeQyi3.d.ts.map +1 -0
  37. package/package.json +21 -21
  38. package/skills/acpx/SKILL.md +9 -4
  39. package/dist/client-D-4_aZf2.d.ts.map +0 -1
  40. package/dist/flags-ceSqz2T6.js.map +0 -1
  41. package/dist/flows-_KmnuUXd.js.map +0 -1
  42. package/dist/ipc-BM335WFg.js.map +0 -1
  43. package/dist/output-C4QhjpM6.js.map +0 -1
  44. package/dist/perf-metrics-D0um6IR6.js.map +0 -1
  45. package/dist/prompt-turn-CXMtXBl-.js.map +0 -1
  46. package/dist/session-BtwAKtJ3.js.map +0 -1
  47. package/dist/types-yxf-gcOE.d.ts.map +0 -1
@@ -1,20 +1,21 @@
1
- import { B as PermissionPromptUnavailableError, C as isAcpResourceNotFoundError, F as AuthPolicyError, G as SessionNotFoundError, I as ClaudeAcpSessionCreateTimeoutError, K as SessionResolutionError, L as CopilotAcpUnsupportedError, M as AgentDisconnectedError, N as AgentSpawnError, P as AgentStartupError, R as GeminiAcpStartupTimeoutError, S as extractAcpError, U as SessionModeReplayError, W as SessionModelReplayError, g as textPrompt, i as measurePerf, j as SESSION_RECORD_SCHEMA, l as extractRuntimeSessionId, q as SessionResumeRequiredError, r as incrementPerfCounter, u as normalizeRuntimeSessionId, v as formatErrorMessage, y as isAcpQueryClosedBeforeResponseError, z as PermissionDeniedError } from "./perf-metrics-D0um6IR6.js";
1
+ import { B as PermissionDeniedError, C as isAcpResourceNotFoundError, F as AgentStartupError, G as SessionModeReplayError, I as AuthPolicyError, J as SessionResolutionError, K as SessionModelReplayError, L as ClaudeAcpSessionCreateTimeoutError, M as SESSION_RECORD_SCHEMA, N as AgentDisconnectedError, P as AgentSpawnError, R as CopilotAcpUnsupportedError, S as extractAcpError, V as PermissionPromptUnavailableError, W as SessionConfigOptionReplayError, Y as SessionResumeRequiredError, g as textPrompt, i as measurePerf, l as extractRuntimeSessionId, q as SessionNotFoundError, r as incrementPerfCounter, u as normalizeRuntimeSessionId, v as formatErrorMessage, y as isAcpQueryClosedBeforeResponseError, z as GeminiAcpStartupTimeoutError } from "./perf-metrics-C2pXfxvR.js";
2
2
  import { r as isSessionUpdateNotification } from "./jsonrpc-DSxh2w5R.js";
3
3
  import fs, { statSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import path from "node:path";
6
6
  import fs$1 from "node:fs/promises";
7
7
  import os from "node:os";
8
- import { spawn } from "node:child_process";
8
+ import { execFile, spawn } from "node:child_process";
9
9
  import { Readable, Writable } from "node:stream";
10
10
  import { ClientSideConnection, PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
11
11
  import readline from "node:readline/promises";
12
+ import { promisify } from "node:util";
12
13
  import { randomUUID } from "node:crypto";
13
14
  //#region src/agent-registry.ts
14
15
  const ACP_ADAPTER_PACKAGE_RANGES = {
15
- pi: "^0.0.22",
16
- codex: "^0.11.1",
17
- claude: "^0.25.0"
16
+ pi: "^0.0.26",
17
+ codex: "^0.12.0",
18
+ claude: "^0.31.0"
18
19
  };
19
20
  const AGENT_REGISTRY = {
20
21
  pi: `npx pi-acp@${ACP_ADAPTER_PACKAGE_RANGES.pi}`,
@@ -278,6 +279,7 @@ const MAP_OBJECT_PATHS = new Set(["request_token_usage", "messages.Agent.tool_re
278
279
  const OPAQUE_VALUE_PATHS = new Set([
279
280
  "agent_capabilities",
280
281
  "messages.Agent.content.ToolUse.input",
282
+ "acpx.desired_config_options",
281
283
  "acpx.config_options"
282
284
  ]);
283
285
  function isRecord(value) {
@@ -480,6 +482,12 @@ function parseAcpxState(raw) {
480
482
  if (record.reset_on_next_ensure === true) state.reset_on_next_ensure = true;
481
483
  if (typeof record.current_mode_id === "string") state.current_mode_id = record.current_mode_id;
482
484
  if (typeof record.desired_mode_id === "string") state.desired_mode_id = record.desired_mode_id;
485
+ const desiredConfigOptions = asRecord$3(record.desired_config_options);
486
+ if (desiredConfigOptions) {
487
+ const parsed = {};
488
+ for (const [key, value] of Object.entries(desiredConfigOptions)) if (typeof key === "string" && typeof value === "string") parsed[key] = value;
489
+ if (Object.keys(parsed).length > 0) state.desired_config_options = parsed;
490
+ }
483
491
  if (typeof record.current_model_id === "string") state.current_model_id = record.current_model_id;
484
492
  if (isStringArray(record.available_models)) state.available_models = [...record.available_models];
485
493
  if (isStringArray(record.available_commands)) state.available_commands = [...record.available_commands];
@@ -490,6 +498,12 @@ function parseAcpxState(raw) {
490
498
  if (typeof sessionOptions.model === "string") parsedSessionOptions.model = sessionOptions.model;
491
499
  if (isStringArray(sessionOptions.allowed_tools)) parsedSessionOptions.allowed_tools = [...sessionOptions.allowed_tools];
492
500
  if (typeof sessionOptions.max_turns === "number" && Number.isInteger(sessionOptions.max_turns) && sessionOptions.max_turns > 0) parsedSessionOptions.max_turns = sessionOptions.max_turns;
501
+ const rawSystemPrompt = sessionOptions.system_prompt;
502
+ if (typeof rawSystemPrompt === "string" && rawSystemPrompt.length > 0) parsedSessionOptions.system_prompt = rawSystemPrompt;
503
+ else {
504
+ const appendRecord = asRecord$3(rawSystemPrompt);
505
+ if (appendRecord && typeof appendRecord.append === "string" && appendRecord.append.length > 0) parsedSessionOptions.system_prompt = { append: appendRecord.append };
506
+ }
493
507
  if (Object.keys(parsedSessionOptions).length > 0) state.session_options = parsedSessionOptions;
494
508
  }
495
509
  return state;
@@ -831,6 +845,58 @@ async function findSessionByDirectoryWalk(options) {
831
845
  if (!isWithinBoundary(walkBoundary, current)) return;
832
846
  }
833
847
  }
848
+ function closedAtOrLastUsedAt(record) {
849
+ return record.closedAt ?? record.lastUsedAt;
850
+ }
851
+ function isSessionStreamFile(fileName, safeId) {
852
+ return fileName === `${safeId}.stream.ndjson` || fileName === `${safeId}.stream.lock` || fileName.startsWith(`${safeId}.stream.`);
853
+ }
854
+ async function pruneSessions(options = {}) {
855
+ await ensureSessionDir();
856
+ let eligible = (await loadSessionIndexEntries()).filter((entry) => entry.closed);
857
+ if (options.agentCommand) eligible = eligible.filter((entry) => entry.agentCommand === options.agentCommand);
858
+ const cutoff = options.before ?? (options.olderThanMs != null ? new Date(Date.now() - options.olderThanMs) : void 0);
859
+ const records = [];
860
+ for (const entry of eligible) {
861
+ const record = await loadRecordFromIndexEntry(entry);
862
+ if (record && (!cutoff || closedAtOrLastUsedAt(record) < cutoff.toISOString())) records.push(record);
863
+ }
864
+ if (options.dryRun) return {
865
+ pruned: records,
866
+ bytesFreed: 0,
867
+ dryRun: true
868
+ };
869
+ const sessionDir = sessionBaseDir();
870
+ let bytesFreed = 0;
871
+ let dirEntries = [];
872
+ if (options.includeHistory) try {
873
+ dirEntries = await fs$1.readdir(sessionDir);
874
+ } catch {}
875
+ for (const record of records) {
876
+ const safeId = encodeURIComponent(record.acpxRecordId);
877
+ const jsonFile = path.join(sessionDir, `${safeId}.json`);
878
+ try {
879
+ const stat = await fs$1.stat(jsonFile);
880
+ bytesFreed += stat.size;
881
+ } catch {}
882
+ await fs$1.unlink(jsonFile).catch(() => void 0);
883
+ if (options.includeHistory) for (const name of dirEntries) {
884
+ if (!isSessionStreamFile(name, safeId)) continue;
885
+ const filePath = path.join(sessionDir, name);
886
+ try {
887
+ const stat = await fs$1.stat(filePath);
888
+ bytesFreed += stat.size;
889
+ } catch {}
890
+ await fs$1.unlink(filePath).catch(() => void 0);
891
+ }
892
+ }
893
+ await rebuildSessionIndex(sessionDir).catch(() => {});
894
+ return {
895
+ pruned: records,
896
+ bytesFreed,
897
+ dryRun: false
898
+ };
899
+ }
834
900
  //#endregion
835
901
  //#region src/permission-prompt.ts
836
902
  async function promptForPermission(options) {
@@ -875,7 +941,7 @@ async function defaultConfirmWrite(filePath, preview) {
875
941
  });
876
942
  }
877
943
  function canPromptForPermission$2() {
878
- return Boolean(process.stdin.isTTY && process.stderr.isTTY);
944
+ return process.stdin.isTTY && process.stderr.isTTY;
879
945
  }
880
946
  var FileSystemHandlers = class {
881
947
  rootDir;
@@ -1039,7 +1105,7 @@ async function promptForToolPermission(params) {
1039
1105
  return await promptForPermission({ prompt: `\n[permission] Allow ${params.toolCall.title ?? "tool"} [${inferToolKind(params) ?? "other"}]? (y/N) ` });
1040
1106
  }
1041
1107
  function canPromptForPermission$1() {
1042
- return Boolean(process.stdin.isTTY && process.stderr.isTTY);
1108
+ return process.stdin.isTTY && process.stderr.isTTY;
1043
1109
  }
1044
1110
  function permissionModeSatisfies(actual, required) {
1045
1111
  return PERMISSION_MODE_RANK[actual] >= PERMISSION_MODE_RANK[required];
@@ -1112,6 +1178,7 @@ function buildSpawnCommandOptions(command, options, platform = process.platform,
1112
1178
  }
1113
1179
  //#endregion
1114
1180
  //#region src/acp/client-process.ts
1181
+ const execFileAsync = promisify(execFile);
1115
1182
  function isoNow$1() {
1116
1183
  return (/* @__PURE__ */ new Date()).toISOString();
1117
1184
  }
@@ -1203,6 +1270,34 @@ function splitCommandLine(value) {
1203
1270
  function asAbsoluteCwd(cwd) {
1204
1271
  return path.resolve(cwd);
1205
1272
  }
1273
+ async function resolveAgentSessionCwd(cwd, agentCommand, options = {}) {
1274
+ const resolved = asAbsoluteCwd(cwd);
1275
+ if (!shouldTranslateWslWindowsCwd(agentCommand, options)) return resolved;
1276
+ const translated = (await (options.runWslpath ?? runWslpath)(resolved)).trim();
1277
+ if (!translated) throw new Error(`wslpath returned an empty Windows path for cwd: ${resolved}`);
1278
+ return translated;
1279
+ }
1280
+ function shouldTranslateWslWindowsCwd(agentCommand, options) {
1281
+ if (!isWsl(options)) return false;
1282
+ try {
1283
+ const { command } = splitCommandLine(agentCommand);
1284
+ return isWindowsExecutableCommand(command);
1285
+ } catch {
1286
+ return false;
1287
+ }
1288
+ }
1289
+ function isWsl(options) {
1290
+ if ((options.platform ?? process.platform) !== "linux") return false;
1291
+ return (options.existsSync ?? fs.existsSync)("/proc/sys/fs/binfmt_misc/WSLInterop");
1292
+ }
1293
+ function isWindowsExecutableCommand(command) {
1294
+ const normalized = command.replace(/\\/g, "/").toLowerCase();
1295
+ return normalized.endsWith(".exe") || normalized.startsWith("/mnt/c/");
1296
+ }
1297
+ async function runWslpath(cwd) {
1298
+ const { stdout } = await execFileAsync("wslpath", ["-w", cwd], { encoding: "utf8" });
1299
+ return stdout;
1300
+ }
1206
1301
  function basenameToken(value) {
1207
1302
  return path.basename(value).toLowerCase().replace(/\.(cmd|exe|bat)$/u, "");
1208
1303
  }
@@ -1304,46 +1399,8 @@ function compareVersionParts(left, right) {
1304
1399
  return 0;
1305
1400
  }
1306
1401
  async function detectGeminiVersion(command) {
1307
- return await new Promise((resolve) => {
1308
- const child = spawn(command, ["--version"], buildSpawnCommandOptions(command, {
1309
- stdio: [
1310
- "ignore",
1311
- "pipe",
1312
- "pipe"
1313
- ],
1314
- windowsHide: true
1315
- }));
1316
- let stdout = "";
1317
- let stderr = "";
1318
- let settled = false;
1319
- const finish = (value) => {
1320
- if (settled) return;
1321
- settled = true;
1322
- clearTimeout(timer);
1323
- child.removeAllListeners();
1324
- child.stdout?.removeAllListeners();
1325
- child.stderr?.removeAllListeners();
1326
- resolve(value);
1327
- };
1328
- const timer = setTimeout(() => {
1329
- child.kill("SIGKILL");
1330
- finish(void 0);
1331
- }, GEMINI_VERSION_TIMEOUT_MS);
1332
- child.stdout?.setEncoding("utf8");
1333
- child.stderr?.setEncoding("utf8");
1334
- child.stdout?.on("data", (chunk) => {
1335
- stdout += chunk;
1336
- });
1337
- child.stderr?.on("data", (chunk) => {
1338
- stderr += chunk;
1339
- });
1340
- child.once("error", () => {
1341
- finish(void 0);
1342
- });
1343
- child.once("close", () => {
1344
- finish(parseGeminiVersion(`${stdout}\n${stderr}`.split(/\r?\n/).map((line) => line.trim()).find((line) => /\d+\.\d+\.\d+/.test(line))));
1345
- });
1346
- });
1402
+ const versionLine = (await readCommandOutput(command, ["--version"], GEMINI_VERSION_TIMEOUT_MS))?.split(/\r?\n/).map((line) => line.trim()).find((line) => /\d+\.\d+\.\d+/.test(line));
1403
+ return parseGeminiVersion(versionLine);
1347
1404
  }
1348
1405
  async function resolveGeminiCommandArgs(command, args) {
1349
1406
  if (basenameToken(command) !== "gemini" || !args.includes("--acp")) return [...args];
@@ -1425,46 +1482,57 @@ function buildClaudeCodeOptionsMeta(options) {
1425
1482
  if (typeof options.model === "string" && options.model.trim().length > 0) claudeCodeOptions.model = options.model;
1426
1483
  if (Array.isArray(options.allowedTools)) claudeCodeOptions.allowedTools = [...options.allowedTools];
1427
1484
  if (typeof options.maxTurns === "number") claudeCodeOptions.maxTurns = options.maxTurns;
1428
- if (Object.keys(claudeCodeOptions).length === 0) return;
1429
- return { claudeCode: { options: claudeCodeOptions } };
1485
+ const meta = {};
1486
+ if (Object.keys(claudeCodeOptions).length > 0) meta.claudeCode = { options: claudeCodeOptions };
1487
+ const systemPrompt = options.systemPrompt;
1488
+ if (typeof systemPrompt === "string" && systemPrompt.length > 0) meta.systemPrompt = systemPrompt;
1489
+ else if (systemPrompt && typeof systemPrompt === "object" && typeof systemPrompt.append === "string" && systemPrompt.append.length > 0) meta.systemPrompt = { append: systemPrompt.append };
1490
+ if (Object.keys(meta).length === 0) return;
1491
+ return meta;
1430
1492
  }
1431
1493
  //#endregion
1432
1494
  //#region src/acp/auth-env.ts
1495
+ const AUTH_ENV_PREFIX = "ACPX_AUTH_";
1433
1496
  function toEnvToken(value) {
1434
1497
  return value.trim().replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1435
1498
  }
1436
- function buildAuthEnvKeys(methodId) {
1499
+ function buildAuthEnvKey(methodId) {
1437
1500
  const token = toEnvToken(methodId);
1438
- const keys = new Set([methodId]);
1439
- if (token) {
1440
- keys.add(token);
1441
- keys.add(`ACPX_AUTH_${token}`);
1442
- }
1443
- return [...keys];
1501
+ return token.length > 0 ? `${AUTH_ENV_PREFIX}${token}` : void 0;
1444
1502
  }
1445
- const authEnvKeysCache = /* @__PURE__ */ new Map();
1446
- function authEnvKeys(methodId) {
1447
- const cached = authEnvKeysCache.get(methodId);
1448
- if (cached) return cached;
1449
- const keys = buildAuthEnvKeys(methodId);
1450
- authEnvKeysCache.set(methodId, keys);
1451
- return keys;
1503
+ const authEnvKeyCache = /* @__PURE__ */ new Map();
1504
+ function authEnvKey(methodId) {
1505
+ const cached = authEnvKeyCache.get(methodId);
1506
+ if (cached !== void 0) return cached;
1507
+ const key = buildAuthEnvKey(methodId);
1508
+ authEnvKeyCache.set(methodId, key);
1509
+ return key;
1452
1510
  }
1453
1511
  function readEnvCredential(methodId) {
1454
- for (const key of authEnvKeys(methodId)) {
1455
- const value = process.env[key];
1456
- if (typeof value === "string" && value.trim().length > 0) return value;
1512
+ const key = authEnvKey(methodId);
1513
+ if (!key) return;
1514
+ const value = process.env[key];
1515
+ if (typeof value === "string" && value.trim().length > 0) return value;
1516
+ }
1517
+ function promotePrefixedAuthEnvironment(env) {
1518
+ for (const [key, value] of Object.entries(env)) {
1519
+ if (!key.startsWith(AUTH_ENV_PREFIX)) continue;
1520
+ if (typeof value !== "string" || value.trim().length === 0) continue;
1521
+ const normalized = key.slice(10);
1522
+ if (!normalized || env[normalized] != null) continue;
1523
+ env[normalized] = value;
1457
1524
  }
1458
1525
  }
1459
1526
  function buildAgentEnvironment(authCredentials) {
1460
1527
  const env = { ...process.env };
1528
+ promotePrefixedAuthEnvironment(env);
1461
1529
  if (!authCredentials) return env;
1462
1530
  for (const [methodId, credential] of Object.entries(authCredentials)) {
1463
1531
  if (typeof credential !== "string" || credential.trim().length === 0) continue;
1464
1532
  if (!methodId.includes("=") && !methodId.includes("\0") && env[methodId] == null) env[methodId] = credential;
1465
1533
  const normalized = toEnvToken(methodId);
1466
1534
  if (normalized) {
1467
- const prefixed = `ACPX_AUTH_${normalized}`;
1535
+ const prefixed = `${AUTH_ENV_PREFIX}${normalized}`;
1468
1536
  if (env[prefixed] == null) env[prefixed] = credential;
1469
1537
  if (env[normalized] == null) env[normalized] = credential;
1470
1538
  }
@@ -1570,7 +1638,7 @@ async function defaultConfirmExecute(commandLine) {
1570
1638
  return await promptForPermission({ prompt: `\n[permission] Allow terminal command "${commandLine}"? (y/N) ` });
1571
1639
  }
1572
1640
  function canPromptForPermission() {
1573
- return Boolean(process.stdin.isTTY && process.stderr.isTTY);
1641
+ return process.stdin.isTTY && process.stderr.isTTY;
1574
1642
  }
1575
1643
  function waitMs(ms) {
1576
1644
  return new Promise((resolve) => {
@@ -1966,6 +2034,7 @@ var AcpClient = class {
1966
2034
  updateRuntimeOptions(options) {
1967
2035
  if (options.permissionMode) this.options.permissionMode = options.permissionMode;
1968
2036
  if (options.nonInteractivePermissions !== void 0) this.options.nonInteractivePermissions = options.nonInteractivePermissions;
2037
+ if (options.terminal !== void 0) this.options.terminal = options.terminal;
1969
2038
  if (options.permissionMode || options.nonInteractivePermissions !== void 0) {
1970
2039
  this.filesystem.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
1971
2040
  this.terminalManager.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
@@ -2057,7 +2126,7 @@ var AcpClient = class {
2057
2126
  readTextFile: true,
2058
2127
  writeTextFile: true
2059
2128
  },
2060
- terminal: true
2129
+ terminal: this.options.terminal !== false
2061
2130
  },
2062
2131
  clientInfo: {
2063
2132
  name: "acpx",
@@ -2075,6 +2144,7 @@ var AcpClient = class {
2075
2144
  this.log(`initialized protocol version ${initResult.protocolVersion}`);
2076
2145
  } catch (error) {
2077
2146
  startupFailure.dispose();
2147
+ const normalizedError = await this.normalizeInitializeError(error, child, startupStderr);
2078
2148
  try {
2079
2149
  child.kill();
2080
2150
  } catch {}
@@ -2082,7 +2152,7 @@ var AcpClient = class {
2082
2152
  cause: error,
2083
2153
  retryable: true
2084
2154
  });
2085
- throw error;
2155
+ throw normalizedError;
2086
2156
  }
2087
2157
  }
2088
2158
  createTappedStream(base) {
@@ -2126,10 +2196,11 @@ var AcpClient = class {
2126
2196
  const connection = this.getConnection();
2127
2197
  const { command, args } = splitCommandLine(this.options.agentCommand);
2128
2198
  const claudeAcp = isClaudeAcpCommand(command, args);
2199
+ const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
2129
2200
  let result;
2130
2201
  try {
2131
2202
  const createPromise = this.runConnectionRequest(() => connection.newSession({
2132
- cwd: asAbsoluteCwd(cwd),
2203
+ cwd: sessionCwd,
2133
2204
  mcpServers: this.options.mcpServers ?? [],
2134
2205
  _meta: buildClaudeCodeOptionsMeta(this.options.sessionOptions)
2135
2206
  }));
@@ -2154,6 +2225,7 @@ var AcpClient = class {
2154
2225
  }
2155
2226
  async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
2156
2227
  const connection = this.getConnection();
2228
+ const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
2157
2229
  const previousSuppression = this.suppressSessionUpdates;
2158
2230
  const previousReplaySuppression = this.suppressReplaySessionUpdateMessages;
2159
2231
  this.suppressSessionUpdates = previousSuppression || Boolean(options.suppressReplayUpdates);
@@ -2162,7 +2234,7 @@ var AcpClient = class {
2162
2234
  try {
2163
2235
  response = await this.runConnectionRequest(() => connection.loadSession({
2164
2236
  sessionId,
2165
- cwd: asAbsoluteCwd(cwd),
2237
+ cwd: sessionCwd,
2166
2238
  mcpServers: this.options.mcpServers ?? []
2167
2239
  }));
2168
2240
  await this.waitForSessionUpdateDrain(options.replayIdleMs ?? REPLAY_IDLE_MS, options.replayDrainTimeoutMs ?? REPLAY_DRAIN_TIMEOUT_MS);
@@ -2255,7 +2327,7 @@ var AcpClient = class {
2255
2327
  }
2256
2328
  async closeSession(sessionId) {
2257
2329
  const connection = this.getConnection();
2258
- await this.runConnectionRequest(() => connection.unstable_closeSession({ sessionId }));
2330
+ await this.runConnectionRequest(() => connection.unstable_closeNes({ sessionId }));
2259
2331
  if (this.loadedSessionId === sessionId) this.loadedSessionId = void 0;
2260
2332
  }
2261
2333
  async requestCancelActivePrompt() {
@@ -2402,6 +2474,20 @@ var AcpClient = class {
2402
2474
  dispose: () => finish()
2403
2475
  };
2404
2476
  }
2477
+ async normalizeInitializeError(error, child, startupStderr) {
2478
+ if (error instanceof AgentStartupError) return error;
2479
+ const connectionClosedDuringInitialize = error instanceof Error && /acp connection closed/i.test(error.message);
2480
+ await waitForChildExit(child, 100);
2481
+ const childExited = child.exitCode !== null || child.signalCode !== null;
2482
+ if (!connectionClosedDuringInitialize && !childExited) return error;
2483
+ return new AgentStartupError({
2484
+ agentCommand: this.options.agentCommand,
2485
+ exitCode: child.exitCode ?? null,
2486
+ signal: child.signalCode ?? null,
2487
+ stderrSummary: this.summarizeStartupStderr(startupStderr),
2488
+ cause: error
2489
+ });
2490
+ }
2405
2491
  selectAuthMethod(methods) {
2406
2492
  for (const method of methods) {
2407
2493
  const envCredential = readEnvCredential(method.id);
@@ -2851,6 +2937,7 @@ function cloneSessionAcpxState(state) {
2851
2937
  return {
2852
2938
  current_mode_id: state.current_mode_id,
2853
2939
  desired_mode_id: state.desired_mode_id,
2940
+ desired_config_options: state.desired_config_options ? { ...state.desired_config_options } : void 0,
2854
2941
  current_model_id: state.current_model_id,
2855
2942
  available_models: state.available_models ? [...state.available_models] : void 0,
2856
2943
  available_commands: state.available_commands ? [...state.available_commands] : void 0,
@@ -2858,7 +2945,8 @@ function cloneSessionAcpxState(state) {
2858
2945
  session_options: state.session_options ? {
2859
2946
  model: state.session_options.model,
2860
2947
  allowed_tools: state.session_options.allowed_tools ? [...state.session_options.allowed_tools] : void 0,
2861
- max_turns: state.session_options.max_turns
2948
+ max_turns: state.session_options.max_turns,
2949
+ ...state.session_options.system_prompt !== void 0 ? { system_prompt: typeof state.session_options.system_prompt === "string" ? state.session_options.system_prompt : { append: state.session_options.system_prompt.append } } : {}
2862
2950
  } : void 0
2863
2951
  };
2864
2952
  }
@@ -2990,6 +3078,14 @@ function normalizeModelId(modelId) {
2990
3078
  function getDesiredModeId(state) {
2991
3079
  return normalizeModeId(state?.desired_mode_id);
2992
3080
  }
3081
+ function getDesiredConfigOptions(state) {
3082
+ const desired = state?.desired_config_options;
3083
+ if (!desired) return {};
3084
+ return Object.fromEntries(Object.entries(desired).flatMap(([configId, value]) => {
3085
+ const normalizedConfigId = normalizeModeId(configId);
3086
+ return normalizedConfigId && typeof value === "string" ? [[normalizedConfigId, value]] : [];
3087
+ }));
3088
+ }
2993
3089
  function setDesiredModeId(record, modeId) {
2994
3090
  const acpx = ensureAcpxState(record.acpx);
2995
3091
  const normalized = normalizeModeId(modeId);
@@ -2997,6 +3093,17 @@ function setDesiredModeId(record, modeId) {
2997
3093
  else delete acpx.desired_mode_id;
2998
3094
  record.acpx = acpx;
2999
3095
  }
3096
+ function setDesiredConfigOption(record, configId, value) {
3097
+ const normalizedConfigId = normalizeModeId(configId);
3098
+ if (!normalizedConfigId || normalizedConfigId === "mode" || normalizedConfigId === "model") return;
3099
+ const acpx = ensureAcpxState(record.acpx);
3100
+ const desired = { ...acpx.desired_config_options };
3101
+ if (typeof value === "string") desired[normalizedConfigId] = value;
3102
+ else delete desired[normalizedConfigId];
3103
+ if (Object.keys(desired).length > 0) acpx.desired_config_options = desired;
3104
+ else delete acpx.desired_config_options;
3105
+ record.acpx = acpx;
3106
+ }
3000
3107
  function getDesiredModelId(state) {
3001
3108
  return normalizeModelId(state?.session_options?.model);
3002
3109
  }
@@ -3006,7 +3113,7 @@ function setDesiredModelId(record, modelId) {
3006
3113
  const sessionOptions = { ...acpx.session_options };
3007
3114
  if (normalized) sessionOptions.model = normalized;
3008
3115
  else delete sessionOptions.model;
3009
- if (typeof sessionOptions.model === "string" || Array.isArray(sessionOptions.allowed_tools) || typeof sessionOptions.max_turns === "number") acpx.session_options = sessionOptions;
3116
+ if (typeof sessionOptions.model === "string" || Array.isArray(sessionOptions.allowed_tools) || typeof sessionOptions.max_turns === "number" || sessionOptions.system_prompt !== void 0) acpx.session_options = sessionOptions;
3010
3117
  else delete acpx.session_options;
3011
3118
  record.acpx = acpx;
3012
3119
  }
@@ -3025,6 +3132,30 @@ function syncAdvertisedModelState(record, models) {
3025
3132
  record.acpx = acpx;
3026
3133
  }
3027
3134
  //#endregion
3135
+ //#region src/acp/model-support.ts
3136
+ var RequestedModelUnsupportedError = class extends Error {
3137
+ constructor(message) {
3138
+ super(message);
3139
+ this.name = "RequestedModelUnsupportedError";
3140
+ }
3141
+ };
3142
+ function supportsLegacyClaudeCodeModelMetadata(agentCommand) {
3143
+ if (!agentCommand) return false;
3144
+ const { command, args } = splitCommandLine(agentCommand);
3145
+ return isClaudeAcpCommand(command, args);
3146
+ }
3147
+ function formatAvailableModelIds(models) {
3148
+ const ids = models?.availableModels.map((model) => model.modelId.trim()).filter((modelId) => modelId.length > 0) ?? [];
3149
+ return ids.length > 0 ? ids.join(", ") : "none advertised";
3150
+ }
3151
+ function assertRequestedModelSupported(params) {
3152
+ if (!params.models) {
3153
+ if (supportsLegacyClaudeCodeModelMetadata(params.agentCommand)) return;
3154
+ throw new RequestedModelUnsupportedError(`Cannot ${params.context === "replay" ? "replay saved model" : "apply --model"} "${params.requestedModel}": the ACP agent did not advertise model support. Generic model selection requires ACP models plus session/set_model support, or an adapter-specific startup model flag.`);
3155
+ }
3156
+ if (!new Set(params.models.availableModels.map((model) => model.modelId)).has(params.requestedModel)) throw new RequestedModelUnsupportedError(`Cannot ${params.context === "replay" ? "replay saved model" : "apply --model"} "${params.requestedModel}": the ACP agent did not advertise that model. Available models: ${formatAvailableModelIds(params.models)}.`);
3157
+ }
3158
+ //#endregion
3028
3159
  //#region src/runtime/engine/lifecycle.ts
3029
3160
  function applyLifecycleSnapshotToRecord(record, snapshot) {
3030
3161
  if (!snapshot) return;
@@ -3099,9 +3230,15 @@ async function replayDesiredMode(params) {
3099
3230
  }
3100
3231
  }
3101
3232
  async function replayDesiredModel(params) {
3102
- if (!params.desiredModelId || !params.models) return;
3103
- if (params.models.currentModelId === params.desiredModelId) return;
3233
+ if (!params.desiredModelId) return;
3104
3234
  try {
3235
+ assertRequestedModelSupported({
3236
+ requestedModel: params.desiredModelId,
3237
+ models: params.models,
3238
+ agentCommand: params.record.agentCommand,
3239
+ context: "replay"
3240
+ });
3241
+ if (!params.models || params.models.currentModelId === params.desiredModelId) return;
3105
3242
  await withTimeout(params.client.setSessionModel(params.sessionId, params.desiredModelId), params.timeoutMs);
3106
3243
  if (params.verbose) process.stderr.write(`[acpx] replayed desired model ${params.desiredModelId} on fresh ACP session ${params.sessionId} (previous ${params.previousSessionId})\n`);
3107
3244
  } catch (error) {
@@ -3111,6 +3248,17 @@ async function replayDesiredModel(params) {
3111
3248
  });
3112
3249
  }
3113
3250
  }
3251
+ async function replayDesiredConfigOptions(params) {
3252
+ for (const [configId, value] of Object.entries(params.desiredConfigOptions)) try {
3253
+ await withTimeout(params.client.setSessionConfigOption(params.sessionId, configId, value), params.timeoutMs);
3254
+ if (params.verbose) process.stderr.write(`[acpx] replayed desired config option ${configId} on fresh ACP session ${params.sessionId} (previous ${params.previousSessionId})\n`);
3255
+ } catch (error) {
3256
+ throw new SessionConfigOptionReplayError(`Failed to replay saved session config option ${configId} on fresh ACP session ${params.sessionId}: ${formatErrorMessage(error)}`, {
3257
+ cause: error instanceof Error ? error : void 0,
3258
+ retryable: true
3259
+ });
3260
+ }
3261
+ }
3114
3262
  function restoreOriginalSessionState(params) {
3115
3263
  params.record.acpSessionId = params.sessionId;
3116
3264
  params.record.agentSessionId = params.agentSessionId;
@@ -3123,6 +3271,7 @@ async function connectAndLoadSession(options) {
3123
3271
  const originalAgentSessionId = record.agentSessionId;
3124
3272
  const desiredModeId = getDesiredModeId(record.acpx);
3125
3273
  const desiredModelId = getDesiredModelId(record.acpx);
3274
+ const desiredConfigOptions = getDesiredConfigOptions(record.acpx);
3126
3275
  const storedProcessAlive = isProcessAlive(record.pid);
3127
3276
  const shouldReconnect = Boolean(record.pid) && !storedProcessAlive;
3128
3277
  if (options.verbose) {
@@ -3189,10 +3338,19 @@ async function connectAndLoadSession(options) {
3189
3338
  sessionId,
3190
3339
  desiredModelId,
3191
3340
  previousSessionId: originalSessionId,
3341
+ record,
3192
3342
  models: sessionModels,
3193
3343
  timeoutMs: options.timeoutMs,
3194
3344
  verbose: options.verbose
3195
3345
  });
3346
+ await replayDesiredConfigOptions({
3347
+ client,
3348
+ sessionId,
3349
+ desiredConfigOptions,
3350
+ previousSessionId: originalSessionId,
3351
+ timeoutMs: options.timeoutMs,
3352
+ verbose: options.verbose
3353
+ });
3196
3354
  } catch (error) {
3197
3355
  restoreOriginalSessionState({
3198
3356
  record,
@@ -3217,6 +3375,14 @@ async function connectAndLoadSession(options) {
3217
3375
  }
3218
3376
  //#endregion
3219
3377
  //#region src/runtime/engine/session-options.ts
3378
+ function mergeSessionOptions(preferred, fallback) {
3379
+ const merged = { ...fallback };
3380
+ if (preferred?.model !== void 0) merged.model = preferred.model;
3381
+ if (preferred?.allowedTools !== void 0) merged.allowedTools = preferred.allowedTools;
3382
+ if (preferred?.maxTurns !== void 0) merged.maxTurns = preferred.maxTurns;
3383
+ if (preferred?.systemPrompt !== void 0) merged.systemPrompt = preferred.systemPrompt;
3384
+ return Object.keys(merged).length > 0 ? merged : void 0;
3385
+ }
3220
3386
  function sessionOptionsFromRecord(record) {
3221
3387
  const stored = record.acpx?.session_options;
3222
3388
  if (!stored) return;
@@ -3224,6 +3390,9 @@ function sessionOptionsFromRecord(record) {
3224
3390
  if (typeof stored.model === "string" && stored.model.trim().length > 0) sessionOptions.model = stored.model;
3225
3391
  if (Array.isArray(stored.allowed_tools)) sessionOptions.allowedTools = [...stored.allowed_tools];
3226
3392
  if (typeof stored.max_turns === "number") sessionOptions.maxTurns = stored.max_turns;
3393
+ const storedSystemPrompt = stored.system_prompt;
3394
+ if (typeof storedSystemPrompt === "string" && storedSystemPrompt.length > 0) sessionOptions.systemPrompt = storedSystemPrompt;
3395
+ else if (storedSystemPrompt && typeof storedSystemPrompt === "object" && typeof storedSystemPrompt.append === "string" && storedSystemPrompt.append.length > 0) sessionOptions.systemPrompt = { append: storedSystemPrompt.append };
3227
3396
  return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
3228
3397
  }
3229
3398
  //#endregion
@@ -3254,6 +3423,7 @@ async function withConnectedSession(options) {
3254
3423
  nonInteractivePermissions: options.nonInteractivePermissions,
3255
3424
  authCredentials: options.authCredentials,
3256
3425
  authPolicy: options.authPolicy,
3426
+ terminal: options.terminal,
3257
3427
  verbose: options.verbose,
3258
3428
  sessionOptions: sessionOptionsFromRecord(record)
3259
3429
  }) ?? new AcpClient({
@@ -3264,6 +3434,7 @@ async function withConnectedSession(options) {
3264
3434
  nonInteractivePermissions: options.nonInteractivePermissions,
3265
3435
  authCredentials: options.authCredentials,
3266
3436
  authPolicy: options.authPolicy,
3437
+ terminal: options.terminal,
3267
3438
  verbose: options.verbose,
3268
3439
  sessionOptions: sessionOptionsFromRecord(record)
3269
3440
  });
@@ -3338,8 +3509,13 @@ async function runPromptTurn(params) {
3338
3509
  try {
3339
3510
  const promptPromise = params.client.prompt(params.sessionId, params.prompt);
3340
3511
  await params.onPromptStarted?.();
3512
+ const response = await withTimeout(promptPromise, params.timeoutMs);
3513
+ await params.client.waitForSessionUpdatesIdle?.({
3514
+ idleMs: SESSION_REPLY_IDLE_MS,
3515
+ timeoutMs: SESSION_REPLY_DRAIN_TIMEOUT_MS
3516
+ }).catch(() => {});
3341
3517
  return {
3342
- stopReason: (await withTimeout(promptPromise, params.timeoutMs)).stopReason,
3518
+ stopReason: response.stopReason,
3343
3519
  source: "rpc"
3344
3520
  };
3345
3521
  } catch (error) {
@@ -3356,6 +3532,6 @@ async function runPromptTurn(params) {
3356
3532
  }
3357
3533
  }
3358
3534
  //#endregion
3359
- export { resolveSessionRecord as A, serializeSessionRecordForDisk as B, findGitRepositoryRoot as C, listSessions as D, isoNow$2 as E, sessionBaseDir$1 as F, DEFAULT_AGENT_NAME as G, TimeoutError as H, sessionEventActivePath as I, resolveAgentCommand as J, listBuiltInAgents as K, sessionEventLockPath as L, parseSessionRecord as M, DEFAULT_EVENT_SEGMENT_MAX_BYTES as N, listSessionsForAgent as O, defaultSessionEventLog as P, sessionEventSegmentPath as R, absolutePath as S, findSessionByDirectoryWalk as T, withInterrupt as U, InterruptedError as V, withTimeout as W, recordSessionUpdate as _, applyConversation as a, permissionModeSatisfies as b, setCurrentModelId as c, syncAdvertisedModelState as d, cloneSessionAcpxState as f, recordPromptSubmission as g, recordClientOperation as h, connectAndLoadSession as i, writeSessionRecord as j, normalizeName as k, setDesiredModeId as l, createSessionConversation as m, withConnectedSession as n, applyLifecycleSnapshotToRecord as o, cloneSessionConversation as p, normalizeAgentName$1 as q, sessionOptionsFromRecord as r, reconcileAgentSessionId as s, runPromptTurn as t, setDesiredModelId as u, trimConversationForRuntime as v, findSession as w, DEFAULT_HISTORY_LIMIT as x, AcpClient as y, assertPersistedKeyPolicy as z };
3535
+ export { listSessions as A, sessionEventActivePath as B, permissionModeSatisfies as C, findSession as D, findGitRepositoryRoot as E, writeSessionRecord as F, InterruptedError as G, sessionEventSegmentPath as H, parseSessionRecord as I, withTimeout as J, TimeoutError as K, DEFAULT_EVENT_SEGMENT_MAX_BYTES as L, normalizeName as M, pruneSessions as N, findSessionByDirectoryWalk as O, resolveSessionRecord as P, resolveAgentCommand as Q, defaultSessionEventLog as R, AcpClient as S, absolutePath as T, assertPersistedKeyPolicy as U, sessionEventLockPath as V, serializeSessionRecordForDisk as W, listBuiltInAgents as X, DEFAULT_AGENT_NAME as Y, normalizeAgentName$1 as Z, createSessionConversation as _, connectAndLoadSession as a, recordSessionUpdate as b, reconcileAgentSessionId as c, setDesiredConfigOption as d, setDesiredModeId as f, cloneSessionConversation as g, cloneSessionAcpxState as h, sessionOptionsFromRecord as i, listSessionsForAgent as j, isoNow$2 as k, assertRequestedModelSupported as l, syncAdvertisedModelState as m, withConnectedSession as n, applyConversation as o, setDesiredModelId as p, withInterrupt as q, mergeSessionOptions as r, applyLifecycleSnapshotToRecord as s, runPromptTurn as t, setCurrentModelId as u, recordClientOperation as v, DEFAULT_HISTORY_LIMIT as w, trimConversationForRuntime as x, recordPromptSubmission as y, sessionBaseDir$1 as z };
3360
3536
 
3361
- //# sourceMappingURL=prompt-turn-CXMtXBl-.js.map
3537
+ //# sourceMappingURL=prompt-turn-BY5SwU1F.js.map