openmausbot 0.1.73 → 0.1.75

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 (42) hide show
  1. package/dist/assets/{index-BYbK7ber.js → index-BTlyRwLl.js} +1 -1
  2. package/dist/assets/index-CeMbvsgx.js +305 -0
  3. package/dist/assets/index-DH7Zax6L.css +1 -0
  4. package/dist/index.html +2 -2
  5. package/dist-server/container-mcp.js +9 -0
  6. package/dist-server/index.js +1402 -1048
  7. package/dist-server/mcp-gate.js +58 -16
  8. package/dist-server/openmausbot.js +543 -271
  9. package/dist-server/pair-cli.js +543 -271
  10. package/dist-server/permission-proxy.js +119 -14
  11. package/dist-server/server/auto-approve.js +44 -205
  12. package/dist-server/server/channel-queue.js +20 -2
  13. package/dist-server/server/config.js +36 -1
  14. package/dist-server/server/drivers/acp/core.js +58 -4
  15. package/dist-server/server/drivers/acp/grok.js +15 -2
  16. package/dist-server/server/drivers/antigravity-acp.js +5 -4
  17. package/dist-server/server/drivers/antigravity.js +9 -4
  18. package/dist-server/server/drivers/claude.js +113 -13
  19. package/dist-server/server/drivers/codex.js +37 -15
  20. package/dist-server/server/drivers/retry.js +4 -0
  21. package/dist-server/server/engine-install.js +9 -5
  22. package/dist-server/server/index.js +265 -233
  23. package/dist-server/server/message-db.js +70 -3
  24. package/dist-server/server/permission-proxy.js +90 -15
  25. package/dist-server/server/procs.js +82 -23
  26. package/dist-server/server/routines.js +67 -8
  27. package/dist-server/server/setup-mode.js +6 -7
  28. package/dist-server/server/steer-queue.js +27 -7
  29. package/dist-server/server/store.js +19 -0
  30. package/dist-server/server/team-manifest.js +1 -1
  31. package/dist-server/server/thread-events.js +10 -1
  32. package/dist-server/server/webhooks.js +4 -1
  33. package/dist-server/server/workspace-backup.js +24 -9
  34. package/dist-server/server/workspace.js +13 -0
  35. package/dist-server/shared/approval-mode.js +11 -10
  36. package/dist-server/shared/ask-question.js +172 -0
  37. package/dist-server/shared/provider-safety.js +6 -0
  38. package/dist-server/vps-container-mcp.js +9 -0
  39. package/package.json +1 -1
  40. package/dist/assets/index-BLJ7byG3.js +0 -296
  41. package/dist/assets/index-De2TRLxu.css +0 -1
  42. package/dist-server/server/auto-review.js +0 -79
@@ -9752,8 +9752,8 @@ var capitalizeFirstCharacter, error28;
9752
9752
  var init_lt = __esm({
9753
9753
  "node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/locales/lt.js"() {
9754
9754
  init_util();
9755
- capitalizeFirstCharacter = (text3) => {
9756
- return text3.charAt(0).toUpperCase() + text3.slice(1);
9755
+ capitalizeFirstCharacter = (text4) => {
9756
+ return text4.charAt(0).toUpperCase() + text4.slice(1);
9757
9757
  };
9758
9758
  error28 = () => {
9759
9759
  const Sizable = {
@@ -17585,8 +17585,8 @@ var init_mcp_registry = __esm({
17585
17585
  });
17586
17586
 
17587
17587
  // server/schema.ts
17588
- function parseJson(text3) {
17589
- return JSON.parse(text3);
17588
+ function parseJson(text4) {
17589
+ return JSON.parse(text4);
17590
17590
  }
17591
17591
  function schemaIssue(error51, fallback) {
17592
17592
  const issue2 = error51.issues[0];
@@ -17782,7 +17782,7 @@ function saveConfig(patch, options = {}) {
17782
17782
  const checkedPatch = appConfigSchema.partial().parse(patch);
17783
17783
  const storedProfiles = storedBrowserProfilesSchema.safeParse(disk.browserProfiles);
17784
17784
  if (storedProfiles.success) disk.browserProfiles = storedProfiles.data;
17785
- for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "localVm", "features", "budgets", "billing"]) {
17785
+ for (const key of ["xai", "anthropic", "openaiCompat", "composio", "box", "opencodeGo", "tts", "imageGen", "profile", "rooms", "threads", "localVm", "features", "budgets", "billing", "onboarding"]) {
17786
17786
  const section = checkedPatch[key];
17787
17787
  if (!section) continue;
17788
17788
  const current = jsonObjectSchema.safeParse(disk[key]);
@@ -17905,7 +17905,7 @@ function instanceConfigs(cfg) {
17905
17905
  }
17906
17906
  return map3;
17907
17907
  }
17908
- var optionalText, SSH_ALIAS, LEGACY_BROWSER_PROFILE_ID, BROWSER_PROFILE_ID, MIN_ROOM_TURN_TIMEOUT_MINUTES, MAX_ROOM_TURN_TIMEOUT_MINUTES, MAX_CONCURRENT_BOT_THREADS, MIN_LOCAL_VM_MAX_INSTANCES, MAX_LOCAL_VM_MAX_INSTANCES, vpsConfigSchema, roomConfigSchema, localVmConfigSchema, browserProfileSchema, legacyBrowserProfileSchema, legacyBrowserProfilesSchema, storedBrowserProfilesSchema, browserProfilesSchema, featureConfigSchema, instanceConfigSchema, instanceConfigMapSchema, defaultModelSelectionSchema, appConfigSchema, storedAppConfigSchema, appConfigPatchSchema, jsonObjectSchema, DATA_DIR, LEGACY_DATA_DIR, EVENTS_DIR, NATIVE_DIR, WORKSPACE_CREDENTIAL_ENV, PROVIDER_CREDENTIAL_ENV;
17908
+ var optionalText, SSH_ALIAS, LEGACY_BROWSER_PROFILE_ID, BROWSER_PROFILE_ID, MIN_ROOM_TURN_TIMEOUT_MINUTES, MAX_ROOM_TURN_TIMEOUT_MINUTES, MAX_CONCURRENT_BOT_THREADS, MIN_LOCAL_VM_MAX_INSTANCES, MAX_LOCAL_VM_MAX_INSTANCES, vpsConfigSchema, roomConfigSchema, localVmConfigSchema, browserProfileSchema, legacyBrowserProfileSchema, legacyBrowserProfilesSchema, storedBrowserProfilesSchema, browserProfilesSchema, featureConfigSchema, onboardingConfigSchema, instanceConfigSchema, instanceConfigMapSchema, defaultModelSelectionSchema, appConfigSchema, storedAppConfigSchema, appConfigPatchSchema, jsonObjectSchema, DATA_DIR, LEGACY_DATA_DIR, EVENTS_DIR, NATIVE_DIR, WORKSPACE_CREDENTIAL_ENV, PROVIDER_CREDENTIAL_ENV;
17909
17909
  var init_config = __esm({
17910
17910
  "server/config.ts"() {
17911
17911
  "use strict";
@@ -17979,6 +17979,14 @@ var init_config = __esm({
17979
17979
  * also has its own switch. */
17980
17980
  browser: external_exports.boolean().optional()
17981
17981
  });
17982
+ onboardingConfigSchema = external_exports.object({
17983
+ /** ISO timestamp of finishing (or skipping to the end of) the welcome flow. */
17984
+ completedAt: external_exports.string().trim().max(40).optional(),
17985
+ /** Which welcome flow was completed; a newer flow may re-show itself. */
17986
+ version: external_exports.number().int().min(0).max(1e3).optional(),
17987
+ reelSeen: external_exports.boolean().optional(),
17988
+ hintsSeen: external_exports.array(external_exports.string().trim().min(1).max(60)).max(100).optional()
17989
+ }).strict();
17982
17990
  instanceConfigSchema = external_exports.object({
17983
17991
  driver: external_exports.string().min(1),
17984
17992
  displayName: optionalText,
@@ -18072,6 +18080,7 @@ var init_config = __esm({
18072
18080
  threads: external_exports.object({ maxConcurrentPerBot: external_exports.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS) }).strict().optional(),
18073
18081
  localVm: localVmConfigSchema.optional(),
18074
18082
  features: featureConfigSchema.optional(),
18083
+ onboarding: onboardingConfigSchema.optional(),
18075
18084
  browserProfiles: browserProfilesSchema.optional(),
18076
18085
  instances: instanceConfigMapSchema.optional(),
18077
18086
  /** User-configured MCP servers, mounted into every capable engine. Kept
@@ -18622,14 +18631,14 @@ function nodeExe(near) {
18622
18631
  return process.versions.electron ? null : process.execPath;
18623
18632
  }
18624
18633
  function parseCmdShim(shim) {
18625
- let text3;
18634
+ let text4;
18626
18635
  try {
18627
- text3 = readFileSync6(shim, "utf8");
18636
+ text4 = readFileSync6(shim, "utf8");
18628
18637
  } catch {
18629
18638
  return null;
18630
18639
  }
18631
18640
  const dir = dirname4(shim);
18632
- const targets = [...text3.matchAll(/"%~?dp0%?\\?([^"]+)"/g)].map((m) => join9(dir, m[1])).filter((p) => isFile(p) && basename2(p).toLowerCase() !== "node.exe");
18641
+ const targets = [...text4.matchAll(/"%~?dp0%?\\?([^"]+)"/g)].map((m) => join9(dir, m[1])).filter((p) => isFile(p) && basename2(p).toLowerCase() !== "node.exe");
18633
18642
  const script = targets.find((p) => /\.[cm]?js$/i.test(p));
18634
18643
  if (script) {
18635
18644
  const node = nodeExe(dir);
@@ -18728,6 +18737,7 @@ function spawnCli(cli, args, opts) {
18728
18737
  // win32: taskkill /T does the reaping instead (see killCliTree)
18729
18738
  ...process.platform === "win32" ? { windowsHide: true } : { detached: true }
18730
18739
  });
18740
+ if (process.platform !== "win32") cliGroups.add(child);
18731
18741
  child.stdin?.on("error", () => {
18732
18742
  });
18733
18743
  return child;
@@ -18760,8 +18770,59 @@ function describeSpawnFailure(err, cli) {
18760
18770
  return { message: `spawn failed: ${err.message}`, setup: false };
18761
18771
  }
18762
18772
  function killCliTree(child, timeoutMs = 5e3) {
18773
+ const existing = stopping.get(child);
18774
+ if (existing) return existing;
18763
18775
  const pid = child.pid;
18764
- if (!pid || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);
18776
+ if (!pid) return Promise.resolve(true);
18777
+ if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return Promise.resolve(false);
18778
+ const run3 = stopCliTree(child, pid, Number.isFinite(timeoutMs) ? Math.max(0, timeoutMs) : 5e3);
18779
+ stopping.set(child, run3);
18780
+ void run3.then((stopped) => {
18781
+ if (!stopped) stopping.delete(child);
18782
+ });
18783
+ return run3;
18784
+ }
18785
+ async function stopCliTree(child, pid, timeoutMs) {
18786
+ const exited = () => child.exitCode !== null || child.signalCode !== null;
18787
+ if (process.platform !== "win32") {
18788
+ const group = cliGroups.has(child);
18789
+ const settled = () => {
18790
+ if (!exited()) return false;
18791
+ if (!group) return true;
18792
+ try {
18793
+ process.kill(-pid, 0);
18794
+ return false;
18795
+ } catch (error51) {
18796
+ return error51.code === "ESRCH";
18797
+ }
18798
+ };
18799
+ const signal = (value) => {
18800
+ try {
18801
+ if (group) process.kill(-pid, value);
18802
+ else child.kill(value);
18803
+ } catch {
18804
+ try {
18805
+ child.kill(value);
18806
+ } catch {
18807
+ }
18808
+ }
18809
+ };
18810
+ const wait2 = async (ms) => {
18811
+ const deadline = Date.now() + ms;
18812
+ while (!settled()) {
18813
+ const remaining = deadline - Date.now();
18814
+ if (remaining <= 0) return false;
18815
+ await new Promise((resolve13) => setTimeout(resolve13, Math.min(25, remaining)));
18816
+ }
18817
+ return true;
18818
+ };
18819
+ if (settled()) return true;
18820
+ signal("SIGTERM");
18821
+ if (await wait2(timeoutMs)) return true;
18822
+ signal("SIGKILL");
18823
+ return wait2(1e3);
18824
+ }
18825
+ if (exited()) return true;
18765
18826
  return new Promise((resolve13) => {
18766
18827
  let timer;
18767
18828
  const done = (stopped) => {
@@ -18773,35 +18834,26 @@ function killCliTree(child, timeoutMs = 5e3) {
18773
18834
  child.once("close", closed);
18774
18835
  timer = setTimeout(() => done(false), timeoutMs);
18775
18836
  timer.unref?.();
18776
- if (process.platform === "win32") {
18777
- execFile3("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true }, (err) => {
18778
- if (!err) return;
18779
- try {
18780
- child.kill();
18781
- } catch {
18782
- }
18783
- });
18784
- return;
18785
- }
18786
- try {
18787
- process.kill(-pid, "SIGTERM");
18788
- } catch {
18837
+ execFile3("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true }, (err) => {
18838
+ if (!err) return;
18789
18839
  try {
18790
- child.kill("SIGTERM");
18840
+ child.kill();
18791
18841
  } catch {
18792
18842
  }
18793
- }
18843
+ });
18794
18844
  });
18795
18845
  }
18796
18846
  function brokerSocketPath(dataDir, tag) {
18797
18847
  return process.platform === "win32" ? `\\\\.\\pipe\\openmausbot-perm-${process.pid}-${tag}` : join10(dataDir, `perm-${tag}.sock`);
18798
18848
  }
18799
- var WINDOWS_SAFE_COMMAND_LINE_CHARS;
18849
+ var WINDOWS_SAFE_COMMAND_LINE_CHARS, cliGroups, stopping;
18800
18850
  var init_procs = __esm({
18801
18851
  "server/procs.ts"() {
18802
18852
  "use strict";
18803
18853
  init_env_path();
18804
18854
  WINDOWS_SAFE_COMMAND_LINE_CHARS = 3e4;
18855
+ cliGroups = /* @__PURE__ */ new WeakSet();
18856
+ stopping = /* @__PURE__ */ new WeakMap();
18805
18857
  }
18806
18858
  });
18807
18859
 
@@ -18888,19 +18940,19 @@ function runNpm(args, env, cwd, timeoutMs) {
18888
18940
  let timedOut = false;
18889
18941
  const timer = setTimeout(() => {
18890
18942
  timedOut = true;
18891
- void killCliTree(child);
18943
+ void killCliTree(child).then((stopped) => {
18944
+ rejectRun(new Error(stopped ? "The install took too long and was stopped. Check the server's network connection and try again." : "The install took too long, but npm could not be confirmed stopped. Ask the server administrator to stop the install process before trying again."));
18945
+ });
18892
18946
  }, timeoutMs);
18893
18947
  timer.unref();
18894
18948
  child.once("error", (error51) => {
18949
+ if (timedOut) return;
18895
18950
  clearTimeout(timer);
18896
18951
  rejectRun(new Error(error51.code === "ENOENT" ? "npm is not installed on this server. Install Node.js with npm for the user running OpenMausBot, then try again." : "npm could not start on this server. Check that Node.js is installed for the user running OpenMausBot."));
18897
18952
  });
18898
18953
  child.once("close", (code) => {
18899
18954
  clearTimeout(timer);
18900
- if (timedOut) {
18901
- rejectRun(new Error("The install took too long and was stopped. Check the server's network connection and try again."));
18902
- return;
18903
- }
18955
+ if (timedOut) return;
18904
18956
  resolveRun({ code, output });
18905
18957
  });
18906
18958
  });
@@ -19515,6 +19567,7 @@ var init_container_computer = __esm({
19515
19567
  // shared/approval-mode.ts
19516
19568
  function supportsApprovalMode(driverKind, mode) {
19517
19569
  if (mode === "custom") return driverKind === "codex";
19570
+ if (mode === "edits") return ["claudeAgent", "grokAgent", "antigravityAgent"].includes(driverKind ?? "");
19518
19571
  if (mode !== "full") return true;
19519
19572
  return ["codex", "claudeAgent", "antigravityAgent", "cursorAgent", "grokAgent", "opencodeGo"].includes(driverKind ?? "");
19520
19573
  }
@@ -19530,9 +19583,9 @@ function isSecretName(name) {
19530
19583
  if (SECRET_KEY_PARTS.some((part) => lower.includes(part))) return true;
19531
19584
  return /(^|[_.-])keys?$/.test(lower);
19532
19585
  }
19533
- function redactSecretsInText(text3) {
19534
- if (!text3 || text3.length < 8) return text3;
19535
- let out = text3;
19586
+ function redactSecretsInText(text4) {
19587
+ if (!text4 || text4.length < 8) return text4;
19588
+ let out = text4;
19536
19589
  out = out.replace(PEM_BLOCK, (_m, open2, body, close) => `${open2}
19537
19590
  ${mask(body.trim())}
19538
19591
  ${close}`);
@@ -19643,8 +19696,8 @@ function askInputSummary(input) {
19643
19696
  if (typeof fields.question === "string") return cut(fields.question, QUESTION_LIMIT);
19644
19697
  if (typeof fields.command === "string") return cut(fields.command, LIMIT);
19645
19698
  if (typeof fields.url === "string") return cut(fields.url, LIMIT);
19646
- const text3 = JSON.stringify(fields);
19647
- return text3 === "{}" ? void 0 : cut(text3, LIMIT);
19699
+ const text4 = JSON.stringify(fields);
19700
+ return text4 === "{}" ? void 0 : cut(text4, LIMIT);
19648
19701
  }
19649
19702
  var QUESTION_LIMIT, LIMIT, cut;
19650
19703
  var init_tool_summary = __esm({
@@ -19653,7 +19706,7 @@ var init_tool_summary = __esm({
19653
19706
  init_redact();
19654
19707
  QUESTION_LIMIT = 300;
19655
19708
  LIMIT = 200;
19656
- cut = (text3, limit) => redactSecretsInText(text3).trim().slice(0, limit);
19709
+ cut = (text4, limit) => redactSecretsInText(text4).trim().slice(0, limit);
19657
19710
  }
19658
19711
  });
19659
19712
 
@@ -19676,11 +19729,11 @@ function sanitizeToolLogValue(value, budget, depth = 0) {
19676
19729
  if (typeof value === "string") {
19677
19730
  if (/^data:image\//iu.test(value) || budget.text <= 0) return void 0;
19678
19731
  const limit = Math.min(TOOL_LOG_TEXT_LIMIT, budget.text);
19679
- const text3 = value.length <= limit ? value : `[Earlier output truncated]
19732
+ const text4 = value.length <= limit ? value : `[Earlier output truncated]
19680
19733
 
19681
19734
  ${value.slice(-limit)}`;
19682
- budget.text -= text3.length;
19683
- return text3;
19735
+ budget.text -= text4.length;
19736
+ return text4;
19684
19737
  }
19685
19738
  if (Array.isArray(value)) {
19686
19739
  return value.flatMap((entry) => {
@@ -19712,6 +19765,20 @@ function decodeAcpConfig(defaultCli) {
19712
19765
  };
19713
19766
  };
19714
19767
  }
19768
+ function sessionOperationKey(toolCall) {
19769
+ const rawInput = toolCall?.rawInput;
19770
+ const command = typeof rawInput?.command === "string" ? rawInput.command : void 0;
19771
+ const hasInput = rawInput && typeof rawInput === "object" && Object.keys(rawInput).length > 0;
19772
+ if (!command && !hasInput) return null;
19773
+ const stable = (value) => Array.isArray(value) ? value.map(stable) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])])) : value;
19774
+ return JSON.stringify(stable({
19775
+ kind: toolCall?.kind,
19776
+ title: toolCall?.title,
19777
+ command,
19778
+ input: rawInput,
19779
+ locations: toolCall?.locations
19780
+ }));
19781
+ }
19715
19782
  function createAcpDriver(support11) {
19716
19783
  const DRIVER_KIND8 = support11.driverKind;
19717
19784
  const SOURCE = support11.nativeSource;
@@ -19755,6 +19822,7 @@ function createAcpDriver(support11) {
19755
19822
  if (support11.resolveModelsOnCreate !== false) await refreshModels();
19756
19823
  const listeners = /* @__PURE__ */ new Set();
19757
19824
  const active = /* @__PURE__ */ new Map();
19825
+ const sessionAllows = /* @__PURE__ */ new Map();
19758
19826
  const emit = (event) => {
19759
19827
  for (const listener of listeners) listener(event);
19760
19828
  };
@@ -19972,10 +20040,10 @@ function createAcpDriver(support11) {
19972
20040
  }
19973
20041
  };
19974
20042
  const flushAssistantText = () => {
19975
- const text3 = state.text;
20043
+ const text4 = state.text;
19976
20044
  state.text = "";
19977
- if (!text3.trim()) return;
19978
- emit({ ...base2(threadId, turnId), type: "item.completed", itemType: "assistant_text", text: text3 });
20045
+ if (!text4.trim()) return;
20046
+ emit({ ...base2(threadId, turnId), type: "item.completed", itemType: "assistant_text", text: text4 });
19979
20047
  };
19980
20048
  const settle = (ok, stopReason) => {
19981
20049
  if (state.settled) return;
@@ -20004,6 +20072,7 @@ function createAcpDriver(support11) {
20004
20072
  flushAssistantText();
20005
20073
  const options = Array.isArray(params.options) ? params.options : [];
20006
20074
  const optionFor = (want) => options.find((o) => o.kind === `${want}_once` && typeof o.optionId === "string")?.optionId ?? options.find((o) => String(o.kind ?? "").startsWith(want) && typeof o.optionId === "string")?.optionId ?? null;
20075
+ const optionAlways = options.find((o) => o.kind === "allow_always" && typeof o.optionId === "string")?.optionId ?? null;
20007
20076
  const cancelled = { outcome: { outcome: "cancelled" } };
20008
20077
  const missing = (want) => emit({
20009
20078
  ...base2(threadId, turnId),
@@ -20022,15 +20091,28 @@ function createAcpDriver(support11) {
20022
20091
  });
20023
20092
  }
20024
20093
  const kind = String(toolCall.kind ?? "");
20094
+ const operationKey = isQuestion || controlsHost ? null : sessionOperationKey(toolCall);
20095
+ if (operationKey && sessionAllows.get(threadId)?.has(operationKey)) {
20096
+ const allow = optionFor("allow");
20097
+ if (allow) {
20098
+ return send({ jsonrpc: "2.0", id: msg.id, result: { outcome: { outcome: "selected", optionId: allow } } });
20099
+ }
20100
+ }
20025
20101
  const tool = kind === "execute" ? "shell" : kind === "edit" ? "edit" : kind || "tool";
20026
20102
  const summary = String(toolCall.rawInput?.command ?? toolCall.title ?? tool).slice(0, 200);
20027
20103
  const requestId = newId();
20028
- const finish = (behavior, source = "user", message2) => {
20104
+ const finish = (behavior, source = "user", message2, always) => {
20029
20105
  if (!asks.delete(requestId)) return;
20030
20106
  clearTimeout(timer);
20031
20107
  const want = behavior === "allow" ? "allow" : "reject";
20108
+ const forSession = want === "allow" && always === true && !isQuestion && !controlsHost;
20032
20109
  const named = isQuestion && behavior === "answer" ? options.filter((option) => option.optionId === message2 || option.name?.trim() === message2) : [];
20033
- const optionId = behavior === "cancel" ? null : isQuestion ? named.length === 1 && typeof named[0].optionId === "string" ? named[0].optionId : null : optionFor(want);
20110
+ const optionId = behavior === "cancel" ? null : isQuestion ? named.length === 1 && typeof named[0].optionId === "string" ? named[0].optionId : null : forSession ? optionAlways ?? optionFor("allow") : optionFor(want);
20111
+ if (forSession && !optionAlways && optionId && operationKey) {
20112
+ const remembered = sessionAllows.get(threadId) ?? /* @__PURE__ */ new Set();
20113
+ remembered.add(operationKey);
20114
+ sessionAllows.set(threadId, remembered);
20115
+ }
20034
20116
  if (behavior !== "cancel" && !optionId) missing(isQuestion ? "matching answer" : want);
20035
20117
  send({
20036
20118
  jsonrpc: "2.0",
@@ -20060,7 +20142,9 @@ function createAcpDriver(support11) {
20060
20142
  tool,
20061
20143
  summary,
20062
20144
  choices: isQuestion ? options.flatMap((option) => typeof option.name === "string" && option.name.trim() ? [option.name.trim()] : []) : void 0,
20063
- approvalScope: controlsHost ? "local-computer" : void 0
20145
+ approvalScope: controlsHost ? "local-computer" : void 0,
20146
+ // the driver can honor a session-wide allow either way
20147
+ allowSession: !isQuestion && !controlsHost ? true : void 0
20064
20148
  });
20065
20149
  };
20066
20150
  const handleNotification = (msg) => {
@@ -20215,13 +20299,14 @@ function createAcpDriver(support11) {
20215
20299
  }
20216
20300
  }
20217
20301
  const images = turn.images ?? [];
20218
- const runtimeAcceptsImages = init?.agentCapabilities?.promptCapabilities?.image === true;
20302
+ const runtimeAcceptsImages = init?.agentCapabilities?.promptCapabilities?.image === true || support11.acceptsUnadvertisedImages?.(init) === true;
20219
20303
  if (images.length && support11.images === true && !runtimeAcceptsImages) {
20220
20304
  throw new Error(
20221
20305
  `${support11.displayName} is configured for image attachments, but this installed runtime does not advertise ACP image input. Update the ${support11.displayName} CLI or send the message without an image.`
20222
20306
  );
20223
20307
  }
20224
20308
  const cursor3 = typeof turn.resumeCursor === "string" ? turn.resumeCursor : null;
20309
+ if (!cursor3) sessionAllows.delete(threadId);
20225
20310
  let sessionResult = null;
20226
20311
  if (cursor3) {
20227
20312
  try {
@@ -20287,13 +20372,13 @@ function createAcpDriver(support11) {
20287
20372
  }
20288
20373
  emitSessionStarted();
20289
20374
  state.promptSent = true;
20290
- const text3 = support11.buildPromptText ? support11.buildPromptText(turn) : turn.system ? `${turn.system}
20375
+ const text4 = support11.buildPromptText ? support11.buildPromptText(turn) : turn.system ? `${turn.system}
20291
20376
 
20292
20377
  ${turn.text}` : turn.text;
20293
20378
  const imageBlocks = support11.images === true && runtimeAcceptsImages ? await readAcpImageBlocks(images) : [];
20294
20379
  const result = await request("session/prompt", {
20295
20380
  sessionId,
20296
- prompt: [{ type: "text", text: text3 }, ...imageBlocks]
20381
+ prompt: [{ type: "text", text: text4 }, ...imageBlocks]
20297
20382
  });
20298
20383
  const usage = result?.usage ?? result?._meta ?? {};
20299
20384
  if (typeof usage.inputTokens === "number" || typeof usage.outputTokens === "number") {
@@ -20380,7 +20465,7 @@ ${turn.text}` : turn.text;
20380
20465
  const turn = active.get(threadId);
20381
20466
  const finish = turn?.asks.get(requestId);
20382
20467
  if (!finish) return "unavailable";
20383
- finish(decision.behavior, "user", decision.message);
20468
+ finish(decision.behavior, "user", decision.message, decision.always === true);
20384
20469
  return decision.behavior === "allow" ? "allowed-once" : decision.behavior === "answer" ? "answered" : "rejected";
20385
20470
  },
20386
20471
  hasSession: (threadId) => active.has(threadId),
@@ -20715,6 +20800,7 @@ var init_antigravity_acp = __esm({
20715
20800
  startupDiagnosticBytes = 0;
20716
20801
  nativeStartupHint;
20717
20802
  closed = false;
20803
+ stopping;
20718
20804
  onAuthorizationUrl;
20719
20805
  /** Settles once the runtime process is gone. On Windows a running
20720
20806
  * executable pins its file and its directory, so an installer must not
@@ -20839,10 +20925,10 @@ var init_antigravity_acp = __esm({
20839
20925
  if (this.closed) return;
20840
20926
  this.closed = true;
20841
20927
  this.failAll(new Error("Antigravity ACP was closed."));
20842
- killCliTree(this.child);
20928
+ this.stopping = killCliTree(this.child);
20843
20929
  }
20844
- /** Close, then wait (bounded) for the process to be gone. */
20845
- async closeAndWait(timeoutMs = 5e3) {
20930
+ /** Allow the shared 5s TERM grace and 1s force-stop verification to finish. */
20931
+ async closeAndWait(timeoutMs = 7e3) {
20846
20932
  this.close();
20847
20933
  let timer;
20848
20934
  const timedOut = new Promise((resolve13) => {
@@ -20850,7 +20936,7 @@ var init_antigravity_acp = __esm({
20850
20936
  timer.unref?.();
20851
20937
  });
20852
20938
  try {
20853
- return await Promise.race([this.exited.then(() => true), timedOut]);
20939
+ return await Promise.race([this.stopping, timedOut]);
20854
20940
  } finally {
20855
20941
  clearTimeout(timer);
20856
20942
  }
@@ -21373,8 +21459,9 @@ var init_antigravity_runtime = __esm({
21373
21459
  });
21374
21460
 
21375
21461
  // server/drivers/antigravity.ts
21376
- function antigravityPermissionMode(fullAuto) {
21377
- return fullAuto ? "yolo" : "default";
21462
+ function antigravityPermissionMode(fullAuto, approvalMode) {
21463
+ if (fullAuto) return "yolo";
21464
+ return approvalMode === "edits" ? "auto_edit" : "default";
21378
21465
  }
21379
21466
  var STATIC_ANTIGRAVITY_MODELS, managedAsset, support, AcpAntigravityDriver, AntigravityDriver;
21380
21467
  var init_antigravity = __esm({
@@ -21458,8 +21545,8 @@ var init_antigravity = __esm({
21458
21545
  return { state: "unavailable", reason: error51 instanceof Error ? error51.message : String(error51) };
21459
21546
  }
21460
21547
  },
21461
- configureSession: async ({ request, sessionId, config: config2 }) => {
21462
- const wanted = antigravityPermissionMode(config2.fullAuto);
21548
+ configureSession: async ({ request, sessionId, config: config2, turn }) => {
21549
+ const wanted = antigravityPermissionMode(config2.fullAuto, turn.approvalMode);
21463
21550
  const result = await request("session/set_config_option", {
21464
21551
  sessionId,
21465
21552
  configId: "mode",
@@ -21619,14 +21706,14 @@ var init_boxagent = __esm({
21619
21706
  let lastText = "";
21620
21707
  let pendingText = "";
21621
21708
  const flushAssistantText = () => {
21622
- const text3 = pendingText;
21709
+ const text4 = pendingText;
21623
21710
  pendingText = "";
21624
- if (!text3.trim()) return;
21625
- emit({ ...base2(threadId, turnId), type: "item.completed", itemType: "assistant_text", text: text3 });
21711
+ if (!text4.trim()) return;
21712
+ emit({ ...base2(threadId, turnId), type: "item.completed", itemType: "assistant_text", text: text4 });
21626
21713
  };
21627
- const ingest = (text3) => {
21628
- const delta = text3.startsWith(lastText) ? text3.slice(lastText.length) : text3;
21629
- lastText = text3;
21714
+ const ingest = (text4) => {
21715
+ const delta = text4.startsWith(lastText) ? text4.slice(lastText.length) : text4;
21716
+ lastText = text4;
21630
21717
  if (!delta) return;
21631
21718
  pendingText += delta;
21632
21719
  emit({ ...base2(threadId, turnId), type: "content.delta", streamKind: "assistant_text", delta });
@@ -21643,9 +21730,9 @@ var init_boxagent = __esm({
21643
21730
  seen.add(id);
21644
21731
  appendNative(threadId, { dir: "in", source: "box.events", msg: ev });
21645
21732
  const kind = String(ev.type ?? ev.kind ?? "");
21646
- const text3 = ev.text ?? ev.message ?? ev.data?.text ?? ev.data?.content ?? null;
21647
- if (/assistant|message|output|response/i.test(kind) && typeof text3 === "string" && text3.trim()) {
21648
- ingest(text3);
21733
+ const text4 = ev.text ?? ev.message ?? ev.data?.text ?? ev.data?.content ?? null;
21734
+ if (/assistant|message|output|response/i.test(kind) && typeof text4 === "string" && text4.trim()) {
21735
+ ingest(text4);
21649
21736
  } else if (/tool|command|exec|browse/i.test(kind)) {
21650
21737
  flushAssistantText();
21651
21738
  emit({
@@ -22185,25 +22272,36 @@ var init_mcp_gate_config = __esm({
22185
22272
  }
22186
22273
  });
22187
22274
 
22275
+ // shared/provider-safety.ts
22276
+ function isProviderSafetyBlock(message2) {
22277
+ return /\bblocked by (?:our|the provider['’]s) safety systems\b|\bsafety monitoring\b.{0,100}\b(?:paused|ended|blocked)\b|\b(?:safety_check_failed|safety_policy_violation)\b/i.test(message2);
22278
+ }
22279
+ var init_provider_safety = __esm({
22280
+ "shared/provider-safety.ts"() {
22281
+ "use strict";
22282
+ }
22283
+ });
22284
+
22188
22285
  // server/drivers/retry.ts
22189
22286
  function classifyError(err) {
22190
- const text3 = messageOf(err);
22287
+ const text4 = messageOf(err);
22288
+ if (isProviderSafetyBlock(text4)) return { transient: false, reason: "provider_safety" };
22191
22289
  if (err && "exitCode" in err) {
22192
22290
  const { exitCode: code } = err;
22193
22291
  if (code !== null && code < 0) return { transient: false, reason: "interrupted" };
22194
22292
  for (const { pattern, reason } of TRANSIENT_PATTERNS) {
22195
- if (pattern.test(text3)) return { transient: true, reason };
22293
+ if (pattern.test(text4)) return { transient: true, reason };
22196
22294
  }
22197
22295
  for (const { pattern, reason } of TERMINAL_PATTERNS) {
22198
- if (pattern.test(text3)) return { transient: false, reason };
22296
+ if (pattern.test(text4)) return { transient: false, reason };
22199
22297
  }
22200
22298
  return { transient: false, reason: "terminal_exit" };
22201
22299
  }
22202
22300
  for (const { pattern, reason } of TERMINAL_PATTERNS) {
22203
- if (pattern.test(text3)) return { transient: false, reason };
22301
+ if (pattern.test(text4)) return { transient: false, reason };
22204
22302
  }
22205
22303
  for (const { pattern, reason } of TRANSIENT_PATTERNS) {
22206
- if (pattern.test(text3)) return { transient: true, reason };
22304
+ if (pattern.test(text4)) return { transient: true, reason };
22207
22305
  }
22208
22306
  return { transient: false, reason: "unknown" };
22209
22307
  }
@@ -22234,6 +22332,7 @@ var RETRY_MAX_ATTEMPTS, BACKOFF_BASE_MS, TRANSIENT_PATTERNS, TERMINAL_PATTERNS,
22234
22332
  var init_retry = __esm({
22235
22333
  "server/drivers/retry.ts"() {
22236
22334
  "use strict";
22335
+ init_provider_safety();
22237
22336
  RETRY_MAX_ATTEMPTS = 3;
22238
22337
  BACKOFF_BASE_MS = [1e3, 3e3, 8e3];
22239
22338
  TRANSIENT_PATTERNS = [
@@ -22268,6 +22367,82 @@ var init_retry = __esm({
22268
22367
  }
22269
22368
  });
22270
22369
 
22370
+ // shared/ask-question.ts
22371
+ function text3(value, limit) {
22372
+ if (typeof value !== "string") return void 0;
22373
+ const trimmed = value.trim();
22374
+ return trimmed ? trimmed.slice(0, limit) : void 0;
22375
+ }
22376
+ function isRecord(value) {
22377
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22378
+ }
22379
+ function parseOption(value) {
22380
+ if (typeof value === "string") {
22381
+ const label2 = text3(value, MAX_LABEL);
22382
+ return label2 ? { label: label2 } : null;
22383
+ }
22384
+ if (!isRecord(value)) return null;
22385
+ const label = text3(value.label, MAX_LABEL);
22386
+ if (!label) return null;
22387
+ const description = text3(value.description, MAX_DESCRIPTION);
22388
+ return description ? { label, description } : { label };
22389
+ }
22390
+ function parseQuestion(value) {
22391
+ if (!isRecord(value)) return null;
22392
+ const question = text3(value.question, MAX_QUESTION_TEXT);
22393
+ if (!question) return null;
22394
+ const options = [];
22395
+ const seen = /* @__PURE__ */ new Set();
22396
+ for (const raw of Array.isArray(value.options) ? value.options : []) {
22397
+ const option = parseOption(raw);
22398
+ if (!option || seen.has(option.label)) continue;
22399
+ seen.add(option.label);
22400
+ options.push(option);
22401
+ if (options.length === MAX_OPTIONS) break;
22402
+ }
22403
+ const header = text3(value.header, MAX_LABEL);
22404
+ return {
22405
+ question,
22406
+ ...header ? { header } : {},
22407
+ ...value.multiSelect === true ? { multiSelect: true } : {},
22408
+ options
22409
+ };
22410
+ }
22411
+ function parseAskQuestions(input) {
22412
+ if (!isRecord(input) || !Array.isArray(input.questions)) return null;
22413
+ const questions = [];
22414
+ for (const raw of input.questions) {
22415
+ const question = parseQuestion(raw);
22416
+ if (!question) continue;
22417
+ questions.push(question);
22418
+ if (questions.length === MAX_QUESTIONS) break;
22419
+ }
22420
+ return questions.length ? questions : null;
22421
+ }
22422
+ function askQuestionSummary(questions) {
22423
+ const first = questions[0]?.question ?? "";
22424
+ const rest = questions.length - 1;
22425
+ return rest > 0 ? `${first} (+${rest} more question${rest > 1 ? "s" : ""})` : first;
22426
+ }
22427
+ function questionChoices(questions) {
22428
+ if (questions.length !== 1) return void 0;
22429
+ const only = questions[0];
22430
+ if (only.multiSelect || only.options.length < 2) return void 0;
22431
+ return only.options.map((option) => option.label);
22432
+ }
22433
+ var ASK_USER_QUESTION_TOOL, MAX_QUESTIONS, MAX_OPTIONS, MAX_QUESTION_TEXT, MAX_LABEL, MAX_DESCRIPTION;
22434
+ var init_ask_question = __esm({
22435
+ "shared/ask-question.ts"() {
22436
+ "use strict";
22437
+ ASK_USER_QUESTION_TOOL = "AskUserQuestion";
22438
+ MAX_QUESTIONS = 6;
22439
+ MAX_OPTIONS = 12;
22440
+ MAX_QUESTION_TEXT = 400;
22441
+ MAX_LABEL = 120;
22442
+ MAX_DESCRIPTION = 400;
22443
+ }
22444
+ });
22445
+
22271
22446
  // server/drivers/claude.ts
22272
22447
  import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
22273
22448
  import { chmodSync as chmodSync4, mkdtempSync as mkdtempSync2, readFileSync as readFileSync8, rmSync as rmSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
@@ -22308,9 +22483,9 @@ function resolveClaudeConfigDir(configDir, env = process.env) {
22308
22483
  }
22309
22484
  return normalize(expanded);
22310
22485
  }
22311
- function claudeAuthFailure(frame, text3) {
22486
+ function claudeAuthFailure(frame, text4) {
22312
22487
  if (frame.is_api_error_message !== true && typeof frame.error !== "string") return false;
22313
- return frame.error === "authentication_failed" || classifyError({ text: text3 }).reason === "auth";
22488
+ return frame.error === "authentication_failed" || classifyError({ text: text4 }).reason === "auth";
22314
22489
  }
22315
22490
  function claudeEnvironment(model, source = process.env, configDir, instanceEnvironment = {}) {
22316
22491
  const env = { ...source, PATH: augmentedPath(), NPM_CONFIG_LOGLEVEL: "error" };
@@ -22334,6 +22509,24 @@ function claudeEnvironment(model, source = process.env, configDir, instanceEnvir
22334
22509
  function inheritsUserConfig(env) {
22335
22510
  return env.OMB_CLAUDE_INHERIT_USER_CONFIG === "1";
22336
22511
  }
22512
+ function readClaudeAuthSettings(env, instanceEnvironment = {}) {
22513
+ if (CLAUDE_ACCOUNT_ENV_KEYS.some((key) => instanceEnvironment[key])) return {};
22514
+ try {
22515
+ const settings2 = JSON.parse(readFileSync8(join20(resolveClaudeConfigDir(void 0, env), "settings.json"), "utf8"));
22516
+ const authEnv = {};
22517
+ for (const key of CLAUDE_ACCOUNT_ENV_KEYS) {
22518
+ if (!key.endsWith("_FILE_DESCRIPTOR") && typeof settings2?.env?.[key] === "string") {
22519
+ authEnv[key] = settings2.env[key];
22520
+ }
22521
+ }
22522
+ return {
22523
+ ...Object.keys(authEnv).length ? { env: authEnv } : {},
22524
+ ...typeof settings2?.apiKeyHelper === "string" && settings2.apiKeyHelper.trim() ? { apiKeyHelper: settings2.apiKeyHelper } : {}
22525
+ };
22526
+ } catch {
22527
+ return {};
22528
+ }
22529
+ }
22337
22530
  function projectMcpServers(cwd) {
22338
22531
  let parsed;
22339
22532
  try {
@@ -22438,7 +22631,12 @@ function removePrivateTempDir(filePath) {
22438
22631
  function systemEndedReply(kind) {
22439
22632
  return kind === "question" ? { behavior: "answer", message: "OpenMausBot: the turn is ending \u2014 wrap up." } : { behavior: "deny", message: "OpenMausBot: the turn ended" };
22440
22633
  }
22634
+ function askQuestions(ask) {
22635
+ return ask.tool === ASK_USER_QUESTION_TOOL ? parseAskQuestions(ask.input) : null;
22636
+ }
22441
22637
  function askSummary(ask) {
22638
+ const questions = askQuestions(ask);
22639
+ if (questions) return askQuestionSummary(questions).slice(0, 300);
22442
22640
  return askInputSummary(ask.input) ?? ask.tool ?? "tool";
22443
22641
  }
22444
22642
  function permissionSocketPath(threadId) {
@@ -22505,11 +22703,13 @@ async function createPermissionBroker(opts) {
22505
22703
  continue;
22506
22704
  }
22507
22705
  const ask = { id: askId, kind, tool: msg.tool ?? "tool", input: msg.input ?? {}, at: Date.now() };
22508
- const finish = (behavior, message2, source) => {
22706
+ const finish = (behavior, message2, source, always) => {
22509
22707
  if (!pending.delete(askId)) return;
22510
22708
  clearTimeout(timer);
22511
22709
  try {
22512
- conn.write(JSON.stringify({ t: "answer", id: askId, behavior, message: message2 }) + "\n");
22710
+ conn.write(
22711
+ JSON.stringify({ t: "answer", id: askId, behavior, message: message2, source, ...always ? { always: true } : {} }) + "\n"
22712
+ );
22513
22713
  } catch {
22514
22714
  }
22515
22715
  opts.onResolve({ ...ask, behavior, source });
@@ -22579,11 +22779,11 @@ async function createPermissionBroker(opts) {
22579
22779
  }
22580
22780
  };
22581
22781
  return {
22582
- answer(askId, behavior, message2) {
22782
+ answer(askId, behavior, message2, always) {
22583
22783
  const p = pending.get(askId);
22584
22784
  if (!p) return false;
22585
22785
  if (p.ask.kind === "question" ? behavior !== "answer" : behavior === "answer") return false;
22586
- p.finish(behavior, message2, "user");
22786
+ p.finish(behavior, message2, "user", always && behavior === "allow");
22587
22787
  return true;
22588
22788
  },
22589
22789
  pause() {
@@ -22648,19 +22848,19 @@ function firstText(content) {
22648
22848
  }
22649
22849
  return "";
22650
22850
  }
22651
- function withVolatileNote(text3, volatile) {
22851
+ function withVolatileNote(text4, volatile) {
22652
22852
  const body = volatile.trim() ? `This part of your instructions changed since this session started. It replaces the earlier copy:
22653
22853
 
22654
22854
  ${volatile.trim()}` : "The notes that were in your instructions when this session started have been cleared.";
22655
22855
  const note = `<system-reminder>
22656
22856
  ${body}
22657
22857
  </system-reminder>`;
22658
- return text3 ? `${note}
22858
+ return text4 ? `${note}
22659
22859
 
22660
- ${text3}` : note;
22860
+ ${text4}` : note;
22661
22861
  }
22662
- function claudeUserMessage(text3, images) {
22663
- if (!images?.length) return { type: "user", message: { role: "user", content: text3 } };
22862
+ function claudeUserMessage(text4, images) {
22863
+ if (!images?.length) return { type: "user", message: { role: "user", content: text4 } };
22664
22864
  const content = images.map((image) => ({
22665
22865
  type: "image",
22666
22866
  source: {
@@ -22669,7 +22869,7 @@ function claudeUserMessage(text3, images) {
22669
22869
  data: readFileSync8(image.path).toString("base64")
22670
22870
  }
22671
22871
  }));
22672
- if (text3) content.push({ type: "text", text: text3 });
22872
+ if (text4) content.push({ type: "text", text: text4 });
22673
22873
  return { type: "user", message: { role: "user", content } };
22674
22874
  }
22675
22875
  function diagnosticClaudeUserMessage(message2) {
@@ -22707,6 +22907,7 @@ var init_claude = __esm({
22707
22907
  init_local_inject();
22708
22908
  init_native();
22709
22909
  init_proxy_paths();
22910
+ init_ask_question();
22710
22911
  CLAUDE_ACCOUNT_ENV_KEYS = [
22711
22912
  "CLAUDE_CODE_OAUTH_TOKEN",
22712
22913
  "CLAUDE_CODE_OAUTH_REFRESH_TOKEN",
@@ -22785,6 +22986,11 @@ var init_claude = __esm({
22785
22986
  const configuredIdleMinimum = Number(process.env.OMB_CLAUDE_SESSION_IDLE_MIN_MS);
22786
22987
  const sessionIdleMinimum = Number.isFinite(configuredIdleMinimum) && configuredIdleMinimum > 0 ? configuredIdleMinimum : 1e4;
22787
22988
  const SESSION_IDLE_MS = Math.max(sessionIdleMinimum, Number(process.env.OMB_CLAUDE_SESSION_IDLE_MS) || 10 * 6e4);
22989
+ const stopSession = (session) => {
22990
+ void killCliTree(session.child).then((stopped) => {
22991
+ if (stopped) void session.finishClose?.();
22992
+ });
22993
+ };
22788
22994
  const closeSession = (threadId, why) => {
22789
22995
  const s = sessions.get(threadId);
22790
22996
  if (!s || s.closing) return;
@@ -22799,7 +23005,7 @@ var init_claude = __esm({
22799
23005
  } catch {
22800
23006
  }
22801
23007
  const kill = setTimeout(() => {
22802
- if (s.child.exitCode === null) killCliTree(s.child);
23008
+ stopSession(s);
22803
23009
  }, 5e3);
22804
23010
  kill.unref?.();
22805
23011
  };
@@ -22842,7 +23048,7 @@ var init_claude = __esm({
22842
23048
  const sendTurn = async (turn) => {
22843
23049
  const { threadId } = turn;
22844
23050
  if (active.has(threadId)) throw new Error("a turn is already running on this thread");
22845
- const permissionMode = turn.approvalMode === void 0 ? config2.permissionMode : turn.approvalMode === "full" ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : "default";
23051
+ const permissionMode = turn.approvalMode === void 0 ? config2.permissionMode : turn.approvalMode === "full" ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : turn.approvalMode === "edits" ? "acceptEdits" : "default";
22846
23052
  const controlsHost = turn.integrations?.localComputer?.scope === "local-computer";
22847
23053
  if (controlsHost && permissionMode === "bypassPermissions" && turn.approvalMode !== "full") {
22848
23054
  throw new Error("local computer control requires the interactive approval broker");
@@ -22966,9 +23172,12 @@ var init_claude = __esm({
22966
23172
  args.push("--allowedTools", allowed.join(","));
22967
23173
  }
22968
23174
  const env = environment(turnModel);
23175
+ const authSettings = isolated && !injected.injected ? readClaudeAuthSettings(env, input.environment) : {};
23176
+ const authSettingsPath = mcpConfigPath && Object.keys(authSettings).length ? join20(dirname9(mcpConfigPath), "auth-settings.json") : null;
23177
+ if (authSettingsPath) args.push("--settings", authSettingsPath);
22969
23178
  env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS = "1";
22970
23179
  const cwd = turn.cwd ?? homedir9();
22971
- const privateFileFlags = /* @__PURE__ */ new Set(["--mcp-config"]);
23180
+ const privateFileFlags = /* @__PURE__ */ new Set(["--mcp-config", "--settings"]);
22972
23181
  const keyArgs = args.filter((a2, i2) => !privateFileFlags.has(a2) && !privateFileFlags.has(args[i2 - 1] ?? ""));
22973
23182
  const argsKey = JSON.stringify({
22974
23183
  args: keyArgs,
@@ -22979,7 +23188,12 @@ var init_claude = __esm({
22979
23188
  cwd,
22980
23189
  model: injected.model ?? null,
22981
23190
  base: env.ANTHROPIC_BASE_URL ?? null,
22982
- configDir: env.CLAUDE_CONFIG_DIR ?? null
23191
+ configDir: env.CLAUDE_CONFIG_DIR ?? null,
23192
+ // Rotating an account's key/helper must not reuse the old process.
23193
+ auth: createHash5("sha256").update(JSON.stringify({
23194
+ settings: authSettings,
23195
+ env: Object.fromEntries(CLAUDE_ACCOUNT_ENV_KEYS.map((key) => [key, env[key]]))
23196
+ })).digest("hex")
22983
23197
  });
22984
23198
  const live = sessions.get(threadId);
22985
23199
  if (live && !live.turn && !live.closing && live.child.exitCode === null && live.argsKey === argsKey && (!sessionId || sessionId === live.sessionId)) {
@@ -22987,7 +23201,7 @@ var init_claude = __esm({
22987
23201
  live.turn = { turnId, settled: false, sawStreamDelta: false };
22988
23202
  active.set(threadId, { stop: () => {
22989
23203
  closeSession(threadId, "interrupted");
22990
- killCliTree(live.child);
23204
+ stopSession(live);
22991
23205
  }, turnId, broker: live.broker });
22992
23206
  emit({ ...base2(threadId, turnId), type: "turn.started" });
22993
23207
  const volatile = turn.systemVolatile ?? "";
@@ -23046,6 +23260,9 @@ var init_claude = __esm({
23046
23260
  onAsk: (ask) => {
23047
23261
  const eventTurnId = sessions.get(threadId)?.turn?.turnId ?? turnId;
23048
23262
  askTools.set(ask.id, typeof ask.tool === "string" ? ask.tool : void 0);
23263
+ const nativeMode = sessions.get(threadId)?.nativePermissionMode ?? null;
23264
+ const nativeReview = permissionMode === "auto" && nativeMode !== null ? nativeMode === "auto" ? "active" : "inactive" : void 0;
23265
+ const questions = askQuestions(ask);
23049
23266
  emit({
23050
23267
  ...base2(threadId, eventTurnId),
23051
23268
  type: "request.opened",
@@ -23053,8 +23270,15 @@ var init_claude = __esm({
23053
23270
  requestType: ask.kind,
23054
23271
  tool: ask.tool,
23055
23272
  summary: askSummary(ask),
23273
+ nativeReview,
23274
+ // the proxy hands Claude its own suggested rules on `always`;
23275
+ // host control stays one action at a time
23276
+ allowSession: ask.kind === "permission" && !(controlsHost && typeof ask.tool === "string" && ask.tool.startsWith("mcp__computer")) ? true : void 0,
23056
23277
  approvalScope: typeof ask.tool === "string" && controlsHost && ask.tool.startsWith("mcp__computer") ? "local-computer" : void 0,
23057
- choices: Array.isArray(ask.input?.choices) ? ask.input.choices.slice(0, 5) : void 0
23278
+ questions: questions ?? void 0,
23279
+ // A structured ask still offers flat labels, for the phone
23280
+ // companions and any client that predates the question card.
23281
+ choices: questions ? questionChoices(questions) : Array.isArray(ask.input?.choices) ? ask.input.choices.slice(0, 5) : void 0
23058
23282
  });
23059
23283
  },
23060
23284
  onResolve: (resolved) => {
@@ -23077,6 +23301,9 @@ var init_claude = __esm({
23077
23301
  if (mcpConfigPath) {
23078
23302
  writeFileSync6(mcpConfigPath, JSON.stringify({ mcpServers }), { mode: 384 });
23079
23303
  }
23304
+ if (authSettingsPath) {
23305
+ writeFileSync6(authSettingsPath, JSON.stringify(authSettings), { mode: 384 });
23306
+ }
23080
23307
  if (sessionId) args.push("--resume", sessionId);
23081
23308
  else args.push("--session-id", newSessionId);
23082
23309
  } catch (error51) {
@@ -23103,6 +23330,7 @@ var init_claude = __esm({
23103
23330
  volatile: turn.systemVolatile ?? "",
23104
23331
  sessionId: sessionId ?? newSessionId,
23105
23332
  sawInit: false,
23333
+ nativePermissionMode: null,
23106
23334
  turn: { turnId, settled: false, sawStreamDelta: false },
23107
23335
  idleTimer: null,
23108
23336
  closing: false,
@@ -23132,6 +23360,7 @@ var init_claude = __esm({
23132
23360
  };
23133
23361
  const currentTurnId = () => session.turn?.turnId ?? turnId;
23134
23362
  const handleLine = (line) => {
23363
+ if (session.closing) return;
23135
23364
  let o;
23136
23365
  try {
23137
23366
  o = JSON.parse(line);
@@ -23143,6 +23372,7 @@ var init_claude = __esm({
23143
23372
  case "system":
23144
23373
  if (o.subtype === "init") {
23145
23374
  session.sawInit = true;
23375
+ session.nativePermissionMode = typeof o.permissionMode === "string" ? o.permissionMode : null;
23146
23376
  if (typeof o.session_id === "string") session.sessionId = o.session_id;
23147
23377
  emit({ ...base2(threadId, currentTurnId()), type: "session.started", sessionId: o.session_id, model: o.model });
23148
23378
  } else if (o.subtype === "thinking_tokens") {
@@ -23164,18 +23394,18 @@ var init_claude = __esm({
23164
23394
  }
23165
23395
  case "assistant": {
23166
23396
  const msg = o.message ?? {};
23167
- const text3 = firstText(msg.content);
23168
- if (claudeAuthFailure(o, text3)) {
23397
+ const text4 = firstText(msg.content);
23398
+ if (claudeAuthFailure(o, text4)) {
23169
23399
  if (session.turn) session.turn.authFailed = true;
23170
- emit({ ...base2(threadId, currentTurnId()), type: "runtime.error", message: text3, setup: true });
23400
+ emit({ ...base2(threadId, currentTurnId()), type: "runtime.error", message: text4, setup: true });
23171
23401
  break;
23172
23402
  }
23173
- if (text3.trim()) {
23403
+ if (text4.trim()) {
23174
23404
  if (!session.turn?.sawStreamDelta) {
23175
- emit({ ...base2(threadId, currentTurnId()), type: "content.delta", streamKind: "assistant_text", delta: text3 });
23405
+ emit({ ...base2(threadId, currentTurnId()), type: "content.delta", streamKind: "assistant_text", delta: text4 });
23176
23406
  }
23177
23407
  if (session.turn) session.turn.sawStreamDelta = false;
23178
- emit({ ...base2(threadId, currentTurnId()), type: "item.completed", itemType: "assistant_text", text: text3 });
23408
+ emit({ ...base2(threadId, currentTurnId()), type: "item.completed", itemType: "assistant_text", text: text4 });
23179
23409
  }
23180
23410
  for (const b of Array.isArray(msg.content) ? msg.content : []) {
23181
23411
  if (b.type === "tool_use") {
@@ -23241,7 +23471,17 @@ var init_claude = __esm({
23241
23471
  emit({ ...base2(threadId, currentTurnId()), type: "runtime.error", ...describeSpawnFailure(e, config2.cli) });
23242
23472
  settle(false, "spawn_error");
23243
23473
  });
23244
- child.on("close", (code) => {
23474
+ let closeFinalized = false;
23475
+ const finalizeClose = async (code) => {
23476
+ if (closeFinalized) return;
23477
+ if (!await killCliTree(child, 0)) {
23478
+ session.broker?.close();
23479
+ session.broker = void 0;
23480
+ emit({ ...base2(threadId, currentTurnId()), type: "runtime.error", message: "Claude could not be confirmed stopped; its helper processes may still be running." });
23481
+ return;
23482
+ }
23483
+ if (closeFinalized) return;
23484
+ closeFinalized = true;
23245
23485
  if (session.turn && !session.turn.settled) {
23246
23486
  const message2 = `claude exited ${code} before result${session.stderr ? `: ${session.stderr.trim().slice(-300)}` : ""}`;
23247
23487
  const verdict = classifyError({ exitCode: code, stderr: message2 });
@@ -23377,12 +23617,16 @@ var init_claude = __esm({
23377
23617
  }
23378
23618
  removePrivateTempDir(session.systemPromptPath);
23379
23619
  if (sessions.get(threadId) === session) sessions.delete(threadId);
23620
+ };
23621
+ child.on("close", (code) => {
23622
+ session.finishClose = () => finalizeClose(code);
23623
+ void session.finishClose();
23380
23624
  });
23381
23625
  const stop = () => {
23382
23626
  closeSession(threadId, "interrupted");
23383
23627
  retry.cancelled = true;
23384
23628
  retryAbort.abort();
23385
- killCliTree(child);
23629
+ stopSession(session);
23386
23630
  };
23387
23631
  active.set(threadId, { stop, turnId, broker });
23388
23632
  emit({ ...base2(threadId, turnId), type: "turn.started" });
@@ -23392,10 +23636,10 @@ var init_claude = __esm({
23392
23636
  }
23393
23637
  return { turnId };
23394
23638
  };
23395
- const steer = async (threadId, text3) => {
23639
+ const steer = async (threadId, text4) => {
23396
23640
  const s = sessions.get(threadId);
23397
23641
  if (!s || !s.turn || s.turn.settled || s.closing || s.child.exitCode !== null) return false;
23398
- return writeUser(s, threadId, claudeUserMessage(text3, void 0));
23642
+ return writeUser(s, threadId, claudeUserMessage(text4, void 0));
23399
23643
  };
23400
23644
  const login = new ClaudeLoginController({ cli: config2.cli, environment, onAuthenticated: async () => {
23401
23645
  await refreshModels();
@@ -23508,7 +23752,7 @@ var init_claude = __esm({
23508
23752
  const broker = sessions.get(threadId)?.broker ?? active.get(threadId)?.broker;
23509
23753
  if (!broker) return "unavailable";
23510
23754
  const behavior = decision.behavior === "answer" ? "answer" : decision.behavior;
23511
- if (!broker.answer(requestId, behavior, decision.message)) return "unavailable";
23755
+ if (!broker.answer(requestId, behavior, decision.message, decision.always)) return "unavailable";
23512
23756
  return behavior === "allow" ? "allowed-once" : behavior === "answer" ? "answered" : "rejected";
23513
23757
  },
23514
23758
  hasSession: (threadId) => active.has(threadId),
@@ -23673,7 +23917,7 @@ function unquote(raw) {
23673
23917
  }
23674
23918
  return value;
23675
23919
  }
23676
- function parseCodexToml(text3) {
23920
+ function parseCodexToml(text4) {
23677
23921
  const result = { providers: [] };
23678
23922
  const byId = /* @__PURE__ */ new Map();
23679
23923
  let section = "root";
@@ -23686,7 +23930,7 @@ function parseCodexToml(text3) {
23686
23930
  }
23687
23931
  return provider;
23688
23932
  };
23689
- for (const line of text3.split(/\r?\n/)) {
23933
+ for (const line of text4.split(/\r?\n/)) {
23690
23934
  const stripped = line.trim();
23691
23935
  if (!stripped || stripped.startsWith("#")) continue;
23692
23936
  if (stripped.startsWith("[") && stripped.endsWith("]")) {
@@ -24768,6 +25012,7 @@ var init_codex = __esm({
24768
25012
  const earlyNotifications = [];
24769
25013
  const state = {
24770
25014
  settled: false,
25015
+ lastError: "",
24771
25016
  lastText: "",
24772
25017
  sawStreamDelta: false,
24773
25018
  // codex reports token usage as a running THREAD total; the harness
@@ -24820,11 +25065,17 @@ var init_codex = __esm({
24820
25065
  });
24821
25066
  send({ jsonrpc: "2.0", id, method, params });
24822
25067
  });
24823
- let stopping;
24824
- const terminate = () => stopping ??= killCliTree(child);
24825
- const stop = () => {
25068
+ let stopping2;
25069
+ const terminate = () => stopping2 ??= killCliTree(child).then((stopped) => {
25070
+ if (!stopped) stopping2 = void 0;
25071
+ return stopped;
25072
+ });
25073
+ let completeStoppedTurn;
25074
+ const stop = async () => {
24826
25075
  stopRequested = true;
24827
- return terminate();
25076
+ const stopped = await terminate();
25077
+ if (stopped) completeStoppedTurn?.();
25078
+ return stopped;
24828
25079
  };
24829
25080
  const settle = async (ok, stopReason) => {
24830
25081
  if (state.settled) return;
@@ -24837,12 +25088,9 @@ var init_codex = __esm({
24837
25088
  active.delete(threadId);
24838
25089
  emit({ ...base2(threadId, turnId), type: "turn.completed", ok, stopReason, cost: null, ...state.usage ? { usage: state.usage } : {} });
24839
25090
  };
24840
- if (await stop()) {
24841
- complete();
24842
- } else {
25091
+ completeStoppedTurn = complete;
25092
+ if (!await stop()) {
24843
25093
  emit({ ...base2(threadId, turnId), type: "runtime.error", message: "codex did not shut down after termination was requested" });
24844
- if (child.exitCode !== null || child.signalCode !== null) complete();
24845
- else child.once("close", complete);
24846
25094
  }
24847
25095
  };
24848
25096
  const controlsHost = turn.integrations?.localComputer?.scope === "local-computer";
@@ -25026,13 +25274,26 @@ var init_codex = __esm({
25026
25274
  }
25027
25275
  case "turn/completed": {
25028
25276
  const t2 = p.turn ?? {};
25029
- void settle(t2.status === "completed", t2.status === "completed" ? null : t2.error?.message ?? t2.status ?? "failed");
25277
+ const message2 = typeof t2.error?.message === "string" ? t2.error.message.slice(0, 400) : "";
25278
+ if (t2.status !== "completed" && message2 && message2 !== state.lastError) {
25279
+ state.lastError = message2;
25280
+ emit({
25281
+ ...base2(threadId, turnId),
25282
+ type: "runtime.error",
25283
+ message: message2,
25284
+ ...classifyError({ text: message2 }).reason === "auth" ? { setup: true } : {}
25285
+ });
25286
+ }
25287
+ void settle(t2.status === "completed", t2.status === "completed" ? null : classifyError({ text: message2 || state.lastError }).reason === "provider_safety" ? "provider_safety" : message2 || t2.status || "failed");
25030
25288
  break;
25031
25289
  }
25032
25290
  case "error":
25033
25291
  {
25034
25292
  const message2 = p.message ?? p.error?.message;
25035
- if (message2) emit({ ...base2(threadId, turnId), type: "runtime.error", message: String(message2).slice(0, 400) });
25293
+ if (message2) {
25294
+ state.lastError = String(message2).slice(0, 400);
25295
+ emit({ ...base2(threadId, turnId), type: "runtime.error", message: state.lastError });
25296
+ }
25036
25297
  }
25037
25298
  break;
25038
25299
  }
@@ -25081,6 +25342,10 @@ var init_codex = __esm({
25081
25342
  });
25082
25343
  child.on("close", (code) => {
25083
25344
  if (abandoned) return;
25345
+ if (state.settled) {
25346
+ void stop();
25347
+ return;
25348
+ }
25084
25349
  if (!state.settled) {
25085
25350
  emit({
25086
25351
  ...base2(threadId, turnId),
@@ -25236,7 +25501,7 @@ var init_codex = __esm({
25236
25501
  message: message2,
25237
25502
  ...needsAuth ? { setup: true } : {}
25238
25503
  });
25239
- await settle(false, needsAuth ? "auth_required" : "rpc_error");
25504
+ await settle(false, needsAuth ? "auth_required" : verdict.reason === "provider_safety" ? "provider_safety" : "rpc_error");
25240
25505
  }
25241
25506
  }
25242
25507
  };
@@ -25373,7 +25638,7 @@ function createOpenAIChatRuntime(options) {
25373
25638
  if (!response.body) {
25374
25639
  throw new Error(options.noBodyError ?? `${options.httpErrorLabel} returned no response body`);
25375
25640
  }
25376
- let text3 = "";
25641
+ let text4 = "";
25377
25642
  let reasoning = "";
25378
25643
  let usage = null;
25379
25644
  const reader = response.body.getReader();
@@ -25405,7 +25670,7 @@ function createOpenAIChatRuntime(options) {
25405
25670
  onDelta?.(reasoningDelta, "reasoning_text");
25406
25671
  }
25407
25672
  if (contentDelta) {
25408
- text3 += contentDelta;
25673
+ text4 += contentDelta;
25409
25674
  onDelta?.(contentDelta, "assistant_text");
25410
25675
  }
25411
25676
  if (chunk.usage) usage = usageFrom(chunk.usage);
@@ -25415,7 +25680,7 @@ function createOpenAIChatRuntime(options) {
25415
25680
  await reader.cancel().catch(() => {
25416
25681
  });
25417
25682
  }
25418
- return { text: text3, reasoning, usage };
25683
+ return { text: text4, reasoning, usage };
25419
25684
  };
25420
25685
  const messagesFor = (turn) => [
25421
25686
  ...turn.system ? [{ role: "system", content: turn.system }] : [],
@@ -25532,8 +25797,8 @@ function createOpenAIChatRuntime(options) {
25532
25797
  },
25533
25798
  generateText: async (prompt) => {
25534
25799
  const model = options.generateModel?.() ?? options.models().default;
25535
- const { text: text3, reasoning } = await complete([{ role: "user", content: prompt }], model, false);
25536
- return text3.trim() ? text3 : reasoning;
25800
+ const { text: text4, reasoning } = await complete([{ role: "user", content: prompt }], model, false);
25801
+ return text4.trim() ? text4 : reasoning;
25537
25802
  },
25538
25803
  dispose: async () => {
25539
25804
  for (const abort of active.values()) abort.abort();
@@ -25601,7 +25866,7 @@ var init_grok = __esm({
25601
25866
  nativeLog: {
25602
25867
  source: "xai.chat.completions",
25603
25868
  outgoing: (_turn, messages, model) => ({ model, messages }),
25604
- incoming: ({ text: text3, usage }) => ({ text: text3, usage })
25869
+ incoming: ({ text: text4, usage }) => ({ text: text4, usage })
25605
25870
  }
25606
25871
  });
25607
25872
  }
@@ -25626,9 +25891,9 @@ function unquote2(raw) {
25626
25891
  }
25627
25892
  function readGrokModelCatalog(env = process.env) {
25628
25893
  const path3 = join25(grokHome(env), "config.toml");
25629
- let text3 = "";
25894
+ let text4 = "";
25630
25895
  try {
25631
- text3 = readFileSync11(path3, "utf8");
25896
+ text4 = readFileSync11(path3, "utf8");
25632
25897
  } catch {
25633
25898
  return STATIC_GROK_MODELS;
25634
25899
  }
@@ -25646,7 +25911,7 @@ function readGrokModelCatalog(env = process.env) {
25646
25911
  options.push({ id: current.slug, label: current.name || current.slug, custom: true });
25647
25912
  current = null;
25648
25913
  };
25649
- for (const line of text3.split(/\r?\n/)) {
25914
+ for (const line of text4.split(/\r?\n/)) {
25650
25915
  const stripped = line.trim();
25651
25916
  if (stripped === "[models]") {
25652
25917
  flush();
@@ -25699,11 +25964,11 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
25699
25964
  const host = localHost(inject.host);
25700
25965
  if (!host) return modelId;
25701
25966
  const path3 = join25(grokHome(env), "config.toml");
25702
- let text3 = "";
25967
+ let text4 = "";
25703
25968
  try {
25704
- text3 = readFileSync11(path3, "utf8");
25969
+ text4 = readFileSync11(path3, "utf8");
25705
25970
  } catch {
25706
- text3 = "";
25971
+ text4 = "";
25707
25972
  }
25708
25973
  const taken = new Set(STATIC_GROK_MODELS.options.map((option) => option.id));
25709
25974
  let current = null;
@@ -25716,7 +25981,7 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
25716
25981
  current = null;
25717
25982
  };
25718
25983
  let found = null;
25719
- for (const line of text3.split(/\r?\n/)) {
25984
+ for (const line of text4.split(/\r?\n/)) {
25720
25985
  const stripped = line.trim();
25721
25986
  if (stripped.startsWith("[model.") && stripped.endsWith("]")) {
25722
25987
  flush();
@@ -25749,12 +26014,18 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
25749
26014
  `api_key = ${quoteToml(hostApiKey(host, env))}`,
25750
26015
  ""
25751
26016
  ].join("\n");
25752
- const next = text3 && !text3.endsWith("\n") ? `${text3}
26017
+ const next = text4 && !text4.endsWith("\n") ? `${text4}
25753
26018
 
25754
- ${block2}` : `${text3}${text3 ? "\n" : ""}${block2}`;
26019
+ ${block2}` : `${text4}${text4 ? "\n" : ""}${block2}`;
25755
26020
  writeFileSync7(path3, next);
25756
26021
  return slug;
25757
26022
  }
26023
+ function grokAcceptsUnadvertisedImages(init) {
26024
+ const meta3 = init?._meta;
26025
+ if (meta3?.grokShell !== true || typeof meta3.agentVersion !== "string") return false;
26026
+ const version2 = /^1\.0\.(\d+)$/.exec(meta3.agentVersion);
26027
+ return Boolean(version2 && Number(version2[1]) >= 25);
26028
+ }
25758
26029
  var STATIC_GROK_MODELS, SLUG, support2, GrokAgentDriver;
25759
26030
  var init_grok2 = __esm({
25760
26031
  "server/drivers/acp/grok.ts"() {
@@ -25772,7 +26043,8 @@ var init_grok2 = __esm({
25772
26043
  support2 = {
25773
26044
  driverKind: "grokAgent",
25774
26045
  displayName: "Grok",
25775
- images: false,
26046
+ images: true,
26047
+ acceptsUnadvertisedImages: grokAcceptsUnadvertisedImages,
25776
26048
  models: STATIC_GROK_MODELS,
25777
26049
  resolveModels: (env) => mergeLocalInject(readGrokModelCatalog(env), env),
25778
26050
  // Grok's accepted levels vary by model and the CLI validates lazily — a
@@ -25808,7 +26080,7 @@ var init_grok2 = __esm({
25808
26080
  // crates/codegen/xai-grok-pager-bin/src/main.rs:1259-1273.
25809
26081
  spawnArgs: (config2, turn) => [
25810
26082
  "--permission-mode",
25811
- config2.fullAuto ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : "default",
26083
+ config2.fullAuto ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : turn.approvalMode === "edits" ? "acceptEdits" : "default",
25812
26084
  "agent",
25813
26085
  ...turn.model ? ["-m", turn.model] : [],
25814
26086
  // long form on purpose: `--effort` is documented as an alias, and an
@@ -25946,18 +26218,18 @@ function stripTomlLineComment(line) {
25946
26218
  }
25947
26219
  return line;
25948
26220
  }
25949
- function takeTomlBasicEscape(text3, i2) {
25950
- const code = text3[i2 + 1];
26221
+ function takeTomlBasicEscape(text4, i2) {
26222
+ const code = text4[i2 + 1];
25951
26223
  if (code === void 0) return { ok: false };
25952
26224
  if (code === "u") {
25953
- const hex3 = text3.slice(i2 + 2, i2 + 6);
26225
+ const hex3 = text4.slice(i2 + 2, i2 + 6);
25954
26226
  if (!/^[0-9a-fA-F]{4}$/.test(hex3)) return { ok: false };
25955
26227
  const point = parseInt(hex3, 16);
25956
26228
  if (point >= 55296 && point <= 57343) return { ok: false };
25957
26229
  return { ok: true, value: String.fromCharCode(point), next: i2 + 6 };
25958
26230
  }
25959
26231
  if (code === "U") {
25960
- const hex3 = text3.slice(i2 + 2, i2 + 10);
26232
+ const hex3 = text4.slice(i2 + 2, i2 + 10);
25961
26233
  if (!/^[0-9a-fA-F]{8}$/.test(hex3)) return { ok: false };
25962
26234
  const point = parseInt(hex3, 16);
25963
26235
  if (point > 1114111 || point >= 55296 && point <= 57343) return { ok: false };
@@ -26029,14 +26301,14 @@ function tomlRowKey(row) {
26029
26301
  const eq = row.indexOf("=");
26030
26302
  return unquoteTomlKey(eq < 0 ? row : row.slice(0, eq));
26031
26303
  }
26032
- function tomlTables(text3) {
26304
+ function tomlTables(text4) {
26033
26305
  const headings = [];
26034
26306
  let mode = "out";
26035
26307
  let i2 = 0;
26036
- const atLineStart = (idx) => idx === 0 || text3[idx - 1] === "\n";
26037
- while (i2 < text3.length) {
26308
+ const atLineStart = (idx) => idx === 0 || text4[idx - 1] === "\n";
26309
+ while (i2 < text4.length) {
26038
26310
  if (mode === "mlbasic") {
26039
- if (text3.startsWith('"""', i2)) {
26311
+ if (text4.startsWith('"""', i2)) {
26040
26312
  mode = "out";
26041
26313
  i2 += 3;
26042
26314
  continue;
@@ -26045,7 +26317,7 @@ function tomlTables(text3) {
26045
26317
  continue;
26046
26318
  }
26047
26319
  if (mode === "mllit") {
26048
- if (text3.startsWith("'''", i2)) {
26320
+ if (text4.startsWith("'''", i2)) {
26049
26321
  mode = "out";
26050
26322
  i2 += 3;
26051
26323
  continue;
@@ -26054,61 +26326,61 @@ function tomlTables(text3) {
26054
26326
  continue;
26055
26327
  }
26056
26328
  if (mode === "basic") {
26057
- if (text3[i2] === "\n") {
26329
+ if (text4[i2] === "\n") {
26058
26330
  mode = "out";
26059
26331
  i2 += 1;
26060
26332
  continue;
26061
26333
  }
26062
- if (text3[i2] === "\\") {
26334
+ if (text4[i2] === "\\") {
26063
26335
  i2 += 2;
26064
26336
  continue;
26065
26337
  }
26066
- if (text3[i2] === '"') mode = "out";
26338
+ if (text4[i2] === '"') mode = "out";
26067
26339
  i2 += 1;
26068
26340
  continue;
26069
26341
  }
26070
26342
  if (mode === "literal") {
26071
- if (text3[i2] === "\n") {
26343
+ if (text4[i2] === "\n") {
26072
26344
  mode = "out";
26073
26345
  i2 += 1;
26074
26346
  continue;
26075
26347
  }
26076
- if (text3[i2] === "'") mode = "out";
26348
+ if (text4[i2] === "'") mode = "out";
26077
26349
  i2 += 1;
26078
26350
  continue;
26079
26351
  }
26080
- if (text3.startsWith('"""', i2)) {
26352
+ if (text4.startsWith('"""', i2)) {
26081
26353
  mode = "mlbasic";
26082
26354
  i2 += 3;
26083
26355
  continue;
26084
26356
  }
26085
- if (text3.startsWith("'''", i2)) {
26357
+ if (text4.startsWith("'''", i2)) {
26086
26358
  mode = "mllit";
26087
26359
  i2 += 3;
26088
26360
  continue;
26089
26361
  }
26090
- if (text3[i2] === '"') {
26362
+ if (text4[i2] === '"') {
26091
26363
  mode = "basic";
26092
26364
  i2 += 1;
26093
26365
  continue;
26094
26366
  }
26095
- if (text3[i2] === "'") {
26367
+ if (text4[i2] === "'") {
26096
26368
  mode = "literal";
26097
26369
  i2 += 1;
26098
26370
  continue;
26099
26371
  }
26100
- if (text3[i2] === "#") {
26101
- const nl = text3.indexOf("\n", i2);
26102
- i2 = nl < 0 ? text3.length : nl + 1;
26372
+ if (text4[i2] === "#") {
26373
+ const nl = text4.indexOf("\n", i2);
26374
+ i2 = nl < 0 ? text4.length : nl + 1;
26103
26375
  continue;
26104
26376
  }
26105
26377
  if (atLineStart(i2)) {
26106
26378
  let j = i2;
26107
- while (j < text3.length && (text3[j] === " " || text3[j] === " ")) j += 1;
26108
- if (text3[j] === "[") {
26109
- const nl = text3.indexOf("\n", j);
26110
- const lineEnd = nl < 0 ? text3.length : nl;
26111
- const raw = text3.slice(j, lineEnd).replace(/\r$/, "");
26379
+ while (j < text4.length && (text4[j] === " " || text4[j] === " ")) j += 1;
26380
+ if (text4[j] === "[") {
26381
+ const nl = text4.indexOf("\n", j);
26382
+ const lineEnd = nl < 0 ? text4.length : nl;
26383
+ const raw = text4.slice(j, lineEnd).replace(/\r$/, "");
26112
26384
  const stripped = stripTomlLineComment(raw).trim();
26113
26385
  const array2 = stripped.startsWith("[[");
26114
26386
  const name = array2 ? canonicalizeTomlHeading(`[${stripped.replace(/^\s*\[\[/, "").replace(/\]\]\s*$/, "")}]`) : canonicalizeTomlHeading(raw);
@@ -26121,11 +26393,11 @@ function tomlTables(text3) {
26121
26393
  }
26122
26394
  return headings.map((heading, index) => ({
26123
26395
  heading,
26124
- end: index + 1 < headings.length ? headings[index + 1].lineStart : text3.length
26396
+ end: index + 1 < headings.length ? headings[index + 1].lineStart : text4.length
26125
26397
  })).filter((entry) => entry.heading.patchable && entry.heading.name).map((entry) => ({
26126
26398
  name: entry.heading.name,
26127
26399
  headingStart: entry.heading.lineStart,
26128
- bodyStart: entry.heading.lineEnd + (text3[entry.heading.lineEnd] === "\n" ? 1 : 0),
26400
+ bodyStart: entry.heading.lineEnd + (text4[entry.heading.lineEnd] === "\n" ? 1 : 0),
26129
26401
  end: entry.end
26130
26402
  }));
26131
26403
  }
@@ -26181,22 +26453,22 @@ function tomlKeys(block2) {
26181
26453
  take(block2.length);
26182
26454
  return keys;
26183
26455
  }
26184
- function hasTomlTable(text3, heading) {
26456
+ function hasTomlTable(text4, heading) {
26185
26457
  const name = canonicalizeTomlHeading(heading);
26186
- return name !== null && tomlTables(text3).some((table) => table.name === name);
26458
+ return name !== null && tomlTables(text4).some((table) => table.name === name);
26187
26459
  }
26188
- function patchTomlTable(text3, heading, rows) {
26460
+ function patchTomlTable(text4, heading, rows) {
26189
26461
  const name = canonicalizeTomlHeading(heading);
26190
- if (!name) return text3;
26191
- const table = tomlTables(text3).find((entry) => entry.name === name);
26192
- if (!table) return text3;
26193
- const keys = tomlKeys(text3.slice(table.bodyStart, table.end));
26462
+ if (!name) return text4;
26463
+ const table = tomlTables(text4).find((entry) => entry.name === name);
26464
+ if (!table) return text4;
26465
+ const keys = tomlKeys(text4.slice(table.bodyStart, table.end));
26194
26466
  const missing = rows.filter((row) => !keys.has(tomlRowKey(row)));
26195
- if (!missing.length) return text3;
26467
+ if (!missing.length) return text4;
26196
26468
  let insertAt = table.end;
26197
- while (insertAt > table.bodyStart && (text3[insertAt - 1] === "\n" || text3[insertAt - 1] === "\r")) insertAt -= 1;
26198
- const before = text3.slice(0, insertAt);
26199
- const after = text3.slice(insertAt);
26469
+ while (insertAt > table.bodyStart && (text4[insertAt - 1] === "\n" || text4[insertAt - 1] === "\r")) insertAt -= 1;
26470
+ const before = text4.slice(0, insertAt);
26471
+ const after = text4.slice(insertAt);
26200
26472
  const pad = before.endsWith("\n") || before.length === 0 ? "" : "\n";
26201
26473
  return `${before}${pad}${missing.join("\n")}${after.startsWith("\n") ? "" : "\n"}${after}`;
26202
26474
  }
@@ -26209,17 +26481,17 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
26209
26481
  const dataRoot = kimiDataRoot(env);
26210
26482
  mkdirSync10(dataRoot, { recursive: true });
26211
26483
  const path3 = join27(dataRoot, "config.toml");
26212
- let text3 = "";
26484
+ let text4 = "";
26213
26485
  try {
26214
- text3 = readFileSync13(path3, "utf8");
26486
+ text4 = readFileSync13(path3, "utf8");
26215
26487
  } catch {
26216
- text3 = "";
26488
+ text4 = "";
26217
26489
  }
26218
- const original = text3;
26490
+ const original = text4;
26219
26491
  const providerHeading = `[providers.${inject.host}]`;
26220
26492
  const modelHeading = `[models.${quoteTomlKey(alias)}]`;
26221
26493
  const blocks = [];
26222
- if (!hasTomlTable(text3, providerHeading)) {
26494
+ if (!hasTomlTable(text4, providerHeading)) {
26223
26495
  blocks.push(
26224
26496
  [
26225
26497
  providerHeading,
@@ -26230,8 +26502,8 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
26230
26502
  ].join("\n")
26231
26503
  );
26232
26504
  }
26233
- if (hasTomlTable(text3, modelHeading)) {
26234
- text3 = patchTomlTable(text3, modelHeading, [`protocol = "openai"`, `max_context_size = 262144`]);
26505
+ if (hasTomlTable(text4, modelHeading)) {
26506
+ text4 = patchTomlTable(text4, modelHeading, [`protocol = "openai"`, `max_context_size = 262144`]);
26235
26507
  } else {
26236
26508
  blocks.push(
26237
26509
  [
@@ -26245,13 +26517,13 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
26245
26517
  );
26246
26518
  }
26247
26519
  if (blocks.length) {
26248
- const prefix = text3 && !text3.endsWith("\n") ? `${text3}
26520
+ const prefix = text4 && !text4.endsWith("\n") ? `${text4}
26249
26521
 
26250
- ` : text3 ? `${text3}
26522
+ ` : text4 ? `${text4}
26251
26523
  ` : "";
26252
26524
  writeFileSync8(path3, `${prefix}${blocks.join("\n")}`);
26253
- } else if (text3 !== original) {
26254
- writeFileSync8(path3, text3);
26525
+ } else if (text4 !== original) {
26526
+ writeFileSync8(path3, text4);
26255
26527
  }
26256
26528
  return alias;
26257
26529
  }
@@ -26271,9 +26543,9 @@ function stripKimiModelEnv(env) {
26271
26543
  }
26272
26544
  function readKimiModelCatalog(env) {
26273
26545
  const dataRoot = kimiDataRoot(env);
26274
- let text3 = "";
26546
+ let text4 = "";
26275
26547
  try {
26276
- text3 = readFileSync13(join27(dataRoot, "config.toml"), "utf8");
26548
+ text4 = readFileSync13(join27(dataRoot, "config.toml"), "utf8");
26277
26549
  } catch {
26278
26550
  return STATIC_KIMI_MODELS;
26279
26551
  }
@@ -26289,7 +26561,7 @@ function readKimiModelCatalog(env) {
26289
26561
  options.push({ id: current.slug, label: current.name || current.slug, custom: true });
26290
26562
  current = null;
26291
26563
  };
26292
- for (const line of text3.split(/\r?\n/)) {
26564
+ for (const line of text4.split(/\r?\n/)) {
26293
26565
  const stripped = line.trim();
26294
26566
  if ((stripped.startsWith("[model.") || stripped.startsWith("[models.")) && stripped.endsWith("]")) {
26295
26567
  flush();
@@ -26582,8 +26854,8 @@ function resolveCursorAcpModelId(available, wanted) {
26582
26854
  }
26583
26855
  return null;
26584
26856
  }
26585
- function firstJsonValue(text3) {
26586
- const trimmed = text3.trim();
26857
+ function firstJsonValue(text4) {
26858
+ const trimmed = text4.trim();
26587
26859
  if (!trimmed) return null;
26588
26860
  try {
26589
26861
  return JSON.parse(trimmed);
@@ -26657,12 +26929,12 @@ function stripModelMarkers(label) {
26657
26929
  }
26658
26930
  return { label: cleaned, isDefault, isCurrent };
26659
26931
  }
26660
- function decodeCursorModelText(text3) {
26932
+ function decodeCursorModelText(text4) {
26661
26933
  const options = [];
26662
26934
  const seen = /* @__PURE__ */ new Set();
26663
26935
  let markedDefault;
26664
26936
  let markedCurrent;
26665
- for (const raw of text3.split(/\r?\n/)) {
26937
+ for (const raw of text4.split(/\r?\n/)) {
26666
26938
  const line = raw.trim();
26667
26939
  if (!line || line.startsWith("#") || /^available\s+models?\b/i.test(line) || /^models?\b/i.test(line)) continue;
26668
26940
  const stripped = line.replace(/^[\s*•-]+\s*/, "");
@@ -26715,8 +26987,8 @@ function decodeCursorAuthStatus(payload) {
26715
26987
  }
26716
26988
  return null;
26717
26989
  }
26718
- function decodeCursorAuthText(text3) {
26719
- const normalized = text3.trim().toLowerCase();
26990
+ function decodeCursorAuthText(text4) {
26991
+ const normalized = text4.trim().toLowerCase();
26720
26992
  if (!normalized) return null;
26721
26993
  if (/not (?:logged|signed) in|not authenticated|unauthenticated|logged out/.test(normalized)) return false;
26722
26994
  if (/login successful|logged in|signed in|authenticated/.test(normalized)) return true;
@@ -27136,7 +27408,7 @@ function qwenHome(env) {
27136
27408
  const home = process.platform === "win32" ? env.USERPROFILE || env.HOME || homedir19() : env.HOME || env.USERPROFILE || homedir19();
27137
27409
  return join30(home, ".qwen");
27138
27410
  }
27139
- function isRecord(value) {
27411
+ function isRecord2(value) {
27140
27412
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
27141
27413
  }
27142
27414
  function qwenModelLabel(id, name) {
@@ -27150,15 +27422,15 @@ function readQwenRoutes(env) {
27150
27422
  } catch {
27151
27423
  return [];
27152
27424
  }
27153
- if (!isRecord(settings2) || !isRecord(settings2.modelProviders)) return [];
27425
+ if (!isRecord2(settings2) || !isRecord2(settings2.modelProviders)) return [];
27154
27426
  const routes = [];
27155
27427
  const seen = /* @__PURE__ */ new Set();
27156
- const mappings = isRecord(settings2.providerProtocol) ? settings2.providerProtocol : {};
27428
+ const mappings = isRecord2(settings2.providerProtocol) ? settings2.providerProtocol : {};
27157
27429
  for (const [provider, rows] of Object.entries(settings2.modelProviders)) {
27158
27430
  const protocol = Object.hasOwn(mappings, provider) ? mappings[provider] : provider;
27159
27431
  if (typeof protocol !== "string" || !PROTOCOLS.has(protocol) || !Array.isArray(rows)) continue;
27160
27432
  for (const row of rows) {
27161
- if (!isRecord(row) || typeof row.id !== "string") continue;
27433
+ if (!isRecord2(row) || typeof row.id !== "string") continue;
27162
27434
  const model = row.id;
27163
27435
  if (!model.trim()) continue;
27164
27436
  if (row.baseUrl !== void 0 && typeof row.baseUrl !== "string") continue;
@@ -28304,14 +28576,14 @@ var init_stringifyComment = __esm({
28304
28576
  });
28305
28577
 
28306
28578
  // node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/stringify/foldFlowLines.js
28307
- function foldFlowLines(text3, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
28579
+ function foldFlowLines(text4, indent, mode = "flow", { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
28308
28580
  if (!lineWidth || lineWidth < 0)
28309
- return text3;
28581
+ return text4;
28310
28582
  if (lineWidth < minContentWidth)
28311
28583
  minContentWidth = 0;
28312
28584
  const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
28313
- if (text3.length <= endStep)
28314
- return text3;
28585
+ if (text4.length <= endStep)
28586
+ return text4;
28315
28587
  const folds = [];
28316
28588
  const escapedFolds = {};
28317
28589
  let end = lineWidth - indent.length;
@@ -28328,14 +28600,14 @@ function foldFlowLines(text3, indent, mode = "flow", { indentAtStart, lineWidth
28328
28600
  let escStart = -1;
28329
28601
  let escEnd = -1;
28330
28602
  if (mode === FOLD_BLOCK) {
28331
- i2 = consumeMoreIndentedLines(text3, i2, indent.length);
28603
+ i2 = consumeMoreIndentedLines(text4, i2, indent.length);
28332
28604
  if (i2 !== -1)
28333
28605
  end = i2 + endStep;
28334
28606
  }
28335
- for (let ch; ch = text3[i2 += 1]; ) {
28607
+ for (let ch; ch = text4[i2 += 1]; ) {
28336
28608
  if (mode === FOLD_QUOTED && ch === "\\") {
28337
28609
  escStart = i2;
28338
- switch (text3[i2 + 1]) {
28610
+ switch (text4[i2 + 1]) {
28339
28611
  case "x":
28340
28612
  i2 += 3;
28341
28613
  break;
@@ -28352,12 +28624,12 @@ function foldFlowLines(text3, indent, mode = "flow", { indentAtStart, lineWidth
28352
28624
  }
28353
28625
  if (ch === "\n") {
28354
28626
  if (mode === FOLD_BLOCK)
28355
- i2 = consumeMoreIndentedLines(text3, i2, indent.length);
28627
+ i2 = consumeMoreIndentedLines(text4, i2, indent.length);
28356
28628
  end = i2 + indent.length + endStep;
28357
28629
  split = void 0;
28358
28630
  } else {
28359
28631
  if (ch === " " && prev && prev !== " " && prev !== "\n" && prev !== " ") {
28360
- const next = text3[i2 + 1];
28632
+ const next = text4[i2 + 1];
28361
28633
  if (next && next !== " " && next !== "\n" && next !== " ")
28362
28634
  split = i2;
28363
28635
  }
@@ -28369,12 +28641,12 @@ function foldFlowLines(text3, indent, mode = "flow", { indentAtStart, lineWidth
28369
28641
  } else if (mode === FOLD_QUOTED) {
28370
28642
  while (prev === " " || prev === " ") {
28371
28643
  prev = ch;
28372
- ch = text3[i2 += 1];
28644
+ ch = text4[i2 += 1];
28373
28645
  overflow = true;
28374
28646
  }
28375
28647
  const j = i2 > escEnd + 1 ? i2 - 2 : escStart - 1;
28376
28648
  if (escapedFolds[j])
28377
- return text3;
28649
+ return text4;
28378
28650
  folds.push(j);
28379
28651
  escapedFolds[j] = true;
28380
28652
  end = j + endStep;
@@ -28389,39 +28661,39 @@ function foldFlowLines(text3, indent, mode = "flow", { indentAtStart, lineWidth
28389
28661
  if (overflow && onOverflow)
28390
28662
  onOverflow();
28391
28663
  if (folds.length === 0)
28392
- return text3;
28664
+ return text4;
28393
28665
  if (onFold)
28394
28666
  onFold();
28395
- let res = text3.slice(0, folds[0]);
28667
+ let res = text4.slice(0, folds[0]);
28396
28668
  for (let i3 = 0; i3 < folds.length; ++i3) {
28397
28669
  const fold = folds[i3];
28398
- const end2 = folds[i3 + 1] || text3.length;
28670
+ const end2 = folds[i3 + 1] || text4.length;
28399
28671
  if (fold === 0)
28400
28672
  res = `
28401
- ${indent}${text3.slice(0, end2)}`;
28673
+ ${indent}${text4.slice(0, end2)}`;
28402
28674
  else {
28403
28675
  if (mode === FOLD_QUOTED && escapedFolds[fold])
28404
- res += `${text3[fold]}\\`;
28676
+ res += `${text4[fold]}\\`;
28405
28677
  res += `
28406
- ${indent}${text3.slice(fold + 1, end2)}`;
28678
+ ${indent}${text4.slice(fold + 1, end2)}`;
28407
28679
  }
28408
28680
  }
28409
28681
  return res;
28410
28682
  }
28411
- function consumeMoreIndentedLines(text3, i2, indent) {
28683
+ function consumeMoreIndentedLines(text4, i2, indent) {
28412
28684
  let end = i2;
28413
28685
  let start = i2 + 1;
28414
- let ch = text3[start];
28686
+ let ch = text4[start];
28415
28687
  while (ch === " " || ch === " ") {
28416
28688
  if (i2 < start + indent) {
28417
- ch = text3[++i2];
28689
+ ch = text4[++i2];
28418
28690
  } else {
28419
28691
  do {
28420
- ch = text3[++i2];
28692
+ ch = text4[++i2];
28421
28693
  } while (ch && ch !== "\n");
28422
28694
  end = i2;
28423
28695
  start = i2 + 1;
28424
- ch = text3[start];
28696
+ ch = text4[start];
28425
28697
  }
28426
28698
  }
28427
28699
  return end;
@@ -34247,24 +34519,24 @@ function quoteYaml(value) {
34247
34519
  if (/^[\w./:+-]+$/.test(value)) return value;
34248
34520
  return JSON.stringify(value);
34249
34521
  }
34250
- function upsertHermesProvider(text3, hostId, baseUrl, apiKey) {
34522
+ function upsertHermesProvider(text4, hostId, baseUrl, apiKey) {
34251
34523
  const block2 = [` ${hostId}:`, ` base_url: ${quoteYaml(baseUrl)}`, ` api_key: ${quoteYaml(apiKey)}`, ""].join(
34252
34524
  "\n"
34253
34525
  );
34254
- if (/^providers:\s*$/m.test(text3)) {
34255
- const replaced = replaceHermesHostBlock(text3, hostId, block2);
34526
+ if (/^providers:\s*$/m.test(text4)) {
34527
+ const replaced = replaceHermesHostBlock(text4, hostId, block2);
34256
34528
  if (replaced !== null) return replaced;
34257
- return text3.replace(/^providers:\s*$/m, `providers:
34529
+ return text4.replace(/^providers:\s*$/m, `providers:
34258
34530
  ${block2.trimEnd()}`);
34259
34531
  }
34260
- const prefix = text3 && !text3.endsWith("\n") ? `${text3}
34261
- ` : text3;
34532
+ const prefix = text4 && !text4.endsWith("\n") ? `${text4}
34533
+ ` : text4;
34262
34534
  return `${prefix}
34263
34535
  providers:
34264
34536
  ${block2}`;
34265
34537
  }
34266
- function replaceHermesHostBlock(text3, hostId, block2) {
34267
- const lines = text3.split("\n");
34538
+ function replaceHermesHostBlock(text4, hostId, block2) {
34539
+ const lines = text4.split("\n");
34268
34540
  const start = lines.findIndex((line) => line === ` ${hostId}:`);
34269
34541
  if (start < 0) return null;
34270
34542
  let end = start + 1;
@@ -34284,14 +34556,14 @@ function ensureHermesInjectProvider(modelId, env = process.env) {
34284
34556
  const dir = hermesHome(env);
34285
34557
  mkdirSync14(dir, { recursive: true });
34286
34558
  const path3 = join31(dir, "config.yaml");
34287
- let text3 = "";
34559
+ let text4 = "";
34288
34560
  try {
34289
- text3 = readFileSync17(path3, "utf8");
34561
+ text4 = readFileSync17(path3, "utf8");
34290
34562
  } catch {
34291
- text3 = "";
34563
+ text4 = "";
34292
34564
  }
34293
- const next = upsertHermesProvider(text3, inject.host, host.baseUrl, hostApiKey(host, env));
34294
- if (next !== text3) writeFileSync12(path3, next);
34565
+ const next = upsertHermesProvider(text4, inject.host, host.baseUrl, hostApiKey(host, env));
34566
+ if (next !== text4) writeFileSync12(path3, next);
34295
34567
  return hermesAcpModelId(modelId) ?? modelId;
34296
34568
  }
34297
34569
  function hermesAcpModelId(modelId) {
@@ -34301,8 +34573,8 @@ function hermesAcpModelId(modelId) {
34301
34573
  if (native && !native.includes(INJECT_SEP) && /^[a-z0-9_-]+:[\w./:-]+$/i.test(native)) return native;
34302
34574
  return null;
34303
34575
  }
34304
- function nonEmptyDotenvValue(text3, name) {
34305
- const match = new RegExp(`^[ \\t]*(?:export[ \\t]+)?${name}[ \\t]*=[ \\t]*([^\\r\\n]*)$`, "m").exec(text3);
34576
+ function nonEmptyDotenvValue(text4, name) {
34577
+ const match = new RegExp(`^[ \\t]*(?:export[ \\t]+)?${name}[ \\t]*=[ \\t]*([^\\r\\n]*)$`, "m").exec(text4);
34306
34578
  if (!match) return null;
34307
34579
  const raw = match[1].trim();
34308
34580
  if (!raw || raw.startsWith("#")) return null;
@@ -34319,10 +34591,10 @@ function nonEmptyDotenvValue(text3, name) {
34319
34591
  function yamlString(value) {
34320
34592
  return typeof value === "string" ? value.trim() : "";
34321
34593
  }
34322
- function hermesConfigDefault(text3) {
34594
+ function hermesConfigDefault(text4) {
34323
34595
  let raw;
34324
34596
  try {
34325
- raw = parse3(text3);
34597
+ raw = parse3(text4);
34326
34598
  } catch {
34327
34599
  return null;
34328
34600
  }
@@ -34667,8 +34939,8 @@ var init_openai_compat = __esm({
34667
34939
  nativeLog: {
34668
34940
  source: "openai-compat.chat.completions",
34669
34941
  outgoing: (_turn, messages, model) => ({ model, messageCount: messages.length }),
34670
- incoming: ({ text: text3, reasoning, usage }) => ({
34671
- textLength: text3.length,
34942
+ incoming: ({ text: text4, reasoning, usage }) => ({
34943
+ textLength: text4.length,
34672
34944
  reasoningLength: reasoning.length,
34673
34945
  usage
34674
34946
  })
@@ -35059,10 +35331,10 @@ var init_pi = __esm({
35059
35331
  child.stdin.write(JSON.stringify(obj) + "\n");
35060
35332
  };
35061
35333
  const flushAssistantText = () => {
35062
- const text3 = assistantText;
35334
+ const text4 = assistantText;
35063
35335
  assistantText = "";
35064
- if (!text3.trim()) return;
35065
- emit({ ...base2(threadId, turnId), type: "item.completed", itemType: "assistant_text", text: text3 });
35336
+ if (!text4.trim()) return;
35337
+ emit({ ...base2(threadId, turnId), type: "item.completed", itemType: "assistant_text", text: text4 });
35066
35338
  };
35067
35339
  const settle = (ok, stopReason, usage) => {
35068
35340
  if (settled) return;
@@ -35455,7 +35727,7 @@ var init_minimax = __esm({
35455
35727
  nativeLog: {
35456
35728
  source: "minimax.chat.completions",
35457
35729
  outgoing: (_turn, messages, model) => ({ model, messageCount: messages.length }),
35458
- incoming: ({ text: text3, usage }) => ({ textLength: text3.length, usage })
35730
+ incoming: ({ text: text4, usage }) => ({ textLength: text4.length, usage })
35459
35731
  }
35460
35732
  });
35461
35733
  }
@@ -37122,10 +37394,10 @@ async function verifyHostedEndpoint(endpoint, { fetchImpl, timeoutSignal, timeou
37122
37394
  signal: cancellationSignal ? AbortSignal.any([requestSignal, cancellationSignal]) : requestSignal
37123
37395
  });
37124
37396
  if (!response.ok) return false;
37125
- const text3 = await response.text();
37126
- if (Buffer.byteLength(text3) > 4096) return false;
37397
+ const text4 = await response.text();
37398
+ if (Buffer.byteLength(text4) > 4096) return false;
37127
37399
  try {
37128
- return JSON.parse(text3)?.app === "openmausbot";
37400
+ return JSON.parse(text4)?.app === "openmausbot";
37129
37401
  } catch {
37130
37402
  return false;
37131
37403
  }
@@ -38046,9 +38318,9 @@ async function startCaddy(options) {
38046
38318
  });
38047
38319
  let output = "";
38048
38320
  const receive = (chunk) => {
38049
- const text3 = chunk.toString("utf8");
38050
- if (output.length < 16384) output += text3;
38051
- for (const line of text3.split(/\r?\n/)) {
38321
+ const text4 = chunk.toString("utf8");
38322
+ if (output.length < 16384) output += text4;
38323
+ for (const line of text4.split(/\r?\n/)) {
38052
38324
  if (!line.trim()) continue;
38053
38325
  if (/"level":"(warn|error)"/.test(line) || /^\S+\s+(WARN|ERROR)/.test(line) || !line.startsWith("{")) options.log?.(`caddy: ${line.slice(0, 400)}`);
38054
38326
  }
@@ -38315,8 +38587,8 @@ function agentUnit(spec) {
38315
38587
  function emptyRegistry(domain2) {
38316
38588
  return { version: 1, domain: domain2, nextPort: FLEET_FIRST_PORT, workspaces: {} };
38317
38589
  }
38318
- function parseRegistry(text3) {
38319
- const value = JSON.parse(text3);
38590
+ function parseRegistry(text4) {
38591
+ const value = JSON.parse(text4);
38320
38592
  const record3 = value && typeof value === "object" ? value : null;
38321
38593
  if (!record3 || record3.version !== 1 || typeof record3.domain !== "string" || typeof record3.nextPort !== "number" || !record3.workspaces || typeof record3.workspaces !== "object") {
38322
38594
  throw new Error("fleet.json is not a fleet registry this version understands");
@@ -38740,9 +39012,9 @@ function failed(io, what, output) {
38740
39012
  return 1;
38741
39013
  }
38742
39014
  function loadRegistry(layout, deps) {
38743
- const text3 = deps.readText(layout.registryFile);
38744
- if (text3 === null) throw new Error(`no fleet on this server yet: run \`openmausbot fleet init --domain your.domain\` first`);
38745
- return parseRegistry(text3);
39015
+ const text4 = deps.readText(layout.registryFile);
39016
+ if (text4 === null) throw new Error(`no fleet on this server yet: run \`openmausbot fleet init --domain your.domain\` first`);
39017
+ return parseRegistry(text4);
38746
39018
  }
38747
39019
  function planFleetAction(input, deps) {
38748
39020
  const layout = fleetLayout(input.root ?? "/");
@@ -38889,13 +39161,13 @@ function readUsage(dataDir, range) {
38889
39161
  const from = range.from.getTime();
38890
39162
  const to = range.to.getTime();
38891
39163
  for (const key of monthsBetween(range.from, range.to)) {
38892
- let text3;
39164
+ let text4;
38893
39165
  try {
38894
- text3 = readFileSync2(join4(dataDir, DIR, `${key}.jsonl`), "utf8");
39166
+ text4 = readFileSync2(join4(dataDir, DIR, `${key}.jsonl`), "utf8");
38895
39167
  } catch {
38896
39168
  continue;
38897
39169
  }
38898
- for (const line of text3.split("\n")) {
39170
+ for (const line of text4.split("\n")) {
38899
39171
  if (!line) continue;
38900
39172
  try {
38901
39173
  const value = JSON.parse(line);
@@ -38989,15 +39261,15 @@ function summarizeUsage(rows, groupBy, prices = null) {
38989
39261
  var MAX_BODY = 256 * 1024;
38990
39262
  function readBody(req) {
38991
39263
  return new Promise((resolve13, reject) => {
38992
- let text3 = "";
39264
+ let text4 = "";
38993
39265
  req.on("data", (chunk) => {
38994
- text3 += chunk.toString("utf8");
38995
- if (text3.length > MAX_BODY) reject(Object.assign(new Error("request too large"), { status: 413 }));
39266
+ text4 += chunk.toString("utf8");
39267
+ if (text4.length > MAX_BODY) reject(Object.assign(new Error("request too large"), { status: 413 }));
38996
39268
  });
38997
39269
  req.on("end", () => {
38998
- if (!text3.trim()) return resolve13({});
39270
+ if (!text4.trim()) return resolve13({});
38999
39271
  try {
39000
- const value = JSON.parse(text3);
39272
+ const value = JSON.parse(text4);
39001
39273
  resolve13(value && typeof value === "object" && !Array.isArray(value) ? value : {});
39002
39274
  } catch {
39003
39275
  reject(Object.assign(new Error("body must be JSON"), { status: 400 }));
@@ -39168,8 +39440,8 @@ var tailscaleEnvironment = () => ({
39168
39440
  });
39169
39441
 
39170
39442
  // server/tailscale.ts
39171
- function classifyTailscaleStderr(text3) {
39172
- const t2 = text3.toLowerCase();
39443
+ function classifyTailscaleStderr(text4) {
39444
+ const t2 = text4.toLowerCase();
39173
39445
  if (/not logged in|logged out|needs login|please log in/.test(t2)) return "not-logged-in";
39174
39446
  if (/is tailscale running|tailscaled is not running|connection refused|failed to connect to local tailscaled/.test(t2)) return "not-running";
39175
39447
  if (/access denied|permission denied|operator|must be root|not permitted/.test(t2)) return "needs-operator";
@@ -39900,9 +40172,9 @@ function pairingBlock(input) {
39900
40172
  }
39901
40173
  return lines.join("\n");
39902
40174
  }
39903
- function qrToString(text3) {
40175
+ function qrToString(text4) {
39904
40176
  let out = "";
39905
- import_qrcode_terminal.default.generate(text3, { small: true }, (rendered) => {
40177
+ import_qrcode_terminal.default.generate(text4, { small: true }, (rendered) => {
39906
40178
  out = rendered;
39907
40179
  });
39908
40180
  return out;
@@ -40317,9 +40589,9 @@ async function runServe(options, log = console.log) {
40317
40589
  });
40318
40590
  let tunnel = null;
40319
40591
  let caddy = null;
40320
- let stopping = null;
40592
+ let stopping2 = null;
40321
40593
  const stop = () => {
40322
- stopping ??= (async () => {
40594
+ stopping2 ??= (async () => {
40323
40595
  if (tunnel) await tunnel.stop().catch(() => void 0);
40324
40596
  if (caddy) await caddy.stop().catch(() => void 0);
40325
40597
  if (tailscaleServing && tailscale) await tailscaleServeOff(tailscale).catch(() => void 0);
@@ -40332,7 +40604,7 @@ async function runServe(options, log = console.log) {
40332
40604
  }
40333
40605
  if (plan) cleanupTunnelOrigin(plan.origin);
40334
40606
  })();
40335
- return stopping;
40607
+ return stopping2;
40336
40608
  };
40337
40609
  const onSignal = () => {
40338
40610
  void stop();
@@ -40341,7 +40613,7 @@ async function runServe(options, log = console.log) {
40341
40613
  process.on("SIGTERM", onSignal);
40342
40614
  try {
40343
40615
  const deadline = Date.now() + 6e4;
40344
- while (Date.now() < deadline && exited === null && !stopping) {
40616
+ while (Date.now() < deadline && exited === null && !stopping2) {
40345
40617
  if (await serverUp(options.port, child.pid)) break;
40346
40618
  await new Promise((r2) => setTimeout(r2, 250));
40347
40619
  }
@@ -40349,19 +40621,19 @@ async function runServe(options, log = console.log) {
40349
40621
  if (exited !== 0) log(`OpenMausBot could not start.${logPath ? ` Details: ${logPath}` : " See the output above."}`);
40350
40622
  return exited;
40351
40623
  }
40352
- if (stopping) return await childExit;
40624
+ if (stopping2) return await childExit;
40353
40625
  if (!await serverUp(options.port, child.pid)) {
40354
40626
  console.error(`OpenMausBot did not become ready within a minute.${logPath ? ` Details: ${logPath}` : " See its output above."}`);
40355
40627
  await stop();
40356
40628
  return 1;
40357
40629
  }
40358
- if (stopping || exited !== null) return await childExit;
40630
+ if (stopping2 || exited !== null) return await childExit;
40359
40631
  if (options.domain && caddyBinary) {
40360
40632
  try {
40361
40633
  caddy = await startCaddy({ binary: caddyBinary, dataDir: options.dataDir, domain: options.domain, appPort: options.port, webhookPort: Number(env.OMB_WEBHOOK_PORT), log });
40362
40634
  log(`https: Caddy serves ${publicUrl} \u2192 http://127.0.0.1:${options.port}; it gets the certificate from Let's Encrypt once DNS for ${options.domain} points at this machine`);
40363
40635
  void caddy.exited.then((code) => {
40364
- if (!stopping) log(`caddy: stopped (exit ${code ?? "signal"}); ${publicUrl} is no longer served. Stop and start the server again.`);
40636
+ if (!stopping2) log(`caddy: stopped (exit ${code ?? "signal"}); ${publicUrl} is no longer served. Stop and start the server again.`);
40365
40637
  });
40366
40638
  } catch (error51) {
40367
40639
  console.error(`--domain: ${message(error51)}`);
@@ -40404,7 +40676,7 @@ async function runServe(options, log = console.log) {
40404
40676
  ]);
40405
40677
  if (timer) clearTimeout(timer);
40406
40678
  }
40407
- if (!stopping && exited === null) await showPhonePairing(options, publicUrl, log);
40679
+ if (!stopping2 && exited === null) await showPhonePairing(options, publicUrl, log);
40408
40680
  } else if (options.pair && !options.guided) {
40409
40681
  log("");
40410
40682
  log(await mintPairing(options.port, { label: options.label ? `${options.label} owner` : void 0, client: options.client, publicUrl: publicUrl ?? void 0 }));