@aiden-ade/sandbox-agent 0.1.40 → 0.1.42

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 (2) hide show
  1. package/dist/index.cjs +351 -217
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -13514,6 +13514,16 @@ function resolveBackendRuntimeCommand(backendKind, env = getDaemonCliEnvironment
13514
13514
  cacheResolvedCli(command, resolved);
13515
13515
  return resolved ?? void 0;
13516
13516
  }
13517
+ function revalidateBackendRuntimeCommand(backendKind, env = getDaemonCliEnvironment()) {
13518
+ if (!backendKind) return void 0;
13519
+ const command = BACKEND_CLI_COMMANDS[backendKind];
13520
+ if (!command) return void 0;
13521
+ resolvedCliCache.delete(command);
13522
+ const spec = Object.values(PROVIDER_CLI_COMMANDS).find((entry) => entry.command === command);
13523
+ const envOverride = spec ? spec.envVars.map((name) => env[name]?.trim()).find(Boolean) : void 0;
13524
+ if (envOverride) resolvedCliCache.delete(envOverride);
13525
+ return resolveBackendRuntimeCommand(backendKind, env);
13526
+ }
13517
13527
 
13518
13528
  // src/computer-readiness.ts
13519
13529
  var import_node_fs5 = require("fs");
@@ -14590,9 +14600,9 @@ function getAlanAgentPrompt(agentId) {
14590
14600
  return getAgentSystemPrompt(agentId);
14591
14601
  }
14592
14602
 
14593
- // ../shared/dist/types/frontend.js
14603
+ // ../shared/dist/effort.js
14594
14604
  var EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
14595
- var CLAUDE_48_EFFORT_LEVELS = [
14605
+ var CLAUDE_EFFORT_LEVELS = [
14596
14606
  "minimal",
14597
14607
  "low",
14598
14608
  "medium",
@@ -14600,20 +14610,144 @@ var CLAUDE_48_EFFORT_LEVELS = [
14600
14610
  "xhigh",
14601
14611
  "max"
14602
14612
  ];
14603
- var CLAUDE_5_EFFORT_LEVELS = [
14613
+ var CODEX_5X_EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
14614
+ var GPT_5_5_EFFORT_LEVELS = [
14604
14615
  "minimal",
14616
+ "low",
14617
+ "medium",
14618
+ "high",
14619
+ "xhigh"
14620
+ ];
14621
+ var GPT_5_4_EFFORT_LEVELS = ["low", "medium", "high"];
14622
+ var GPT_5_6_EFFORT_LEVELS = [
14605
14623
  "low",
14606
14624
  "medium",
14607
14625
  "high",
14608
14626
  "xhigh",
14609
14627
  "max"
14610
14628
  ];
14611
- var CODEX_5X_EFFORT_LEVELS = [
14629
+ var GPT_5_6_ULTRA_EFFORT_LEVELS = [
14612
14630
  "low",
14613
14631
  "medium",
14614
14632
  "high",
14615
- "xhigh"
14633
+ "xhigh",
14634
+ "max",
14635
+ "ultra"
14636
+ ];
14637
+ var ATOMIC_MODEL_IDS = /* @__PURE__ */ new Set([
14638
+ "gpt-5.1-codex-max",
14639
+ "opencode/gpt-5.1-codex-max"
14640
+ ]);
14641
+ var EFFORT_SUFFIXES = [
14642
+ { suffix: "-extra-high", level: "xhigh" },
14643
+ { suffix: "-xhigh", level: "xhigh" },
14644
+ { suffix: "-ultra", level: "ultra" },
14645
+ { suffix: "-max", level: "max" },
14646
+ { suffix: "-high", level: "high" },
14647
+ { suffix: "-medium", level: "medium" },
14648
+ { suffix: "-low", level: "low" },
14649
+ { suffix: "-none", level: "minimal" },
14650
+ { suffix: "-minimal", level: "minimal" }
14616
14651
  ];
14652
+ function isAtomicModelId(modelId) {
14653
+ return ATOMIC_MODEL_IDS.has(modelId.trim());
14654
+ }
14655
+ function isEffortLevel(value2) {
14656
+ return EFFORT_LEVELS.includes(value2);
14657
+ }
14658
+ var EFFORT_RANK = {
14659
+ minimal: 0,
14660
+ low: 1,
14661
+ medium: 2,
14662
+ high: 3,
14663
+ xhigh: 4,
14664
+ max: 5,
14665
+ ultra: 6
14666
+ };
14667
+ function clampEffortToSupported(requested, allowed) {
14668
+ if (!requested?.trim() || allowed.length === 0)
14669
+ return null;
14670
+ const normalized = requested.trim().toLowerCase();
14671
+ if (!isEffortLevel(normalized))
14672
+ return null;
14673
+ if (allowed.includes(normalized))
14674
+ return normalized;
14675
+ const targetRank = EFFORT_RANK[normalized];
14676
+ let best = null;
14677
+ for (const level of allowed) {
14678
+ if (EFFORT_RANK[level] <= targetRank) {
14679
+ if (!best || EFFORT_RANK[level] > EFFORT_RANK[best])
14680
+ best = level;
14681
+ }
14682
+ }
14683
+ return best ?? allowed[0] ?? null;
14684
+ }
14685
+ function inferEffortLevelsForModel(harness, modelId) {
14686
+ const id = collapseModelIdToBase(modelId);
14687
+ if (harness === "claude_cli" || id.startsWith("claude-") || id === "sonnet" || id === "opus") {
14688
+ if (id === "haiku" || id.startsWith("claude-haiku-"))
14689
+ return [];
14690
+ return CLAUDE_EFFORT_LEVELS;
14691
+ }
14692
+ if (id === "gpt-5.5")
14693
+ return GPT_5_5_EFFORT_LEVELS;
14694
+ if (id === "gpt-5.4" || id === "gpt-5.4-mini")
14695
+ return GPT_5_4_EFFORT_LEVELS;
14696
+ if (/^gpt-5\.6-/.test(id)) {
14697
+ const hasUltra = id.includes("-sol") || id.includes("-terra");
14698
+ return hasUltra ? GPT_5_6_ULTRA_EFFORT_LEVELS : GPT_5_6_EFFORT_LEVELS;
14699
+ }
14700
+ if (id.includes("codex") || /^gpt-5\.[0-3]/.test(id))
14701
+ return CODEX_5X_EFFORT_LEVELS;
14702
+ return [];
14703
+ }
14704
+ function resolveWireEffort(input) {
14705
+ const allowed = input.effortLevels && input.effortLevels.length > 0 ? input.effortLevels : inferEffortLevelsForModel(input.harness, input.modelId);
14706
+ const clamped = clampEffortToSupported(input.selectedEffortLevel, allowed);
14707
+ if (!clamped)
14708
+ return null;
14709
+ if (input.harness === "cursor_agent_cli" && clamped === "minimal")
14710
+ return "none";
14711
+ if (input.harness === "claude_cli" && clamped === "minimal")
14712
+ return "low";
14713
+ return clamped;
14714
+ }
14715
+ function parseModelEffortSuffix(modelId) {
14716
+ const trimmed = modelId.trim();
14717
+ if (!trimmed)
14718
+ return { baseId: "", effort: null, fast: false };
14719
+ if (isAtomicModelId(trimmed)) {
14720
+ return { baseId: trimmed, effort: null, fast: false };
14721
+ }
14722
+ let id = trimmed;
14723
+ let fast = false;
14724
+ if (id.endsWith("-fast")) {
14725
+ const withoutFast = id.slice(0, -"-fast".length);
14726
+ if (isAtomicModelId(withoutFast)) {
14727
+ return { baseId: withoutFast, effort: null, fast: true };
14728
+ }
14729
+ fast = true;
14730
+ id = withoutFast;
14731
+ }
14732
+ if (isAtomicModelId(id)) {
14733
+ return { baseId: id, effort: null, fast };
14734
+ }
14735
+ for (const { suffix, level } of EFFORT_SUFFIXES) {
14736
+ if (id.endsWith(suffix)) {
14737
+ return { baseId: id.slice(0, -suffix.length), effort: level, fast };
14738
+ }
14739
+ }
14740
+ return { baseId: id, effort: null, fast };
14741
+ }
14742
+ function collapseModelIdToBase(modelId) {
14743
+ const parsed = parseModelEffortSuffix(modelId);
14744
+ if (parsed.fast && !parsed.effort)
14745
+ return modelId.trim();
14746
+ return parsed.baseId;
14747
+ }
14748
+
14749
+ // ../shared/dist/types/frontend.js
14750
+ var CLAUDE_5_EFFORT_LEVELS = CLAUDE_EFFORT_LEVELS;
14617
14751
  var AVAILABLE_MODELS = [
14618
14752
  {
14619
14753
  id: "",
@@ -14628,7 +14762,7 @@ var AVAILABLE_MODELS = [
14628
14762
  {
14629
14763
  id: "claude-opus-4-8",
14630
14764
  name: "Opus 4.8",
14631
- capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_48_EFFORT_LEVELS }
14765
+ capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
14632
14766
  },
14633
14767
  {
14634
14768
  id: "claude-haiku-4-5",
@@ -14867,51 +15001,8 @@ function findModelDef(providerKind, modelId) {
14867
15001
  }
14868
15002
 
14869
15003
  // ../shared/dist/cursor-agent-models.js
14870
- var CLAUDE_5_EFFORT_LEVELS2 = [
14871
- "minimal",
14872
- "low",
14873
- "medium",
14874
- "high",
14875
- "xhigh",
14876
- "max"
14877
- ];
14878
- var CODEX_5X_EFFORT_LEVELS2 = ["low", "medium", "high", "xhigh"];
14879
- var GPT_5_5_EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh"];
14880
- var GPT_5_4_EFFORT_LEVELS = ["low", "medium", "high"];
14881
- var GPT_5_6_EFFORT_LEVELS = [
14882
- "low",
14883
- "medium",
14884
- "high",
14885
- "xhigh",
14886
- "max",
14887
- "ultra"
14888
- ];
14889
- var CURSOR_EFFORT_SUFFIXES = [
14890
- { suffix: "-extra-high", level: "xhigh" },
14891
- { suffix: "-xhigh", level: "xhigh" },
14892
- { suffix: "-ultra", level: "ultra" },
14893
- { suffix: "-max", level: "max" },
14894
- { suffix: "-high", level: "high" },
14895
- { suffix: "-medium", level: "medium" },
14896
- { suffix: "-low", level: "low" },
14897
- { suffix: "-none", level: "minimal" }
14898
- ];
14899
- function parseCursorModelId(modelId) {
14900
- let id = modelId.trim();
14901
- let fast = false;
14902
- if (id.endsWith("-fast")) {
14903
- fast = true;
14904
- id = id.slice(0, -"-fast".length);
14905
- }
14906
- for (const { suffix, level } of CURSOR_EFFORT_SUFFIXES) {
14907
- if (id.endsWith(suffix)) {
14908
- return { baseId: id.slice(0, -suffix.length), effort: level, fast };
14909
- }
14910
- }
14911
- return { baseId: id, effort: null, fast };
14912
- }
14913
15004
  function getCursorModelCollapseKey(modelId) {
14914
- const parsed = parseCursorModelId(modelId);
15005
+ const parsed = parseModelEffortSuffix(modelId);
14915
15006
  if (parsed.fast && !parsed.effort)
14916
15007
  return modelId.trim();
14917
15008
  return parsed.baseId;
@@ -15017,11 +15108,11 @@ function inferSlugModelCapabilities(providerKind, modelId) {
15017
15108
  const hasUltra = id.includes("-sol") || id.includes("-terra");
15018
15109
  return {
15019
15110
  contextWindows: [],
15020
- effortLevels: hasUltra ? GPT_5_6_EFFORT_LEVELS : GPT_5_6_EFFORT_LEVELS.filter((level) => level !== "ultra")
15111
+ effortLevels: hasUltra ? GPT_5_6_ULTRA_EFFORT_LEVELS : GPT_5_6_EFFORT_LEVELS
15021
15112
  };
15022
15113
  }
15023
15114
  if (id.includes("codex") || /^gpt-5\.[0-3]/.test(id)) {
15024
- return { contextWindows: [], effortLevels: CODEX_5X_EFFORT_LEVELS2 };
15115
+ return { contextWindows: [], effortLevels: CODEX_5X_EFFORT_LEVELS };
15025
15116
  }
15026
15117
  return void 0;
15027
15118
  }
@@ -15030,10 +15121,10 @@ function inferSlugModelCapabilities(providerKind, modelId) {
15030
15121
  return { contextWindows: ["200k"], effortLevels: [] };
15031
15122
  }
15032
15123
  if (id === "claude-opus-4-8") {
15033
- return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 };
15124
+ return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS };
15034
15125
  }
15035
15126
  if (id === "sonnet" || id === "opus" || id === "fable" || /^claude-(sonnet|opus|fable)-/.test(id)) {
15036
- return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 };
15127
+ return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS };
15037
15128
  }
15038
15129
  return void 0;
15039
15130
  }
@@ -15201,11 +15292,12 @@ var import_os3 = require("os");
15201
15292
  var import_path3 = require("path");
15202
15293
  var import_readline = require("readline");
15203
15294
  var import_child_process2 = require("child_process");
15295
+ var import_child_process3 = require("child_process");
15204
15296
  var import_crypto2 = require("crypto");
15205
15297
  var import_fs4 = require("fs");
15206
15298
  var import_os4 = require("os");
15207
15299
  var import_path4 = require("path");
15208
- var import_child_process3 = require("child_process");
15300
+ var import_child_process4 = require("child_process");
15209
15301
  var import_util10 = require("util");
15210
15302
  var import_fs5 = require("fs");
15211
15303
  var import_os5 = require("os");
@@ -15795,6 +15887,7 @@ function specForErrorKind(errorKind) {
15795
15887
  const spec = ERROR_SPECS[errorKind];
15796
15888
  return { message: spec.message, errorKind, recoveryClass: spec.recoveryClass };
15797
15889
  }
15890
+ var RESUME_SESSION_UNAVAILABLE_MESSAGE = ERROR_SPECS.resume_failed.message;
15798
15891
  function isLikelyProviderAuthError(stderr) {
15799
15892
  const lower = stderr.toLowerCase();
15800
15893
  return lower.includes("api key") || lower.includes("api_key") || lower.includes("invalid api key") || lower.includes("api key invalid") || lower.includes("unauthorized") || lower.includes("authentication failed") || lower.includes("authentication error") || lower.includes("provider settings") || lower.includes("invalid token") || lower.includes("token expired");
@@ -15950,6 +16043,54 @@ function spawnCli(command, args, context) {
15950
16043
  detached: process.platform !== "win32"
15951
16044
  });
15952
16045
  }
16046
+ function isAlreadyDead(error) {
16047
+ return error?.code === "ESRCH";
16048
+ }
16049
+ function killProcessTree(pid, options = {}) {
16050
+ const { signal = "SIGTERM", child, onError } = options;
16051
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0) {
16052
+ if (child) {
16053
+ try {
16054
+ child.kill(signal);
16055
+ } catch (err) {
16056
+ if (!isAlreadyDead(err)) onError?.("fallback", err);
16057
+ }
16058
+ }
16059
+ return;
16060
+ }
16061
+ if (process.platform === "win32") {
16062
+ try {
16063
+ const killer = (0, import_child_process3.spawn)("taskkill", ["/pid", String(pid), "/t", "/f"], {
16064
+ stdio: "ignore",
16065
+ windowsHide: true
16066
+ });
16067
+ killer.once("error", (err) => {
16068
+ if (child) {
16069
+ try {
16070
+ child.kill();
16071
+ } catch {
16072
+ }
16073
+ }
16074
+ onError?.("taskkill", err);
16075
+ });
16076
+ } catch (err) {
16077
+ onError?.("taskkill", err);
16078
+ }
16079
+ return;
16080
+ }
16081
+ try {
16082
+ process.kill(-pid, signal);
16083
+ } catch (groupErr) {
16084
+ if (!isAlreadyDead(groupErr)) onError?.("group", groupErr);
16085
+ if (child) {
16086
+ try {
16087
+ child.kill(signal);
16088
+ } catch (fallbackErr) {
16089
+ if (!isAlreadyDead(fallbackErr)) onError?.("fallback", fallbackErr);
16090
+ }
16091
+ }
16092
+ }
16093
+ }
15953
16094
  function emitSessionNotice(presenter, kind, message) {
15954
16095
  if (presenter.onNotice) {
15955
16096
  void presenter.onNotice(kind, message);
@@ -16014,6 +16155,12 @@ function formatCliSpawnError(command, error) {
16014
16155
  }
16015
16156
  return error;
16016
16157
  }
16158
+ function waitForSpawnOutcome(child) {
16159
+ return new Promise((resolve22) => {
16160
+ child.once("spawn", () => resolve22(null));
16161
+ child.once("error", (error) => resolve22(error));
16162
+ });
16163
+ }
16017
16164
  function createGenericCliBackend(options) {
16018
16165
  return {
16019
16166
  kind: options.kind,
@@ -16027,7 +16174,23 @@ function createGenericCliBackend(options) {
16027
16174
  };
16028
16175
  const prompt = options.augmentPrompt?.(context) ?? (context.config.mode === "plan" ? buildPlanModePrefix(buildPromptWithSystem(context.config, context.promptText)) : buildPromptWithSystem(context.config, context.promptText));
16029
16176
  const args = options.buildArgs?.(context, prompt) ?? options.args.map((arg) => arg === "{{prompt}}" ? prompt : arg);
16030
- const child = spawnCli(options.command, args, context);
16177
+ let command = options.command;
16178
+ let child = spawnCli(command, args, context);
16179
+ if (context.revalidateCommand) {
16180
+ const spawnError = await waitForSpawnOutcome(child);
16181
+ if (spawnError) {
16182
+ const fresh = spawnError.code === "ENOENT" ? context.revalidateCommand()?.trim() || null : null;
16183
+ if (fresh && fresh !== command) {
16184
+ console.warn(
16185
+ `[${options.kind}] Spawn failed ENOENT for "${command}" \u2014 re-resolved to "${fresh}", retrying once`
16186
+ );
16187
+ command = fresh;
16188
+ child = spawnCli(command, args, context);
16189
+ } else {
16190
+ throw formatCliSpawnError(command, spawnError);
16191
+ }
16192
+ }
16193
+ }
16031
16194
  state.process = child;
16032
16195
  state.lastRawOutputAtMs = Date.now();
16033
16196
  context.onProcessSpawned?.(child);
@@ -16038,8 +16201,8 @@ function createGenericCliBackend(options) {
16038
16201
  const safeArgs = args.map(
16039
16202
  (a, i) => i > 0 && args[i - 1] === "--system-prompt" ? `"<system-prompt ${a.length} chars>"` : a
16040
16203
  );
16041
- console.info(`[${options.kind}] Spawning: ${options.command} ${safeArgs.join(" ")}`);
16042
- presenter.recordRawTranscript?.("system", `${options.command} ${args.join(" ")}`, {
16204
+ console.info(`[${options.kind}] Spawning: ${command} ${safeArgs.join(" ")}`);
16205
+ presenter.recordRawTranscript?.("system", `${command} ${args.join(" ")}`, {
16043
16206
  backendKind: options.kind
16044
16207
  });
16045
16208
  child.stdin.on("error", (err) => {
@@ -16071,14 +16234,7 @@ function createGenericCliBackend(options) {
16071
16234
  console.warn(
16072
16235
  `[${options.kind}] No stdout within ${options.startupTimeoutMs}ms of spawn \u2014 killing hung process`
16073
16236
  );
16074
- try {
16075
- if (process.platform === "win32") {
16076
- child.kill("SIGKILL");
16077
- } else if (child.pid) {
16078
- process.kill(-child.pid, "SIGKILL");
16079
- }
16080
- } catch {
16081
- }
16237
+ killProcessTree(child.pid, { signal: "SIGKILL", child });
16082
16238
  }, options.startupTimeoutMs);
16083
16239
  }
16084
16240
  stdoutRl.on("line", (line) => {
@@ -16121,16 +16277,7 @@ function createGenericCliBackend(options) {
16121
16277
  });
16122
16278
  child.on("exit", (code) => resolve22(code ?? 0));
16123
16279
  const onAbort = () => {
16124
- const pid = child.pid;
16125
- if (!pid) return;
16126
- try {
16127
- process.kill(-pid, "SIGTERM");
16128
- } catch {
16129
- try {
16130
- child.kill("SIGTERM");
16131
- } catch {
16132
- }
16133
- }
16280
+ killProcessTree(child.pid, { signal: "SIGTERM", child });
16134
16281
  };
16135
16282
  context.abortController.signal.addEventListener("abort", onAbort, { once: true });
16136
16283
  });
@@ -16166,14 +16313,7 @@ function createGenericCliBackend(options) {
16166
16313
  console.warn(
16167
16314
  `[${options.kind}] Idle timeout (${IDLE_MS}ms) waiting for ${idleTimeoutReason === "background_task" ? "a background task terminal event" : "a pending user answer"} \u2014 force-killing orphaned process`
16168
16315
  );
16169
- try {
16170
- if (process.platform === "win32") {
16171
- child.kill("SIGKILL");
16172
- } else if (child.pid) {
16173
- process.kill(-child.pid, "SIGKILL");
16174
- }
16175
- } catch {
16176
- }
16316
+ killProcessTree(child.pid, { signal: "SIGKILL", child });
16177
16317
  exitCode = await Promise.race([
16178
16318
  exitPromise,
16179
16319
  new Promise((resolve22) => setTimeout(() => resolve22(1), 5e3))
@@ -16189,14 +16329,7 @@ function createGenericCliBackend(options) {
16189
16329
  console.warn(
16190
16330
  `[${options.kind}] Process still alive ${GRACE_MS}ms after result event, killing`
16191
16331
  );
16192
- try {
16193
- if (process.platform === "win32") {
16194
- child.kill("SIGKILL");
16195
- } else if (child.pid) {
16196
- process.kill(-child.pid, "SIGKILL");
16197
- }
16198
- } catch {
16199
- }
16332
+ killProcessTree(child.pid, { signal: "SIGKILL", child });
16200
16333
  }
16201
16334
  } else {
16202
16335
  exitCode = raceResult;
@@ -16359,6 +16492,9 @@ function createGenericCliBackend(options) {
16359
16492
  classifiedErrorKind = detailed.errorKind;
16360
16493
  classifiedRecoveryClass = detailed.recoveryClass;
16361
16494
  }
16495
+ if (classifiedErrorKind === "resume_failed" && !requestedResumeId) {
16496
+ classifiedErrorKind = void 0;
16497
+ }
16362
16498
  }
16363
16499
  return {
16364
16500
  success: !failed,
@@ -16367,7 +16503,11 @@ function createGenericCliBackend(options) {
16367
16503
  planFilesCreated: [],
16368
16504
  iterations: Math.max(state.iterations, 1),
16369
16505
  error: classifiedError,
16370
- ...classifiedErrorKind ? { errorKind: classifiedErrorKind } : {},
16506
+ // Surface every recognized, machine-actionable kind (model_mismatch,
16507
+ // resume_failed, auth_*, …). The catch-all unknown_cli_error carries no routing
16508
+ // signal — nothing downstream keys on it — so leave errorKind absent for it,
16509
+ // keeping an unrelated failure untagged even when a resume id was set.
16510
+ ...classifiedErrorKind && classifiedErrorKind !== "unknown_cli_error" ? { errorKind: classifiedErrorKind } : {},
16371
16511
  ...classifiedRecoveryClass ? { recoveryClass: classifiedRecoveryClass } : {},
16372
16512
  providerSessionId: state.runtimeSessionId,
16373
16513
  runtimeSessionId: state.runtimeSessionId,
@@ -16825,7 +16965,7 @@ function claudeSessionLogExists(input) {
16825
16965
  if (!(0, import_fs4.existsSync)(projectDir)) return false;
16826
16966
  return (0, import_fs4.existsSync)((0, import_path4.join)(projectDir, `${input.sessionId}.jsonl`));
16827
16967
  }
16828
- var execFileAsync = (0, import_util10.promisify)(import_child_process3.execFile);
16968
+ var execFileAsync = (0, import_util10.promisify)(import_child_process4.execFile);
16829
16969
  var flagSupportCache = /* @__PURE__ */ new Map();
16830
16970
  function helpAdvertisesFlag(helpText, flag) {
16831
16971
  return helpText.includes(flag);
@@ -17347,11 +17487,15 @@ function createClaudeCliBackend(command = "claude", defaultArgs = []) {
17347
17487
  if (context.config.teamId?.trim() && await cliSupportsFlag(command, "--approve-mcps", context.env)) {
17348
17488
  args.push("--approve-mcps");
17349
17489
  }
17350
- const baseModel = context.config.selectedModel?.trim();
17490
+ const baseModel = collapseModelIdToBase(context.config.selectedModel?.trim() || "");
17351
17491
  if (baseModel) {
17352
17492
  args.push("--model", buildClaudeModelArg(baseModel, context.config.selectedContextWindow));
17353
17493
  }
17354
- const claudeEffort = context.config.selectedEffortLevel?.trim();
17494
+ const claudeEffort = resolveWireEffort({
17495
+ harness: "claude_cli",
17496
+ modelId: baseModel,
17497
+ selectedEffortLevel: context.config.selectedEffortLevel
17498
+ });
17355
17499
  if (claudeEffort) {
17356
17500
  args.push("--effort", claudeEffort);
17357
17501
  }
@@ -17556,18 +17700,7 @@ function armCodexExitGraceKill(state) {
17556
17700
  console.warn(
17557
17701
  "[codex_app_server] Process did not exit after turn completion; killing process group"
17558
17702
  );
17559
- const pid = child.pid;
17560
- if (pid) {
17561
- try {
17562
- process.kill(-pid, "SIGTERM");
17563
- return;
17564
- } catch {
17565
- }
17566
- }
17567
- try {
17568
- child.kill("SIGTERM");
17569
- } catch {
17570
- }
17703
+ killProcessTree(child.pid, { signal: "SIGTERM", child });
17571
17704
  }, CODEX_EXIT_GRACE_MS);
17572
17705
  timer.unref?.();
17573
17706
  state.exitGraceKillTimer = timer;
@@ -17872,8 +18005,14 @@ var parseCodexStructuredLine = createStructuredLineParser(
17872
18005
  "codex_app_server",
17873
18006
  handleCodexStructuredEvent
17874
18007
  );
17875
- function buildCodexEffortArgs(selectedEffortLevel) {
17876
- const level = selectedEffortLevel?.trim();
18008
+ function buildCodexEffortArgs(selectedEffortLevel, options) {
18009
+ const modelId = collapseModelIdToBase(options?.modelId?.trim() || "");
18010
+ const level = resolveWireEffort({
18011
+ harness: "codex_app_server",
18012
+ modelId,
18013
+ selectedEffortLevel,
18014
+ effortLevels: options?.effortLevels
18015
+ });
17877
18016
  if (!level) return [];
17878
18017
  return ["-c", `model_reasoning_effort=${level}`];
17879
18018
  }
@@ -17923,8 +18062,11 @@ function createCodexRuntimeBackend(command = "codex", defaultArgs = []) {
17923
18062
  startupTimeoutMs: CODEX_STARTUP_TIMEOUT_MS,
17924
18063
  buildArgs: (ctx) => {
17925
18064
  const resumeId = resumableSessionId;
17926
- const modelArgs = ctx.config.selectedModel?.trim() ? ["--model", ctx.config.selectedModel.trim()] : [];
17927
- const effortArgs = buildCodexEffortArgs(ctx.config.selectedEffortLevel);
18065
+ const selectedModel = collapseModelIdToBase(ctx.config.selectedModel?.trim() || "");
18066
+ const modelArgs = selectedModel ? ["--model", selectedModel] : [];
18067
+ const effortArgs = buildCodexEffortArgs(ctx.config.selectedEffortLevel, {
18068
+ modelId: selectedModel
18069
+ });
17928
18070
  const permissionArgs = getCodexPermissionArgs(ctx.config);
17929
18071
  const imageArgs = imagePaths.flatMap((p) => ["--image", p]);
17930
18072
  const baseArgs = resumeId ? [
@@ -18228,58 +18370,48 @@ var parseCursorStructuredLine = createStructuredLineParser(
18228
18370
  "cursor_agent_cli",
18229
18371
  handleCursorStructuredEvent
18230
18372
  );
18231
- var CURSOR_EFFORT_SUFFIXES2 = [
18232
- { suffix: "-extra-high", level: "xhigh" },
18233
- { suffix: "-xhigh", level: "xhigh" },
18234
- { suffix: "-max", level: "max" },
18235
- { suffix: "-high", level: "high" },
18236
- { suffix: "-medium", level: "medium" },
18237
- { suffix: "-low", level: "low" },
18238
- { suffix: "-none", level: "minimal" }
18239
- ];
18240
- function parseCursorModelId2(modelId) {
18241
- let id = modelId.trim();
18242
- let fast = false;
18243
- if (id.endsWith("-fast")) {
18244
- fast = true;
18245
- id = id.slice(0, -"-fast".length);
18246
- }
18247
- for (const { suffix, level } of CURSOR_EFFORT_SUFFIXES2) {
18248
- if (id.endsWith(suffix)) {
18249
- return { baseId: id.slice(0, -suffix.length), effort: level, fast };
18250
- }
18251
- }
18252
- return { baseId: id, effort: null, fast };
18253
- }
18254
- function cursorEffortForBracket(level) {
18255
- if (level === "minimal") return "none";
18256
- return level;
18257
- }
18258
- function asEffortLevel(value2, allowed) {
18259
- if (!value2) return null;
18260
- return allowed.includes(value2) ? value2 : null;
18261
- }
18262
18373
  function asContextWindow(value2) {
18263
18374
  if (value2 === "1m" || value2 === "200k") return value2;
18264
18375
  return null;
18265
18376
  }
18377
+ function cursorEffortSuffix(level, baseId) {
18378
+ if (level === "minimal") return "-none";
18379
+ if (level === "xhigh") {
18380
+ if (/^gpt-5\.5(?:-|$)/.test(baseId)) return "-extra-high";
18381
+ return "-xhigh";
18382
+ }
18383
+ if (level === "ultra") return "-max";
18384
+ return `-${level}`;
18385
+ }
18266
18386
  function buildCursorAgentModelArg(modelId, options) {
18267
18387
  const trimmed = modelId.trim();
18268
18388
  if (!trimmed) return trimmed;
18269
- const parsed = parseCursorModelId2(trimmed);
18389
+ const parsed = parseModelEffortSuffix(trimmed);
18270
18390
  if (parsed.fast && !parsed.effort) return trimmed;
18391
+ const baseId = collapseModelIdToBase(trimmed);
18271
18392
  const effortLevels = options?.effortLevels ?? [];
18272
- const overrides = [];
18273
- const contextWindow = asContextWindow(options?.selectedContextWindow);
18274
- if (contextWindow === "1m") {
18275
- overrides.push("context=1m");
18393
+ const wireEffort = resolveWireEffort({
18394
+ harness: "cursor_agent_cli",
18395
+ modelId: baseId,
18396
+ selectedEffortLevel: options?.selectedEffortLevel,
18397
+ effortLevels
18398
+ });
18399
+ let id = baseId;
18400
+ if (wireEffort) {
18401
+ const alanLevel = wireEffort === "none" ? "minimal" : wireEffort;
18402
+ if (isEffortLevel(alanLevel)) {
18403
+ const allowed = effortLevels.length === 0 || effortLevels.includes(alanLevel) || alanLevel === "minimal" && effortLevels.includes("minimal");
18404
+ if (allowed) {
18405
+ id = `${baseId}${cursorEffortSuffix(alanLevel, baseId)}`;
18406
+ }
18407
+ }
18276
18408
  }
18277
- const effort = asEffortLevel(options?.selectedEffortLevel, effortLevels);
18278
- if (effort) {
18279
- overrides.push(`effort=${cursorEffortForBracket(effort)}`);
18409
+ const contextWindow = asContextWindow(options?.selectedContextWindow);
18410
+ if (contextWindow === "1m" && id === baseId) {
18411
+ return `${baseId}[context=1m]`;
18280
18412
  }
18281
- if (overrides.length === 0) return parsed.baseId;
18282
- return `${parsed.baseId}[${overrides.join(",")}]`;
18413
+ if (parsed.fast) return `${id}-fast`;
18414
+ return id;
18283
18415
  }
18284
18416
  function isCursorAgentCliModelId(model) {
18285
18417
  return model === "auto" || /^composer-/.test(model) || /^gpt-/.test(model) || /^claude-/.test(model) || /^gemini-/.test(model) || /^grok-/.test(model) || /^kimi-/.test(model);
@@ -18359,7 +18491,7 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
18359
18491
  }
18360
18492
  const model = ctx.config.selectedModel?.trim();
18361
18493
  if (model && isDispatchableCursorModel(model)) {
18362
- const modelDef = findModelDef("cursor_agent_cli", model);
18494
+ const modelDef = findModelDef("cursor_agent_cli", model) ?? findModelDef("cursor_agent_cli", model.replace(/-fast$/, ""));
18363
18495
  args.push(
18364
18496
  "--model",
18365
18497
  buildCursorAgentModelArg(model, {
@@ -19147,17 +19279,7 @@ function handleOpencodeStructuredEvent(parsed, context, state) {
19147
19279
  void presenter.onError(message);
19148
19280
  state.error = message;
19149
19281
  }
19150
- const pid = state.process?.pid;
19151
- if (pid) {
19152
- try {
19153
- process.kill(-pid, "SIGTERM");
19154
- } catch {
19155
- try {
19156
- state.process?.kill("SIGTERM");
19157
- } catch {
19158
- }
19159
- }
19160
- }
19282
+ killProcessTree(state.process?.pid, { signal: "SIGTERM", child: state.process });
19161
19283
  return true;
19162
19284
  }
19163
19285
  default:
@@ -19707,6 +19829,8 @@ Prefer relative paths and keep your work scoped to this project.`
19707
19829
  runtimeCommand || "generic-cli",
19708
19830
  runtimeArgs
19709
19831
  );
19832
+ const revalidateRuntimeCommand = this.revalidateRuntimeCommand;
19833
+ const revalidateCommand = revalidateRuntimeCommand ? () => revalidateRuntimeCommand.call(this) : void 0;
19710
19834
  let lastResult = null;
19711
19835
  for (let attempt = 0; attempt <= _BaseMachineAgent.MAX_RETRIES; attempt++) {
19712
19836
  if (this.abortController?.signal.aborted) break;
@@ -19717,7 +19841,8 @@ Prefer relative paths and keep your work scoped to this project.`
19717
19841
  cwd,
19718
19842
  env,
19719
19843
  promptText,
19720
- onProcessSpawned: this.getOnProcessSpawned()
19844
+ onProcessSpawned: this.getOnProcessSpawned(),
19845
+ revalidateCommand
19721
19846
  });
19722
19847
  lastResult = {
19723
19848
  ...result,
@@ -19767,7 +19892,8 @@ ${runtimeConfig.task}` } : {}
19767
19892
  cwd,
19768
19893
  env,
19769
19894
  promptText: fallbackContext ? this.buildPromptText(runtimeConfig) : promptText,
19770
- onProcessSpawned: this.getOnProcessSpawned()
19895
+ onProcessSpawned: this.getOnProcessSpawned(),
19896
+ revalidateCommand
19771
19897
  });
19772
19898
  lastResult = {
19773
19899
  ...retryResult,
@@ -20187,38 +20313,32 @@ var CoreAgent = class _CoreAgent extends BaseMachineAgent {
20187
20313
  const pid = child.pid;
20188
20314
  if (!pid) return false;
20189
20315
  console.info("[CoreAgent] Killing agent process", { pid });
20190
- try {
20191
- if (process.platform === "win32") {
20192
- child.kill("SIGTERM");
20193
- } else {
20194
- process.kill(-pid, "SIGTERM");
20195
- }
20196
- } catch (err) {
20197
- if (err.code !== "ESRCH") {
20198
- console.warn("[CoreAgent] SIGTERM failed", { pid, err });
20199
- }
20200
- try {
20201
- child.kill("SIGTERM");
20202
- } catch {
20203
- }
20204
- }
20316
+ killProcessTree(pid, {
20317
+ signal: "SIGTERM",
20318
+ child,
20319
+ onError: (stage, err) => console.warn(`[CoreAgent] SIGTERM failed (${stage})`, { pid, err })
20320
+ });
20205
20321
  setTimeout(() => {
20206
20322
  if (child.killed || child.exitCode !== null) return;
20207
20323
  console.warn("[CoreAgent] Escalating to SIGKILL", { pid });
20208
- try {
20209
- if (process.platform === "win32") {
20210
- child.kill("SIGKILL");
20211
- } else {
20212
- process.kill(-pid, "SIGKILL");
20213
- }
20214
- } catch (err) {
20215
- if (err.code !== "ESRCH") {
20216
- console.warn("[CoreAgent] SIGKILL failed", { pid, err });
20217
- }
20218
- }
20324
+ killProcessTree(pid, {
20325
+ signal: "SIGKILL",
20326
+ child,
20327
+ onError: (stage, err) => console.warn(`[CoreAgent] SIGKILL failed (${stage})`, { pid, err })
20328
+ });
20219
20329
  }, _CoreAgent.SIGKILL_DELAY_MS);
20220
20330
  return true;
20221
20331
  }
20332
+ /**
20333
+ * Re-resolve this agent's CLI executable from scratch when a spawn fails
20334
+ * ENOENT. The daemon caches resolved CLI paths, so a provider binary that was
20335
+ * moved or reinstalled mid-session would otherwise fail every turn with
20336
+ * "CLI command not found" until the daemon restarts. Invalidating the cache
20337
+ * and re-resolving once lets the current run recover against the new location.
20338
+ */
20339
+ revalidateRuntimeCommand() {
20340
+ return revalidateBackendRuntimeCommand(this.runtime.backendKind) ?? null;
20341
+ }
20222
20342
  // ── Interactive tool response (WS relay → stdin) ───────────────────────
20223
20343
  /**
20224
20344
  * Send a tool_result to the CLI's stdin (stream-json format).
@@ -20571,6 +20691,8 @@ var EncryptedEventOutbox = class {
20571
20691
  inFlightEventId = null;
20572
20692
  ackTimer = null;
20573
20693
  retryTimer = null;
20694
+ /** Latch so a persistent disk failure logs once per streak, not per event. */
20695
+ persistFailureLogged = false;
20574
20696
  key;
20575
20697
  maxEncryptedBytes;
20576
20698
  maxIntermediateEventsPerRun;
@@ -20774,30 +20896,42 @@ var EncryptedEventOutbox = class {
20774
20896
  }
20775
20897
  }
20776
20898
  persist() {
20777
- if (this.entries.length === 0) {
20778
- (0, import_node_fs6.rmSync)(this.path, { force: true });
20779
- return;
20780
- }
20781
- (0, import_node_fs6.mkdirSync)((0, import_node_path5.dirname)(this.path), { recursive: true, mode: 448 });
20782
- const iv = (0, import_node_crypto.randomBytes)(12);
20783
- const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", this.key, iv);
20784
- const ciphertext = Buffer.concat([
20785
- cipher.update(JSON.stringify({ entries: this.entries }), "utf8"),
20786
- cipher.final()
20787
- ]);
20788
- const envelope = {
20789
- version: OUTBOX_VERSION,
20790
- iv: iv.toString("base64url"),
20791
- authTag: cipher.getAuthTag().toString("base64url"),
20792
- ciphertext: ciphertext.toString("base64url")
20793
- };
20794
- const pendingPath = `${this.path}.pending-${process.pid}-${(0, import_node_crypto.randomBytes)(6).toString("hex")}`;
20795
20899
  try {
20796
- (0, import_node_fs6.writeFileSync)(pendingPath, JSON.stringify(envelope), { mode: 384 });
20797
- (0, import_node_fs6.chmodSync)(pendingPath, 384);
20798
- (0, import_node_fs6.renameSync)(pendingPath, this.path);
20799
- } finally {
20800
- (0, import_node_fs6.rmSync)(pendingPath, { force: true });
20900
+ if (this.entries.length === 0) {
20901
+ (0, import_node_fs6.rmSync)(this.path, { force: true });
20902
+ this.persistFailureLogged = false;
20903
+ return;
20904
+ }
20905
+ (0, import_node_fs6.mkdirSync)((0, import_node_path5.dirname)(this.path), { recursive: true, mode: 448 });
20906
+ const iv = (0, import_node_crypto.randomBytes)(12);
20907
+ const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", this.key, iv);
20908
+ const ciphertext = Buffer.concat([
20909
+ cipher.update(JSON.stringify({ entries: this.entries }), "utf8"),
20910
+ cipher.final()
20911
+ ]);
20912
+ const envelope = {
20913
+ version: OUTBOX_VERSION,
20914
+ iv: iv.toString("base64url"),
20915
+ authTag: cipher.getAuthTag().toString("base64url"),
20916
+ ciphertext: ciphertext.toString("base64url")
20917
+ };
20918
+ const pendingPath = `${this.path}.pending-${process.pid}-${(0, import_node_crypto.randomBytes)(6).toString("hex")}`;
20919
+ try {
20920
+ (0, import_node_fs6.writeFileSync)(pendingPath, JSON.stringify(envelope), { mode: 384 });
20921
+ (0, import_node_fs6.chmodSync)(pendingPath, 384);
20922
+ (0, import_node_fs6.renameSync)(pendingPath, this.path);
20923
+ } finally {
20924
+ (0, import_node_fs6.rmSync)(pendingPath, { force: true });
20925
+ }
20926
+ this.persistFailureLogged = false;
20927
+ } catch (error) {
20928
+ if (!this.persistFailureLogged) {
20929
+ this.persistFailureLogged = true;
20930
+ const detail = error instanceof Error ? error.message : String(error);
20931
+ this.pushLog(
20932
+ `event_outbox_persist_failed error=${detail} pending_entries=${this.entries.length}`
20933
+ );
20934
+ }
20801
20935
  }
20802
20936
  }
20803
20937
  };
@@ -22443,7 +22577,7 @@ var RunStartGate = class {
22443
22577
  };
22444
22578
 
22445
22579
  // src/version.ts
22446
- var AGENT_VERSION = "0.1.40";
22580
+ var AGENT_VERSION = "0.1.42";
22447
22581
 
22448
22582
  // src/workspace-relocation.ts
22449
22583
  var import_node_child_process3 = require("child_process");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiden-ade/sandbox-agent",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "type": "module",
5
5
  "description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
6
6
  "bin": {