acpx 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +12 -4
  2. package/dist/{cli-ChWsO-bb.js → cli-rGyZlX2p.js} +4 -4
  3. package/dist/{cli-ChWsO-bb.js.map → cli-rGyZlX2p.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 +100 -24
  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-DG-3Vfgg.js} +25 -6
  11. package/dist/flags-DG-3Vfgg.js.map +1 -0
  12. package/dist/{flows-_KmnuUXd.js → flows-gbxyIf6o.js} +13 -6
  13. package/dist/flows-gbxyIf6o.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-CkAW8Qvc.js} +51 -9
  18. package/dist/ipc-CkAW8Qvc.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-DvT_gvUh.js} +12 -2
  22. package/dist/perf-metrics-DvT_gvUh.js.map +1 -0
  23. package/dist/{prompt-turn-CXMtXBl-.js → prompt-turn-BOoZaDEq.js} +221 -38
  24. package/dist/prompt-turn-BOoZaDEq.js.map +1 -0
  25. package/dist/{render-Br-kVPK_.js → render-CyodRDtK.js} +35 -3
  26. package/dist/{render-Br-kVPK_.js.map → render-CyodRDtK.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-DcIse8N0.js} +66 -15
  32. package/dist/session-DcIse8N0.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 +20 -20
  38. package/skills/acpx/SKILL.md +7 -2
  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 PermissionPromptUnavailableError, C as isAcpResourceNotFoundError, F as AuthPolicyError, G as SessionModelReplayError, I as ClaudeAcpSessionCreateTimeoutError, J as SessionResumeRequiredError, K as SessionNotFoundError, L as CopilotAcpUnsupportedError, M as AgentDisconnectedError, N as AgentSpawnError, P as AgentStartupError, R as GeminiAcpStartupTimeoutError, S as extractAcpError, U as SessionConfigOptionReplayError, W as SessionModeReplayError, g as textPrompt, i as measurePerf, j as SESSION_RECORD_SCHEMA, l as extractRuntimeSessionId, q as SessionResolutionError, r as incrementPerfCounter, u as normalizeRuntimeSessionId, v as formatErrorMessage, y as isAcpQueryClosedBeforeResponseError, z as PermissionDeniedError } from "./perf-metrics-DvT_gvUh.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
  }
@@ -1425,46 +1520,57 @@ function buildClaudeCodeOptionsMeta(options) {
1425
1520
  if (typeof options.model === "string" && options.model.trim().length > 0) claudeCodeOptions.model = options.model;
1426
1521
  if (Array.isArray(options.allowedTools)) claudeCodeOptions.allowedTools = [...options.allowedTools];
1427
1522
  if (typeof options.maxTurns === "number") claudeCodeOptions.maxTurns = options.maxTurns;
1428
- if (Object.keys(claudeCodeOptions).length === 0) return;
1429
- return { claudeCode: { options: claudeCodeOptions } };
1523
+ const meta = {};
1524
+ if (Object.keys(claudeCodeOptions).length > 0) meta.claudeCode = { options: claudeCodeOptions };
1525
+ const systemPrompt = options.systemPrompt;
1526
+ if (typeof systemPrompt === "string" && systemPrompt.length > 0) meta.systemPrompt = systemPrompt;
1527
+ else if (systemPrompt && typeof systemPrompt === "object" && typeof systemPrompt.append === "string" && systemPrompt.append.length > 0) meta.systemPrompt = { append: systemPrompt.append };
1528
+ if (Object.keys(meta).length === 0) return;
1529
+ return meta;
1430
1530
  }
1431
1531
  //#endregion
1432
1532
  //#region src/acp/auth-env.ts
1533
+ const AUTH_ENV_PREFIX = "ACPX_AUTH_";
1433
1534
  function toEnvToken(value) {
1434
1535
  return value.trim().replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1435
1536
  }
1436
- function buildAuthEnvKeys(methodId) {
1537
+ function buildAuthEnvKey(methodId) {
1437
1538
  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];
1539
+ return token.length > 0 ? `${AUTH_ENV_PREFIX}${token}` : void 0;
1444
1540
  }
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;
1541
+ const authEnvKeyCache = /* @__PURE__ */ new Map();
1542
+ function authEnvKey(methodId) {
1543
+ const cached = authEnvKeyCache.get(methodId);
1544
+ if (cached !== void 0) return cached;
1545
+ const key = buildAuthEnvKey(methodId);
1546
+ authEnvKeyCache.set(methodId, key);
1547
+ return key;
1452
1548
  }
1453
1549
  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;
1550
+ const key = authEnvKey(methodId);
1551
+ if (!key) return;
1552
+ const value = process.env[key];
1553
+ if (typeof value === "string" && value.trim().length > 0) return value;
1554
+ }
1555
+ function promotePrefixedAuthEnvironment(env) {
1556
+ for (const [key, value] of Object.entries(env)) {
1557
+ if (!key.startsWith(AUTH_ENV_PREFIX)) continue;
1558
+ if (typeof value !== "string" || value.trim().length === 0) continue;
1559
+ const normalized = key.slice(10);
1560
+ if (!normalized || env[normalized] != null) continue;
1561
+ env[normalized] = value;
1457
1562
  }
1458
1563
  }
1459
1564
  function buildAgentEnvironment(authCredentials) {
1460
1565
  const env = { ...process.env };
1566
+ promotePrefixedAuthEnvironment(env);
1461
1567
  if (!authCredentials) return env;
1462
1568
  for (const [methodId, credential] of Object.entries(authCredentials)) {
1463
1569
  if (typeof credential !== "string" || credential.trim().length === 0) continue;
1464
1570
  if (!methodId.includes("=") && !methodId.includes("\0") && env[methodId] == null) env[methodId] = credential;
1465
1571
  const normalized = toEnvToken(methodId);
1466
1572
  if (normalized) {
1467
- const prefixed = `ACPX_AUTH_${normalized}`;
1573
+ const prefixed = `${AUTH_ENV_PREFIX}${normalized}`;
1468
1574
  if (env[prefixed] == null) env[prefixed] = credential;
1469
1575
  if (env[normalized] == null) env[normalized] = credential;
1470
1576
  }
@@ -1570,7 +1676,7 @@ async function defaultConfirmExecute(commandLine) {
1570
1676
  return await promptForPermission({ prompt: `\n[permission] Allow terminal command "${commandLine}"? (y/N) ` });
1571
1677
  }
1572
1678
  function canPromptForPermission() {
1573
- return Boolean(process.stdin.isTTY && process.stderr.isTTY);
1679
+ return process.stdin.isTTY && process.stderr.isTTY;
1574
1680
  }
1575
1681
  function waitMs(ms) {
1576
1682
  return new Promise((resolve) => {
@@ -1966,6 +2072,7 @@ var AcpClient = class {
1966
2072
  updateRuntimeOptions(options) {
1967
2073
  if (options.permissionMode) this.options.permissionMode = options.permissionMode;
1968
2074
  if (options.nonInteractivePermissions !== void 0) this.options.nonInteractivePermissions = options.nonInteractivePermissions;
2075
+ if (options.terminal !== void 0) this.options.terminal = options.terminal;
1969
2076
  if (options.permissionMode || options.nonInteractivePermissions !== void 0) {
1970
2077
  this.filesystem.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
1971
2078
  this.terminalManager.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
@@ -2057,7 +2164,7 @@ var AcpClient = class {
2057
2164
  readTextFile: true,
2058
2165
  writeTextFile: true
2059
2166
  },
2060
- terminal: true
2167
+ terminal: this.options.terminal !== false
2061
2168
  },
2062
2169
  clientInfo: {
2063
2170
  name: "acpx",
@@ -2075,6 +2182,7 @@ var AcpClient = class {
2075
2182
  this.log(`initialized protocol version ${initResult.protocolVersion}`);
2076
2183
  } catch (error) {
2077
2184
  startupFailure.dispose();
2185
+ const normalizedError = await this.normalizeInitializeError(error, child, startupStderr);
2078
2186
  try {
2079
2187
  child.kill();
2080
2188
  } catch {}
@@ -2082,7 +2190,7 @@ var AcpClient = class {
2082
2190
  cause: error,
2083
2191
  retryable: true
2084
2192
  });
2085
- throw error;
2193
+ throw normalizedError;
2086
2194
  }
2087
2195
  }
2088
2196
  createTappedStream(base) {
@@ -2126,10 +2234,11 @@ var AcpClient = class {
2126
2234
  const connection = this.getConnection();
2127
2235
  const { command, args } = splitCommandLine(this.options.agentCommand);
2128
2236
  const claudeAcp = isClaudeAcpCommand(command, args);
2237
+ const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
2129
2238
  let result;
2130
2239
  try {
2131
2240
  const createPromise = this.runConnectionRequest(() => connection.newSession({
2132
- cwd: asAbsoluteCwd(cwd),
2241
+ cwd: sessionCwd,
2133
2242
  mcpServers: this.options.mcpServers ?? [],
2134
2243
  _meta: buildClaudeCodeOptionsMeta(this.options.sessionOptions)
2135
2244
  }));
@@ -2154,6 +2263,7 @@ var AcpClient = class {
2154
2263
  }
2155
2264
  async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
2156
2265
  const connection = this.getConnection();
2266
+ const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
2157
2267
  const previousSuppression = this.suppressSessionUpdates;
2158
2268
  const previousReplaySuppression = this.suppressReplaySessionUpdateMessages;
2159
2269
  this.suppressSessionUpdates = previousSuppression || Boolean(options.suppressReplayUpdates);
@@ -2162,7 +2272,7 @@ var AcpClient = class {
2162
2272
  try {
2163
2273
  response = await this.runConnectionRequest(() => connection.loadSession({
2164
2274
  sessionId,
2165
- cwd: asAbsoluteCwd(cwd),
2275
+ cwd: sessionCwd,
2166
2276
  mcpServers: this.options.mcpServers ?? []
2167
2277
  }));
2168
2278
  await this.waitForSessionUpdateDrain(options.replayIdleMs ?? REPLAY_IDLE_MS, options.replayDrainTimeoutMs ?? REPLAY_DRAIN_TIMEOUT_MS);
@@ -2255,7 +2365,7 @@ var AcpClient = class {
2255
2365
  }
2256
2366
  async closeSession(sessionId) {
2257
2367
  const connection = this.getConnection();
2258
- await this.runConnectionRequest(() => connection.unstable_closeSession({ sessionId }));
2368
+ await this.runConnectionRequest(() => connection.unstable_closeNes({ sessionId }));
2259
2369
  if (this.loadedSessionId === sessionId) this.loadedSessionId = void 0;
2260
2370
  }
2261
2371
  async requestCancelActivePrompt() {
@@ -2402,6 +2512,20 @@ var AcpClient = class {
2402
2512
  dispose: () => finish()
2403
2513
  };
2404
2514
  }
2515
+ async normalizeInitializeError(error, child, startupStderr) {
2516
+ if (error instanceof AgentStartupError) return error;
2517
+ const connectionClosedDuringInitialize = error instanceof Error && /acp connection closed/i.test(error.message);
2518
+ await waitForChildExit(child, 100);
2519
+ const childExited = child.exitCode !== null || child.signalCode !== null;
2520
+ if (!connectionClosedDuringInitialize && !childExited) return error;
2521
+ return new AgentStartupError({
2522
+ agentCommand: this.options.agentCommand,
2523
+ exitCode: child.exitCode ?? null,
2524
+ signal: child.signalCode ?? null,
2525
+ stderrSummary: this.summarizeStartupStderr(startupStderr),
2526
+ cause: error
2527
+ });
2528
+ }
2405
2529
  selectAuthMethod(methods) {
2406
2530
  for (const method of methods) {
2407
2531
  const envCredential = readEnvCredential(method.id);
@@ -2851,6 +2975,7 @@ function cloneSessionAcpxState(state) {
2851
2975
  return {
2852
2976
  current_mode_id: state.current_mode_id,
2853
2977
  desired_mode_id: state.desired_mode_id,
2978
+ desired_config_options: state.desired_config_options ? { ...state.desired_config_options } : void 0,
2854
2979
  current_model_id: state.current_model_id,
2855
2980
  available_models: state.available_models ? [...state.available_models] : void 0,
2856
2981
  available_commands: state.available_commands ? [...state.available_commands] : void 0,
@@ -2858,7 +2983,8 @@ function cloneSessionAcpxState(state) {
2858
2983
  session_options: state.session_options ? {
2859
2984
  model: state.session_options.model,
2860
2985
  allowed_tools: state.session_options.allowed_tools ? [...state.session_options.allowed_tools] : void 0,
2861
- max_turns: state.session_options.max_turns
2986
+ max_turns: state.session_options.max_turns,
2987
+ ...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
2988
  } : void 0
2863
2989
  };
2864
2990
  }
@@ -2990,6 +3116,14 @@ function normalizeModelId(modelId) {
2990
3116
  function getDesiredModeId(state) {
2991
3117
  return normalizeModeId(state?.desired_mode_id);
2992
3118
  }
3119
+ function getDesiredConfigOptions(state) {
3120
+ const desired = state?.desired_config_options;
3121
+ if (!desired) return {};
3122
+ return Object.fromEntries(Object.entries(desired).flatMap(([configId, value]) => {
3123
+ const normalizedConfigId = normalizeModeId(configId);
3124
+ return normalizedConfigId && typeof value === "string" ? [[normalizedConfigId, value]] : [];
3125
+ }));
3126
+ }
2993
3127
  function setDesiredModeId(record, modeId) {
2994
3128
  const acpx = ensureAcpxState(record.acpx);
2995
3129
  const normalized = normalizeModeId(modeId);
@@ -2997,6 +3131,17 @@ function setDesiredModeId(record, modeId) {
2997
3131
  else delete acpx.desired_mode_id;
2998
3132
  record.acpx = acpx;
2999
3133
  }
3134
+ function setDesiredConfigOption(record, configId, value) {
3135
+ const normalizedConfigId = normalizeModeId(configId);
3136
+ if (!normalizedConfigId || normalizedConfigId === "mode" || normalizedConfigId === "model") return;
3137
+ const acpx = ensureAcpxState(record.acpx);
3138
+ const desired = { ...acpx.desired_config_options };
3139
+ if (typeof value === "string") desired[normalizedConfigId] = value;
3140
+ else delete desired[normalizedConfigId];
3141
+ if (Object.keys(desired).length > 0) acpx.desired_config_options = desired;
3142
+ else delete acpx.desired_config_options;
3143
+ record.acpx = acpx;
3144
+ }
3000
3145
  function getDesiredModelId(state) {
3001
3146
  return normalizeModelId(state?.session_options?.model);
3002
3147
  }
@@ -3006,7 +3151,7 @@ function setDesiredModelId(record, modelId) {
3006
3151
  const sessionOptions = { ...acpx.session_options };
3007
3152
  if (normalized) sessionOptions.model = normalized;
3008
3153
  else delete sessionOptions.model;
3009
- if (typeof sessionOptions.model === "string" || Array.isArray(sessionOptions.allowed_tools) || typeof sessionOptions.max_turns === "number") acpx.session_options = sessionOptions;
3154
+ 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
3155
  else delete acpx.session_options;
3011
3156
  record.acpx = acpx;
3012
3157
  }
@@ -3111,6 +3256,17 @@ async function replayDesiredModel(params) {
3111
3256
  });
3112
3257
  }
3113
3258
  }
3259
+ async function replayDesiredConfigOptions(params) {
3260
+ for (const [configId, value] of Object.entries(params.desiredConfigOptions)) try {
3261
+ await withTimeout(params.client.setSessionConfigOption(params.sessionId, configId, value), params.timeoutMs);
3262
+ if (params.verbose) process.stderr.write(`[acpx] replayed desired config option ${configId} on fresh ACP session ${params.sessionId} (previous ${params.previousSessionId})\n`);
3263
+ } catch (error) {
3264
+ throw new SessionConfigOptionReplayError(`Failed to replay saved session config option ${configId} on fresh ACP session ${params.sessionId}: ${formatErrorMessage(error)}`, {
3265
+ cause: error instanceof Error ? error : void 0,
3266
+ retryable: true
3267
+ });
3268
+ }
3269
+ }
3114
3270
  function restoreOriginalSessionState(params) {
3115
3271
  params.record.acpSessionId = params.sessionId;
3116
3272
  params.record.agentSessionId = params.agentSessionId;
@@ -3123,6 +3279,7 @@ async function connectAndLoadSession(options) {
3123
3279
  const originalAgentSessionId = record.agentSessionId;
3124
3280
  const desiredModeId = getDesiredModeId(record.acpx);
3125
3281
  const desiredModelId = getDesiredModelId(record.acpx);
3282
+ const desiredConfigOptions = getDesiredConfigOptions(record.acpx);
3126
3283
  const storedProcessAlive = isProcessAlive(record.pid);
3127
3284
  const shouldReconnect = Boolean(record.pid) && !storedProcessAlive;
3128
3285
  if (options.verbose) {
@@ -3193,6 +3350,14 @@ async function connectAndLoadSession(options) {
3193
3350
  timeoutMs: options.timeoutMs,
3194
3351
  verbose: options.verbose
3195
3352
  });
3353
+ await replayDesiredConfigOptions({
3354
+ client,
3355
+ sessionId,
3356
+ desiredConfigOptions,
3357
+ previousSessionId: originalSessionId,
3358
+ timeoutMs: options.timeoutMs,
3359
+ verbose: options.verbose
3360
+ });
3196
3361
  } catch (error) {
3197
3362
  restoreOriginalSessionState({
3198
3363
  record,
@@ -3217,6 +3382,14 @@ async function connectAndLoadSession(options) {
3217
3382
  }
3218
3383
  //#endregion
3219
3384
  //#region src/runtime/engine/session-options.ts
3385
+ function mergeSessionOptions(preferred, fallback) {
3386
+ const merged = { ...fallback };
3387
+ if (preferred?.model !== void 0) merged.model = preferred.model;
3388
+ if (preferred?.allowedTools !== void 0) merged.allowedTools = preferred.allowedTools;
3389
+ if (preferred?.maxTurns !== void 0) merged.maxTurns = preferred.maxTurns;
3390
+ if (preferred?.systemPrompt !== void 0) merged.systemPrompt = preferred.systemPrompt;
3391
+ return Object.keys(merged).length > 0 ? merged : void 0;
3392
+ }
3220
3393
  function sessionOptionsFromRecord(record) {
3221
3394
  const stored = record.acpx?.session_options;
3222
3395
  if (!stored) return;
@@ -3224,6 +3397,9 @@ function sessionOptionsFromRecord(record) {
3224
3397
  if (typeof stored.model === "string" && stored.model.trim().length > 0) sessionOptions.model = stored.model;
3225
3398
  if (Array.isArray(stored.allowed_tools)) sessionOptions.allowedTools = [...stored.allowed_tools];
3226
3399
  if (typeof stored.max_turns === "number") sessionOptions.maxTurns = stored.max_turns;
3400
+ const storedSystemPrompt = stored.system_prompt;
3401
+ if (typeof storedSystemPrompt === "string" && storedSystemPrompt.length > 0) sessionOptions.systemPrompt = storedSystemPrompt;
3402
+ else if (storedSystemPrompt && typeof storedSystemPrompt === "object" && typeof storedSystemPrompt.append === "string" && storedSystemPrompt.append.length > 0) sessionOptions.systemPrompt = { append: storedSystemPrompt.append };
3227
3403
  return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
3228
3404
  }
3229
3405
  //#endregion
@@ -3254,6 +3430,7 @@ async function withConnectedSession(options) {
3254
3430
  nonInteractivePermissions: options.nonInteractivePermissions,
3255
3431
  authCredentials: options.authCredentials,
3256
3432
  authPolicy: options.authPolicy,
3433
+ terminal: options.terminal,
3257
3434
  verbose: options.verbose,
3258
3435
  sessionOptions: sessionOptionsFromRecord(record)
3259
3436
  }) ?? new AcpClient({
@@ -3264,6 +3441,7 @@ async function withConnectedSession(options) {
3264
3441
  nonInteractivePermissions: options.nonInteractivePermissions,
3265
3442
  authCredentials: options.authCredentials,
3266
3443
  authPolicy: options.authPolicy,
3444
+ terminal: options.terminal,
3267
3445
  verbose: options.verbose,
3268
3446
  sessionOptions: sessionOptionsFromRecord(record)
3269
3447
  });
@@ -3338,8 +3516,13 @@ async function runPromptTurn(params) {
3338
3516
  try {
3339
3517
  const promptPromise = params.client.prompt(params.sessionId, params.prompt);
3340
3518
  await params.onPromptStarted?.();
3519
+ const response = await withTimeout(promptPromise, params.timeoutMs);
3520
+ await params.client.waitForSessionUpdatesIdle?.({
3521
+ idleMs: SESSION_REPLY_IDLE_MS,
3522
+ timeoutMs: SESSION_REPLY_DRAIN_TIMEOUT_MS
3523
+ }).catch(() => {});
3341
3524
  return {
3342
- stopReason: (await withTimeout(promptPromise, params.timeoutMs)).stopReason,
3525
+ stopReason: response.stopReason,
3343
3526
  source: "rpc"
3344
3527
  };
3345
3528
  } catch (error) {
@@ -3356,6 +3539,6 @@ async function runPromptTurn(params) {
3356
3539
  }
3357
3540
  }
3358
3541
  //#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 };
3542
+ export { listSessionsForAgent as A, sessionEventLockPath as B, DEFAULT_HISTORY_LIMIT as C, findSessionByDirectoryWalk as D, findSession as E, parseSessionRecord as F, TimeoutError as G, assertPersistedKeyPolicy as H, DEFAULT_EVENT_SEGMENT_MAX_BYTES as I, DEFAULT_AGENT_NAME as J, withInterrupt as K, defaultSessionEventLog as L, pruneSessions as M, resolveSessionRecord as N, isoNow$2 as O, writeSessionRecord as P, sessionBaseDir$1 as R, permissionModeSatisfies as S, findGitRepositoryRoot as T, serializeSessionRecordForDisk as U, sessionEventSegmentPath as V, InterruptedError as W, normalizeAgentName$1 as X, listBuiltInAgents as Y, resolveAgentCommand as Z, recordClientOperation as _, connectAndLoadSession as a, trimConversationForRuntime as b, reconcileAgentSessionId as c, setDesiredModeId as d, setDesiredModelId as f, createSessionConversation as g, cloneSessionConversation as h, sessionOptionsFromRecord as i, normalizeName as j, listSessions as k, setCurrentModelId as l, cloneSessionAcpxState as m, withConnectedSession as n, applyConversation as o, syncAdvertisedModelState as p, withTimeout as q, mergeSessionOptions as r, applyLifecycleSnapshotToRecord as s, runPromptTurn as t, setDesiredConfigOption as u, recordPromptSubmission as v, absolutePath as w, AcpClient as x, recordSessionUpdate as y, sessionEventActivePath as z };
3360
3543
 
3361
- //# sourceMappingURL=prompt-turn-CXMtXBl-.js.map
3544
+ //# sourceMappingURL=prompt-turn-BOoZaDEq.js.map