acpx 0.11.0 → 0.11.2

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/dist/flows.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { c as NonInteractivePermissionPolicy, l as PermissionMode, o as AuthPolicy, p as PromptInput, s as McpServer$1, t as SessionAgentOptions, u as PermissionPolicy } from "./session-options-Co1oGEK8.js";
1
+ import { c as NonInteractivePermissionPolicy, l as PermissionMode, o as AuthPolicy, p as PromptInput, s as McpServer$1, t as SessionAgentOptions, u as PermissionPolicy } from "./session-options-jkYbBxGE.js";
2
2
  import { SetSessionConfigOptionResponse } from "@agentclientprotocol/sdk";
3
3
 
4
4
  //#region src/flows/types.d.ts
package/dist/flows.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as parseStrictJsonObject, d as checkpoint, f as compute, i as parseJsonObject, l as acp, m as shell, n as decisionEdge, o as FlowRunner, p as defineFlow, r as extractJsonObject, s as flowRunsBaseDir, t as decision, u as action } from "./flows-BabqiU0u.js";
1
+ import { a as parseStrictJsonObject, d as checkpoint, f as compute, i as parseJsonObject, l as acp, m as shell, n as decisionEdge, o as FlowRunner, p as defineFlow, r as extractJsonObject, s as flowRunsBaseDir, t as decision, u as action } from "./flows-7OHjgEgq.js";
2
2
  export { FlowRunner, acp, action, checkpoint, compute, decision, decisionEdge, defineFlow, extractJsonObject, flowRunsBaseDir, parseJsonObject, parseStrictJsonObject, shell };
@@ -222,7 +222,7 @@ const OUTPUT_ERROR_ORIGINS = [
222
222
  const SESSION_RECORD_SCHEMA = "acpx.session.v1";
223
223
  //#endregion
224
224
  //#region src/acp/error-shapes.ts
225
- const RESOURCE_NOT_FOUND_ACP_CODES = new Set([-32001, -32002]);
225
+ const RESOURCE_NOT_FOUND_ACP_CODES = /* @__PURE__ */ new Set([-32001, -32002]);
226
226
  function asRecord$8(value) {
227
227
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
228
228
  return value;
@@ -295,7 +295,7 @@ function isAcpResourceNotFoundError(error) {
295
295
  }
296
296
  //#endregion
297
297
  //#region src/acp/error-normalization.ts
298
- const AUTH_REQUIRED_ACP_CODES = new Set([-32e3]);
298
+ const AUTH_REQUIRED_ACP_CODES = /* @__PURE__ */ new Set([-32e3]);
299
299
  const QUERY_CLOSED_BEFORE_RESPONSE_DETAIL = "query closed before response received";
300
300
  function asRecord$7(value) {
301
301
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
@@ -835,6 +835,9 @@ function asRecord$5(value) {
835
835
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
836
836
  return value;
837
837
  }
838
+ function isAcpMessageObject(value) {
839
+ return asRecord$5(value) !== null;
840
+ }
838
841
  function hasValidId(value) {
839
842
  return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
840
843
  }
@@ -1263,6 +1266,7 @@ function assignParsedSessionOptions(state, raw) {
1263
1266
  assignSessionOptionAllowedTools(parsedSessionOptions, sessionOptions.allowed_tools);
1264
1267
  assignSessionOptionMaxTurns(parsedSessionOptions, sessionOptions.max_turns);
1265
1268
  assignSessionOptionSystemPrompt(parsedSessionOptions, sessionOptions.system_prompt);
1269
+ assignSessionOptionEnv(parsedSessionOptions, sessionOptions.env);
1266
1270
  if (Object.keys(parsedSessionOptions).length > 0) state.session_options = parsedSessionOptions;
1267
1271
  }
1268
1272
  function assignSessionOptionModel(options, value) {
@@ -1282,6 +1286,15 @@ function assignSessionOptionSystemPrompt(options, value) {
1282
1286
  const appendRecord = asRecord$4(value);
1283
1287
  if (appendRecord && typeof appendRecord.append === "string" && appendRecord.append.length > 0) options.system_prompt = { append: appendRecord.append };
1284
1288
  }
1289
+ function assignSessionOptionEnv(options, value) {
1290
+ const env = asRecord$4(value);
1291
+ if (!env) return;
1292
+ const parsed = Object.fromEntries(Object.entries(env).filter((entry) => {
1293
+ const [, raw] = entry;
1294
+ return typeof raw === "string";
1295
+ }));
1296
+ if (Object.keys(parsed).length > 0) options.env = parsed;
1297
+ }
1285
1298
  function parseEventLog(raw, sessionId) {
1286
1299
  const record = asRecord$4(raw);
1287
1300
  if (!record || !hasValidEventLogCore(record)) return defaultSessionEventLog(sessionId);
@@ -1506,7 +1519,7 @@ function formatPerfMetric(name, durationMsValue) {
1506
1519
  //#endregion
1507
1520
  //#region src/persisted-key-policy.ts
1508
1521
  const SNAKE_CASE_KEY = /^[a-z][a-z0-9_]*$/;
1509
- const ZED_TAG_KEYS = new Set([
1522
+ const ZED_TAG_KEYS = /* @__PURE__ */ new Set([
1510
1523
  "User",
1511
1524
  "Agent",
1512
1525
  "Resume",
@@ -1518,8 +1531,8 @@ const ZED_TAG_KEYS = new Set([
1518
1531
  "RedactedThinking",
1519
1532
  "ToolUse"
1520
1533
  ]);
1521
- const MAP_OBJECT_PATHS = new Set(["request_token_usage", "messages.Agent.tool_results"]);
1522
- const OPAQUE_VALUE_PATHS = new Set([
1534
+ const MAP_OBJECT_PATHS = /* @__PURE__ */ new Set(["request_token_usage", "messages.Agent.tool_results"]);
1535
+ const OPAQUE_VALUE_PATHS = /* @__PURE__ */ new Set([
1523
1536
  "agent_capabilities",
1524
1537
  "messages.Agent.content.ToolUse.input",
1525
1538
  "acpx.desired_config_options",
@@ -1724,7 +1737,7 @@ async function writeSessionRecord(record) {
1724
1737
  const entries = index.entries.filter((entry) => entry.file !== fileName);
1725
1738
  entries.push(toSessionIndexEntry(record, fileName));
1726
1739
  await writeSessionIndex(sessionDir, {
1727
- files: [...new Set([...index.files.filter((entry) => entry !== fileName), fileName])],
1740
+ files: [.../* @__PURE__ */ new Set([...index.files.filter((entry) => entry !== fileName), fileName])],
1728
1741
  entries
1729
1742
  });
1730
1743
  });
@@ -2338,11 +2351,42 @@ function findExistingCommandInDirectory(directory, candidates) {
2338
2351
  if (trimmedDirectory.length === 0) return;
2339
2352
  return candidates.map((candidate) => path.join(trimmedDirectory, candidate)).find((resolved) => fs.existsSync(resolved));
2340
2353
  }
2354
+ function resolveWindowsWrapperToken(token, wrapperPath) {
2355
+ const relative = token.match(/%~?dp0%?\s*[\\/]*(.*)$/i)?.[1]?.trim();
2356
+ if (!relative) return;
2357
+ const candidate = path.resolve(path.dirname(wrapperPath), relative.replace(/[\\/]+/g, path.sep).replace(/^[\\/]+/, ""));
2358
+ return path.extname(candidate).toLowerCase() === ".exe" && fs.existsSync(candidate) ? candidate : void 0;
2359
+ }
2360
+ function resolveWindowsWrapperExecutable(wrapperPath) {
2361
+ if (!fs.existsSync(wrapperPath)) return;
2362
+ try {
2363
+ return [...fs.readFileSync(wrapperPath, "utf8").matchAll(/"([^"\r\n]*)"/g)].map((match) => resolveWindowsWrapperToken(match[1] ?? "", wrapperPath)).find((candidate) => candidate !== void 0);
2364
+ } catch {
2365
+ return;
2366
+ }
2367
+ }
2341
2368
  function resolveWindowsCommand(command, env = process.env) {
2342
2369
  const candidates = commandCandidates(command, env);
2343
2370
  if (commandHasPath(command)) return candidates.find((candidate) => fs.existsSync(candidate));
2344
2371
  return resolveWindowsPathCommand(command, env);
2345
2372
  }
2373
+ /**
2374
+ * Resolve a Windows command to a native executable suitable for direct spawn.
2375
+ *
2376
+ * Batch and PowerShell shims are intentionally rejected unless they point at a
2377
+ * real `.exe` entrypoint. Callers that need shell execution should use the
2378
+ * command-specific shell policy instead.
2379
+ */
2380
+ function resolveWindowsExecutablePath(command, env = process.env) {
2381
+ const resolved = resolveWindowsCommand(command, env);
2382
+ if (!resolved) return;
2383
+ const absolute = path.resolve(resolved);
2384
+ const extension = path.extname(absolute).toLowerCase();
2385
+ if (extension === ".exe") return absolute;
2386
+ if (extension !== ".cmd" && extension !== ".bat" && extension !== ".ps1") return;
2387
+ const siblingExecutable = `${absolute.slice(0, -extension.length)}.exe`;
2388
+ return fs.existsSync(siblingExecutable) ? siblingExecutable : resolveWindowsWrapperExecutable(absolute);
2389
+ }
2346
2390
  function shouldUseWindowsBatchShell(command, platform = process.platform, env = process.env) {
2347
2391
  if (platform !== "win32") return false;
2348
2392
  const resolvedCommand = resolveWindowsCommand(command, env) ?? command;
@@ -2477,22 +2521,29 @@ function splitCommandLine(value) {
2477
2521
  let current = "";
2478
2522
  let quote = null;
2479
2523
  let escaping = false;
2524
+ let hasPart = false;
2480
2525
  for (const ch of value) {
2481
2526
  const next = readCommandLineChar({
2482
2527
  ch,
2483
2528
  current,
2484
2529
  quote,
2485
2530
  escaping,
2486
- parts
2531
+ parts,
2532
+ hasPart
2487
2533
  });
2488
2534
  current = next.current;
2489
2535
  quote = next.quote;
2490
2536
  escaping = next.escaping;
2537
+ hasPart = next.hasPart;
2538
+ }
2539
+ if (escaping) {
2540
+ current += "\\";
2541
+ hasPart = true;
2491
2542
  }
2492
- if (escaping) current += "\\";
2493
2543
  if (quote) throw new Error("Invalid --agent command: unterminated quote");
2494
- if (current.length > 0) parts.push(current);
2544
+ if (hasPart) parts.push(current);
2495
2545
  if (parts.length === 0) throw new Error("Invalid --agent command: empty command");
2546
+ if (parts[0] === "") throw new Error("Invalid --agent command: empty command");
2496
2547
  return {
2497
2548
  command: parts[0],
2498
2549
  args: parts.slice(1)
@@ -2502,17 +2553,20 @@ function readCommandLineChar(state) {
2502
2553
  if (state.escaping) return {
2503
2554
  current: state.current + state.ch,
2504
2555
  quote: state.quote,
2505
- escaping: false
2556
+ escaping: false,
2557
+ hasPart: true
2506
2558
  };
2507
2559
  if (state.ch === "\\" && state.quote !== "'") return {
2508
2560
  current: state.current,
2509
2561
  quote: state.quote,
2510
- escaping: true
2562
+ escaping: true,
2563
+ hasPart: state.hasPart
2511
2564
  };
2512
2565
  if (state.quote) return readQuotedCommandLineChar({
2513
2566
  ch: state.ch,
2514
2567
  current: state.current,
2515
- quote: state.quote
2568
+ quote: state.quote,
2569
+ hasPart: state.hasPart
2516
2570
  });
2517
2571
  return readUnquotedCommandLineChar(state);
2518
2572
  }
@@ -2520,36 +2574,41 @@ function readQuotedCommandLineChar(state) {
2520
2574
  if (state.ch === state.quote) return {
2521
2575
  current: state.current,
2522
2576
  quote: null,
2523
- escaping: false
2577
+ escaping: false,
2578
+ hasPart: true
2524
2579
  };
2525
2580
  return {
2526
2581
  current: state.current + state.ch,
2527
2582
  quote: state.quote,
2528
- escaping: false
2583
+ escaping: false,
2584
+ hasPart: true
2529
2585
  };
2530
2586
  }
2531
2587
  function readUnquotedCommandLineChar(state) {
2532
2588
  if (state.ch === "'" || state.ch === "\"") return {
2533
2589
  current: state.current,
2534
2590
  quote: state.ch,
2535
- escaping: false
2591
+ escaping: false,
2592
+ hasPart: true
2536
2593
  };
2537
2594
  if (/\s/.test(state.ch)) {
2538
- flushCommandLinePart(state.parts, state.current);
2595
+ flushCommandLinePart(state.parts, state.current, state.hasPart);
2539
2596
  return {
2540
2597
  current: "",
2541
2598
  quote: null,
2542
- escaping: false
2599
+ escaping: false,
2600
+ hasPart: false
2543
2601
  };
2544
2602
  }
2545
2603
  return {
2546
2604
  current: state.current + state.ch,
2547
2605
  quote: null,
2548
- escaping: false
2606
+ escaping: false,
2607
+ hasPart: true
2549
2608
  };
2550
2609
  }
2551
- function flushCommandLinePart(parts, current) {
2552
- if (current.length > 0) parts.push(current);
2610
+ function flushCommandLinePart(parts, current, hasPart) {
2611
+ if (hasPart) parts.push(current);
2553
2612
  }
2554
2613
  function asAbsoluteCwd(cwd) {
2555
2614
  return path.resolve(cwd);
@@ -2600,7 +2659,7 @@ const GEMINI_ACP_FLAG_VERSION = [
2600
2659
  ];
2601
2660
  const COPILOT_HELP_TIMEOUT_MS = 2e3;
2602
2661
  const CLAUDE_CODE_DEFAULT_SETTING_SOURCES = ["project", "local"];
2603
- const QODER_BENIGN_STDOUT_LINES = new Set(["Received interrupt signal. Cleaning up resources...", "Cleanup completed. Exiting..."]);
2662
+ const QODER_BENIGN_STDOUT_LINES = /* @__PURE__ */ new Set(["Received interrupt signal. Cleaning up resources...", "Cleanup completed. Exiting..."]);
2604
2663
  function resolveAgentCloseAfterStdinEndMs(agentCommand) {
2605
2664
  const { command } = splitCommandLine(agentCommand);
2606
2665
  return basenameToken(command) === "qodercli" ? QODER_AGENT_CLOSE_AFTER_STDIN_END_MS : DEFAULT_AGENT_CLOSE_AFTER_STDIN_END_MS;
@@ -2622,6 +2681,10 @@ function isCopilotAcpCommand(command, args) {
2622
2681
  function isQoderAcpCommand(command, args) {
2623
2682
  return basenameToken(command) === "qodercli" && args.includes("--acp");
2624
2683
  }
2684
+ function isCursorAcpCommand(command, args) {
2685
+ const commandToken = basenameToken(command);
2686
+ return commandToken === "cursor-agent" || commandToken === "agent" && args.includes("acp");
2687
+ }
2625
2688
  function isDevinAcpCommand(command, args) {
2626
2689
  return basenameToken(command) === "devin" && (args.includes("acp") || args.includes("--acp") || args.includes("--experimental-acp"));
2627
2690
  }
@@ -2797,9 +2860,7 @@ function isAppendSystemPrompt(value) {
2797
2860
  function resolveClaudeCodeExecutable(platform = process.platform, env = process.env) {
2798
2861
  if (platform !== "win32") return;
2799
2862
  if (readWindowsEnvValue(env, "CLAUDE_CODE_EXECUTABLE")) return;
2800
- const resolved = resolveWindowsCommand("claude", env);
2801
- if (!resolved) return;
2802
- return path.resolve(resolved);
2863
+ return resolveWindowsExecutablePath("claude", env);
2803
2864
  }
2804
2865
  //#endregion
2805
2866
  //#region src/acp/auth-env.ts
@@ -2825,22 +2886,58 @@ function readEnvCredential(methodId) {
2825
2886
  const value = process.env[key];
2826
2887
  if (typeof value === "string" && value.trim().length > 0) return value;
2827
2888
  }
2889
+ function protectedEnvKey(key) {
2890
+ return process.platform === "win32" ? key.toUpperCase() : key;
2891
+ }
2892
+ function isAuthEnvKey(key) {
2893
+ return protectedEnvKey(key).startsWith(AUTH_ENV_PREFIX);
2894
+ }
2895
+ function authEnvSuffix(key) {
2896
+ return key.slice(10);
2897
+ }
2898
+ function protectEnvKey(protectedKeys, key) {
2899
+ protectedKeys.add(protectedEnvKey(key));
2900
+ }
2828
2901
  function promotePrefixedAuthEnvironment(env) {
2902
+ const protectedKeys = /* @__PURE__ */ new Set();
2829
2903
  for (const [key, value] of Object.entries(env)) {
2830
- if (!key.startsWith(AUTH_ENV_PREFIX)) continue;
2904
+ if (!isAuthEnvKey(key)) continue;
2831
2905
  if (typeof value !== "string" || value.trim().length === 0) continue;
2832
- const normalized = key.slice(10);
2833
- if (!normalized || env[normalized] != null) continue;
2834
- env[normalized] = value;
2906
+ const normalized = toEnvToken(authEnvSuffix(key));
2907
+ if (!normalized) continue;
2908
+ protectEnvKey(protectedKeys, key);
2909
+ protectEnvKey(protectedKeys, normalized);
2910
+ if (env[normalized] == null) env[normalized] = value;
2835
2911
  }
2912
+ return protectedKeys;
2836
2913
  }
2837
- function buildAgentEnvironment(authCredentials) {
2914
+ function buildAgentEnvironment(authCredentials, sessionEnv) {
2838
2915
  const env = { ...process.env };
2839
- promotePrefixedAuthEnvironment(env);
2840
- if (!authCredentials) return env;
2841
- for (const [methodId, credential] of Object.entries(authCredentials)) assignAuthCredentialEnv(env, methodId, credential);
2916
+ const protectedAuthEnvKeys = promotePrefixedAuthEnvironment(env);
2917
+ if (authCredentials) for (const [methodId, credential] of Object.entries(authCredentials)) {
2918
+ addAuthCredentialEnvKeys(protectedAuthEnvKeys, methodId, credential);
2919
+ assignAuthCredentialEnv(env, methodId, credential);
2920
+ }
2921
+ if (sessionEnv) for (const [key, value] of Object.entries(sessionEnv)) {
2922
+ if (typeof value !== "string" || protectedAuthEnvKeys.has(protectedEnvKey(key))) continue;
2923
+ assignSessionEnv(env, key, value);
2924
+ }
2842
2925
  return env;
2843
2926
  }
2927
+ function assignSessionEnv(env, key, value) {
2928
+ const normalizedKey = protectedEnvKey(key);
2929
+ for (const existingKey of Object.keys(env)) if (protectedEnvKey(existingKey) === normalizedKey) delete env[existingKey];
2930
+ env[key] = value;
2931
+ }
2932
+ function addAuthCredentialEnvKeys(protectedKeys, methodId, credential) {
2933
+ if (typeof credential !== "string" || credential.trim().length === 0) return;
2934
+ if (!methodId.includes("=") && !methodId.includes("\0")) protectEnvKey(protectedKeys, methodId);
2935
+ const normalized = toEnvToken(methodId);
2936
+ if (normalized) {
2937
+ protectEnvKey(protectedKeys, `${AUTH_ENV_PREFIX}${normalized}`);
2938
+ protectEnvKey(protectedKeys, normalized);
2939
+ }
2940
+ }
2844
2941
  function assignAuthCredentialEnv(env, methodId, credential) {
2845
2942
  if (typeof credential !== "string" || credential.trim().length === 0) return;
2846
2943
  if (!methodId.includes("=") && !methodId.includes("\0") && env[methodId] == null) env[methodId] = credential;
@@ -2857,10 +2954,10 @@ function resolveConfiguredAuthCredential(methodId, authCredentials) {
2857
2954
  const configCredentials = authCredentials ?? {};
2858
2955
  return configCredentials[methodId] ?? configCredentials[toEnvToken(methodId)];
2859
2956
  }
2860
- function buildAgentSpawnOptions(cwd, authCredentials) {
2957
+ function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv) {
2861
2958
  return {
2862
2959
  cwd,
2863
- env: buildAgentEnvironment(authCredentials),
2960
+ env: buildAgentEnvironment(authCredentials, sessionEnv),
2864
2961
  stdio: [
2865
2962
  "pipe",
2866
2963
  "pipe",
@@ -2871,12 +2968,26 @@ function buildAgentSpawnOptions(cwd, authCredentials) {
2871
2968
  }
2872
2969
  //#endregion
2873
2970
  //#region src/acp/model-support.ts
2971
+ const REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE = "ACP_MODEL_UNSUPPORTED";
2972
+ const REQUESTED_MODEL_UNSUPPORTED_REASONS = ["missing-capability", "unadvertised-model"];
2874
2973
  var RequestedModelUnsupportedError = class extends Error {
2875
- constructor(message) {
2974
+ code = REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE;
2975
+ reason;
2976
+ constructor(message, reason) {
2876
2977
  super(message);
2877
2978
  this.name = "RequestedModelUnsupportedError";
2979
+ this.reason = reason;
2878
2980
  }
2879
2981
  };
2982
+ function isRequestedModelUnsupportedReason(value) {
2983
+ return typeof value === "string" && REQUESTED_MODEL_UNSUPPORTED_REASONS.includes(value);
2984
+ }
2985
+ function isRequestedModelUnsupportedError(value) {
2986
+ if (value instanceof RequestedModelUnsupportedError) return true;
2987
+ if (!value || typeof value !== "object") return false;
2988
+ const candidate = value;
2989
+ return candidate.name === "RequestedModelUnsupportedError" && candidate.code === "ACP_MODEL_UNSUPPORTED" && isRequestedModelUnsupportedReason(candidate.reason);
2990
+ }
2880
2991
  function supportsLegacyClaudeCodeModelMetadata(agentCommand) {
2881
2992
  if (!agentCommand) return false;
2882
2993
  const { command, args } = splitCommandLine(agentCommand);
@@ -2951,19 +3062,32 @@ function formatAvailableModelIds(models) {
2951
3062
  const ids = models?.availableModels.map((model) => model.modelId.trim()).filter((modelId) => modelId.length > 0) ?? [];
2952
3063
  return ids.length > 0 ? ids.join(", ") : "none advertised";
2953
3064
  }
3065
+ function resolveRequestedModelId(params) {
3066
+ if (!params.models || !isCursorAcpCommandForModelAlias(params.agentCommand)) return params.requestedModel;
3067
+ if (params.models.availableModels.some((model) => model.modelId === params.requestedModel)) return params.requestedModel;
3068
+ const candidates = params.models.availableModels.map((model) => model.modelId).filter((modelId) => modelId.startsWith(`${params.requestedModel}[`));
3069
+ return candidates.length === 1 ? candidates[0] : params.requestedModel;
3070
+ }
3071
+ function isCursorAcpCommandForModelAlias(agentCommand) {
3072
+ if (!agentCommand) return false;
3073
+ const { command, args } = splitCommandLine(agentCommand);
3074
+ return isCursorAcpCommand(command, args);
3075
+ }
2954
3076
  function assertRequestedModelSupported(params) {
2955
3077
  if (!params.models) {
2956
3078
  if (supportsLegacyClaudeCodeModelMetadata(params.agentCommand)) return;
2957
- throw new RequestedModelUnsupportedError(`Cannot ${params.context === "replay" ? "replay saved model" : "apply --model"} "${params.requestedModel}": the ACP agent did not advertise model support through a session config option or legacy models metadata, and the adapter does not support a startup model flag.`);
3079
+ throw new RequestedModelUnsupportedError(`Cannot ${params.context === "replay" ? "replay saved model" : "apply --model"} "${params.requestedModel}": the ACP agent did not advertise model support through a session config option or legacy models metadata, and the adapter does not support a startup model flag.`, "missing-capability");
2958
3080
  }
2959
3081
  if (!new Set(params.models.availableModels.map((model) => model.modelId)).has(params.requestedModel)) {
3082
+ const resolvedModel = resolveRequestedModelId(params);
3083
+ if (resolvedModel !== params.requestedModel) return `Cursor ACP advertised "${resolvedModel}" for requested model "${params.requestedModel}"; using the advertised id.`;
2960
3084
  if (supportsLegacyClaudeCodeModelMetadata(params.agentCommand)) return `requested model "${params.requestedModel}" was not in the Claude ACP advertised model list (${formatAvailableModelIds(params.models)}); forwarding it to Claude Code so the adapter can accept or reject it.`;
2961
- 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)}.`);
3085
+ 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)}.`, "unadvertised-model");
2962
3086
  }
2963
3087
  }
2964
3088
  //#endregion
2965
3089
  //#region src/acp/session-control-errors.ts
2966
- const SESSION_CONTROL_UNSUPPORTED_ACP_CODES = new Set([-32601, -32602]);
3090
+ const SESSION_CONTROL_UNSUPPORTED_ACP_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
2967
3091
  function asRecord$1(value) {
2968
3092
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
2969
3093
  return value;
@@ -3653,12 +3777,16 @@ function enqueueNdJsonLine(agentCommand, line, controller) {
3653
3777
  const trimmedLine = line.trim();
3654
3778
  if (!trimmedLine || shouldIgnoreNonJsonAgentOutputLine(agentCommand, trimmedLine)) return;
3655
3779
  try {
3656
- const message = JSON.parse(trimmedLine);
3657
- controller.enqueue(message);
3780
+ const message = parseAcpJsonMessageLine(trimmedLine);
3781
+ if (message) controller.enqueue(message);
3658
3782
  } catch (err) {
3659
3783
  console.error("Failed to parse JSON message:", trimmedLine, err);
3660
3784
  }
3661
3785
  }
3786
+ function parseAcpJsonMessageLine(line) {
3787
+ const message = JSON.parse(line);
3788
+ return isAcpMessageObject(message) ? message : void 0;
3789
+ }
3662
3790
  function enqueueNdJsonLines(agentCommand, lines, controller) {
3663
3791
  for (const line of lines) enqueueNdJsonLine(agentCommand, line, controller);
3664
3792
  }
@@ -3865,7 +3993,7 @@ var AcpClient = class {
3865
3993
  geminiAcp: isGeminiAcpCommand(spawnCommand, args),
3866
3994
  copilotAcp: isCopilotAcpCommand(spawnCommand, args),
3867
3995
  claudeAcp: isClaudeAcpCommand(spawnCommand, args),
3868
- spawnOptions: buildAgentSpawnOptions(this.options.cwd, this.options.authCredentials)
3996
+ spawnOptions: buildAgentSpawnOptions(this.options.cwd, this.options.authCredentials, this.options.sessionOptions?.env)
3869
3997
  };
3870
3998
  }
3871
3999
  logAgentLaunch(plan) {
@@ -3908,7 +4036,9 @@ var AcpClient = class {
3908
4036
  },
3909
4037
  extMethod: async (method) => {
3910
4038
  if (launch.devinAcp && isDevinRequestDiagnosticsMethod(method)) return {};
3911
- throw RequestError.methodNotFound(method);
4039
+ const error = RequestError.methodNotFound(method);
4040
+ if (!this.options.suppressSdkConsoleErrors) console.error(error.message);
4041
+ throw error;
3912
4042
  },
3913
4043
  readTextFile: async (params) => {
3914
4044
  return this.handleReadTextFile(params);
@@ -4164,8 +4294,13 @@ var AcpClient = class {
4164
4294
  }
4165
4295
  async setSessionModel(sessionId, modelId, controlOverride) {
4166
4296
  const control = this.resolveModelControl(sessionId, controlOverride);
4167
- if (!control) throw new RequestedModelUnsupportedError(`Cannot set model "${modelId}": the ACP session did not advertise a model config option or legacy session/set_model support.`);
4168
- return control.kind === "config_option" ? await this.setSessionModelThroughConfig(sessionId, modelId, control.configId) : await this.setSessionModelThroughLegacyMethod(sessionId, modelId);
4297
+ if (!control) throw new RequestedModelUnsupportedError(`Cannot set model "${modelId}": the ACP session did not advertise a model config option or legacy session/set_model support.`, "missing-capability");
4298
+ const resolvedModelId = resolveRequestedModelId({
4299
+ requestedModel: modelId,
4300
+ models: controlOverride?.availableModels ? { availableModels: controlOverride.availableModels } : void 0,
4301
+ agentCommand: this.options.agentCommand
4302
+ });
4303
+ return control.kind === "config_option" ? await this.setSessionModelThroughConfig(sessionId, resolvedModelId, control.configId) : await this.setSessionModelThroughLegacyMethod(sessionId, resolvedModelId);
4169
4304
  }
4170
4305
  async setSessionModelThroughConfig(sessionId, modelId, configId) {
4171
4306
  const connection = this.getConnection();
@@ -4715,8 +4850,16 @@ function mergeSessionOptions(preferred, fallback) {
4715
4850
  assignDefinedOption(merged, "allowedTools", preferred?.allowedTools);
4716
4851
  assignDefinedOption(merged, "maxTurns", preferred?.maxTurns);
4717
4852
  assignDefinedOption(merged, "systemPrompt", preferred?.systemPrompt);
4853
+ assignDefinedOption(merged, "env", mergeEnvRecords(fallback?.env, preferred?.env));
4718
4854
  return Object.keys(merged).length > 0 ? merged : void 0;
4719
4855
  }
4856
+ function mergeEnvRecords(fallback, preferred) {
4857
+ if (!fallback && !preferred) return;
4858
+ return {
4859
+ ...fallback,
4860
+ ...preferred
4861
+ };
4862
+ }
4720
4863
  function assignDefinedOption(target, key, value) {
4721
4864
  if (value !== void 0) target[key] = value;
4722
4865
  }
@@ -4740,6 +4883,7 @@ function sessionOptionsFromRecord(record) {
4740
4883
  assignStoredOption(sessionOptions, "allowedTools", storedAllowedTools(stored.allowed_tools));
4741
4884
  assignStoredOption(sessionOptions, "maxTurns", storedMaxTurns(stored.max_turns));
4742
4885
  assignStoredOption(sessionOptions, "systemPrompt", storedSystemPromptOption(stored.system_prompt));
4886
+ assignStoredOption(sessionOptions, "env", storedEnvRecord(stored.env));
4743
4887
  return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
4744
4888
  }
4745
4889
  function persistedSessionOptions(options) {
@@ -4747,12 +4891,23 @@ function persistedSessionOptions(options) {
4747
4891
  model: nonEmptyString(options.model),
4748
4892
  allowed_tools: Array.isArray(options.allowedTools) ? [...options.allowedTools] : void 0,
4749
4893
  max_turns: typeof options.maxTurns === "number" ? options.maxTurns : void 0,
4750
- system_prompt: normalizeSystemPromptOption(options.systemPrompt)
4894
+ system_prompt: normalizeSystemPromptOption(options.systemPrompt),
4895
+ env: storedEnvRecord(options.env)
4751
4896
  };
4752
4897
  return hasPersistedSessionOptions(next) ? next : void 0;
4753
4898
  }
4754
4899
  function hasPersistedSessionOptions(options) {
4755
- return options.model !== void 0 || options.allowed_tools !== void 0 || options.max_turns !== void 0 || options.system_prompt !== void 0;
4900
+ return options.model !== void 0 || options.allowed_tools !== void 0 || options.max_turns !== void 0 || options.system_prompt !== void 0 || options.env !== void 0;
4901
+ }
4902
+ function storedEnvRecord(value) {
4903
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return;
4904
+ const entries = Object.entries(value);
4905
+ const result = {};
4906
+ for (const [key, raw] of entries) {
4907
+ if (typeof raw !== "string") continue;
4908
+ result[key] = raw;
4909
+ }
4910
+ return Object.keys(result).length > 0 ? result : void 0;
4756
4911
  }
4757
4912
  function normalizeSystemPromptOption(value) {
4758
4913
  const prompt = nonEmptyString(value);
@@ -5074,30 +5229,35 @@ function numberField(source, keys) {
5074
5229
  if (typeof value === "number" && Number.isFinite(value) && value >= 0) return value;
5075
5230
  }
5076
5231
  }
5077
- function usageToTokenUsage(update) {
5078
- const updateRecord = asRecord(update);
5079
- const usageMeta = asRecord(updateRecord?._meta)?.usage;
5080
- const source = asRecord(usageMeta) ?? updateRecord;
5081
- if (!source) return;
5232
+ function sourceToTokenUsage(source) {
5233
+ const usageRecord = asRecord(source);
5234
+ if (!usageRecord) return;
5082
5235
  const normalized = {
5083
- input_tokens: numberField(source, ["input_tokens", "inputTokens"]),
5084
- output_tokens: numberField(source, ["output_tokens", "outputTokens"]),
5085
- cache_creation_input_tokens: numberField(source, [
5236
+ input_tokens: numberField(usageRecord, ["input_tokens", "inputTokens"]),
5237
+ output_tokens: numberField(usageRecord, ["output_tokens", "outputTokens"]),
5238
+ cache_creation_input_tokens: numberField(usageRecord, [
5086
5239
  "cache_creation_input_tokens",
5087
5240
  "cacheCreationInputTokens",
5088
5241
  "cachedWriteTokens"
5089
5242
  ]),
5090
- cache_read_input_tokens: numberField(source, [
5243
+ cache_read_input_tokens: numberField(usageRecord, [
5091
5244
  "cache_read_input_tokens",
5092
5245
  "cacheReadInputTokens",
5093
5246
  "cachedReadTokens"
5094
5247
  ]),
5095
- thought_tokens: numberField(source, ["thought_tokens", "thoughtTokens"]),
5096
- total_tokens: numberField(source, ["total_tokens", "totalTokens"])
5248
+ thought_tokens: numberField(usageRecord, ["thought_tokens", "thoughtTokens"]),
5249
+ total_tokens: numberField(usageRecord, ["total_tokens", "totalTokens"])
5097
5250
  };
5098
5251
  if (!hasTokenUsageValue(normalized)) return;
5099
5252
  return normalized;
5100
5253
  }
5254
+ function usageToTokenUsage(update) {
5255
+ const updateRecord = asRecord(update);
5256
+ const usageMeta = asRecord(updateRecord?._meta)?.usage;
5257
+ const source = asRecord(usageMeta) ?? updateRecord;
5258
+ if (!source) return;
5259
+ return sourceToTokenUsage(source);
5260
+ }
5101
5261
  function hasTokenUsageValue(usage) {
5102
5262
  return Object.values(usage).some((value) => value !== void 0);
5103
5263
  }
@@ -5169,7 +5329,8 @@ function cloneSessionOptions(options) {
5169
5329
  model: options.model,
5170
5330
  allowed_tools: options.allowed_tools ? [...options.allowed_tools] : void 0,
5171
5331
  max_turns: options.max_turns,
5172
- ...options.system_prompt !== void 0 ? { system_prompt: cloneSystemPromptOption(options.system_prompt) } : {}
5332
+ ...options.system_prompt !== void 0 ? { system_prompt: cloneSystemPromptOption(options.system_prompt) } : {},
5333
+ ...options.env !== void 0 ? { env: { ...options.env } } : {}
5173
5334
  };
5174
5335
  }
5175
5336
  function cloneSystemPromptOption(option) {
@@ -5212,6 +5373,14 @@ function recordSessionUpdate(conversation, state, notification, timestamp = isoN
5212
5373
  trimConversationForRuntime(conversation);
5213
5374
  return acpx;
5214
5375
  }
5376
+ function recordPromptResponseUsage(conversation, usage, promptMessageId, timestamp = isoNow()) {
5377
+ const tokenUsage = sourceToTokenUsage(usage);
5378
+ if (!tokenUsage) return false;
5379
+ applyTokenUsage(conversation, tokenUsage, promptMessageId);
5380
+ updateConversationTimestamp(conversation, timestamp);
5381
+ trimConversationForRuntime(conversation);
5382
+ return true;
5383
+ }
5215
5384
  function applySessionUpdate(conversation, acpx, update) {
5216
5385
  const handler = SESSION_UPDATE_HANDLERS[update.sessionUpdate];
5217
5386
  handler?.(conversation, acpx, update);
@@ -5264,13 +5433,14 @@ function applyUsageUpdate(conversation, update) {
5264
5433
  const usage = usageToTokenUsage(update);
5265
5434
  const cost = usageCost(update);
5266
5435
  if (!usage && !cost) return;
5267
- if (usage) {
5268
- conversation.cumulative_token_usage = usage;
5269
- const userId = lastUserMessageId(conversation);
5270
- if (userId) conversation.request_token_usage[userId] = usage;
5271
- }
5436
+ if (usage) applyTokenUsage(conversation, usage);
5272
5437
  if (cost) conversation.cumulative_cost = cost;
5273
5438
  }
5439
+ function applyTokenUsage(conversation, usage, promptMessageId) {
5440
+ conversation.cumulative_token_usage = usage;
5441
+ const userId = promptMessageId ?? lastUserMessageId(conversation);
5442
+ if (userId) conversation.request_token_usage[userId] = usage;
5443
+ }
5274
5444
  function applySessionInfoUpdate(conversation, update) {
5275
5445
  if (hasOwn(update, "title")) conversation.title = update.title ?? null;
5276
5446
  if (hasOwn(update, "updatedAt")) conversation.updated_at = update.updatedAt ?? conversation.updated_at;
@@ -5380,13 +5550,16 @@ function clearDesiredConfigOption(state, configId) {
5380
5550
  function getDesiredModelId(state) {
5381
5551
  return normalizeModelId(state?.session_options?.model);
5382
5552
  }
5553
+ function hasStoredSessionOptions(options) {
5554
+ return typeof options.model === "string" || Array.isArray(options.allowed_tools) || typeof options.max_turns === "number" || options.system_prompt !== void 0 || options.env !== void 0;
5555
+ }
5383
5556
  function setDesiredModelId(record, modelId, modelConfigId) {
5384
5557
  const acpx = ensureAcpxState(record.acpx);
5385
5558
  const normalized = normalizeModelId(modelId);
5386
5559
  const sessionOptions = { ...acpx.session_options };
5387
5560
  if (normalized) sessionOptions.model = normalized;
5388
5561
  else delete sessionOptions.model;
5389
- if (typeof sessionOptions.model === "string" || Array.isArray(sessionOptions.allowed_tools) || typeof sessionOptions.max_turns === "number" || sessionOptions.system_prompt !== void 0) acpx.session_options = sessionOptions;
5562
+ if (hasStoredSessionOptions(sessionOptions)) acpx.session_options = sessionOptions;
5390
5563
  else delete acpx.session_options;
5391
5564
  clearDesiredConfigOption(acpx, modelConfigId ?? modelStateFromConfigOptions(acpx.config_options)?.configId);
5392
5565
  record.acpx = acpx;
@@ -5437,7 +5610,7 @@ function isProcessAlive(pid) {
5437
5610
  return false;
5438
5611
  }
5439
5612
  }
5440
- const SESSION_LOAD_UNSUPPORTED_CODES = new Set([-32601, -32602]);
5613
+ const SESSION_LOAD_UNSUPPORTED_CODES = /* @__PURE__ */ new Set([-32601, -32602]);
5441
5614
  function shouldFallbackToNewSession(error, record) {
5442
5615
  if (isHardReconnectFailure(error)) return false;
5443
5616
  const acp = extractAcpError(error);
@@ -5879,6 +6052,7 @@ async function runPromptTurn(params) {
5879
6052
  idleMs: SESSION_REPLY_IDLE_MS,
5880
6053
  timeoutMs: SESSION_REPLY_DRAIN_TIMEOUT_MS
5881
6054
  }).catch(() => {});
6055
+ recordPromptResponseUsage(params.conversation, response.usage, params.promptMessageId);
5882
6056
  return {
5883
6057
  stopReason: response.stopReason,
5884
6058
  source: "rpc"
@@ -5950,6 +6124,6 @@ var LiveSessionCheckpoint = class {
5950
6124
  }
5951
6125
  };
5952
6126
  //#endregion
5953
- export { setPerfGauge as $, assertRequestedModelSupported as A, isRetryablePromptError as At, listSessions as B, OUTPUT_FORMATS as Bt, mergeSessionOptions as C, withTimeout as Ct, applyLifecycleSnapshotToRecord as D, resolveAgentCommand as Dt, applyConversation as E, normalizeAgentName$1 as Et, absolutePath as F, AUTH_POLICIES as Ft, writeSessionRecord as G, AgentSpawnError as Gt, normalizeName as H, PERMISSION_POLICY_ACTIONS as Ht, findGitRepositoryRoot as I, EXIT_CODES as It, getPerfMetricsSnapshot as J, assertPersistedKeyPolicy as K, QueueConnectionError as Kt, findSession as L, NON_INTERACTIVE_PERMISSION_POLICIES as Lt, getAcpxVersion as M, extractAcpError as Mt, permissionModeSatisfies as N, isAcpResourceNotFoundError as Nt, reconcileAgentSessionId as O, exitCodeForOutputErrorCode as Ot, DEFAULT_HISTORY_LIMIT as P, toAcpErrorPayload as Pt, resetPerfMetrics as Q, findSessionByDirectoryWalk as R, OUTPUT_ERROR_CODES as Rt, advertisedModelState as S, withInterrupt as St, sessionOptionsFromRecord as T, listBuiltInAgents as Tt, pruneSessions as U, SESSION_RECORD_SCHEMA as Ut, listSessionsForAgent as V, PERMISSION_MODES as Vt, resolveSessionRecord as W, AcpxOperationalError as Wt, measurePerf as X, incrementPerfCounter as Y, recordPerfDuration as Z, createSessionConversation as _, parsePromptSource as _t, applyRequestedModelIfAdvertised as a, defaultSessionEventLog as at, recordSessionUpdate as b, InterruptedError as bt, setCurrentModelId as c, sessionEventLockPath as ct, setDesiredModelId as d, isAcpJsonRpcMessage as dt, startPerfTimer as et, syncAdvertisedModelState as f, parseJsonRpcErrorMessage as ft, cloneSessionConversation as g, mergePromptSourceWithText as gt, cloneSessionAcpxState as h, isPromptInput as ht, connectAndLoadSession as i, DEFAULT_EVENT_SEGMENT_MAX_BYTES as it, modelStateFromConfigOptions as j, normalizeOutputError as jt, AcpClient as k, formatErrorMessage as kt, setDesiredConfigOption as l, sessionEventSegmentPath as lt, applyConfigOptionsToState as m, PromptInputValidationError as mt, runPromptTurn as n, serializeSessionRecordForDisk as nt, currentModelIdFromSetModelResponse as o, sessionBaseDir$1 as ot, applyConfigOptionsToRecord as p, parsePromptStopReason as pt, formatPerfMetric as q, QueueProtocolError as qt, withConnectedSession as r, normalizeRuntimeSessionId as rt, clearDesiredConfigOption as s, sessionEventActivePath as st, LiveSessionCheckpoint as t, parseSessionRecord as tt, setDesiredModeId as u, extractSessionUpdateNotification as ut, recordClientOperation as v, promptToDisplayText as vt, persistSessionOptions as w, DEFAULT_AGENT_NAME as wt, trimConversationForRuntime as x, TimeoutError as xt, recordPromptSubmission as y, textPrompt as yt, isoNow$2 as z, OUTPUT_ERROR_ORIGINS as zt };
6127
+ export { getPerfMetricsSnapshot as $, REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE as A, listBuiltInAgents as At, absolutePath as B, AUTH_POLICIES as Bt, mergeSessionOptions as C, promptToDisplayText as Ct, applyLifecycleSnapshotToRecord as D, withInterrupt as Dt, applyConversation as E, TimeoutError as Et, modelStateFromConfigOptions as F, isRetryablePromptError as Ft, listSessions as G, OUTPUT_FORMATS as Gt, findSession as H, NON_INTERACTIVE_PERMISSION_POLICIES as Ht, splitCommandLine as I, normalizeOutputError as It, pruneSessions as J, SESSION_RECORD_SCHEMA as Jt, listSessionsForAgent as K, PERMISSION_MODES as Kt, getAcpxVersion as L, extractAcpError as Lt, RequestedModelUnsupportedError as M, resolveAgentCommand as Mt, assertRequestedModelSupported as N, exitCodeForOutputErrorCode as Nt, reconcileAgentSessionId as O, withTimeout as Ot, isRequestedModelUnsupportedError as P, formatErrorMessage as Pt, formatPerfMetric as Q, QueueProtocolError as Qt, permissionModeSatisfies as R, isAcpResourceNotFoundError as Rt, advertisedModelState as S, parsePromptSource as St, sessionOptionsFromRecord as T, InterruptedError as Tt, findSessionByDirectoryWalk as U, OUTPUT_ERROR_CODES as Ut, findGitRepositoryRoot as V, EXIT_CODES as Vt, isoNow$2 as W, OUTPUT_ERROR_ORIGINS as Wt, writeSessionRecord as X, AgentSpawnError as Xt, resolveSessionRecord as Y, AcpxOperationalError as Yt, assertPersistedKeyPolicy as Z, QueueConnectionError as Zt, createSessionConversation as _, parseJsonRpcErrorMessage as _t, applyRequestedModelIfAdvertised as a, startPerfTimer as at, recordSessionUpdate as b, isPromptInput as bt, setCurrentModelId as c, normalizeRuntimeSessionId as ct, setDesiredModelId as d, sessionBaseDir$1 as dt, incrementPerfCounter as et, syncAdvertisedModelState as f, sessionEventActivePath as ft, cloneSessionConversation as g, isAcpJsonRpcMessage as gt, cloneSessionAcpxState as h, extractSessionUpdateNotification as ht, connectAndLoadSession as i, setPerfGauge as it, REQUESTED_MODEL_UNSUPPORTED_REASONS as j, normalizeAgentName$1 as jt, AcpClient as k, DEFAULT_AGENT_NAME as kt, setDesiredConfigOption as l, DEFAULT_EVENT_SEGMENT_MAX_BYTES as lt, applyConfigOptionsToState as m, sessionEventSegmentPath as mt, runPromptTurn as n, recordPerfDuration as nt, currentModelIdFromSetModelResponse as o, parseSessionRecord as ot, applyConfigOptionsToRecord as p, sessionEventLockPath as pt, normalizeName as q, PERMISSION_POLICY_ACTIONS as qt, withConnectedSession as r, resetPerfMetrics as rt, clearDesiredConfigOption as s, serializeSessionRecordForDisk as st, LiveSessionCheckpoint as t, measurePerf as tt, setDesiredModeId as u, defaultSessionEventLog as ut, recordClientOperation as v, parsePromptStopReason as vt, persistSessionOptions as w, textPrompt as wt, trimConversationForRuntime as x, mergePromptSourceWithText as xt, recordPromptSubmission as y, PromptInputValidationError as yt, DEFAULT_HISTORY_LIMIT as z, toAcpErrorPayload as zt };
5954
6128
 
5955
- //# sourceMappingURL=live-checkpoint-BZrk9Mjz.js.map
6129
+ //# sourceMappingURL=live-checkpoint-mdAaF3qJ.js.map