openmausbot 0.1.68 → 0.1.70

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 (41) hide show
  1. package/dist/assets/index-B2F__IRS.css +1 -0
  2. package/dist/assets/index-CLj3t5Ba.js +280 -0
  3. package/dist/assets/{index-HqooKFTS.js → index-D1RGhLUK.js} +1 -1
  4. package/dist/index.html +2 -2
  5. package/dist-server/container-mcp.js +40 -2
  6. package/dist-server/drivers/agents-proxy.js +188 -5
  7. package/dist-server/index.js +2431 -984
  8. package/dist-server/local-computer-proxy.js +2 -0
  9. package/dist-server/openmausbot.js +923 -334
  10. package/dist-server/pair-cli.js +923 -334
  11. package/dist-server/prepare-cloudflared.js +20 -3
  12. package/dist-server/server/avatar-image.js +86 -34
  13. package/dist-server/server/bot-package.js +60 -14
  14. package/dist-server/server/config.js +23 -2
  15. package/dist-server/server/delegations.js +132 -74
  16. package/dist-server/server/drivers/acp/qwen.js +142 -5
  17. package/dist-server/server/drivers/agents-proxy.js +224 -4
  18. package/dist-server/server/drivers/claude-login-auth.js +102 -9
  19. package/dist-server/server/drivers/claude.js +11 -5
  20. package/dist-server/server/drivers/codex-device-auth.js +102 -3
  21. package/dist-server/server/drivers/codex-identity.js +115 -0
  22. package/dist-server/server/drivers/codex.js +6 -0
  23. package/dist-server/server/engine-install.js +137 -0
  24. package/dist-server/server/env-path.js +12 -0
  25. package/dist-server/server/harness/registry.js +33 -6
  26. package/dist-server/server/index.js +365 -26
  27. package/dist-server/server/package-export.js +7 -0
  28. package/dist-server/server/peer-provenance.js +6 -2
  29. package/dist-server/server/provider-auth-sessions.js +24 -0
  30. package/dist-server/server/routine-requests.js +270 -25
  31. package/dist-server/server/routines.js +297 -69
  32. package/dist-server/server/steer-queue.js +48 -1
  33. package/dist-server/server/store.js +22 -4
  34. package/dist-server/server/system-prompt.js +1 -0
  35. package/dist-server/server/team-backup.js +18 -4
  36. package/dist-server/shared/image-generation.js +28 -0
  37. package/dist-server/shared/team-backup.js +1 -0
  38. package/dist-server/vps-container-mcp.js +40 -2
  39. package/package.json +1 -1
  40. package/dist/assets/index-CbaejjQA.js +0 -278
  41. package/dist/assets/index-aJ5EWZOQ.css +0 -1
@@ -2298,7 +2298,7 @@ function displayText(value, multiline = false) {
2298
2298
  }
2299
2299
  function plainText(question, hidden, context) {
2300
2300
  const { input, output, signal } = context;
2301
- return new Promise((resolve12, reject) => {
2301
+ return new Promise((resolve13, reject) => {
2302
2302
  input.setRawMode?.(hidden);
2303
2303
  const rl = createInterface({ input, terminal: hidden });
2304
2304
  let finished = false;
@@ -2309,7 +2309,7 @@ function plainText(question, hidden, context) {
2309
2309
  rl.close();
2310
2310
  output.write("\n");
2311
2311
  if (error51) reject(error51);
2312
- else resolve12(answer ?? "");
2312
+ else resolve13(answer ?? "");
2313
2313
  };
2314
2314
  const cancel = () => finish(void 0, signal.reason ?? new SetupCancelled());
2315
2315
  signal.addEventListener("abort", cancel, { once: true });
@@ -17526,6 +17526,30 @@ var init_zod = __esm({
17526
17526
  }
17527
17527
  });
17528
17528
 
17529
+ // shared/image-generation.ts
17530
+ function normalizeImageGenerationUrl(value) {
17531
+ const message2 = "Use an HTTPS API base URL, or HTTP for a local router, without passwords, query parameters or fragments";
17532
+ let url2;
17533
+ try {
17534
+ url2 = new URL(value.trim());
17535
+ } catch {
17536
+ throw new Error(message2);
17537
+ }
17538
+ if (value.length > 2048 || url2.username || url2.password || url2.search || url2.hash) throw new Error(message2);
17539
+ const host = url2.hostname.toLowerCase();
17540
+ const ipv43 = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(host);
17541
+ const local = host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host === "host.docker.internal" || host === "host.containers.internal" || host === "[::1]" || /^\[f[cd][0-9a-f]{2}:/.test(host) || ipv43 && (Number(ipv43[1]) === 127 || Number(ipv43[1]) === 10 || Number(ipv43[1]) === 192 && Number(ipv43[2]) === 168 || Number(ipv43[1]) === 172 && Number(ipv43[2]) >= 16 && Number(ipv43[2]) <= 31);
17542
+ if (url2.protocol !== "https:" && !(url2.protocol === "http:" && local)) throw new Error(message2);
17543
+ if (ipv43 && (Number(ipv43[1]) === 0 || Number(ipv43[1]) === 169 && Number(ipv43[2]) === 254)) throw new Error(message2);
17544
+ url2.pathname = url2.pathname.replace(/\/+$/, "").replace(/\/images\/generations$/, "");
17545
+ return url2.toString().replace(/\/+$/, "");
17546
+ }
17547
+ var init_image_generation = __esm({
17548
+ "shared/image-generation.ts"() {
17549
+ "use strict";
17550
+ }
17551
+ });
17552
+
17529
17553
  // server/contracts.ts
17530
17554
  var EFFORT_LEVELS, eventCounter, newEventId, newId;
17531
17555
  var init_contracts = __esm({
@@ -17732,6 +17756,7 @@ function loadConfig() {
17732
17756
  if (process.env.OMB_TTS_KEY !== void 0) cfg.tts.key = process.env.OMB_TTS_KEY;
17733
17757
  cfg.imageGen = { ...cfg.imageGen };
17734
17758
  if (process.env.OMB_OPENAI_IMAGE_KEY !== void 0) cfg.imageGen.key = process.env.OMB_OPENAI_IMAGE_KEY;
17759
+ if (process.env.OMB_CUSTOM_IMAGE_KEY !== void 0) cfg.imageGen.customApiKey = process.env.OMB_CUSTOM_IMAGE_KEY;
17735
17760
  const splitEmails = (value) => value.split(/[,\s]+/).map((entry) => entry.trim().toLowerCase()).filter(Boolean);
17736
17761
  if (process.env.OMB_SIGNIN_EMAILS !== void 0 || process.env.OMB_SIGNIN_MEMBER_EMAILS !== void 0) {
17737
17762
  cfg.signIn = { ...cfg.signIn };
@@ -17880,6 +17905,7 @@ var init_config = __esm({
17880
17905
  "server/config.ts"() {
17881
17906
  "use strict";
17882
17907
  init_zod();
17908
+ init_image_generation();
17883
17909
  init_atomic();
17884
17910
  init_contracts();
17885
17911
  init_mcp_registry();
@@ -17988,8 +18014,25 @@ var init_config = __esm({
17988
18014
  * engine: "elevenlabs" (default; needs a key) or "system" (the Mac's
17989
18015
  * built-in voices, no key). */
17990
18016
  tts: external_exports.object({ key: optionalText, voice: optionalText, provider: external_exports.enum(["elevenlabs", "system"]).optional() }).optional(),
17991
- /** OpenAI key used only by the in-process avatar image generator. */
17992
- imageGen: external_exports.object({ key: optionalText }).optional(),
18017
+ /** Avatar provider credentials stay separate; choosing a router never reuses a cloud key. */
18018
+ imageGen: external_exports.object({
18019
+ provider: external_exports.enum(["openai", "xai", "custom"]).optional(),
18020
+ key: optionalText,
18021
+ customApiKey: optionalText,
18022
+ customUrl: external_exports.string().trim().max(2048).transform((value, ctx) => {
18023
+ if (!value) return "";
18024
+ try {
18025
+ return normalizeImageGenerationUrl(value);
18026
+ } catch (error51) {
18027
+ ctx.addIssue({ code: "custom", message: error51.message });
18028
+ return external_exports.NEVER;
18029
+ }
18030
+ }).optional(),
18031
+ customModel: external_exports.string().trim().max(200).refine(
18032
+ (value) => !["\r", "\n", "\0"].some((character) => value.includes(character)),
18033
+ "Use a model ID without control characters"
18034
+ ).optional()
18035
+ }).optional(),
17993
18036
  /** Non-secret profile details shown in the sidebar. */
17994
18037
  profile: external_exports.object({ name: optionalText, email: optionalText }).optional(),
17995
18038
  /** UI language override (BCP-47, lowercase). Empty/absent = follow the
@@ -18024,6 +18067,7 @@ var init_config = __esm({
18024
18067
  "OPENCODE_API_KEY",
18025
18068
  "OMB_TTS_KEY",
18026
18069
  "OMB_OPENAI_IMAGE_KEY",
18070
+ "OMB_CUSTOM_IMAGE_KEY",
18027
18071
  "COMPOSIO_API_KEY",
18028
18072
  "OMB_COMPOSIO_BROKER_TOKEN",
18029
18073
  // Harness-private filesystem hints are not credentials themselves, but
@@ -18431,6 +18475,11 @@ function windowsKnownDirs() {
18431
18475
  join7(home, "go", "bin")
18432
18476
  ];
18433
18477
  }
18478
+ function registerPathDir(dir) {
18479
+ if (registeredDirs.includes(dir)) return;
18480
+ registeredDirs.unshift(dir);
18481
+ resetPathCache();
18482
+ }
18434
18483
  function resetPathCache() {
18435
18484
  cached2 = null;
18436
18485
  probed = false;
@@ -18438,6 +18487,7 @@ function resetPathCache() {
18438
18487
  function augmentedPath() {
18439
18488
  if (cached2 === null) {
18440
18489
  cached2 = mergePaths([
18490
+ ...registeredDirs.filter((d) => existsSync5(d)),
18441
18491
  ...process.env.OMB_EXTRA_PATH ? process.env.OMB_EXTRA_PATH.split(delimiter3) : [],
18442
18492
  ...process.env.PATH ? process.env.PATH.split(delimiter3) : [],
18443
18493
  // Keep the last successful login-shell result while a rescan starts a
@@ -18602,13 +18652,14 @@ function resolveCliSpawn(cli, args) {
18602
18652
  }
18603
18653
  return resolveWord(cli, args);
18604
18654
  }
18605
- var cached2, probed, loginShellPath;
18655
+ var cached2, probed, loginShellPath, registeredDirs;
18606
18656
  var init_env_path = __esm({
18607
18657
  "server/env-path.ts"() {
18608
18658
  "use strict";
18609
18659
  cached2 = null;
18610
18660
  probed = false;
18611
18661
  loginShellPath = null;
18662
+ registeredDirs = [];
18612
18663
  }
18613
18664
  });
18614
18665
 
@@ -18679,12 +18730,12 @@ function describeSpawnFailure(err, cli) {
18679
18730
  function killCliTree(child, timeoutMs = 5e3) {
18680
18731
  const pid = child.pid;
18681
18732
  if (!pid || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);
18682
- return new Promise((resolve12) => {
18733
+ return new Promise((resolve13) => {
18683
18734
  let timer;
18684
18735
  const done = (stopped) => {
18685
18736
  clearTimeout(timer);
18686
18737
  child.off("close", closed);
18687
- resolve12(stopped);
18738
+ resolve13(stopped);
18688
18739
  };
18689
18740
  const closed = () => done(true);
18690
18741
  child.once("close", closed);
@@ -18722,7 +18773,124 @@ var init_procs = __esm({
18722
18773
  }
18723
18774
  });
18724
18775
 
18776
+ // server/engine-install.ts
18777
+ import { existsSync as existsSync6, mkdirSync as mkdirSync6 } from "node:fs";
18778
+ import { join as join9 } from "node:path";
18779
+ import { stripVTControlCharacters as stripVTControlCharacters3 } from "node:util";
18780
+ function enginesPrefix(baseDir = DATA_DIR) {
18781
+ return join9(baseDir, "tools", "npm");
18782
+ }
18783
+ function enginesBinDir(baseDir = DATA_DIR, platform = process.platform) {
18784
+ return platform === "win32" ? enginesPrefix(baseDir) : join9(enginesPrefix(baseDir), "bin");
18785
+ }
18786
+ function npmPackageOf(install) {
18787
+ const line = install?.command?.linux ?? install?.command?.darwin ?? install?.command?.win32;
18788
+ const match = line ? /^npm install -g ((?:@[\w.-]+\/)?[\w.-]+)$/.exec(line.trim()) : null;
18789
+ return match ? match[1] : null;
18790
+ }
18791
+ function npmAvailable() {
18792
+ return findCliCandidates("npm").length > 0;
18793
+ }
18794
+ function serverInstallFor(install, npmPresent = npmAvailable()) {
18795
+ if (!install || install.managed) return null;
18796
+ const pkg = npmPackageOf(install);
18797
+ return pkg && npmPresent ? { package: pkg } : null;
18798
+ }
18799
+ function installNpmEngine(pkg, options = {}) {
18800
+ const key = `${options.baseDir ?? DATA_DIR} ${pkg}`;
18801
+ const existing = running.get(key);
18802
+ if (existing) return existing;
18803
+ const run3 = installOnce(pkg, options).finally(() => running.delete(key));
18804
+ running.set(key, run3);
18805
+ return run3;
18806
+ }
18807
+ async function installOnce(pkg, options) {
18808
+ const prefix = enginesPrefix(options.baseDir);
18809
+ mkdirSync6(prefix, { recursive: true });
18810
+ const env = {
18811
+ ...options.env ?? process.env,
18812
+ PATH: options.path ?? augmentedPath(),
18813
+ NO_COLOR: "1",
18814
+ npm_config_update_notifier: "false",
18815
+ npm_config_fund: "false",
18816
+ npm_config_audit: "false"
18817
+ };
18818
+ stripWorkspaceCredentialEnv(env);
18819
+ const args = ["install", "-g", "--prefix", prefix, "--loglevel=error", `--allow-scripts=${pkg}`, `${pkg}@latest`];
18820
+ const result = await runNpm(args, env, prefix, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
18821
+ if (result.code !== 0) {
18822
+ throw new Error(`npm could not install ${pkg} on this server.${tail(result.output)}`);
18823
+ }
18824
+ registerPathDir(enginesBinDir(options.baseDir));
18825
+ resetPathCache();
18826
+ if (options.cli) {
18827
+ const binDir = enginesBinDir(options.baseDir);
18828
+ if (!findCliCandidates(options.cli).some((path3) => path3.startsWith(binDir))) {
18829
+ throw new Error(`${pkg} installed, but it did not provide a \`${options.cli}\` command. Check the package name in this engine's install descriptor.`);
18830
+ }
18831
+ }
18832
+ }
18833
+ function tail(output) {
18834
+ const clean = stripVTControlCharacters3(output).trim();
18835
+ if (!clean) return "";
18836
+ const lines = clean.split(/\r?\n/).filter((line) => line.trim()).slice(-6);
18837
+ return `
18838
+ ${lines.join("\n").slice(-600)}`;
18839
+ }
18840
+ function runNpm(args, env, cwd, timeoutMs) {
18841
+ return new Promise((resolveRun, rejectRun) => {
18842
+ let child;
18843
+ try {
18844
+ child = spawnCli("npm", args, { env, cwd, stdio: ["pipe", "pipe", "pipe"] });
18845
+ } catch {
18846
+ rejectRun(new Error("npm could not start on this server. Install Node.js with npm for the user running OpenMausBot, then try again."));
18847
+ return;
18848
+ }
18849
+ child.stdin.end();
18850
+ let output = "";
18851
+ const receive = (chunk) => {
18852
+ if (output.length < MAX_OUTPUT) output += chunk.toString("utf8").slice(0, MAX_OUTPUT - output.length);
18853
+ };
18854
+ child.stdout.on("data", receive);
18855
+ child.stderr.on("data", receive);
18856
+ let timedOut = false;
18857
+ const timer = setTimeout(() => {
18858
+ timedOut = true;
18859
+ void killCliTree(child);
18860
+ }, timeoutMs);
18861
+ timer.unref();
18862
+ child.once("error", (error51) => {
18863
+ clearTimeout(timer);
18864
+ 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."));
18865
+ });
18866
+ child.once("close", (code) => {
18867
+ clearTimeout(timer);
18868
+ if (timedOut) {
18869
+ rejectRun(new Error("The install took too long and was stopped. Check the server's network connection and try again."));
18870
+ return;
18871
+ }
18872
+ resolveRun({ code, output });
18873
+ });
18874
+ });
18875
+ }
18876
+ var MAX_OUTPUT, DEFAULT_TIMEOUT_MS, running;
18877
+ var init_engine_install = __esm({
18878
+ "server/engine-install.ts"() {
18879
+ "use strict";
18880
+ init_config();
18881
+ init_env_path();
18882
+ init_procs();
18883
+ MAX_OUTPUT = 64 * 1024;
18884
+ DEFAULT_TIMEOUT_MS = 10 * 6e4;
18885
+ running = /* @__PURE__ */ new Map();
18886
+ }
18887
+ });
18888
+
18725
18889
  // server/harness/registry.ts
18890
+ function withServerInstall(install, npmPresent) {
18891
+ const server = install ? serverInstallFor(install, npmPresent) : null;
18892
+ return server ? { ...install, server } : install;
18893
+ }
18726
18894
  function cliDefaultOf(driver) {
18727
18895
  if (!driver) return void 0;
18728
18896
  try {
@@ -18741,13 +18909,21 @@ var init_registry = __esm({
18741
18909
  "server/harness/registry.ts"() {
18742
18910
  "use strict";
18743
18911
  init_env_path();
18912
+ init_engine_install();
18744
18913
  ProviderRegistry = class {
18745
18914
  byId = /* @__PURE__ */ new Map();
18746
18915
  /** decoded per-instance `cli` overrides, for describe() — drivers spawn
18747
18916
  * from their own config; this map only reports what was configured */
18748
18917
  cliByInstance = /* @__PURE__ */ new Map();
18749
18918
  driversByKind;
18750
- constructor(drivers) {
18919
+ /** Where Settings-driven npm installs go; the data directory by default. */
18920
+ enginesBaseDir;
18921
+ /** Whether npm is on this machine; injectable because the PATH scan also
18922
+ * looks in standard install locations, which tests cannot empty. */
18923
+ npmPresent;
18924
+ constructor(drivers, options = {}) {
18925
+ this.enginesBaseDir = options.enginesBaseDir;
18926
+ this.npmPresent = options.npmAvailable ?? npmAvailable;
18751
18927
  this.driversByKind = new Map(drivers.map((d) => [d.driverKind, d]));
18752
18928
  }
18753
18929
  async load(configs) {
@@ -18822,10 +18998,20 @@ var init_registry = __esm({
18822
18998
  await instance.refreshModels?.();
18823
18999
  return true;
18824
19000
  }
19001
+ /** A driver's own installer (a managed download) first; otherwise the
19002
+ * app's npm prefix, when the driver's install one-liner is an npm package
19003
+ * and npm is on PATH. False means Settings has nothing to offer here. */
18825
19004
  async installRuntime(instanceId) {
18826
- const instance = this.get(instanceId);
18827
- if (!instance?.installRuntime) return false;
18828
- await instance.installRuntime();
19005
+ const entry = this.byId.get(instanceId);
19006
+ if (!entry) return false;
19007
+ if (entry.live?.installRuntime) {
19008
+ await entry.live.installRuntime();
19009
+ return true;
19010
+ }
19011
+ const driver = this.driversByKind.get(entry.shadow?.driverKind ?? entry.live.driverKind);
19012
+ const server = serverInstallFor(driver?.install, this.npmPresent());
19013
+ if (!server) return false;
19014
+ await installNpmEngine(server.package, { baseDir: this.enginesBaseDir, cli: cliDefaultOf(driver) });
18829
19015
  return true;
18830
19016
  }
18831
19017
  async startAuthentication(instanceId) {
@@ -18860,6 +19046,7 @@ var init_registry = __esm({
18860
19046
  candidatesByName.set(name, found);
18861
19047
  return found;
18862
19048
  };
19049
+ const npmPresent = this.npmPresent();
18863
19050
  return Promise.all(
18864
19051
  this.entries().map(async (entry) => {
18865
19052
  const driver = this.driversByKind.get(entry.shadow?.driverKind ?? entry.live.driverKind);
@@ -18873,7 +19060,7 @@ var init_registry = __esm({
18873
19060
  capabilities: { computerMcp: false, agentsMcp: false, localComputerMcp: false },
18874
19061
  // an unknown driver has no driver record, hence no install path
18875
19062
  access: driver?.metadata.access ?? "subscription",
18876
- install: driver?.install,
19063
+ install: withServerInstall(driver?.install, npmPresent),
18877
19064
  cli: entry.shadow.cli,
18878
19065
  cliDefault: cliDefaultOf(driver),
18879
19066
  // a shadow is exactly the "your CLI is broken, pick another"
@@ -18907,10 +19094,12 @@ var init_registry = __esm({
18907
19094
  approvalReview: inst.reviewPermission !== void 0
18908
19095
  },
18909
19096
  access: driver?.metadata.access ?? "subscription",
18910
- install: driver?.install,
19097
+ install: withServerInstall(driver?.install, npmPresent),
18911
19098
  authentication: inst.startAuthentication ? {
18912
- method: inst.getAuthentication && inst.completeAuthentication ? "paste-code" : inst.getAuthentication ? "device-code" : "browser"
19099
+ method: inst.getAuthentication && inst.completeAuthentication ? "paste-code" : inst.getAuthentication ? "device-code" : "browser",
18913
19100
  // a link and a callback URL (managed engines)
19101
+ // the browser may remove the stored sign-in to switch accounts
19102
+ signOut: inst.signOut !== void 0
18914
19103
  } : void 0,
18915
19104
  cli: this.cliByInstance.get(inst.instanceId),
18916
19105
  cliDefault: cliDefaultOf(driver),
@@ -18940,7 +19129,7 @@ var init_registry = __esm({
18940
19129
  // server/drivers/local-inject.ts
18941
19130
  import { readFileSync as readFileSync5 } from "node:fs";
18942
19131
  import { homedir as homedir6 } from "node:os";
18943
- import { join as join9 } from "node:path";
19132
+ import { join as join10 } from "node:path";
18944
19133
  function contextWindowsFromPs(extra) {
18945
19134
  const out = /* @__PURE__ */ new Map();
18946
19135
  const rec = extra && typeof extra === "object" ? extra : null;
@@ -19025,7 +19214,7 @@ function firstUnslothToken(row) {
19025
19214
  function readUnslothKey(env) {
19026
19215
  const home = env.HOME || env.USERPROFILE || homedir6();
19027
19216
  try {
19028
- const raw = JSON.parse(readFileSync5(join9(home, ".unsloth", "studio", "auth", "agent_api_key.json"), "utf8"));
19217
+ const raw = JSON.parse(readFileSync5(join10(home, ".unsloth", "studio", "auth", "agent_api_key.json"), "utf8"));
19029
19218
  if (raw.servers && typeof raw.servers === "object") {
19030
19219
  const servers = raw.servers;
19031
19220
  for (const url2 of ["http://127.0.0.1:8888", "http://localhost:8888"]) {
@@ -19084,12 +19273,12 @@ function loadedIdsFromPayloads(_host, catalog, extra) {
19084
19273
  };
19085
19274
  if (extra && typeof extra === "object") {
19086
19275
  const rec = extra;
19087
- const running = Array.isArray(rec.models) ? rec.models : Array.isArray(rec.data) ? rec.data : [];
19088
- const hasLoadedFlags = running.some(
19276
+ const running2 = Array.isArray(rec.models) ? rec.models : Array.isArray(rec.data) ? rec.data : [];
19277
+ const hasLoadedFlags = running2.some(
19089
19278
  (row) => row && typeof row === "object" && ("loaded" in row || "state" in row)
19090
19279
  );
19091
19280
  if (!hasLoadedFlags && typeof rec.default_model === "string") add(rec.default_model);
19092
- for (const row of running) {
19281
+ for (const row of running2) {
19093
19282
  if (typeof row === "string") {
19094
19283
  if (!hasLoadedFlags) add(row);
19095
19284
  continue;
@@ -19226,12 +19415,12 @@ var init_local_inject = __esm({
19226
19415
  });
19227
19416
 
19228
19417
  // server/proxy-paths.ts
19229
- import { existsSync as existsSync6 } from "node:fs";
19230
- import { dirname as dirname4, join as join10 } from "node:path";
19418
+ import { existsSync as existsSync7 } from "node:fs";
19419
+ import { dirname as dirname4, join as join11 } from "node:path";
19231
19420
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19232
19421
  function resolveProxy(relative2) {
19233
- const source = join10(SERVER_ROOT, `${relative2}.ts`);
19234
- return existsSync6(source) ? source : join10(SERVER_ROOT, `${relative2}.js`);
19422
+ const source = join11(SERVER_ROOT, `${relative2}.ts`);
19423
+ return existsSync7(source) ? source : join11(SERVER_ROOT, `${relative2}.js`);
19235
19424
  }
19236
19425
  var SERVER_ROOT, SPAWNED_PROXIES;
19237
19426
  var init_proxy_paths = __esm({
@@ -19259,7 +19448,7 @@ var init_proxy_paths = __esm({
19259
19448
 
19260
19449
  // server/container-computer.ts
19261
19450
  import { execFile as execFile4 } from "node:child_process";
19262
- import { join as join11, resolve as resolve3 } from "node:path";
19451
+ import { join as join12, resolve as resolve3 } from "node:path";
19263
19452
  import { promisify } from "node:util";
19264
19453
  function computerProxyEnv(computer) {
19265
19454
  return {
@@ -19283,7 +19472,7 @@ var init_container_computer = __esm({
19283
19472
  IMAGE_REPOSITORY = "localhost/openmausbot/cua-local-vm";
19284
19473
  IMAGE_LAYER_VERSION = "5";
19285
19474
  IMAGE = `${IMAGE_REPOSITORY}:driver-${CUA_DRIVER_VERSION}-v${IMAGE_LAYER_VERSION}`;
19286
- VM_WORKSPACE_DIR = join11(DATA_DIR, "vm-home");
19475
+ VM_WORKSPACE_DIR = join12(DATA_DIR, "vm-home");
19287
19476
  MEMORY_BYTES = 4 * 1024 * 1024 * 1024;
19288
19477
  SHM_BYTES = 512 * 1024 * 1024;
19289
19478
  containerMcpPath = SPAWNED_PROXIES.containerMcp;
@@ -19374,11 +19563,11 @@ var init_redact = __esm({
19374
19563
 
19375
19564
  // server/drivers/native.ts
19376
19565
  import { appendFileSync } from "node:fs";
19377
- import { join as join12 } from "node:path";
19566
+ import { join as join13 } from "node:path";
19378
19567
  function appendNative(threadId, entry) {
19379
19568
  try {
19380
19569
  appendFileSync(
19381
- join12(NATIVE_DIR, `${threadId}.ndjson`),
19570
+ join13(NATIVE_DIR, `${threadId}.ndjson`),
19382
19571
  JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry, msg: redactSecrets(entry.msg) }) + "\n",
19383
19572
  { mode: 384 }
19384
19573
  );
@@ -19625,7 +19814,7 @@ function createAcpDriver(support11) {
19625
19814
  }
19626
19815
  appendNative(threadId, { dir: "out", source: SOURCE, msg: nativeLogMessage(obj) });
19627
19816
  };
19628
- const request = (method, params, timeoutMs) => new Promise((resolve12, reject) => {
19817
+ const request = (method, params, timeoutMs) => new Promise((resolve13, reject) => {
19629
19818
  const id = nextId++;
19630
19819
  let timer = null;
19631
19820
  if (timeoutMs) {
@@ -19635,7 +19824,7 @@ function createAcpDriver(support11) {
19635
19824
  }, timeoutMs);
19636
19825
  timer.unref?.();
19637
19826
  }
19638
- rpcPending.set(id, { resolve: resolve12, reject, timer });
19827
+ rpcPending.set(id, { resolve: resolve13, reject, timer });
19639
19828
  send({ jsonrpc: "2.0", id, method, params });
19640
19829
  });
19641
19830
  const stop = () => killCliTree(child);
@@ -20071,12 +20260,12 @@ ${turn.text}` : turn.text;
20071
20260
  const snapshot = async () => {
20072
20261
  const env = childEnv();
20073
20262
  if (support11.snapshot) return support11.snapshot(env, config2, instanceId);
20074
- const version2 = await new Promise((resolve12) => {
20263
+ const version2 = await new Promise((resolve13) => {
20075
20264
  execCli(
20076
20265
  config2.cli,
20077
20266
  ["--version"],
20078
20267
  { timeout: 8e3, env },
20079
- (err, stdout2) => resolve12(err ? null : stdout2.trim())
20268
+ (err, stdout2) => resolve13(err ? null : stdout2.trim())
20080
20269
  );
20081
20270
  });
20082
20271
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
@@ -20164,7 +20353,7 @@ import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypt
20164
20353
  import { mkdir as mkdir2, mkdtemp, readFile as readFile2, rm, stat as stat2 } from "node:fs/promises";
20165
20354
  import { request as httpRequest } from "node:http";
20166
20355
  import { tmpdir as tmpdir2 } from "node:os";
20167
- import { delimiter as delimiter4, join as join13, resolve as resolve5 } from "node:path";
20356
+ import { delimiter as delimiter4, join as join14, resolve as resolve5 } from "node:path";
20168
20357
  function quoteBrowserArgument(value) {
20169
20358
  return `'${value.replaceAll("'", `'"'"'`)}'`;
20170
20359
  }
@@ -20199,11 +20388,11 @@ function authorizationUrlFromLine(line) {
20199
20388
  }
20200
20389
  }
20201
20390
  function antigravityProfileDirectory(instanceId, baseDir = DATA_DIR) {
20202
- return join13(baseDir, "providers", "antigravity", createHash3("sha256").update(instanceId).digest("hex"));
20391
+ return join14(baseDir, "providers", "antigravity", createHash3("sha256").update(instanceId).digest("hex"));
20203
20392
  }
20204
20393
  async function prepareAntigravityProfile(input) {
20205
20394
  const directory = resolve5(input.profileDirectory ?? antigravityProfileDirectory(input.instanceId, input.baseDir));
20206
- const acpDirectory = join13(directory, "antigravity-acp");
20395
+ const acpDirectory = join14(directory, "antigravity-acp");
20207
20396
  await mkdir2(acpDirectory, { recursive: true, mode: 448 });
20208
20397
  if (process.platform !== "win32") {
20209
20398
  const { chmod: chmod2 } = await import("node:fs/promises");
@@ -20211,7 +20400,7 @@ async function prepareAntigravityProfile(input) {
20211
20400
  await chmod2(acpDirectory, 448);
20212
20401
  }
20213
20402
  writeFileAtomic(
20214
- join13(acpDirectory, "settings.json"),
20403
+ join14(acpDirectory, "settings.json"),
20215
20404
  `${JSON.stringify({ auth: { type: "oauth-personal" } })}
20216
20405
  `,
20217
20406
  { mode: 384 }
@@ -20234,7 +20423,7 @@ async function prepareAntigravityProfile(input) {
20234
20423
  PYTHONUNBUFFERED: "1",
20235
20424
  ELECTRON_RUN_AS_NODE: "1"
20236
20425
  });
20237
- return { directory, tokenPath: join13(acpDirectory, "acp_token.json"), environment };
20426
+ return { directory, tokenPath: join14(acpDirectory, "acp_token.json"), environment };
20238
20427
  }
20239
20428
  async function antigravityProfileAuthenticated(profile) {
20240
20429
  try {
@@ -20363,7 +20552,7 @@ function isValidAntigravityInitializeResult(initialized, expectedVersion) {
20363
20552
  return true;
20364
20553
  }
20365
20554
  async function validateAntigravityRuntime(runtime, expectedVersion) {
20366
- const profileDirectory = await mkdtemp(join13(tmpdir2(), "openmaus-antigravity-verify-"));
20555
+ const profileDirectory = await mkdtemp(join14(tmpdir2(), "openmaus-antigravity-verify-"));
20367
20556
  let client;
20368
20557
  let failed = false;
20369
20558
  let failure;
@@ -20466,14 +20655,14 @@ var init_antigravity_acp = __esm({
20466
20655
  this.child.stderr.setEncoding("utf8");
20467
20656
  this.child.stderr.on("data", (chunk) => this.consumeDiagnostics(chunk));
20468
20657
  this.child.once("error", (error51) => this.failAll(error51));
20469
- this.exited = new Promise((resolve12) => {
20658
+ this.exited = new Promise((resolve13) => {
20470
20659
  this.child.once("close", (code, signal) => {
20471
20660
  this.noteStartupDiagnostic(this.diagnosticBuffer);
20472
20661
  this.diagnosticBuffer = "";
20473
20662
  if (!this.closed) this.failAll(new Error(
20474
20663
  `Antigravity ACP exited ${code ?? signal ?? "unexpectedly"}.${this.nativeStartupHint ? ` ${this.nativeStartupHint}` : ""}`
20475
20664
  ));
20476
- resolve12();
20665
+ resolve13();
20477
20666
  });
20478
20667
  });
20479
20668
  }
@@ -20579,8 +20768,8 @@ var init_antigravity_acp = __esm({
20579
20768
  async closeAndWait(timeoutMs = 5e3) {
20580
20769
  this.close();
20581
20770
  let timer;
20582
- const timedOut = new Promise((resolve12) => {
20583
- timer = setTimeout(() => resolve12(false), timeoutMs);
20771
+ const timedOut = new Promise((resolve13) => {
20772
+ timer = setTimeout(() => resolve13(false), timeoutMs);
20584
20773
  timer.unref?.();
20585
20774
  });
20586
20775
  try {
@@ -20752,7 +20941,7 @@ import {
20752
20941
  writeFile as writeFile2
20753
20942
  } from "node:fs/promises";
20754
20943
  import { constants } from "node:fs";
20755
- import { delimiter as delimiter5, dirname as dirname6, isAbsolute as isAbsolute2, join as join14, resolve as resolve6 } from "node:path";
20944
+ import { delimiter as delimiter5, dirname as dirname6, isAbsolute as isAbsolute2, join as join15, resolve as resolve6 } from "node:path";
20756
20945
  import { Transform } from "node:stream";
20757
20946
  import { pipeline } from "node:stream/promises";
20758
20947
  import { createInflateRaw } from "node:zlib";
@@ -20773,7 +20962,7 @@ async function retryOnWindowsFileLock(step, options = {}) {
20773
20962
  }
20774
20963
  }
20775
20964
  function runtimeRoot(baseDir = DATA_DIR) {
20776
- return join14(baseDir, "tools", "antigravity-acp", `${process.platform}-${process.arch}`);
20965
+ return join15(baseDir, "tools", "antigravity-acp", `${process.platform}-${process.arch}`);
20777
20966
  }
20778
20967
  function executableNames(platform = process.platform) {
20779
20968
  return platform === "win32" ? { executable: "agy_acp_server.exe", harness: "localharness_external.exe" } : { executable: "agy_acp_server.par", harness: "localharness_external" };
@@ -20790,10 +20979,10 @@ async function executableFile(path3, bytes) {
20790
20979
  }
20791
20980
  async function completedRelease(directory, asset) {
20792
20981
  try {
20793
- const record3 = JSON.parse(await readFile3(join14(directory, INSTALL_RECORD), "utf8"));
20982
+ const record3 = JSON.parse(await readFile3(join15(directory, INSTALL_RECORD), "utf8"));
20794
20983
  if (record3.sha256 !== asset.sha256 || record3.version !== asset.version || record3.executable.name !== asset.executable.name || record3.executable.bytes !== asset.executable.bytes || record3.harness.name !== asset.harness.name || record3.harness.bytes !== asset.harness.bytes) return null;
20795
- const executablePath = join14(directory, asset.executable.name);
20796
- const harnessPath = join14(directory, asset.harness.name);
20984
+ const executablePath = join15(directory, asset.executable.name);
20985
+ const harnessPath = join15(directory, asset.harness.name);
20797
20986
  if (!await executableFile(executablePath, asset.executable.bytes)) return null;
20798
20987
  if (!await executableFile(harnessPath, asset.harness.bytes)) return null;
20799
20988
  return { executablePath, harnessPath, source: "managed", version: asset.version };
@@ -20809,7 +20998,7 @@ function pathCandidates(binary2, env) {
20809
20998
  async function externalRuntime(candidate, source) {
20810
20999
  const names = executableNames();
20811
21000
  const executablePath = resolve6(candidate);
20812
- const harnessPath = join14(dirname6(executablePath), names.harness);
21001
+ const harnessPath = join15(dirname6(executablePath), names.harness);
20813
21002
  if (!await executableFile(executablePath) || !await executableFile(harnessPath)) return null;
20814
21003
  return { executablePath, harnessPath, source, version: null };
20815
21004
  }
@@ -20829,7 +21018,7 @@ async function resolveAntigravityRuntime(binaryPath, env = process.env, baseDir
20829
21018
  }
20830
21019
  const asset = resolveAntigravityReleaseAsset();
20831
21020
  if (asset) {
20832
- const managed = await completedRelease(join14(runtimeRoot(baseDir), "versions", asset.sha256), asset);
21021
+ const managed = await completedRelease(join15(runtimeRoot(baseDir), "versions", asset.sha256), asset);
20833
21022
  if (managed) return managed;
20834
21023
  }
20835
21024
  const names = executableNames();
@@ -20849,25 +21038,25 @@ async function pinnedZipEntries(path3) {
20849
21038
  try {
20850
21039
  const info = await handle.stat();
20851
21040
  const tailBytes = Math.min(info.size, MAX_EOCD_BYTES);
20852
- const tail = Buffer.alloc(tailBytes);
21041
+ const tail2 = Buffer.alloc(tailBytes);
20853
21042
  const tailOffset = info.size - tailBytes;
20854
- if ((await handle.read(tail, 0, tailBytes, tailOffset)).bytesRead !== tailBytes) {
21043
+ if ((await handle.read(tail2, 0, tailBytes, tailOffset)).bytesRead !== tailBytes) {
20855
21044
  throw new Error("The verified archive was truncated.");
20856
21045
  }
20857
21046
  let eocd = -1;
20858
- for (let cursor4 = tail.length - 22; cursor4 >= 0; cursor4 -= 1) {
20859
- if (tail.readUInt32LE(cursor4) === EOCD_SIGNATURE && cursor4 + 22 + tail.readUInt16LE(cursor4 + 20) === tail.length) {
21047
+ for (let cursor4 = tail2.length - 22; cursor4 >= 0; cursor4 -= 1) {
21048
+ if (tail2.readUInt32LE(cursor4) === EOCD_SIGNATURE && cursor4 + 22 + tail2.readUInt16LE(cursor4 + 20) === tail2.length) {
20860
21049
  eocd = cursor4;
20861
21050
  break;
20862
21051
  }
20863
21052
  }
20864
21053
  if (eocd < 0) throw new Error("The verified archive has no valid ZIP directory.");
20865
- const disk = tail.readUInt16LE(eocd + 4);
20866
- const directoryDisk = tail.readUInt16LE(eocd + 6);
20867
- const diskEntries = tail.readUInt16LE(eocd + 8);
20868
- const entryCount = tail.readUInt16LE(eocd + 10);
20869
- const directoryBytes = tail.readUInt32LE(eocd + 12);
20870
- const directoryOffset = tail.readUInt32LE(eocd + 16);
21054
+ const disk = tail2.readUInt16LE(eocd + 4);
21055
+ const directoryDisk = tail2.readUInt16LE(eocd + 6);
21056
+ const diskEntries = tail2.readUInt16LE(eocd + 8);
21057
+ const entryCount = tail2.readUInt16LE(eocd + 10);
21058
+ const directoryBytes = tail2.readUInt32LE(eocd + 12);
21059
+ const directoryOffset = tail2.readUInt32LE(eocd + 16);
20871
21060
  const eocdOffset = tailOffset + eocd;
20872
21061
  if (disk !== 0 || directoryDisk !== 0 || diskEntries !== entryCount || entryCount !== 2 || directoryBytes === 4294967295 || directoryOffset === 4294967295 || directoryOffset + directoryBytes > eocdOffset) throw new Error("The verified archive uses an unsupported ZIP layout.");
20873
21062
  const directory = Buffer.alloc(directoryBytes);
@@ -20951,19 +21140,19 @@ async function extractPinnedArchive(archivePath, outputDirectory, asset) {
20951
21140
  start: dataOffset,
20952
21141
  end: dataOffset + entry.compressedBytes - 1
20953
21142
  });
20954
- const destination = createWriteStream(join14(outputDirectory, entry.name), { flags: "wx", mode: 448 });
21143
+ const destination = createWriteStream(join15(outputDirectory, entry.name), { flags: "wx", mode: 448 });
20955
21144
  if (entry.compression === 8) await pipeline(source, createInflateRaw(), counter, destination);
20956
21145
  else await pipeline(source, counter, destination);
20957
21146
  if (bytes !== expectedBytes) throw new Error("An extracted file was truncated.");
20958
21147
  }
20959
21148
  if (seen.size !== 2) throw new Error("The archive is missing an expected file.");
20960
21149
  }
20961
- async function installOnce(options) {
21150
+ async function installOnce2(options) {
20962
21151
  const asset = options.asset === void 0 ? resolveAntigravityReleaseAsset() : options.asset;
20963
21152
  if (!asset) throw new Error(`Google does not publish an Antigravity runtime for ${process.platform}-${process.arch}.`);
20964
21153
  const root = runtimeRoot(options.baseDir);
20965
- const versions = join14(root, "versions");
20966
- const destination = join14(versions, asset.sha256);
21154
+ const versions = join15(root, "versions");
21155
+ const destination = join15(versions, asset.sha256);
20967
21156
  await mkdir3(versions, { recursive: true, mode: 448 });
20968
21157
  const existing = await completedRelease(destination, asset);
20969
21158
  if (existing) {
@@ -20979,11 +21168,11 @@ async function installOnce(options) {
20979
21168
  } catch (error51) {
20980
21169
  if (error51 instanceof Error && error51.message.includes("Antigravity needs")) throw error51;
20981
21170
  }
20982
- const staging = await mkdtemp2(join14(versions, `${STAGING_PREFIX}${randomUUID7()}-`));
21171
+ const staging = await mkdtemp2(join15(versions, `${STAGING_PREFIX}${randomUUID7()}-`));
20983
21172
  let failed = false;
20984
21173
  try {
20985
- const archivePath = join14(staging, "download.zip");
20986
- const runtimeDirectory = join14(staging, "runtime");
21174
+ const archivePath = join15(staging, "download.zip");
21175
+ const runtimeDirectory = join15(staging, "runtime");
20987
21176
  await mkdir3(runtimeDirectory, { mode: 448 });
20988
21177
  const controller = new AbortController();
20989
21178
  const timeout = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS2);
@@ -21029,12 +21218,12 @@ async function installOnce(options) {
21029
21218
  }
21030
21219
  await extractPinnedArchive(archivePath, runtimeDirectory, asset);
21031
21220
  if (process.platform !== "win32") {
21032
- await chmod(join14(runtimeDirectory, asset.executable.name), 493);
21033
- await chmod(join14(runtimeDirectory, asset.harness.name), 493);
21221
+ await chmod(join15(runtimeDirectory, asset.executable.name), 493);
21222
+ await chmod(join15(runtimeDirectory, asset.harness.name), 493);
21034
21223
  }
21035
21224
  const candidate = {
21036
- executablePath: join14(runtimeDirectory, asset.executable.name),
21037
- harnessPath: join14(runtimeDirectory, asset.harness.name),
21225
+ executablePath: join15(runtimeDirectory, asset.executable.name),
21226
+ harnessPath: join15(runtimeDirectory, asset.harness.name),
21038
21227
  source: "managed",
21039
21228
  version: asset.version
21040
21229
  };
@@ -21045,7 +21234,7 @@ async function installOnce(options) {
21045
21234
  executable: asset.executable,
21046
21235
  harness: asset.harness
21047
21236
  };
21048
- await writeFile2(join14(runtimeDirectory, INSTALL_RECORD), `${JSON.stringify(record3)}
21237
+ await writeFile2(join15(runtimeDirectory, INSTALL_RECORD), `${JSON.stringify(record3)}
21049
21238
  `, { flag: "wx", mode: 384 });
21050
21239
  try {
21051
21240
  await retryOnWindowsFileLock(() => rename(runtimeDirectory, destination));
@@ -21072,9 +21261,9 @@ function installAntigravityRuntime(options = {}) {
21072
21261
  const key = runtimeRoot(options.baseDir);
21073
21262
  const existing = installs.get(key);
21074
21263
  if (existing) return existing;
21075
- const running = installOnce(options).finally(() => installs.delete(key));
21076
- installs.set(key, running);
21077
- return running;
21264
+ const running2 = installOnce2(options).finally(() => installs.delete(key));
21265
+ installs.set(key, running2);
21266
+ return running2;
21078
21267
  }
21079
21268
  function antigravityManagedInstallAvailable() {
21080
21269
  return resolveAntigravityReleaseAsset() !== null;
@@ -21089,7 +21278,7 @@ var init_antigravity_runtime = __esm({
21089
21278
  FREE_SPACE_MARGIN = 256 * 1024 * 1024;
21090
21279
  DOWNLOAD_TIMEOUT_MS2 = 45 * 6e4;
21091
21280
  STAGING_PREFIX = ".install-";
21092
- wait = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
21281
+ wait = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
21093
21282
  INSTALL_RECORD = ".install-complete.json";
21094
21283
  AntigravitySetupError = class extends Error {
21095
21284
  status = 409;
@@ -21485,14 +21674,14 @@ var init_boxagent = __esm({
21485
21674
  import { randomUUID as randomUUID8 } from "node:crypto";
21486
21675
  import { realpathSync } from "node:fs";
21487
21676
  import { homedir as homedir8 } from "node:os";
21488
- import { basename as basename4, dirname as dirname7, isAbsolute as isAbsolute3, join as join15, resolve as resolve7 } from "node:path";
21489
- import { stripVTControlCharacters as stripVTControlCharacters3 } from "node:util";
21677
+ import { basename as basename4, dirname as dirname7, isAbsolute as isAbsolute3, join as join16, resolve as resolve7 } from "node:path";
21678
+ import { stripVTControlCharacters as stripVTControlCharacters4 } from "node:util";
21490
21679
  function canonicalPath(path3) {
21491
21680
  try {
21492
21681
  return realpathSync(path3);
21493
21682
  } catch {
21494
21683
  const parent = dirname7(path3);
21495
- return parent === path3 ? path3 : join15(canonicalPath(parent), basename4(path3));
21684
+ return parent === path3 ? path3 : join16(canonicalPath(parent), basename4(path3));
21496
21685
  }
21497
21686
  }
21498
21687
  function claudeSignInLink(value) {
@@ -21507,7 +21696,7 @@ function claudeSignInLink(value) {
21507
21696
  }
21508
21697
  }
21509
21698
  function claudeLoginPrompt(output) {
21510
- const lines = stripVTControlCharacters3(output).split(/\r?\n/).slice(0, -1);
21699
+ const lines = stripVTControlCharacters4(output).split(/\r?\n/).slice(0, -1);
21511
21700
  for (const line of lines) {
21512
21701
  const match = /(https:\/\/\S+)/.exec(line.trim());
21513
21702
  const link = match ? claudeSignInLink(match[1].replace(/[),.;]+$/, "")) : null;
@@ -21519,17 +21708,18 @@ function claudeLoginCode(value) {
21519
21708
  const code = value.trim();
21520
21709
  return /^[A-Za-z0-9_\-#.:]{8,1024}$/.test(code) ? code : null;
21521
21710
  }
21522
- var MAX_OUTPUT, SIGN_IN_HOSTS, authenticatingHomes, NOT_AVAILABLE, ClaudeLoginController;
21711
+ var MAX_OUTPUT2, SIGN_IN_HOSTS, authenticatingHomes, NOT_AVAILABLE, ClaudeLoginController;
21523
21712
  var init_claude_login_auth = __esm({
21524
21713
  "server/drivers/claude-login-auth.ts"() {
21525
21714
  "use strict";
21526
21715
  init_procs();
21527
- MAX_OUTPUT = 32768;
21716
+ MAX_OUTPUT2 = 32768;
21528
21717
  SIGN_IN_HOSTS = ["claude.com", "claude.ai", "console.anthropic.com", "platform.claude.com"];
21529
21718
  authenticatingHomes = /* @__PURE__ */ new Set();
21530
21719
  NOT_AVAILABLE = "This sign-in is no longer available. Start sign-in again.";
21531
21720
  ClaudeLoginController = class {
21532
21721
  flow = null;
21722
+ logoutChild = null;
21533
21723
  disposed = false;
21534
21724
  options;
21535
21725
  constructor(options) {
@@ -21548,7 +21738,7 @@ var init_claude_login_auth = __esm({
21548
21738
  if (!isAbsolute3(home) || env.CLAUDE_CONFIG_DIR && !isAbsolute3(env.CLAUDE_CONFIG_DIR)) {
21549
21739
  throw new Error("Use an absolute HOME and CLAUDE_CONFIG_DIR path for this server's Claude provider before signing in.");
21550
21740
  }
21551
- const homeKey = canonicalPath(resolve7(env.CLAUDE_CONFIG_DIR || join15(home, ".claude")));
21741
+ const homeKey = canonicalPath(resolve7(env.CLAUDE_CONFIG_DIR || join16(home, ".claude")));
21552
21742
  if (authenticatingHomes.has(homeKey)) {
21553
21743
  throw new Error("A Claude sign-in is already running for this server account. Finish or cancel it before starting another.");
21554
21744
  }
@@ -21621,43 +21811,121 @@ var init_claude_login_auth = __esm({
21621
21811
  if (this.flow?.status.phase === "waiting") this.finish(this.flow, "cancelled", "Claude sign-in cancelled.");
21622
21812
  await this.flow?.stopping;
21623
21813
  if (this.flow?.terminationFailed) throw new Error(this.flow.status.message);
21814
+ if (this.logoutChild && !await this.stopChild(this.logoutChild)) {
21815
+ throw new Error("Claude Code could not be stopped on this server. Ask the server administrator to stop the account command before trying again.");
21816
+ }
21624
21817
  }
21625
21818
  async dispose() {
21626
21819
  this.disposed = true;
21627
21820
  await this.cancel();
21628
21821
  this.flow = null;
21629
21822
  }
21823
+ /** Remove the sign-in Claude Code stores for this server account (its
21824
+ * configuration directory) so a different subscription can sign in. A
21825
+ * sign-in in progress is never pulled away underneath the browser
21826
+ * completing it, and the CLI's own status is the verdict, as for sign-in. */
21827
+ async signOut() {
21828
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
21829
+ if (this.flow?.status.phase === "waiting") throw new Error("Finish or cancel the Claude sign-in in progress before signing out.");
21830
+ await this.flow?.stopping;
21831
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
21832
+ const env = this.options.environment();
21833
+ const home = env.HOME || env.USERPROFILE || homedir8();
21834
+ if (!isAbsolute3(home) || env.CLAUDE_CONFIG_DIR && !isAbsolute3(env.CLAUDE_CONFIG_DIR)) {
21835
+ throw new Error("Use an absolute HOME and CLAUDE_CONFIG_DIR path for this server's Claude provider before signing out.");
21836
+ }
21837
+ const homeKey = canonicalPath(resolve7(env.CLAUDE_CONFIG_DIR || join16(home, ".claude")));
21838
+ if (authenticatingHomes.has(homeKey)) {
21839
+ throw new Error("A Claude sign-in is running for this server account. Finish or cancel it before signing out.");
21840
+ }
21841
+ authenticatingHomes.add(homeKey);
21842
+ try {
21843
+ await this.logout(env);
21844
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
21845
+ const status = await this.authStatus(env);
21846
+ if (status === "in") throw new Error("Claude Code still reports a sign-in on this server. Update Claude Code and check its auth status before trying again.");
21847
+ if (status === "unknown") throw new Error("Claude Code could not confirm the sign-out on this server. Update Claude Code and check its auth status before trying again.");
21848
+ } finally {
21849
+ const child = this.logoutChild;
21850
+ if (child && child.exitCode === null && child.signalCode === null) {
21851
+ child.once("close", () => authenticatingHomes.delete(homeKey));
21852
+ } else authenticatingHomes.delete(homeKey);
21853
+ }
21854
+ }
21855
+ /** `claude auth logout`, bounded and non-interactive. Its output stays
21856
+ * here; the status command afterwards decides whether it worked. */
21857
+ logout(env) {
21858
+ return new Promise((resolveDone, rejectDone) => {
21859
+ if (this.disposed) {
21860
+ rejectDone(new Error("This provider was removed. Refresh Settings before signing out."));
21861
+ return;
21862
+ }
21863
+ let child;
21864
+ try {
21865
+ child = spawnCli(this.options.cli, ["auth", "logout"], { env: { ...env, NO_COLOR: "1" }, stdio: ["pipe", "pipe", "pipe"] });
21866
+ } catch {
21867
+ rejectDone(new Error("Claude Code could not start on this server. Install or update the configured Claude CLI, then try again."));
21868
+ return;
21869
+ }
21870
+ this.logoutChild = child;
21871
+ child.stdin.end();
21872
+ child.stdout.on("data", () => {
21873
+ });
21874
+ child.stderr.on("data", () => {
21875
+ });
21876
+ const timer = setTimeout(() => {
21877
+ void this.stopChild(child).catch(() => false).then((stopped) => {
21878
+ if (!stopped) rejectDone(new Error("Claude Code could not be stopped on this server. Ask the server administrator to stop the account command before trying again."));
21879
+ });
21880
+ }, this.options.startupTimeoutMs ?? 3e4);
21881
+ timer.unref();
21882
+ child.once("error", (error51) => {
21883
+ clearTimeout(timer);
21884
+ rejectDone(new Error(error51.code === "ENOENT" ? "Claude Code is not installed on this server. Install it on the server, then try again." : "Claude Code could not start on this server. Check the configured CLI path and its executable permissions."));
21885
+ });
21886
+ child.once("close", () => {
21887
+ clearTimeout(timer);
21888
+ if (this.logoutChild === child) this.logoutChild = null;
21889
+ resolveDone();
21890
+ });
21891
+ });
21892
+ }
21630
21893
  signedIn(env) {
21894
+ return this.authStatus(env).then((status) => status === "in");
21895
+ }
21896
+ /** `claude auth status --json`: signed in, signed out, or not answered. */
21897
+ authStatus(env) {
21631
21898
  return new Promise((resolveStatus) => {
21632
21899
  let child;
21633
21900
  try {
21634
21901
  child = spawnCli(this.options.cli, ["auth", "status", "--json"], { env: { ...env, NO_COLOR: "1" }, stdio: ["ignore", "pipe", "pipe"] });
21635
21902
  } catch {
21636
- resolveStatus(false);
21903
+ resolveStatus("unknown");
21637
21904
  return;
21638
21905
  }
21639
21906
  let stdout2 = "";
21640
21907
  child.stdout.on("data", (chunk) => {
21641
- if (stdout2.length < MAX_OUTPUT) stdout2 += chunk.toString("utf8");
21908
+ if (stdout2.length < MAX_OUTPUT2) stdout2 += chunk.toString("utf8");
21642
21909
  });
21643
21910
  child.stderr.on("data", () => {
21644
21911
  });
21645
21912
  const timer = setTimeout(() => {
21646
21913
  child.kill("SIGKILL");
21647
- resolveStatus(false);
21914
+ resolveStatus("unknown");
21648
21915
  }, 8e3);
21649
21916
  timer.unref();
21650
21917
  child.once("error", () => {
21651
21918
  clearTimeout(timer);
21652
- resolveStatus(false);
21919
+ resolveStatus("unknown");
21653
21920
  });
21654
- child.once("close", () => {
21921
+ child.once("close", (code) => {
21655
21922
  clearTimeout(timer);
21656
21923
  try {
21657
21924
  const status = JSON.parse(stdout2);
21658
- resolveStatus(typeof status === "object" && status !== null && Reflect.get(status, "loggedIn") === true);
21925
+ const loggedIn = typeof status === "object" && status !== null ? Reflect.get(status, "loggedIn") : void 0;
21926
+ resolveStatus(code === 0 && loggedIn === true ? "in" : code === 1 && loggedIn === false ? "out" : "unknown");
21659
21927
  } catch {
21660
- resolveStatus(false);
21928
+ resolveStatus("unknown");
21661
21929
  }
21662
21930
  });
21663
21931
  });
@@ -21678,7 +21946,7 @@ var init_claude_login_auth = __esm({
21678
21946
  flow.child = child;
21679
21947
  const receive = (chunk) => {
21680
21948
  if (flow.status.phase !== "waiting") return;
21681
- if (flow.output.length + chunk.length > MAX_OUTPUT) {
21949
+ if (flow.output.length + chunk.length > MAX_OUTPUT2) {
21682
21950
  this.finish(flow, "failed", "Claude Code returned an unexpected sign-in response. Update the server's Claude CLI and try again.");
21683
21951
  return;
21684
21952
  }
@@ -21700,7 +21968,7 @@ var init_claude_login_auth = __esm({
21700
21968
  child.once("close", (code) => {
21701
21969
  if (flow.child === child) flow.child = null;
21702
21970
  if (flow.status.phase !== "waiting") return;
21703
- const output = stripVTControlCharacters3(flow.output);
21971
+ const output = stripVTControlCharacters4(flow.output);
21704
21972
  flow.output = "";
21705
21973
  void this.signedIn(flow.env).then((signedIn) => {
21706
21974
  if (flow.status.phase !== "waiting") return;
@@ -21733,7 +22001,7 @@ var init_claude_login_auth = __esm({
21733
22001
  else flow.completion.reject(new Error(message2 ?? "Claude sign-in did not finish."));
21734
22002
  flow.completion = void 0;
21735
22003
  }
21736
- flow.stopping = this.stopChild(flow).catch(() => false).then((stopped) => {
22004
+ flow.stopping = this.stopChild(flow.child).catch(() => false).then((stopped) => {
21737
22005
  const release = () => authenticatingHomes.delete(flow.homeKey);
21738
22006
  if (stopped) {
21739
22007
  release();
@@ -21748,8 +22016,7 @@ var init_claude_login_auth = __esm({
21748
22016
  if (phase === "succeeded") void this.options.onAuthenticated?.().catch(() => {
21749
22017
  });
21750
22018
  }
21751
- async stopChild(flow) {
21752
- const child = flow.child;
22019
+ async stopChild(child) {
21753
22020
  if (!child || await killCliTree(child, this.options.terminateTimeoutMs ?? 1500)) return true;
21754
22021
  if (process.platform !== "win32" && child.pid) {
21755
22022
  try {
@@ -21803,13 +22070,13 @@ function computeBackoff(attempt, random = Math.random) {
21803
22070
  function interruptibleDelay(ms, signal) {
21804
22071
  let timer = null;
21805
22072
  let onCancel = null;
21806
- const promise2 = new Promise((resolve12) => {
21807
- timer = setTimeout(() => resolve12("elapsed"), Math.max(1, ms));
22073
+ const promise2 = new Promise((resolve13) => {
22074
+ timer = setTimeout(() => resolve13("elapsed"), Math.max(1, ms));
21808
22075
  timer.unref?.();
21809
- if (signal?.aborted) return resolve12("cancelled");
22076
+ if (signal?.aborted) return resolve13("cancelled");
21810
22077
  onCancel = () => {
21811
22078
  clearTimeout(timer);
21812
- resolve12("cancelled");
22079
+ resolve13("cancelled");
21813
22080
  };
21814
22081
  signal?.addEventListener("abort", onCancel, { once: true });
21815
22082
  });
@@ -21861,34 +22128,34 @@ import { createHash as createHash5, randomBytes as randomBytes2 } from "node:cry
21861
22128
  import { chmodSync as chmodSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
21862
22129
  import { createServer as createNetServer } from "node:net";
21863
22130
  import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
21864
- import { join as join16, dirname as dirname8, isAbsolute as isAbsolute4, normalize } from "node:path";
22131
+ import { join as join17, dirname as dirname8, isAbsolute as isAbsolute4, normalize } from "node:path";
21865
22132
  function claudeAuthStatus(cli, env, run3 = execCli) {
21866
- return new Promise((resolve12) => {
22133
+ return new Promise((resolve13) => {
21867
22134
  run3(cli, ["auth", "status", "--json"], { timeout: 8e3, maxBuffer: 65536, env }, (_error, stdout2) => {
21868
22135
  try {
21869
22136
  const status = JSON.parse(stdout2);
21870
22137
  if (!status || typeof status !== "object" || !("loggedIn" in status) || status.loggedIn !== true) {
21871
- return resolve12({ authenticated: false });
22138
+ return resolve13({ authenticated: false });
21872
22139
  }
21873
22140
  const identity = status;
21874
22141
  const boundedText = (value, max) => typeof value === "string" && value.trim().length > 0 && value.length <= max && !/[\p{Cc}\p{Cf}]/u.test(value) ? value.trim() : void 0;
21875
22142
  const candidateEmail = boundedText(identity.email, 254);
21876
22143
  const email3 = candidateEmail && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(candidateEmail) ? candidateEmail : void 0;
21877
22144
  const organization = boundedText(identity.orgName, 160);
21878
- resolve12({
22145
+ resolve13({
21879
22146
  authenticated: true,
21880
22147
  ...email3 || organization ? { account: { ...email3 ? { email: email3 } : {}, ...organization ? { organization } : {} } } : {}
21881
22148
  });
21882
22149
  } catch {
21883
- resolve12({ authenticated: false });
22150
+ resolve13({ authenticated: false });
21884
22151
  }
21885
22152
  });
21886
22153
  });
21887
22154
  }
21888
22155
  function resolveClaudeConfigDir(configDir, env = process.env) {
21889
22156
  const home = env.HOME || env.USERPROFILE || homedir9();
21890
- const configured = configDir?.trim() || env.CLAUDE_CONFIG_DIR?.trim() || join16(home, ".claude");
21891
- const expanded = configured === "~" ? home : configured.startsWith("~/") ? join16(home, configured.slice(2)) : configured;
22157
+ const configured = configDir?.trim() || env.CLAUDE_CONFIG_DIR?.trim() || join17(home, ".claude");
22158
+ const expanded = configured === "~" ? home : configured.startsWith("~/") ? join17(home, configured.slice(2)) : configured;
21892
22159
  if (!isAbsolute4(expanded) || /[\p{Cc}\p{Cf}]/u.test(expanded)) {
21893
22160
  throw new Error("claude: configDir must be an absolute path or start with ~/");
21894
22161
  }
@@ -21940,7 +22207,7 @@ function extrasFromUnknown(value) {
21940
22207
  function readClaudeModelCatalog(env = process.env) {
21941
22208
  let settings2 = {};
21942
22209
  try {
21943
- settings2 = JSON.parse(readFileSync6(join16(resolveClaudeConfigDir(void 0, env), "settings.json"), "utf8"));
22210
+ settings2 = JSON.parse(readFileSync6(join17(resolveClaudeConfigDir(void 0, env), "settings.json"), "utf8"));
21944
22211
  } catch {
21945
22212
  return STATIC_CLAUDE_MODELS;
21946
22213
  }
@@ -21990,7 +22257,7 @@ function brokerSocketCandidates(threadId) {
21990
22257
  const base2 = permissionSocketPath(threadId);
21991
22258
  if (process.platform !== "win32") {
21992
22259
  const scope = createHash5("sha256").update(`${DATA_DIR}\0${process.pid}\0${threadId}`).digest("hex").slice(0, 16);
21993
- return [base2, join16(tmpdir3(), `omb-perm-${scope}.sock`)];
22260
+ return [base2, join17(tmpdir3(), `omb-perm-${scope}.sock`)];
21994
22261
  }
21995
22262
  return [
21996
22263
  base2,
@@ -22071,9 +22338,9 @@ async function createPermissionBroker(opts) {
22071
22338
  unlinkSync3(candidate);
22072
22339
  } catch {
22073
22340
  }
22074
- let outcome = await new Promise((resolve12) => {
22075
- attempt.once("listening", () => resolve12("listening"));
22076
- attempt.once("error", (error51) => resolve12(error51));
22341
+ let outcome = await new Promise((resolve13) => {
22342
+ attempt.once("listening", () => resolve13("listening"));
22343
+ attempt.once("error", (error51) => resolve13(error51));
22077
22344
  attempt.listen(candidate);
22078
22345
  });
22079
22346
  if (outcome === "listening" && process.platform !== "win32") {
@@ -22330,19 +22597,19 @@ var init_claude = __esm({
22330
22597
  };
22331
22598
  const writeUser = (s, threadId, promptMsg) => {
22332
22599
  if (!s.child.stdin.writable || s.child.stdin.destroyed) return Promise.resolve(false);
22333
- return new Promise((resolve12) => {
22600
+ return new Promise((resolve13) => {
22334
22601
  try {
22335
22602
  s.child.stdin.write(JSON.stringify(promptMsg) + "\n", (error51) => {
22336
- if (error51) return resolve12(false);
22603
+ if (error51) return resolve13(false);
22337
22604
  appendNative(threadId, {
22338
22605
  dir: "out",
22339
22606
  source: "claude.sdk.message",
22340
22607
  msg: diagnosticClaudeUserMessage(promptMsg)
22341
22608
  });
22342
- resolve12(true);
22609
+ resolve13(true);
22343
22610
  });
22344
22611
  } catch {
22345
- resolve12(false);
22612
+ resolve13(false);
22346
22613
  }
22347
22614
  });
22348
22615
  };
@@ -22456,7 +22723,7 @@ var init_claude = __esm({
22456
22723
  allowed.push("mcp__ogb");
22457
22724
  let mcpConfigPath = null;
22458
22725
  if (Object.keys(mcpServers).length) {
22459
- mcpConfigPath = join16(mkdtempSync2(join16(tmpdir3(), "omb-mcp-")), "mcp.json");
22726
+ mcpConfigPath = join17(mkdtempSync2(join17(tmpdir3(), "omb-mcp-")), "mcp.json");
22460
22727
  args.push("--mcp-config", mcpConfigPath);
22461
22728
  args.push("--allowedTools", allowed.join(","));
22462
22729
  }
@@ -22524,7 +22791,7 @@ var init_claude = __esm({
22524
22791
  };
22525
22792
  try {
22526
22793
  if (turn.system) {
22527
- systemPromptPath = join16(mkdtempSync2(join16(tmpdir3(), "omb-system-")), "prompt.txt");
22794
+ systemPromptPath = join17(mkdtempSync2(join17(tmpdir3(), "omb-system-")), "prompt.txt");
22528
22795
  writeFileSync5(systemPromptPath, turn.system, { mode: 384 });
22529
22796
  args.push("--append-system-prompt-file", systemPromptPath);
22530
22797
  }
@@ -22832,19 +23099,19 @@ var init_claude = __esm({
22832
23099
  } });
22833
23100
  const snapshot = async () => {
22834
23101
  const env = environment();
22835
- const version2 = await new Promise((resolve12) => {
23102
+ const version2 = await new Promise((resolve13) => {
22836
23103
  execCli(
22837
23104
  config2.cli,
22838
23105
  ["--version"],
22839
23106
  { timeout: 8e3, env },
22840
- (err, stdout2) => resolve12(err ? null : stdout2.trim())
23107
+ (err, stdout2) => resolve13(err ? null : stdout2.trim())
22841
23108
  );
22842
23109
  });
22843
23110
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
22844
23111
  const auth = await claudeAuthStatus(config2.cli, env);
22845
23112
  return { state: "available", version: version2, ...auth, billing: "subscription" };
22846
23113
  };
22847
- const generateReview = (prompt, signal) => new Promise((resolve12, reject) => {
23114
+ const generateReview = (prompt, signal) => new Promise((resolve13, reject) => {
22848
23115
  const child = spawnCli(
22849
23116
  config2.cli,
22850
23117
  ["-p", "--model", "claude-haiku-4-5", "--output-format", "text"],
@@ -22862,7 +23129,7 @@ var init_claude = __esm({
22862
23129
  clearTimeout(timer);
22863
23130
  signal?.removeEventListener("abort", onAbort);
22864
23131
  if (error51) reject(error51);
22865
- else resolve12(stdout2.trim());
23132
+ else resolve13(stdout2.trim());
22866
23133
  };
22867
23134
  const onAbort = () => {
22868
23135
  killCliTree(child);
@@ -22910,6 +23177,7 @@ var init_claude = __esm({
22910
23177
  getAuthentication: (flowId) => login.get(flowId),
22911
23178
  completeAuthentication: (flowId, code) => login.complete(flowId, code),
22912
23179
  cancelAuthentication: () => login.cancel(),
23180
+ signOut: () => login.signOut(),
22913
23181
  adapter: {
22914
23182
  provider: DRIVER_KIND2,
22915
23183
  capabilities: {
@@ -22951,9 +23219,13 @@ var init_claude = __esm({
22951
23219
  generateText: (prompt) => generateReview(prompt),
22952
23220
  reviewPermission: generateReview,
22953
23221
  dispose: async () => {
22954
- for (const { stop } of active.values()) stop();
22955
- for (const threadId of [...sessions.keys()]) closeSession(threadId, "dispose");
22956
- listeners.clear();
23222
+ try {
23223
+ await login.dispose();
23224
+ } finally {
23225
+ for (const { stop } of active.values()) stop();
23226
+ for (const threadId of [...sessions.keys()]) closeSession(threadId, "dispose");
23227
+ listeners.clear();
23228
+ }
22957
23229
  }
22958
23230
  };
22959
23231
  }
@@ -22964,7 +23236,7 @@ var init_claude = __esm({
22964
23236
  // server/drivers/codex-catalog.ts
22965
23237
  import { readdirSync as readdirSync2, readFileSync as readFileSync7 } from "node:fs";
22966
23238
  import { homedir as homedir10 } from "node:os";
22967
- import { basename as basename5, join as join17 } from "node:path";
23239
+ import { basename as basename5, join as join18 } from "node:path";
22968
23240
  function encodeCodexSelection(provider, model) {
22969
23241
  return `${provider}${SEP}${model}`;
22970
23242
  }
@@ -22977,7 +23249,7 @@ function decodeCodexSelection(id) {
22977
23249
  return { model: id, modelProvider: MODEL_ID2.test(id) ? OFFICIAL_CODEX_PROVIDER : null };
22978
23250
  }
22979
23251
  function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
22980
- return new Promise((resolve12) => {
23252
+ return new Promise((resolve13) => {
22981
23253
  const child = spawnCli(cli, ["app-server"], {
22982
23254
  cwd: homedir10(),
22983
23255
  env,
@@ -22994,7 +23266,7 @@ function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
22994
23266
  settled = true;
22995
23267
  clearTimeout(timer);
22996
23268
  killCliTree(child);
22997
- resolve12(catalog);
23269
+ resolve13(catalog);
22998
23270
  };
22999
23271
  const request = (method, params, kind) => {
23000
23272
  const id = nextId++;
@@ -23080,7 +23352,7 @@ function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
23080
23352
  }
23081
23353
  function codexHome(env) {
23082
23354
  if (env.CODEX_HOME) return env.CODEX_HOME;
23083
- return join17(env.HOME || env.USERPROFILE || homedir10(), ".codex");
23355
+ return join18(env.HOME || env.USERPROFILE || homedir10(), ".codex");
23084
23356
  }
23085
23357
  function unquote(raw) {
23086
23358
  let value = raw.trim();
@@ -23166,11 +23438,11 @@ function niceLabel(model, provider, known, named) {
23166
23438
  }
23167
23439
  function collectCatalogNames(home) {
23168
23440
  const named = /* @__PURE__ */ new Map();
23169
- for (const file2 of listDir(join17(home, "model-catalogs"))) {
23441
+ for (const file2 of listDir(join18(home, "model-catalogs"))) {
23170
23442
  if (!file2.endsWith(".json")) continue;
23171
23443
  const provider = basename5(file2, ".json").replace(/-models$/, "");
23172
23444
  if (!PROVIDER_ID.test(provider)) continue;
23173
- const raw = readText(join17(home, "model-catalogs", file2));
23445
+ const raw = readText(join18(home, "model-catalogs", file2));
23174
23446
  if (!raw) continue;
23175
23447
  let parsed;
23176
23448
  try {
@@ -23222,7 +23494,7 @@ async function probeProviderModels(provider, env, fetchImpl) {
23222
23494
  async function readCodexModelCatalog(env = process.env, fetchImpl = fetch, cli) {
23223
23495
  const official = (cli ? await readCodexAppServerModelCatalog(cli, env) : null) ?? STATIC_CODEX_MODELS;
23224
23496
  const home = codexHome(env);
23225
- const mainText = readText(join17(home, "config.toml"));
23497
+ const mainText = readText(join18(home, "config.toml"));
23226
23498
  if (!mainText) return mergeLocalInject(official, env, fetchImpl);
23227
23499
  const main2 = parseCodexToml(mainText);
23228
23500
  const known = new Map(main2.providers.map((provider) => [provider.id, provider]));
@@ -23237,7 +23509,7 @@ async function readCodexModelCatalog(env = process.env, fetchImpl = fetch, cli)
23237
23509
  remember(main2.modelProvider, main2.model);
23238
23510
  for (const file2 of listDir(home)) {
23239
23511
  if (!file2.endsWith(".config.toml")) continue;
23240
- const profile = parseCodexToml(readText(join17(home, file2)) ?? "");
23512
+ const profile = parseCodexToml(readText(join18(home, file2)) ?? "");
23241
23513
  for (const provider of profile.providers) {
23242
23514
  if (!known.has(provider.id)) known.set(provider.id, provider);
23243
23515
  }
@@ -23303,8 +23575,8 @@ var init_codex_catalog = __esm({
23303
23575
 
23304
23576
  // server/drivers/codex-instructions.ts
23305
23577
  import { createHash as createHash6 } from "node:crypto";
23306
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
23307
- import { join as join18 } from "node:path";
23578
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync8 } from "node:fs";
23579
+ import { join as join19 } from "node:path";
23308
23580
  function codexDeveloperInstructions(config2, botInstructions) {
23309
23581
  if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) {
23310
23582
  throw new Error("Codex returned no effective configuration; cannot safely update bot instructions.");
@@ -23318,8 +23590,8 @@ function codexDeveloperInstructions(config2, botInstructions) {
23318
23590
  ${configured}` : botInstructions;
23319
23591
  }
23320
23592
  async function syncCodexInstructions(key, nativeThreadId, instructions, resumed, request) {
23321
- const directory = join18(DATA_DIR, "codex-instructions");
23322
- const path3 = join18(directory, `${digest(JSON.stringify([key, nativeThreadId]))}.sha256`);
23593
+ const directory = join19(DATA_DIR, "codex-instructions");
23594
+ const path3 = join19(directory, `${digest(JSON.stringify([key, nativeThreadId]))}.sha256`);
23323
23595
  const fingerprint = digest(instructions);
23324
23596
  let previous;
23325
23597
  try {
@@ -23348,7 +23620,7 @@ async function syncCodexInstructions(key, nativeThreadId, instructions, resumed,
23348
23620
  }
23349
23621
  }
23350
23622
  if (!resumed || previous !== fingerprint) {
23351
- mkdirSync6(directory, { recursive: true });
23623
+ mkdirSync7(directory, { recursive: true });
23352
23624
  writeFileAtomic(path3, fingerprint, { mode: 384 });
23353
23625
  }
23354
23626
  }
@@ -23366,18 +23638,18 @@ var init_codex_instructions = __esm({
23366
23638
  import { randomUUID as randomUUID9 } from "node:crypto";
23367
23639
  import { realpathSync as realpathSync2 } from "node:fs";
23368
23640
  import { homedir as homedir11 } from "node:os";
23369
- import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute5, join as join19, resolve as resolve8 } from "node:path";
23370
- import { stripVTControlCharacters as stripVTControlCharacters4 } from "node:util";
23641
+ import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute5, join as join20, resolve as resolve8 } from "node:path";
23642
+ import { stripVTControlCharacters as stripVTControlCharacters5 } from "node:util";
23371
23643
  function canonicalPath2(path3) {
23372
23644
  try {
23373
23645
  return realpathSync2(path3);
23374
23646
  } catch {
23375
23647
  const parent = dirname9(path3);
23376
- return parent === path3 ? path3 : join19(canonicalPath2(parent), basename6(path3));
23648
+ return parent === path3 ? path3 : join20(canonicalPath2(parent), basename6(path3));
23377
23649
  }
23378
23650
  }
23379
23651
  function codexDevicePrompt(output) {
23380
- const clean = stripVTControlCharacters4(output);
23652
+ const clean = stripVTControlCharacters5(output);
23381
23653
  const lines = clean.split(/\r?\n/).slice(0, -1).map((line) => line.trim());
23382
23654
  if (!lines.some((line) => /^https:\/\/auth\.openai\.com\/codex\/device\/?$/.test(line))) return null;
23383
23655
  const userCode = lines.find((line) => /^[A-Z0-9]{4,8}-[A-Z0-9]{4,8}$/.test(line));
@@ -23395,16 +23667,17 @@ function loginFailure(output) {
23395
23667
  }
23396
23668
  return "ChatGPT sign-in did not finish. Check the server's connection and that device-code login is enabled in ChatGPT, then try again.";
23397
23669
  }
23398
- var DEVICE_URL, MAX_OUTPUT2, authenticatingHomes2, CodexDeviceAuthController;
23670
+ var DEVICE_URL, MAX_OUTPUT3, authenticatingHomes2, CodexDeviceAuthController;
23399
23671
  var init_codex_device_auth = __esm({
23400
23672
  "server/drivers/codex-device-auth.ts"() {
23401
23673
  "use strict";
23402
23674
  init_procs();
23403
23675
  DEVICE_URL = "https://auth.openai.com/codex/device";
23404
- MAX_OUTPUT2 = 16384;
23676
+ MAX_OUTPUT3 = 16384;
23405
23677
  authenticatingHomes2 = /* @__PURE__ */ new Set();
23406
23678
  CodexDeviceAuthController = class {
23407
23679
  flow = null;
23680
+ command = null;
23408
23681
  disposed = false;
23409
23682
  options;
23410
23683
  constructor(options) {
@@ -23423,7 +23696,7 @@ var init_codex_device_auth = __esm({
23423
23696
  if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
23424
23697
  throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing in.");
23425
23698
  }
23426
- const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join19(home, ".codex")));
23699
+ const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join20(home, ".codex")));
23427
23700
  if (authenticatingHomes2.has(homeKey)) {
23428
23701
  throw new Error("A ChatGPT sign-in is already running for this server account. Finish or cancel it before starting another.");
23429
23702
  }
@@ -23480,12 +23753,92 @@ var init_codex_device_auth = __esm({
23480
23753
  if (this.flow?.status.phase === "waiting") this.finish(this.flow, "cancelled", "ChatGPT sign-in cancelled.");
23481
23754
  await this.flow?.stopping;
23482
23755
  if (this.flow?.terminationFailed) throw new Error(this.flow.status.message);
23756
+ if (this.command && !await this.stopChild(this.command)) {
23757
+ throw new Error("Codex could not be stopped on this server. Ask the server administrator to stop the account command before trying again.");
23758
+ }
23483
23759
  }
23484
23760
  async dispose() {
23485
23761
  this.disposed = true;
23486
23762
  await this.cancel();
23487
23763
  this.flow = null;
23488
23764
  }
23765
+ /** Remove the ChatGPT sign-in Codex stores for this server account so a
23766
+ * different account can connect. A sign-in in progress is never pulled
23767
+ * away underneath the browser completing it. */
23768
+ async signOut() {
23769
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
23770
+ if (this.flow?.status.phase === "waiting") throw new Error("Finish or cancel the ChatGPT sign-in in progress before signing out.");
23771
+ await this.flow?.stopping;
23772
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
23773
+ const env = this.options.environment();
23774
+ const home = env.HOME || env.USERPROFILE || homedir11();
23775
+ if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
23776
+ throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing out.");
23777
+ }
23778
+ const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join20(home, ".codex")));
23779
+ if (authenticatingHomes2.has(homeKey)) {
23780
+ throw new Error("A ChatGPT sign-in is running for this server account. Finish or cancel it before signing out.");
23781
+ }
23782
+ authenticatingHomes2.add(homeKey);
23783
+ try {
23784
+ const before = await this.exec(["login", "status"], env, home);
23785
+ if (before.code === 1 && /^not logged in\b/im.test(before.output)) return;
23786
+ if (before.code !== 0 || !/^logged in.*chatgpt\b/im.test(before.output)) {
23787
+ throw new Error("Codex did not confirm a ChatGPT sign-in. Other authentication methods will not be removed; ask the server administrator to check the account.");
23788
+ }
23789
+ const logout = await this.exec(["logout"], env, home);
23790
+ if (logout.code !== 0) throw new Error("Codex could not remove the sign-in on this server. Check the server's Codex installation and try again.");
23791
+ const status = await this.exec(["login", "status"], env, home);
23792
+ if (status.code !== 1 || !/^not logged in\b/im.test(status.output)) {
23793
+ throw new Error("Codex still reports a sign-in on this server. Update Codex and check its login status before trying again.");
23794
+ }
23795
+ } finally {
23796
+ const child = this.command;
23797
+ if (child && child.exitCode === null && child.signalCode === null) {
23798
+ child.once("close", () => authenticatingHomes2.delete(homeKey));
23799
+ } else authenticatingHomes2.delete(homeKey);
23800
+ }
23801
+ }
23802
+ /** One bounded, non-interactive Codex command. Its output stays here;
23803
+ * callers see an exit code and a status-line match, never the text. */
23804
+ exec(args, env, cwd) {
23805
+ return new Promise((resolveExec, rejectExec) => {
23806
+ if (this.disposed) {
23807
+ rejectExec(new Error("This provider was removed. Refresh Settings before signing out."));
23808
+ return;
23809
+ }
23810
+ let child;
23811
+ try {
23812
+ child = spawnCli(this.options.cli, args, { env: { ...env, NO_COLOR: "1" }, cwd, stdio: ["pipe", "pipe", "pipe"] });
23813
+ } catch {
23814
+ rejectExec(new Error("Codex could not start on this server. Install or update the configured Codex CLI, then try again."));
23815
+ return;
23816
+ }
23817
+ this.command = child;
23818
+ child.stdin.end();
23819
+ let output = "";
23820
+ const receive = (chunk) => {
23821
+ if (output.length < MAX_OUTPUT3) output += chunk.toString("utf8").slice(0, MAX_OUTPUT3 - output.length);
23822
+ };
23823
+ child.stdout.on("data", receive);
23824
+ child.stderr.on("data", receive);
23825
+ const timer = setTimeout(() => {
23826
+ void this.stopChild(child).catch(() => false).then((stopped) => {
23827
+ if (!stopped) rejectExec(new Error("Codex could not be stopped on this server. Ask the server administrator to stop the account command before trying again."));
23828
+ });
23829
+ }, this.options.startupTimeoutMs ?? 3e4);
23830
+ timer.unref();
23831
+ child.once("error", (error51) => {
23832
+ clearTimeout(timer);
23833
+ rejectExec(new Error(error51.code === "ENOENT" ? "Codex is not installed on this server. Run npm install -g @openai/codex@latest on the server, then try again." : "Codex could not start on this server. Check the configured CLI path and its executable permissions."));
23834
+ });
23835
+ child.once("close", (code) => {
23836
+ clearTimeout(timer);
23837
+ if (this.command === child) this.command = null;
23838
+ resolveExec({ code, output: stripVTControlCharacters5(output) });
23839
+ });
23840
+ });
23841
+ }
23489
23842
  run(flow, args, env, cwd, done, parsePrompt = false) {
23490
23843
  if (flow.status.phase !== "waiting") return;
23491
23844
  let child;
@@ -23500,7 +23853,7 @@ var init_codex_device_auth = __esm({
23500
23853
  let output = "";
23501
23854
  const receive = (chunk) => {
23502
23855
  if (flow.status.phase !== "waiting") return;
23503
- if (output.length + chunk.length > MAX_OUTPUT2) {
23856
+ if (output.length + chunk.length > MAX_OUTPUT3) {
23504
23857
  this.finish(flow, "failed", "Codex returned an unexpected sign-in response. Update the server's Codex CLI and try again.");
23505
23858
  return;
23506
23859
  }
@@ -23521,7 +23874,7 @@ var init_codex_device_auth = __esm({
23521
23874
  });
23522
23875
  child.once("close", (code) => {
23523
23876
  if (flow.child === child) flow.child = null;
23524
- if (flow.status.phase === "waiting") done(code, stripVTControlCharacters4(output));
23877
+ if (flow.status.phase === "waiting") done(code, stripVTControlCharacters5(output));
23525
23878
  output = "";
23526
23879
  });
23527
23880
  }
@@ -23540,7 +23893,7 @@ var init_codex_device_auth = __esm({
23540
23893
  if (phase === "succeeded") flow.resolve({ ...flow.status, phase });
23541
23894
  else flow.reject(new Error(message2 ?? "ChatGPT sign-in did not finish."));
23542
23895
  }
23543
- flow.stopping = this.stopChild(flow).catch(() => false).then((stopped) => {
23896
+ flow.stopping = this.stopChild(flow.child).catch(() => false).then((stopped) => {
23544
23897
  const release = () => authenticatingHomes2.delete(flow.homeKey);
23545
23898
  if (stopped) {
23546
23899
  release();
@@ -23555,8 +23908,7 @@ var init_codex_device_auth = __esm({
23555
23908
  if (phase === "succeeded") void this.options.onAuthenticated?.().catch(() => {
23556
23909
  });
23557
23910
  }
23558
- async stopChild(flow) {
23559
- const child = flow.child;
23911
+ async stopChild(child) {
23560
23912
  if (!child || await killCliTree(child, this.options.terminateTimeoutMs ?? 1500)) return true;
23561
23913
  if (process.platform !== "win32" && child.pid) {
23562
23914
  try {
@@ -23580,9 +23932,122 @@ var init_codex_device_auth = __esm({
23580
23932
  }
23581
23933
  });
23582
23934
 
23583
- // server/drivers/codex.ts
23584
- import { existsSync as existsSync7 } from "node:fs";
23935
+ // server/drivers/codex-identity.ts
23585
23936
  import { homedir as homedir12 } from "node:os";
23937
+ import { isAbsolute as isAbsolute6, join as join21, resolve as resolve9 } from "node:path";
23938
+ function codexHome2(env) {
23939
+ if (env.CODEX_HOME) return isAbsolute6(env.CODEX_HOME) ? resolve9(env.CODEX_HOME) : null;
23940
+ const home = env.HOME || env.USERPROFILE || homedir12();
23941
+ return isAbsolute6(home) ? join21(home, ".codex") : null;
23942
+ }
23943
+ async function codexAccountEmail(cli, env, timeoutMs = 3e3) {
23944
+ const cwd = env.HOME || env.USERPROFILE || homedir12();
23945
+ if (!isAbsolute6(cwd) || !codexHome2(env)) return null;
23946
+ return new Promise((resolveEmail) => {
23947
+ let child;
23948
+ try {
23949
+ child = spawnCli(cli, ["app-server"], { cwd, env, stdio: ["pipe", "pipe", "pipe"] });
23950
+ } catch {
23951
+ resolveEmail(null);
23952
+ return;
23953
+ }
23954
+ let finishing = false;
23955
+ let buffer = "";
23956
+ let outputBytes = 0;
23957
+ let initialized = false;
23958
+ const finish = async (email3) => {
23959
+ if (finishing) return;
23960
+ finishing = true;
23961
+ clearTimeout(timer);
23962
+ let stopped = await killCliTree(child, 1e3);
23963
+ if (!stopped && child.pid) {
23964
+ try {
23965
+ if (process.platform === "win32") child.kill("SIGKILL");
23966
+ else process.kill(-child.pid, "SIGKILL");
23967
+ } catch {
23968
+ try {
23969
+ child.kill("SIGKILL");
23970
+ } catch {
23971
+ }
23972
+ }
23973
+ stopped = await killCliTree(child, 1e3);
23974
+ }
23975
+ resolveEmail(stopped ? email3 : null);
23976
+ };
23977
+ const timer = setTimeout(() => {
23978
+ void finish(null);
23979
+ }, timeoutMs);
23980
+ timer.unref();
23981
+ const send = (message2) => {
23982
+ try {
23983
+ child.stdin.write(`${JSON.stringify(message2)}
23984
+ `);
23985
+ } catch {
23986
+ void finish(null);
23987
+ }
23988
+ };
23989
+ child.stdin.on("error", () => {
23990
+ void finish(null);
23991
+ });
23992
+ child.stderr.resume();
23993
+ child.on("error", () => {
23994
+ void finish(null);
23995
+ });
23996
+ child.on("close", () => {
23997
+ void finish(null);
23998
+ });
23999
+ child.stdout.setEncoding("utf8");
24000
+ child.stdout.on("data", (chunk) => {
24001
+ if (finishing) return;
24002
+ outputBytes += Buffer.byteLength(chunk);
24003
+ if (outputBytes > MAX_OUTPUT4) {
24004
+ void finish(null);
24005
+ return;
24006
+ }
24007
+ buffer += chunk;
24008
+ let newline;
24009
+ while (!finishing && (newline = buffer.indexOf("\n")) !== -1) {
24010
+ const line = buffer.slice(0, newline);
24011
+ buffer = buffer.slice(newline + 1);
24012
+ if (!line.trim()) continue;
24013
+ let message2;
24014
+ try {
24015
+ message2 = JSON.parse(line);
24016
+ } catch {
24017
+ void finish(null);
24018
+ return;
24019
+ }
24020
+ if (!initialized && message2?.id === 1) {
24021
+ if (message2.error || !message2.result) {
24022
+ void finish(null);
24023
+ return;
24024
+ }
24025
+ initialized = true;
24026
+ send({ method: "initialized", params: {} });
24027
+ send({ id: 2, method: "account/read", params: { refreshToken: false } });
24028
+ } else if (initialized && message2?.id === 2) {
24029
+ const account = message2.error ? null : message2.result?.account;
24030
+ const email3 = account?.type === "chatgpt" ? account.email : null;
24031
+ void finish(typeof email3 === "string" && email3.length <= 254 && EMAIL.test(email3) && !/[\p{Cc}\p{Cf}]/u.test(email3) ? email3 : null);
24032
+ }
24033
+ }
24034
+ });
24035
+ send({ id: 1, method: "initialize", params: { clientInfo: { name: "openmausbot", version: "1" } } });
24036
+ });
24037
+ }
24038
+ var MAX_OUTPUT4, EMAIL;
24039
+ var init_codex_identity = __esm({
24040
+ "server/drivers/codex-identity.ts"() {
24041
+ "use strict";
24042
+ init_procs();
24043
+ MAX_OUTPUT4 = 16384;
24044
+ EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
24045
+ }
24046
+ });
24047
+
24048
+ // server/drivers/codex.ts
24049
+ import { existsSync as existsSync8 } from "node:fs";
24050
+ import { homedir as homedir13 } from "node:os";
23586
24051
  function codexPredatesAstra(version2) {
23587
24052
  const value = version2.trim();
23588
24053
  const match = /\bcodex-cli\s+v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9a-z.-]+)?(?![\d.])\b/i.exec(value) ?? /^v?(\d+)\.(\d+)\.(\d+)(?:[-+][0-9a-z.-]+)?$/i.exec(value);
@@ -23598,7 +24063,7 @@ function codexPredatesAstra(version2) {
23598
24063
  function codexUpdateCommand(cli, platform = process.platform) {
23599
24064
  if (cli === "codex") return "codex update";
23600
24065
  const trimmed = cli.trim();
23601
- const tokens = trimmed.includes(" ") && existsSync7(trimmed) ? [trimmed] : splitCliString(trimmed);
24066
+ const tokens = trimmed.includes(" ") && existsSync8(trimmed) ? [trimmed] : splitCliString(trimmed);
23602
24067
  const quote = platform === "win32" ? (token) => `'${token.replaceAll("'", "''")}'` : (token) => `'${token.replaceAll("'", `'\\''`)}'`;
23603
24068
  const command = (tokens.length > 0 ? tokens : [trimmed]).map(quote).join(" ");
23604
24069
  return platform === "win32" ? `& ${command} update` : `${command} update`;
@@ -23852,6 +24317,7 @@ var init_codex = __esm({
23852
24317
  init_native();
23853
24318
  init_codex_instructions();
23854
24319
  init_codex_device_auth();
24320
+ init_codex_identity();
23855
24321
  init_codex_catalog();
23856
24322
  DRIVER_KIND3 = "codex";
23857
24323
  ASTRA_MODEL_ID = "gpt-6-astra";
@@ -23985,7 +24451,7 @@ var init_codex = __esm({
23985
24451
  );
23986
24452
  }
23987
24453
  const child = spawnCli(config2.cli, appServerArgs, {
23988
- cwd: turn.cwd ?? homedir12(),
24454
+ cwd: turn.cwd ?? homedir13(),
23989
24455
  env,
23990
24456
  stdio: ["pipe", "pipe", "pipe"]
23991
24457
  });
@@ -24013,7 +24479,7 @@ var init_codex = __esm({
24013
24479
  msg: codexNativeLogMessage(obj)
24014
24480
  });
24015
24481
  };
24016
- const request = (method, params, timeoutMs = 6e4) => new Promise((resolve12, reject) => {
24482
+ const request = (method, params, timeoutMs = 6e4) => new Promise((resolve13, reject) => {
24017
24483
  const id = nextId++;
24018
24484
  if (method === "config/read") sensitiveResponseIds.add(id);
24019
24485
  const timer = setTimeout(() => {
@@ -24023,7 +24489,7 @@ var init_codex = __esm({
24023
24489
  rpcPending.set(id, {
24024
24490
  resolve: (v) => {
24025
24491
  clearTimeout(timer);
24026
- resolve12(v);
24492
+ resolve13(v);
24027
24493
  },
24028
24494
  reject: (e) => {
24029
24495
  clearTimeout(timer);
@@ -24291,7 +24757,7 @@ var init_codex = __esm({
24291
24757
  let effectiveConfig;
24292
24758
  try {
24293
24759
  const configured = await request("config/read", {
24294
- cwd: turn.cwd ?? homedir12(),
24760
+ cwd: turn.cwd ?? homedir13(),
24295
24761
  includeLayers: false
24296
24762
  });
24297
24763
  effectiveConfig = configured?.config;
@@ -24335,7 +24801,7 @@ var init_codex = __esm({
24335
24801
  const selection = decodeCodexSelection(turn.model);
24336
24802
  const startThread = () => request("thread/start", {
24337
24803
  developerInstructions,
24338
- cwd: turn.cwd ?? homedir12(),
24804
+ cwd: turn.cwd ?? homedir13(),
24339
24805
  model: selection.model,
24340
24806
  ...selection.modelProvider ? { modelProvider: selection.modelProvider } : {},
24341
24807
  ...approvalParams.thread,
@@ -24402,8 +24868,8 @@ var init_codex = __esm({
24402
24868
  void settle(false, "shutdown_timeout");
24403
24869
  return;
24404
24870
  }
24405
- await new Promise((resolve12) => {
24406
- const timer = setTimeout(resolve12, Math.max(1, Math.round(delayMs * retryScale)));
24871
+ await new Promise((resolve13) => {
24872
+ const timer = setTimeout(resolve13, Math.max(1, Math.round(delayMs * retryScale)));
24407
24873
  timer.unref?.();
24408
24874
  });
24409
24875
  if (!stopRequested) {
@@ -24431,28 +24897,30 @@ var init_codex = __esm({
24431
24897
  };
24432
24898
  const snapshot = async () => {
24433
24899
  const env = childEnv();
24434
- const version2 = await new Promise((resolve12) => {
24900
+ const version2 = await new Promise((resolve13) => {
24435
24901
  execCli(
24436
24902
  config2.cli,
24437
24903
  ["--version"],
24438
24904
  { timeout: 8e3, env },
24439
- (err, stdout2) => resolve12(err ? null : stdout2.trim())
24905
+ (err, stdout2) => resolve13(err ? null : stdout2.trim())
24440
24906
  );
24441
24907
  });
24442
24908
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
24443
- const authenticated = await new Promise((resolve12) => {
24909
+ const authenticated = await new Promise((resolve13) => {
24444
24910
  execCli(
24445
24911
  config2.cli,
24446
24912
  ["login", "status"],
24447
24913
  { timeout: 8e3, env },
24448
- (err, stdout2, stderr) => resolve12(!err && /^logged in\b/im.test(`${stdout2}
24914
+ (err, stdout2, stderr) => resolve13(!err && /^logged in\b/im.test(`${stdout2}
24449
24915
  ${stderr ?? ""}`))
24450
24916
  );
24451
24917
  });
24918
+ const email3 = authenticated ? await codexAccountEmail(config2.cli, env) : null;
24452
24919
  return {
24453
24920
  state: "available",
24454
24921
  version: version2,
24455
24922
  authenticated,
24923
+ ...email3 ? { account: { email: email3 } } : {},
24456
24924
  update: codexAstraUpdate(version2, models, config2.cli),
24457
24925
  billing: "subscription"
24458
24926
  };
@@ -24469,6 +24937,7 @@ ${stderr ?? ""}`))
24469
24937
  startAuthentication: () => authentication.start(),
24470
24938
  getAuthentication: (flowId) => authentication.get(flowId),
24471
24939
  cancelAuthentication: () => authentication.cancel(),
24940
+ signOut: () => authentication.signOut(),
24472
24941
  snapshot,
24473
24942
  adapter: {
24474
24943
  provider: DRIVER_KIND3,
@@ -24792,12 +25261,12 @@ var init_grok = __esm({
24792
25261
  });
24793
25262
 
24794
25263
  // server/drivers/acp/grok.ts
24795
- import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
24796
- import { homedir as homedir13 } from "node:os";
24797
- import { join as join20 } from "node:path";
25264
+ import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
25265
+ import { homedir as homedir14 } from "node:os";
25266
+ import { join as join22 } from "node:path";
24798
25267
  function grokHome(env) {
24799
25268
  if (env.GROK_HOME) return env.GROK_HOME;
24800
- return join20(env.HOME || env.USERPROFILE || homedir13(), ".grok");
25269
+ return join22(env.HOME || env.USERPROFILE || homedir14(), ".grok");
24801
25270
  }
24802
25271
  function unquote2(raw) {
24803
25272
  const value = raw.trim();
@@ -24807,7 +25276,7 @@ function unquote2(raw) {
24807
25276
  return value;
24808
25277
  }
24809
25278
  function readGrokModelCatalog(env = process.env) {
24810
- const path3 = join20(grokHome(env), "config.toml");
25279
+ const path3 = join22(grokHome(env), "config.toml");
24811
25280
  let text2 = "";
24812
25281
  try {
24813
25282
  text2 = readFileSync9(path3, "utf8");
@@ -24880,7 +25349,7 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
24880
25349
  if (!inject) return modelId;
24881
25350
  const host = localHost(inject.host);
24882
25351
  if (!host) return modelId;
24883
- const path3 = join20(grokHome(env), "config.toml");
25352
+ const path3 = join22(grokHome(env), "config.toml");
24884
25353
  let text2 = "";
24885
25354
  try {
24886
25355
  text2 = readFileSync9(path3, "utf8");
@@ -25015,7 +25484,7 @@ var init_grok2 = __esm({
25015
25484
  // an unauthenticated CLI is a user action, not something to paper over.
25016
25485
  pickAuthMethod: (methods) => methods.some((m) => m.id === "cached_token") ? "cached_token" : null,
25017
25486
  authFailure: "fail",
25018
- isAuthenticated: () => existsSync8(join20(homedir13(), ".grok", "auth.json")),
25487
+ isAuthenticated: () => existsSync9(join22(homedir14(), ".grok", "auth.json")),
25019
25488
  // `--append-system-prompt`/`--rules` are accepted by the CLI but do NOT
25020
25489
  // reach the agent-stdio system prompt (verified against 1.0.0), so the
25021
25490
  // persona is prepended codex-style.
@@ -25028,12 +25497,12 @@ ${turn.text}` : turn.text
25028
25497
  });
25029
25498
 
25030
25499
  // server/drivers/acp/gemini.ts
25031
- import { existsSync as existsSync9, readFileSync as readFileSync10 } from "node:fs";
25032
- import { homedir as homedir14 } from "node:os";
25033
- import { join as join21 } from "node:path";
25500
+ import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
25501
+ import { homedir as homedir15 } from "node:os";
25502
+ import { join as join23 } from "node:path";
25034
25503
  function liveOauthCredential() {
25035
25504
  try {
25036
- const creds = JSON.parse(readFileSync10(join21(homedir14(), ".gemini", "oauth_creds.json"), "utf8"));
25505
+ const creds = JSON.parse(readFileSync10(join23(homedir15(), ".gemini", "oauth_creds.json"), "utf8"));
25037
25506
  if (typeof creds.access_token !== "string" || creds.access_token.trim().length === 0) return false;
25038
25507
  const hasRefresh = typeof creds.refresh_token === "string" && creds.refresh_token.trim().length > 0;
25039
25508
  if (creds.expiry_date !== void 0) {
@@ -25046,7 +25515,7 @@ function liveOauthCredential() {
25046
25515
  }
25047
25516
  }
25048
25517
  function geminiIsAuthenticated(env) {
25049
- return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync9(join21(homedir14(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
25518
+ return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync10(join23(homedir15(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
25050
25519
  }
25051
25520
  var AUTH_PREFERENCE, nonBlank, support3, GeminiAgentDriver;
25052
25521
  var init_gemini = __esm({
@@ -25088,17 +25557,17 @@ ${turn.text}` : turn.text
25088
25557
  });
25089
25558
 
25090
25559
  // server/drivers/acp/kimi.ts
25091
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
25092
- import { homedir as homedir15 } from "node:os";
25093
- import { join as join22 } from "node:path";
25560
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
25561
+ import { homedir as homedir16 } from "node:os";
25562
+ import { join as join24 } from "node:path";
25094
25563
  function isLocalInjectAlias(slug) {
25095
25564
  return LOCAL_PROVIDER_PREFIXES.some((prefix) => slug.startsWith(prefix));
25096
25565
  }
25097
25566
  function kimiDataRoot(env) {
25098
- return env.KIMI_CODE_HOME || join22(env.HOME || env.USERPROFILE || homedir15(), ".kimi-code");
25567
+ return env.KIMI_CODE_HOME || join24(env.HOME || env.USERPROFILE || homedir16(), ".kimi-code");
25099
25568
  }
25100
25569
  function credentialsPath(env) {
25101
- return join22(kimiDataRoot(env), "credentials", "kimi-code.json");
25570
+ return join24(kimiDataRoot(env), "credentials", "kimi-code.json");
25102
25571
  }
25103
25572
  function quoteToml2(value) {
25104
25573
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
@@ -25385,8 +25854,8 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
25385
25854
  if (!host) return modelId;
25386
25855
  const alias = `${inject.host}/${inject.model.replace(/\//g, "-")}`;
25387
25856
  const dataRoot = kimiDataRoot(env);
25388
- mkdirSync7(dataRoot, { recursive: true });
25389
- const path3 = join22(dataRoot, "config.toml");
25857
+ mkdirSync8(dataRoot, { recursive: true });
25858
+ const path3 = join24(dataRoot, "config.toml");
25390
25859
  let text2 = "";
25391
25860
  try {
25392
25861
  text2 = readFileSync11(path3, "utf8");
@@ -25451,7 +25920,7 @@ function readKimiModelCatalog(env) {
25451
25920
  const dataRoot = kimiDataRoot(env);
25452
25921
  let text2 = "";
25453
25922
  try {
25454
- text2 = readFileSync11(join22(dataRoot, "config.toml"), "utf8");
25923
+ text2 = readFileSync11(join24(dataRoot, "config.toml"), "utf8");
25455
25924
  } catch {
25456
25925
  return STATIC_KIMI_MODELS;
25457
25926
  }
@@ -25560,7 +26029,7 @@ var init_kimi = __esm({
25560
26029
  authFailure: "continue",
25561
26030
  // Match the child CLI's own data-root precedence. A custom instance HOME or
25562
26031
  // KIMI_CODE_HOME must not be checked against the server user's home instead.
25563
- isAuthenticated: (env) => existsSync10(credentialsPath(env)),
26032
+ isAuthenticated: (env) => existsSync11(credentialsPath(env)),
25564
26033
  buildPromptText: (turn) => turn.system ? `${turn.system}
25565
26034
 
25566
26035
  ${turn.text}` : turn.text
@@ -25570,19 +26039,19 @@ ${turn.text}` : turn.text
25570
26039
  });
25571
26040
 
25572
26041
  // server/drivers/acp/droid.ts
25573
- import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
25574
- import { homedir as homedir16 } from "node:os";
25575
- import { join as join23 } from "node:path";
26042
+ import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
26043
+ import { homedir as homedir17 } from "node:os";
26044
+ import { join as join25 } from "node:path";
25576
26045
  function authFilePaths(env) {
25577
- const home = env.FACTORY_HOME_OVERRIDE || env.HOME || homedir16();
25578
- return AUTH_FILES.map((name) => join23(home, ".factory", name));
26046
+ const home = env.FACTORY_HOME_OVERRIDE || env.HOME || homedir17();
26047
+ return AUTH_FILES.map((name) => join25(home, ".factory", name));
25579
26048
  }
25580
26049
  function droidInjectId(host, model) {
25581
26050
  const safe = `${host}-${model}`.replace(/[^a-zA-Z0-9._+-]+/g, "-").replace(/-+/g, "-");
25582
26051
  return `${INJECT_ID_PREFIX}${safe}`;
25583
26052
  }
25584
26053
  function factoryHome(env) {
25585
- return env.FACTORY_HOME_OVERRIDE || env.HOME || env.USERPROFILE || homedir16();
26054
+ return env.FACTORY_HOME_OVERRIDE || env.HOME || env.USERPROFILE || homedir17();
25586
26055
  }
25587
26056
  function ensureDroidInjectModel(modelId, env = process.env) {
25588
26057
  const inject = decodeInjectId(modelId);
@@ -25590,14 +26059,14 @@ function ensureDroidInjectModel(modelId, env = process.env) {
25590
26059
  const host = localHost(inject.host);
25591
26060
  if (!host) return modelId;
25592
26061
  const id = droidInjectId(inject.host, inject.model);
25593
- const dir = join23(factoryHome(env), ".factory");
25594
- mkdirSync8(dir, { recursive: true });
25595
- const path3 = join23(dir, "settings.json");
26062
+ const dir = join25(factoryHome(env), ".factory");
26063
+ mkdirSync9(dir, { recursive: true });
26064
+ const path3 = join25(dir, "settings.json");
25596
26065
  let settings2 = {};
25597
26066
  try {
25598
26067
  settings2 = JSON.parse(readFileSync12(path3, "utf8"));
25599
26068
  } catch (error51) {
25600
- if (existsSync11(path3)) throw error51;
26069
+ if (existsSync12(path3)) throw error51;
25601
26070
  }
25602
26071
  const custom2 = Array.isArray(settings2.customModels) ? [...settings2.customModels] : [];
25603
26072
  const match = custom2.find(
@@ -25628,11 +26097,11 @@ function ensureDroidInjectModel(modelId, env = process.env) {
25628
26097
  function applyDroidLocalAuthEnv(env, modelId) {
25629
26098
  if (!decodeInjectId(modelId)) return;
25630
26099
  if (env.FACTORY_API_KEY?.trim()) return;
25631
- if (authFilePaths(env).some(existsSync11)) return;
26100
+ if (authFilePaths(env).some(existsSync12)) return;
25632
26101
  env.FACTORY_API_KEY = "openmausbot-local";
25633
26102
  }
25634
26103
  function readSettings(env) {
25635
- return JSON.parse(readFileSync12(join23(factoryHome(env), ".factory", "settings.json"), "utf8"));
26104
+ return JSON.parse(readFileSync12(join25(factoryHome(env), ".factory", "settings.json"), "utf8"));
25636
26105
  }
25637
26106
  async function resolveModels(env) {
25638
26107
  let catalog = MODELS3;
@@ -25719,7 +26188,7 @@ var init_droid = __esm({
25719
26188
  // The signed-in CLI is the primary source; FACTORY_API_KEY is the fallback
25720
26189
  // droid itself advertises, and it is checked last so an ambient key can
25721
26190
  // never be what makes an otherwise logged-out instance look ready.
25722
- isAuthenticated: (env) => authFilePaths(env).some(existsSync11) || Boolean(env.FACTORY_API_KEY),
26191
+ isAuthenticated: (env) => authFilePaths(env).some(existsSync12) || Boolean(env.FACTORY_API_KEY),
25723
26192
  resolveModels,
25724
26193
  resolveTurnModel: (model, env) => model ? ensureDroidInjectModel(model, env) : model,
25725
26194
  applyTurnEnv: (env, { requestedModel }) => {
@@ -25901,10 +26370,10 @@ function decodeCursorAuthText(text2) {
25901
26370
  return null;
25902
26371
  }
25903
26372
  function execText(run3, cli, args, env) {
25904
- return new Promise((resolve12) => {
26373
+ return new Promise((resolve13) => {
25905
26374
  run3(cli, args, { timeout: EXEC_TIMEOUT_MS, env }, (err, stdout2) => {
25906
- if (err) return resolve12(null);
25907
- resolve12(String(stdout2 ?? ""));
26375
+ if (err) return resolve13(null);
26376
+ resolve13(String(stdout2 ?? ""));
25908
26377
  });
25909
26378
  });
25910
26379
  }
@@ -26022,9 +26491,9 @@ ${turn.text}` : turn.text
26022
26491
  });
26023
26492
 
26024
26493
  // server/drivers/acp/opencode-go.ts
26025
- import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
26026
- import { homedir as homedir17 } from "node:os";
26027
- import { join as join24 } from "node:path";
26494
+ import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
26495
+ import { homedir as homedir18 } from "node:os";
26496
+ import { join as join26 } from "node:path";
26028
26497
  function labelForModel(id) {
26029
26498
  return id.split(/[-_.]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
26030
26499
  }
@@ -26098,7 +26567,7 @@ function parseOpenCodeModelsOutput(stdout2) {
26098
26567
  return { default: (preferred ?? options[0]).id, options };
26099
26568
  }
26100
26569
  function runOpenCodeModels(cli, environment, verbose) {
26101
- return new Promise((resolve12, reject) => {
26570
+ return new Promise((resolve13, reject) => {
26102
26571
  execCli(
26103
26572
  cli,
26104
26573
  ["models", ...verbose ? ["--verbose"] : []],
@@ -26108,7 +26577,7 @@ function runOpenCodeModels(cli, environment, verbose) {
26108
26577
  reject(new Error(stderr?.trim() || error51.message, { cause: error51 }));
26109
26578
  return;
26110
26579
  }
26111
- resolve12(stdout2);
26580
+ resolve13(stdout2);
26112
26581
  }
26113
26582
  );
26114
26583
  });
@@ -26124,8 +26593,8 @@ async function discoverOpenCodeModels(environment, cli = "opencode") {
26124
26593
  }
26125
26594
  }
26126
26595
  function opencodeConfigDir(env) {
26127
- const home = env.HOME || env.USERPROFILE || homedir17();
26128
- return join24(env.XDG_CONFIG_HOME || join24(home, ".config"), "opencode");
26596
+ const home = env.HOME || env.USERPROFILE || homedir18();
26597
+ return join26(env.XDG_CONFIG_HOME || join26(home, ".config"), "opencode");
26129
26598
  }
26130
26599
  function ensureOpenCodeInjectModel(modelId, env = process.env) {
26131
26600
  const inject = decodeInjectId(modelId);
@@ -26134,10 +26603,10 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
26134
26603
  if (!host) return modelId;
26135
26604
  const native = `${inject.host}/${inject.model}`;
26136
26605
  const dir = opencodeConfigDir(env);
26137
- mkdirSync9(dir, { recursive: true });
26138
- const path3 = join24(dir, "opencode.json");
26606
+ mkdirSync10(dir, { recursive: true });
26607
+ const path3 = join26(dir, "opencode.json");
26139
26608
  let config2 = { $schema: "https://opencode.ai/config.json" };
26140
- if (existsSync12(path3)) {
26609
+ if (existsSync13(path3)) {
26141
26610
  try {
26142
26611
  config2 = JSON.parse(readFileSync13(path3, "utf8"));
26143
26612
  } catch {
@@ -26171,12 +26640,12 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
26171
26640
  return native;
26172
26641
  }
26173
26642
  function storedAuthPaths(env) {
26174
- const home = env.HOME || env.USERPROFILE || homedir17();
26643
+ const home = env.HOME || env.USERPROFILE || homedir18();
26175
26644
  const roots = [
26176
- env.XDG_DATA_HOME || join24(home, ".local", "share"),
26177
- process.platform === "darwin" ? join24(home, "Library", "Application Support") : process.platform === "win32" ? env.LOCALAPPDATA || join24(home, "AppData", "Local") : ""
26645
+ env.XDG_DATA_HOME || join26(home, ".local", "share"),
26646
+ process.platform === "darwin" ? join26(home, "Library", "Application Support") : process.platform === "win32" ? env.LOCALAPPDATA || join26(home, "AppData", "Local") : ""
26178
26647
  ].filter(Boolean);
26179
- return [...new Set(roots)].map((root) => join24(root, "opencode", "auth.json"));
26648
+ return [...new Set(roots)].map((root) => join26(root, "opencode", "auth.json"));
26180
26649
  }
26181
26650
  function usableAuthEntry(parsed) {
26182
26651
  return Object.values(parsed).some((auth) => {
@@ -26306,11 +26775,97 @@ ${turn.text}` : turn.text
26306
26775
  });
26307
26776
 
26308
26777
  // server/drivers/acp/qwen.ts
26309
- import { chmodSync as chmodSync4, existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
26310
- import { homedir as homedir18 } from "node:os";
26311
- import { join as join25 } from "node:path";
26778
+ import { chmodSync as chmodSync4, existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
26779
+ import { createHash as createHash7 } from "node:crypto";
26780
+ import { homedir as homedir19 } from "node:os";
26781
+ import { join as join27 } from "node:path";
26312
26782
  function qwenHome(env) {
26313
- return join25(env.HOME || env.USERPROFILE || homedir18(), ".qwen");
26783
+ const home = process.platform === "win32" ? env.USERPROFILE || env.HOME || homedir19() : env.HOME || env.USERPROFILE || homedir19();
26784
+ return join27(home, ".qwen");
26785
+ }
26786
+ function isRecord(value) {
26787
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
26788
+ }
26789
+ function qwenModelLabel(id, name) {
26790
+ if (!name || name.toLocaleLowerCase().endsWith(id.toLocaleLowerCase())) return id;
26791
+ return `${id} \u2014 ${name}`;
26792
+ }
26793
+ function readQwenRoutes(env) {
26794
+ let settings2;
26795
+ try {
26796
+ settings2 = JSON.parse(readFileSync14(join27(qwenHome(env), "settings.json"), "utf8"));
26797
+ } catch {
26798
+ return [];
26799
+ }
26800
+ if (!isRecord(settings2) || !isRecord(settings2.modelProviders)) return [];
26801
+ const routes = [];
26802
+ const seen = /* @__PURE__ */ new Set();
26803
+ const mappings = isRecord(settings2.providerProtocol) ? settings2.providerProtocol : {};
26804
+ for (const [provider, rows] of Object.entries(settings2.modelProviders)) {
26805
+ const protocol = Object.hasOwn(mappings, provider) ? mappings[provider] : provider;
26806
+ if (typeof protocol !== "string" || !PROTOCOLS.has(protocol) || !Array.isArray(rows)) continue;
26807
+ for (const row of rows) {
26808
+ if (!isRecord(row) || typeof row.id !== "string") continue;
26809
+ const model = row.id;
26810
+ if (!model.trim()) continue;
26811
+ if (row.baseUrl !== void 0 && typeof row.baseUrl !== "string") continue;
26812
+ const baseUrl = typeof row.baseUrl === "string" && row.baseUrl ? row.baseUrl : void 0;
26813
+ if (baseUrl) {
26814
+ try {
26815
+ new URL(baseUrl);
26816
+ } catch {
26817
+ throw new Error("A Qwen model has an invalid endpoint. Fix its baseUrl in Qwen settings and refresh models.");
26818
+ }
26819
+ }
26820
+ const identity = JSON.stringify([protocol, model, baseUrl ?? null]);
26821
+ if (seen.has(identity)) continue;
26822
+ seen.add(identity);
26823
+ if (row.imageOnly === true || row.voiceOnly === true || row.fastOnly === true) continue;
26824
+ routes.push({
26825
+ id: `${model}(${protocol})`,
26826
+ model,
26827
+ provider,
26828
+ protocol,
26829
+ baseUrl,
26830
+ label: typeof row.name === "string" && row.name ? row.name : model,
26831
+ envKey: typeof row.envKey === "string" ? row.envKey : void 0
26832
+ });
26833
+ }
26834
+ }
26835
+ const counts = /* @__PURE__ */ new Map();
26836
+ for (const route of routes) counts.set(route.id, (counts.get(route.id) ?? 0) + 1);
26837
+ for (const route of routes) {
26838
+ if (counts.get(route.id) === 1) continue;
26839
+ const endpoint = route.baseUrl ?? (route.protocol === "openai" ? "https://api.openai.com/v1" : "");
26840
+ let publicEndpoint = null;
26841
+ if (endpoint) {
26842
+ try {
26843
+ const url2 = new URL(endpoint);
26844
+ url2.username = "";
26845
+ url2.password = "";
26846
+ url2.search = "";
26847
+ url2.hash = "";
26848
+ publicEndpoint = url2.href;
26849
+ } catch {
26850
+ throw new Error("A Qwen model has an invalid endpoint. Fix its baseUrl in Qwen settings and refresh models.");
26851
+ }
26852
+ }
26853
+ const identity = [route.id, route.label, route.envKey ?? null, route.baseUrl === void 0, publicEndpoint];
26854
+ route.id = `qwen-route:v1:${createHash7("sha256").update(JSON.stringify(identity)).digest("base64url").slice(0, 16)}`;
26855
+ }
26856
+ if (new Set(routes.map((route) => route.id)).size !== routes.length) {
26857
+ throw new Error("Qwen has indistinguishable model routes. Give them distinct names, envKey values, or public endpoints in Qwen settings.");
26858
+ }
26859
+ return routes;
26860
+ }
26861
+ function readQwenModelCatalog(env = process.env) {
26862
+ const options = readQwenRoutes(env).map(({ id, model, label, provider }) => ({
26863
+ id,
26864
+ label: qwenModelLabel(model, label),
26865
+ custom: true,
26866
+ provider
26867
+ }));
26868
+ return { default: options[0]?.id ?? "", options };
26314
26869
  }
26315
26870
  function envKeyFor(hostId) {
26316
26871
  return `OPENMAUSBOT_QWEN_${hostId.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
@@ -26321,10 +26876,10 @@ function ensureQwenInjectModel(modelId, env = process.env) {
26321
26876
  const host = localHost(inject.host);
26322
26877
  if (!host) return modelId;
26323
26878
  const dir = qwenHome(env);
26324
- mkdirSync10(dir, { recursive: true });
26325
- const path3 = join25(dir, "settings.json");
26879
+ mkdirSync11(dir, { recursive: true });
26880
+ const path3 = join27(dir, "settings.json");
26326
26881
  let settings2 = {};
26327
- if (existsSync13(path3)) {
26882
+ if (existsSync14(path3)) {
26328
26883
  try {
26329
26884
  settings2 = JSON.parse(readFileSync14(path3, "utf8"));
26330
26885
  } catch {
@@ -26359,23 +26914,54 @@ function ensureQwenInjectModel(modelId, env = process.env) {
26359
26914
  return inject.model;
26360
26915
  }
26361
26916
  async function resolveModels2(env) {
26362
- const catalog = await mergeLocalInject(EMPTY, env);
26363
- return { default: catalog.options[0]?.id ?? "", options: catalog.options };
26364
- }
26365
- var EMPTY, support8, QwenAgentDriver;
26917
+ const catalog = await mergeLocalInject(readQwenModelCatalog(env), env);
26918
+ const routes = readQwenRoutes(env);
26919
+ const replacements = /* @__PURE__ */ new Map();
26920
+ for (const option of catalog.options) {
26921
+ const injected = decodeInjectId(option.id);
26922
+ if (!injected) continue;
26923
+ const endpoint = localHost(injected.host)?.baseUrl;
26924
+ for (const route of routes) {
26925
+ if (route.protocol === "openai" && route.model === injected.model && route.baseUrl === endpoint) {
26926
+ replacements.set(route.id, option.id);
26927
+ }
26928
+ }
26929
+ }
26930
+ const options = catalog.options.filter((option) => !replacements.has(option.id));
26931
+ const preferred = replacements.get(catalog.default) ?? catalog.default;
26932
+ return { default: options.some((option) => option.id === preferred) ? preferred : options[0]?.id ?? "", options };
26933
+ }
26934
+ function resolveQwenTurnModel(model, env) {
26935
+ if (!model) return model;
26936
+ const injected = decodeInjectId(model);
26937
+ if (injected) ensureQwenInjectModel(model, env);
26938
+ const routes = readQwenRoutes(env);
26939
+ if (injected) {
26940
+ const route = routes.find((row) => row.protocol === "openai" && row.model === injected.model && row.baseUrl === localHost(injected.host)?.baseUrl);
26941
+ if (!route) throw new Error("Qwen could not configure this local model. Refresh models and select it again.");
26942
+ return route.id;
26943
+ }
26944
+ if (routes.some((route) => route.id === model)) return model;
26945
+ const matches = routes.filter((route) => route.model === model);
26946
+ if (matches.length > 1) throw new Error("This Qwen model has multiple providers. Refresh models and select the intended provider again.");
26947
+ if (!matches.length) throw new Error("This Qwen model is no longer configured. Refresh models and select it again.");
26948
+ return matches[0].id;
26949
+ }
26950
+ var EMPTY, PROTOCOLS, support8, QwenAgentDriver;
26366
26951
  var init_qwen = __esm({
26367
26952
  "server/drivers/acp/qwen.ts"() {
26368
26953
  "use strict";
26369
26954
  init_local_inject();
26370
26955
  init_core3();
26371
26956
  EMPTY = { default: "", options: [] };
26957
+ PROTOCOLS = /* @__PURE__ */ new Set(["openai", "anthropic", "gemini", "vertex-ai"]);
26372
26958
  support8 = {
26373
26959
  driverKind: "qwenAgent",
26374
26960
  displayName: "Qwen",
26375
26961
  access: "custom",
26376
26962
  models: EMPTY,
26377
26963
  resolveModels: resolveModels2,
26378
- resolveTurnModel: (model, env) => model ? ensureQwenInjectModel(model, env) : model,
26964
+ resolveTurnModel: resolveQwenTurnModel,
26379
26965
  defaultCli: "qwen",
26380
26966
  nativeSource: "qwen.acp",
26381
26967
  loginNote: "Qwen Code CLI is not installed",
@@ -26387,7 +26973,10 @@ var init_qwen = __esm({
26387
26973
  },
26388
26974
  docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/overview/"
26389
26975
  },
26390
- spawnArgs: (_config, turn) => ["--acp", ...turn.model ? ["-m", turn.model] : []],
26976
+ // A raw -m only changes the model within the saved provider. ACP switches
26977
+ // the complete route and confirms it before any prompt leaves OMB.
26978
+ spawnArgs: () => ["--acp"],
26979
+ selectModel: { configId: "model" },
26391
26980
  pickAuthMethod: () => null,
26392
26981
  authFailure: "continue",
26393
26982
  isAuthenticated: () => true,
@@ -33287,9 +33876,9 @@ var init_browser = __esm({
33287
33876
 
33288
33877
  // server/drivers/acp/hermes.ts
33289
33878
  import { spawn as spawn5 } from "node:child_process";
33290
- import { mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
33291
- import { homedir as homedir19 } from "node:os";
33292
- import { join as join26 } from "node:path";
33879
+ import { mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
33880
+ import { homedir as homedir20 } from "node:os";
33881
+ import { join as join28 } from "node:path";
33293
33882
  function bindHermesScreenshotCompat(env, modelId) {
33294
33883
  delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT];
33295
33884
  delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL];
@@ -33299,7 +33888,7 @@ function bindHermesScreenshotCompat(env, modelId) {
33299
33888
  env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL] = inject.model;
33300
33889
  }
33301
33890
  function hermesHome(env) {
33302
- return env.HERMES_HOME || join26(env.HOME || env.USERPROFILE || homedir19(), ".hermes");
33891
+ return env.HERMES_HOME || join28(env.HOME || env.USERPROFILE || homedir20(), ".hermes");
33303
33892
  }
33304
33893
  function quoteYaml(value) {
33305
33894
  if (/^[\w./:+-]+$/.test(value)) return value;
@@ -33340,8 +33929,8 @@ function ensureHermesInjectProvider(modelId, env = process.env) {
33340
33929
  const host = localHost(inject.host);
33341
33930
  if (!host) return modelId;
33342
33931
  const dir = hermesHome(env);
33343
- mkdirSync11(dir, { recursive: true });
33344
- const path3 = join26(dir, "config.yaml");
33932
+ mkdirSync12(dir, { recursive: true });
33933
+ const path3 = join28(dir, "config.yaml");
33345
33934
  let text2 = "";
33346
33935
  try {
33347
33936
  text2 = readFileSync15(path3, "utf8");
@@ -33412,13 +34001,13 @@ function hermesConfiguredModel(env = process.env) {
33412
34001
  const dir = hermesHome(env);
33413
34002
  let secrets = "";
33414
34003
  try {
33415
- secrets = readFileSync15(join26(dir, ".env"), "utf8");
34004
+ secrets = readFileSync15(join28(dir, ".env"), "utf8");
33416
34005
  } catch {
33417
34006
  }
33418
34007
  const hasHostedProviderKey = HERMES_HOSTED_PROVIDER_KEYS.some((name) => nonEmptyDotenvValue(secrets, name));
33419
34008
  let configuredDefault = null;
33420
34009
  try {
33421
- configuredDefault = hermesConfigDefault(readFileSync15(join26(dir, "config.yaml"), "utf8"));
34010
+ configuredDefault = hermesConfigDefault(readFileSync15(join28(dir, "config.yaml"), "utf8"));
33422
34011
  } catch {
33423
34012
  }
33424
34013
  const configuredProvider = configuredDefault?.provider.toLowerCase() ?? "";
@@ -33434,12 +34023,12 @@ function hermesConfiguredModel(env = process.env) {
33434
34023
  };
33435
34024
  }
33436
34025
  async function fetchHermesAcpModels(cli, env) {
33437
- return await new Promise((resolve12) => {
34026
+ return await new Promise((resolve13) => {
33438
34027
  let child;
33439
34028
  try {
33440
34029
  child = spawn5(cli, ["acp"], { stdio: ["pipe", "pipe", "ignore"], env });
33441
34030
  } catch {
33442
- return resolve12([]);
34031
+ return resolve13([]);
33443
34032
  }
33444
34033
  let settled = false;
33445
34034
  let timer;
@@ -33460,7 +34049,7 @@ async function fetchHermesAcpModels(cli, env) {
33460
34049
  }
33461
34050
  } catch {
33462
34051
  }
33463
- resolve12(out);
34052
+ resolve13(out);
33464
34053
  };
33465
34054
  timer = setTimeout(() => done([]), 5e3);
33466
34055
  child.once("error", () => done([]));
@@ -33503,7 +34092,7 @@ async function fetchHermesAcpModels(cli, env) {
33503
34092
  }
33504
34093
  if (msg?.id === initId) {
33505
34094
  if (!msg.result) return done([]);
33506
- sessionId = send("session/new", { cwd: env.HOME || env.USERPROFILE || homedir19(), mcpServers: [] });
34095
+ sessionId = send("session/new", { cwd: env.HOME || env.USERPROFILE || homedir20(), mcpServers: [] });
33507
34096
  } else if (sessionId && msg?.id === sessionId) {
33508
34097
  const list = Array.isArray(msg.result?.models?.availableModels) ? msg.result.models.availableModels : [];
33509
34098
  done(
@@ -33738,9 +34327,9 @@ var init_openai_compat = __esm({
33738
34327
  });
33739
34328
 
33740
34329
  // server/drivers/pi.ts
33741
- import { chmodSync as chmodSync5, existsSync as existsSync14, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, rmSync as rmSync3, writeFileSync as writeFileSync12 } from "node:fs";
33742
- import { homedir as homedir20, tmpdir as tmpdir4 } from "node:os";
33743
- import { join as join27 } from "node:path";
34330
+ import { chmodSync as chmodSync5, existsSync as existsSync15, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync3, readFileSync as readFileSync16, rmSync as rmSync3, writeFileSync as writeFileSync12 } from "node:fs";
34331
+ import { homedir as homedir21, tmpdir as tmpdir4 } from "node:os";
34332
+ import { join as join29 } from "node:path";
33744
34333
  function readPiPromptImages(turn) {
33745
34334
  return (turn.images ?? []).map((image) => ({
33746
34335
  type: "image",
@@ -33847,7 +34436,7 @@ async function applyPiLocalCatalog(catalog, env = process.env, fetchImpl = fetch
33847
34436
  return preferPiInjectRows(await mergeLocalInject(catalog, env, fetchImpl));
33848
34437
  }
33849
34438
  function piAgentDir(env) {
33850
- return join27(env.HOME || env.USERPROFILE || homedir20(), ".pi", "agent");
34439
+ return join29(env.HOME || env.USERPROFILE || homedir21(), ".pi", "agent");
33851
34440
  }
33852
34441
  function ensurePiInjectModel(modelId, env = process.env) {
33853
34442
  const split = splitPiModel(modelId);
@@ -33857,10 +34446,10 @@ function ensurePiInjectModel(modelId, env = process.env) {
33857
34446
  const host = localHost(inject.host);
33858
34447
  if (!host) return split;
33859
34448
  const dir = piAgentDir(env);
33860
- mkdirSync12(dir, { recursive: true });
33861
- const path3 = join27(dir, "models.json");
34449
+ mkdirSync13(dir, { recursive: true });
34450
+ const path3 = join29(dir, "models.json");
33862
34451
  let root = { providers: {} };
33863
- if (existsSync14(path3)) {
34452
+ if (existsSync15(path3)) {
33864
34453
  try {
33865
34454
  const parsed = JSON.parse(readFileSync16(path3, "utf8"));
33866
34455
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
@@ -33912,7 +34501,7 @@ function ensurePiInjectModel(modelId, env = process.env) {
33912
34501
  return split;
33913
34502
  }
33914
34503
  function readPiDefaultModel(env) {
33915
- const home = env.HOME || env.USERPROFILE || homedir20();
34504
+ const home = env.HOME || env.USERPROFILE || homedir21();
33916
34505
  try {
33917
34506
  const s = JSON.parse(readFileSync16(`${home}/.pi/agent/settings.json`, "utf8"));
33918
34507
  return s.defaultProvider && s.defaultModel ? `${s.defaultProvider}/${s.defaultModel}` : "";
@@ -33922,7 +34511,7 @@ function readPiDefaultModel(env) {
33922
34511
  }
33923
34512
  async function fetchPiModels(cli, env) {
33924
34513
  const child = spawnCli(cli, PI_ARGS, { stdio: ["pipe", "pipe", "pipe"], env });
33925
- return new Promise((resolve12) => {
34514
+ return new Promise((resolve13) => {
33926
34515
  let buf = "";
33927
34516
  let done = false;
33928
34517
  const fallbackDefault = readPiDefaultModel(env);
@@ -33933,7 +34522,7 @@ async function fetchPiModels(cli, env) {
33933
34522
  killCliTree(child);
33934
34523
  } catch {
33935
34524
  }
33936
- resolve12(catalog);
34525
+ resolve13(catalog);
33937
34526
  };
33938
34527
  const timer = setTimeout(() => finish({ default: "", options: [] }), 15e3);
33939
34528
  timer.unref?.();
@@ -34060,9 +34649,9 @@ var init_pi = __esm({
34060
34649
  const mcpServers = buildMcpServers(turn);
34061
34650
  let mcpTempDir = null;
34062
34651
  if (mcpServers) {
34063
- mcpTempDir = mkdtempSync3(join27(tmpdir4(), "omb-pi-mcp-"));
34652
+ mcpTempDir = mkdtempSync3(join29(tmpdir4(), "omb-pi-mcp-"));
34064
34653
  try {
34065
- writeFileSync12(join27(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
34654
+ writeFileSync12(join29(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
34066
34655
  } catch (err) {
34067
34656
  try {
34068
34657
  rmSync3(mcpTempDir, { recursive: true, force: true });
@@ -34080,7 +34669,7 @@ var init_pi = __esm({
34080
34669
  env: piEnvironment({
34081
34670
  ...process.env,
34082
34671
  ...input.environment,
34083
- ...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join27(mcpTempDir, "mcp.json") } : {}
34672
+ ...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join29(mcpTempDir, "mcp.json") } : {}
34084
34673
  })
34085
34674
  });
34086
34675
  } catch (err) {
@@ -34103,13 +34692,13 @@ var init_pi = __esm({
34103
34692
  }
34104
34693
  responseWaiters.clear();
34105
34694
  };
34106
- const awaitResponse = (command, timeoutMs = 2e4) => new Promise((resolve12, reject) => {
34695
+ const awaitResponse = (command, timeoutMs = 2e4) => new Promise((resolve13, reject) => {
34107
34696
  const timer = setTimeout(() => {
34108
34697
  responseWaiters.delete(command);
34109
34698
  reject(new Error(`pi ${command} timed out`));
34110
34699
  }, timeoutMs);
34111
34700
  timer.unref?.();
34112
- responseWaiters.set(command, { resolve: resolve12, reject, timer });
34701
+ responseWaiters.set(command, { resolve: resolve13, reject, timer });
34113
34702
  });
34114
34703
  child.stdin.on("error", () => rejectWaiters(new Error("pi stdin closed")));
34115
34704
  const send = (obj) => {
@@ -34317,7 +34906,7 @@ ${turn.text}` : turn.text;
34317
34906
  return { turnId };
34318
34907
  };
34319
34908
  const snapshot = async () => {
34320
- const version2 = await new Promise((resolve12) => {
34909
+ const version2 = await new Promise((resolve13) => {
34321
34910
  const child = spawnCli(config2.cli, ["--version"], {
34322
34911
  stdio: ["ignore", "pipe", "pipe"],
34323
34912
  env: piEnvironment({ ...process.env, ...input.environment })
@@ -34330,16 +34919,16 @@ ${turn.text}` : turn.text;
34330
34919
  killCliTree(child);
34331
34920
  } catch {
34332
34921
  }
34333
- resolve12(null);
34922
+ resolve13(null);
34334
34923
  }, 8e3);
34335
34924
  timer.unref?.();
34336
34925
  child.on("error", () => {
34337
34926
  clearTimeout(timer);
34338
- resolve12(null);
34927
+ resolve13(null);
34339
34928
  });
34340
34929
  child.on("close", () => {
34341
34930
  clearTimeout(timer);
34342
- resolve12(out.trim() || null);
34931
+ resolve13(out.trim() || null);
34343
34932
  });
34344
34933
  });
34345
34934
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
@@ -34418,15 +35007,15 @@ ${turn.text}` : turn.text;
34418
35007
 
34419
35008
  // server/drivers/minimax.ts
34420
35009
  import { readFileSync as readFileSync17 } from "node:fs";
34421
- import { homedir as homedir21 } from "node:os";
34422
- import { join as join28 } from "node:path";
35010
+ import { homedir as homedir22 } from "node:os";
35011
+ import { join as join30 } from "node:path";
34423
35012
  function normalizedApiUrl(value) {
34424
35013
  const root = value.trim().replace(/\/+$/, "");
34425
35014
  return root.endsWith("/v1") ? root : `${root}/v1`;
34426
35015
  }
34427
- function loadLocalMiniMaxConfig(home = homedir21()) {
35016
+ function loadLocalMiniMaxConfig(home = homedir22()) {
34428
35017
  try {
34429
- const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join28(home, ".mmx", "config.json"), "utf8")));
35018
+ const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join30(home, ".mmx", "config.json"), "utf8")));
34430
35019
  const configuredUrl = raw.base_url?.trim() ? raw.base_url : raw.region === "cn" ? CN_URL : DEFAULT_URL2;
34431
35020
  return {
34432
35021
  apiKey: raw.api_key?.trim() ?? "",
@@ -34694,7 +35283,7 @@ __export(cli_setup_exports, {
34694
35283
  });
34695
35284
  import { spawn as spawn6 } from "node:child_process";
34696
35285
  import { readFileSync as readFileSync18 } from "node:fs";
34697
- import { join as join29, resolve as resolve9 } from "node:path";
35286
+ import { join as join31, resolve as resolve10 } from "node:path";
34698
35287
  import { randomUUID as randomUUID10 } from "node:crypto";
34699
35288
  async function inspect(id, entry) {
34700
35289
  const registry2 = new ProviderRegistry(BUILT_IN_DRIVERS);
@@ -34727,11 +35316,11 @@ async function runSetupCli(cli, args, environment = {}) {
34727
35316
  resetPathCache();
34728
35317
  }
34729
35318
  function assertDataDir(dataDir) {
34730
- if (resolve9(dataDir) !== resolve9(DATA_DIR)) throw new Error("Setup data directory mismatch. Restart the CLI with --data-dir.");
35319
+ if (resolve10(dataDir) !== resolve10(DATA_DIR)) throw new Error("Setup data directory mismatch. Restart the CLI with --data-dir.");
34731
35320
  }
34732
35321
  function checkStoredConfig(dataDir) {
34733
35322
  try {
34734
- parseStoredConfig(JSON.parse(readFileSync18(join29(dataDir, "config.json"), "utf8")));
35323
+ parseStoredConfig(JSON.parse(readFileSync18(join31(dataDir, "config.json"), "utf8")));
34735
35324
  } catch (error51) {
34736
35325
  if (error51.code === "ENOENT") return;
34737
35326
  throw new Error("Existing config.json could not be read or validated. Setup has not changed it; repair it before continuing.");
@@ -35009,7 +35598,7 @@ var init_browser_engine_release = __esm({
35009
35598
  });
35010
35599
 
35011
35600
  // server/browser-bundle-release.ts
35012
- import { join as join30 } from "node:path";
35601
+ import { join as join32 } from "node:path";
35013
35602
  function browserBundleSpec(target) {
35014
35603
  if (!Object.hasOwn(CHROME_ASSETS, target)) throw new Error(`Unsupported desktop browser target: ${target}`);
35015
35604
  const pinned = CHROME_ASSETS[target];
@@ -35045,10 +35634,10 @@ function browserBundlePaths(bundleDirectory, target) {
35045
35634
  const spec = browserBundleSpec(target);
35046
35635
  return {
35047
35636
  directory: bundleDirectory,
35048
- manifest: join30(bundleDirectory, "manifest.json"),
35049
- engine: join30(bundleDirectory, spec.engine.executable),
35050
- chrome: join30(bundleDirectory, spec.chrome.executable),
35051
- licenses: join30(bundleDirectory, "licenses")
35637
+ manifest: join32(bundleDirectory, "manifest.json"),
35638
+ engine: join32(bundleDirectory, spec.engine.executable),
35639
+ chrome: join32(bundleDirectory, spec.chrome.executable),
35640
+ licenses: join32(bundleDirectory, "licenses")
35052
35641
  };
35053
35642
  }
35054
35643
  var CHROME_VERSION, CHROME_ASSETS;
@@ -35102,27 +35691,27 @@ __export(browser_engine_exports, {
35102
35691
  resolveAgentBrowserBinary: () => resolveAgentBrowserBinary
35103
35692
  });
35104
35693
  import { spawn as spawn7 } from "node:child_process";
35105
- import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
35106
- import { chmodSync as chmodSync6, constants as constants2, copyFileSync, existsSync as existsSync15, mkdirSync as mkdirSync13, readFileSync as readFileSync19, readdirSync as readdirSync3, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "node:fs";
35107
- import { homedir as homedir22, tmpdir as tmpdir5 } from "node:os";
35108
- import { delimiter as delimiter6, dirname as dirname10, join as join31, resolve as resolve10 } from "node:path";
35694
+ import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
35695
+ import { chmodSync as chmodSync6, constants as constants2, copyFileSync, existsSync as existsSync16, mkdirSync as mkdirSync14, readFileSync as readFileSync19, readdirSync as readdirSync3, renameSync as renameSync5, rmSync as rmSync4, statSync as statSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "node:fs";
35696
+ import { homedir as homedir23, tmpdir as tmpdir5 } from "node:os";
35697
+ import { delimiter as delimiter6, dirname as dirname10, join as join33, resolve as resolve11 } from "node:path";
35109
35698
  function browserRestoreKey(session) {
35110
35699
  if (!/^[A-Za-z0-9_-]{1,96}$/.test(session)) throw new Error("Invalid browser session.");
35111
- return `omb-${createHash7("sha256").update(session).digest("hex")}`;
35700
+ return `omb-${createHash8("sha256").update(session).digest("hex")}`;
35112
35701
  }
35113
35702
  function browserSessionsDirectory(env) {
35114
35703
  const namespace = env.AGENT_BROWSER_NAMESPACE;
35115
35704
  if (namespace && !/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(namespace)) throw new Error("Invalid browser namespace.");
35116
- const home = (process.platform === "win32" ? env.USERPROFILE : env.HOME) || homedir22();
35117
- const stateRoot = namespace ? join31(home, ".agent-browser", "namespaces", namespace, "state") : join31(home, ".agent-browser");
35118
- return join31(stateRoot, "sessions");
35705
+ const home = (process.platform === "win32" ? env.USERPROFILE : env.HOME) || homedir23();
35706
+ const stateRoot = namespace ? join33(home, ".agent-browser", "namespaces", namespace, "state") : join33(home, ".agent-browser");
35707
+ return join33(stateRoot, "sessions");
35119
35708
  }
35120
35709
  function managedBrowserConfigPath(env) {
35121
- return join31(browserSessionsDirectory(env), "..", "omb-managed-config.json");
35710
+ return join33(browserSessionsDirectory(env), "..", "omb-managed-config.json");
35122
35711
  }
35123
35712
  function ensureManagedBrowserConfig(env) {
35124
35713
  const path3 = managedBrowserConfigPath(env);
35125
- mkdirSync13(dirname10(path3), { recursive: true, mode: 448 });
35714
+ mkdirSync14(dirname10(path3), { recursive: true, mode: 448 });
35126
35715
  try {
35127
35716
  writeFileSync13(path3, "{}\n", { flag: "wx", mode: 384 });
35128
35717
  } catch (error51) {
@@ -35191,7 +35780,7 @@ async function closeBrowserSession(binaryPath, env, timeoutMs = 15e3) {
35191
35780
  } catch {
35192
35781
  return false;
35193
35782
  }
35194
- await new Promise((resolve12) => setTimeout(resolve12, Math.min(25, Math.max(1, deadline - Date.now()))));
35783
+ await new Promise((resolve13) => setTimeout(resolve13, Math.min(25, Math.max(1, deadline - Date.now()))));
35195
35784
  }
35196
35785
  return false;
35197
35786
  }
@@ -35205,12 +35794,12 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35205
35794
  ensureManagedBrowserConfig(env);
35206
35795
  if (options.persistent === false) return;
35207
35796
  const directory = browserSessionsDirectory(env);
35208
- const key = join31(directory, session);
35797
+ const key = join33(directory, session);
35209
35798
  let pending = preparedBrowserSessions.get(key);
35210
35799
  if (!pending) {
35211
35800
  pending = (async () => {
35212
- const targetBase = join31(directory, `${restoreKey}-${session}`);
35213
- const hasTarget = () => existsSync15(`${targetBase}.json.enc`) || existsSync15(`${targetBase}.json`);
35801
+ const targetBase = join33(directory, `${restoreKey}-${session}`);
35802
+ const hasTarget = () => existsSync16(`${targetBase}.json.enc`) || existsSync16(`${targetBase}.json`);
35214
35803
  if (hasTarget()) return;
35215
35804
  check2();
35216
35805
  if (!await closeBrowserSession(binaryPath, { ...env, AGENT_BROWSER_RESTORE: session }, options.timeoutMs)) {
@@ -35219,7 +35808,7 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35219
35808
  check2();
35220
35809
  if (hasTarget()) return;
35221
35810
  const candidates = [".json.enc", ".json"].flatMap((suffix) => {
35222
- const path3 = join31(directory, `${session}-${session}${suffix}`);
35811
+ const path3 = join33(directory, `${session}-${session}${suffix}`);
35223
35812
  try {
35224
35813
  const stat4 = statSync3(path3);
35225
35814
  if (!stat4.isFile()) throw new Error("Saved browser state is not a file.");
@@ -35249,19 +35838,19 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35249
35838
  function executableName(platform = process.platform) {
35250
35839
  return platform === "win32" ? "agent-browser.exe" : "agent-browser";
35251
35840
  }
35252
- function isMusl(platform = process.platform, exists = existsSync15) {
35841
+ function isMusl(platform = process.platform, exists = existsSync16) {
35253
35842
  return platform === "linux" && (exists("/lib/ld-musl-x86_64.so.1") || exists("/lib/ld-musl-aarch64.so.1"));
35254
35843
  }
35255
35844
  function pinnedBinaryPath(dataDir = DATA_DIR, platform = process.platform, arch = process.arch) {
35256
35845
  const version2 = agentBrowserReleaseVersion(resolveAgentBrowserReleaseAsset(platform, arch));
35257
- return join31(dataDir, ENGINE_DIR, version2, executableName(platform));
35846
+ return join33(dataDir, ENGINE_DIR, version2, executableName(platform));
35258
35847
  }
35259
35848
  function onPath(env, platform, exists) {
35260
35849
  const pathValue = platform === "win32" ? Object.entries(env).findLast(([key]) => key.toUpperCase() === "PATH")?.[1] : env.PATH;
35261
35850
  for (const part of (pathValue ?? "").split(delimiter6)) {
35262
35851
  const dir = part.trim().replace(/^"|"$/gu, "");
35263
35852
  if (!dir) continue;
35264
- const candidate = resolve10(dir, executableName(platform));
35853
+ const candidate = resolve11(dir, executableName(platform));
35265
35854
  if (exists(candidate)) return candidate;
35266
35855
  }
35267
35856
  return null;
@@ -35270,7 +35859,7 @@ function packagedBrowser(options) {
35270
35859
  const resources = (options.env ?? process.env).OMB_RESOURCES_PATH;
35271
35860
  if (!resources) return null;
35272
35861
  try {
35273
- return browserBundlePaths(join31(resolve10(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
35862
+ return browserBundlePaths(join33(resolve11(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
35274
35863
  } catch {
35275
35864
  return null;
35276
35865
  }
@@ -35281,9 +35870,9 @@ function completePackage(bundle, exists) {
35281
35870
  function resolveAgentBrowserBinary(options = {}) {
35282
35871
  const env = options.env ?? process.env;
35283
35872
  const platform = options.platform ?? process.platform;
35284
- const exists = options.exists ?? existsSync15;
35873
+ const exists = options.exists ?? existsSync16;
35285
35874
  const override = env.OMB_AGENT_BROWSER_PATH?.trim();
35286
- if (override) return resolve10(override) && exists(resolve10(override)) ? resolve10(override) : null;
35875
+ if (override) return resolve11(override) && exists(resolve11(override)) ? resolve11(override) : null;
35287
35876
  const bundle = packagedBrowser(options);
35288
35877
  if (bundle && exists(bundle.directory)) return completePackage(bundle, exists) ? bundle.engine : null;
35289
35878
  const pinned = pinnedBinaryPath(options.dataDir, platform, options.arch);
@@ -35295,8 +35884,8 @@ async function installAgentBrowserBinary(options = {}) {
35295
35884
  const asset = options.asset ?? resolveAgentBrowserReleaseAsset(platform, options.arch ?? process.arch, options.musl ?? isMusl(platform));
35296
35885
  if (!asset) throw new Error(`agent-browser publishes no build for ${platform}-${options.arch ?? process.arch}.`);
35297
35886
  const destination = pinnedBinaryPath(options.dataDir, platform, options.arch);
35298
- const directory = join31(destination, "..");
35299
- mkdirSync13(directory, { recursive: true, mode: 448 });
35887
+ const directory = join33(destination, "..");
35888
+ mkdirSync14(directory, { recursive: true, mode: 448 });
35300
35889
  const url2 = agentBrowserReleaseUrl(asset);
35301
35890
  options.log?.(`downloading agent-browser ${agentBrowserReleaseVersion(asset)} (${Math.round(asset.bytes / 1024 / 1024)} MB, digest pinned)`);
35302
35891
  const controller = new AbortController();
@@ -35311,7 +35900,7 @@ async function installAgentBrowserBinary(options = {}) {
35311
35900
  clearTimeout(timer);
35312
35901
  }
35313
35902
  if (body.length !== asset.bytes) throw new Error("the agent-browser download did not match its pinned size; nothing was installed");
35314
- const digest2 = createHash7("sha256").update(body).digest("hex");
35903
+ const digest2 = createHash8("sha256").update(body).digest("hex");
35315
35904
  if (digest2 !== asset.sha256) throw new Error("the agent-browser download failed its SHA-256 check; nothing was installed");
35316
35905
  const staging = `${destination}.${randomBytes3(6).toString("hex")}.part`;
35317
35906
  writeFileSync13(staging, body, { mode: 493 });
@@ -35321,7 +35910,7 @@ async function installAgentBrowserBinary(options = {}) {
35321
35910
  }
35322
35911
  function ensureChrome(binaryPath, options = {}) {
35323
35912
  const bundle = packagedBrowser(options);
35324
- if (!options.withDeps && bundle && resolve10(binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
35913
+ if (!options.withDeps && bundle && resolve11(binaryPath) === bundle.engine && completePackage(bundle, existsSync16)) {
35325
35914
  options.log?.("agent-browser: the bundled browser is ready; no download needed");
35326
35915
  return Promise.resolve();
35327
35916
  }
@@ -35347,14 +35936,14 @@ function ensureChrome(binaryPath, options = {}) {
35347
35936
  });
35348
35937
  }
35349
35938
  function browserEngineEncryptionKey(dataDir = DATA_DIR) {
35350
- const file2 = join31(dataDir, KEY_FILE);
35939
+ const file2 = join33(dataDir, KEY_FILE);
35351
35940
  try {
35352
35941
  const existing = readFileSync19(file2, "utf8").trim();
35353
35942
  if (/^[0-9a-f]{64}$/u.test(existing)) return existing;
35354
35943
  } catch {
35355
35944
  }
35356
35945
  const key = randomBytes3(32).toString("hex");
35357
- mkdirSync13(dataDir, { recursive: true });
35946
+ mkdirSync14(dataDir, { recursive: true });
35358
35947
  writeFileAtomic(file2, `${key}
35359
35948
  `, { mode: 384 });
35360
35949
  return key;
@@ -35368,7 +35957,7 @@ function browserEngineStatus(options = {}) {
35368
35957
  const version2 = managed ? agentBrowserReleaseVersion(resolveAgentBrowserReleaseAsset(platform2, options.arch)) : AGENT_BROWSER_VERSION;
35369
35958
  return { kind: "ready", binaryPath, version: version2 };
35370
35959
  }
35371
- if (bundle && (options.exists ?? existsSync15)(bundle.directory)) {
35960
+ if (bundle && (options.exists ?? existsSync16)(bundle.directory)) {
35372
35961
  return { kind: "unavailable", reason: "The desktop browser bundle is incomplete. Reinstall or update OpenMausBot to repair it.", installable: false };
35373
35962
  }
35374
35963
  const platform = options.platform ?? process.platform;
@@ -35401,13 +35990,13 @@ function agentBrowserIntegration(input) {
35401
35990
  if (sourceEnv[name]) env[name] = sourceEnv[name];
35402
35991
  }
35403
35992
  const bundle = packagedBrowser({ env: sourceEnv });
35404
- if (!env.AGENT_BROWSER_EXECUTABLE_PATH && bundle && resolve10(input.binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
35993
+ if (!env.AGENT_BROWSER_EXECUTABLE_PATH && bundle && resolve11(input.binaryPath) === bundle.engine && completePackage(bundle, existsSync16)) {
35405
35994
  env.AGENT_BROWSER_EXECUTABLE_PATH = bundle.chrome;
35406
35995
  }
35407
35996
  return { command: input.binaryPath, args: ["mcp", "--tools", "core", "--no-webmcp"], env };
35408
35997
  }
35409
35998
  function agentBrowserFrame(input) {
35410
- const file2 = join31(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
35999
+ const file2 = join33(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
35411
36000
  return new Promise((settle, fail) => {
35412
36001
  const child = spawn7(input.binaryPath, ["screenshot", file2], {
35413
36002
  env: browserRuntimeEnv(input.env),
@@ -35477,8 +36066,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
35477
36066
  }
35478
36067
  };
35479
36068
  try {
35480
- for (const base2 of bases) for (const suffix of [".json", ".json.enc", ".json.previous", ".json.enc.previous"]) remove(join31(directory, base2 + suffix));
35481
- const pendingDirectory = join31(directory, ".tmp");
36069
+ for (const base2 of bases) for (const suffix of [".json", ".json.enc", ".json.previous", ".json.enc.previous"]) remove(join33(directory, base2 + suffix));
36070
+ const pendingDirectory = join33(directory, ".tmp");
35482
36071
  let pendingFiles = [];
35483
36072
  try {
35484
36073
  pendingFiles = readdirSync3(pendingDirectory);
@@ -35486,8 +36075,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
35486
36075
  if (error51.code !== "ENOENT") throw error51;
35487
36076
  }
35488
36077
  const candidates = bases.map((base2) => new RegExp(`^${base2}-candidate-[0-9]+\\.json(?:\\.enc)?$`));
35489
- for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(join31(pendingDirectory, name));
35490
- preparedBrowserSessions.delete(join31(directory, session));
36078
+ for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(join33(pendingDirectory, name));
36079
+ preparedBrowserSessions.delete(join33(directory, session));
35491
36080
  return true;
35492
36081
  } catch {
35493
36082
  return false;
@@ -35514,9 +36103,9 @@ var init_browser_engine = __esm({
35514
36103
  // server/cli.ts
35515
36104
  var import_qrcode_terminal = __toESM(require_main(), 1);
35516
36105
  import { spawn as spawn8 } from "node:child_process";
35517
- import { closeSync as closeSync3, existsSync as existsSync16, mkdirSync as mkdirSync14, openSync as openSync3, readFileSync as readFileSync20 } from "node:fs";
35518
- import { homedir as homedir23 } from "node:os";
35519
- import { dirname as dirname11, join as join32, resolve as resolve11 } from "node:path";
36106
+ import { closeSync as closeSync3, existsSync as existsSync17, mkdirSync as mkdirSync15, openSync as openSync3, readFileSync as readFileSync20 } from "node:fs";
36107
+ import { homedir as homedir24 } from "node:os";
36108
+ import { dirname as dirname11, join as join34, resolve as resolve12 } from "node:path";
35520
36109
  import { createInterface as createInterface2 } from "node:readline/promises";
35521
36110
  import { fileURLToPath as fileURLToPath3 } from "node:url";
35522
36111
 
@@ -36114,13 +36703,13 @@ function writePrivateToken(runtimeRoot2, token, { fileSystem, processId, identif
36114
36703
  }
36115
36704
  async function waitForExit(child, milliseconds) {
36116
36705
  if (child.exitCode !== null || child.signalCode !== null) return;
36117
- await new Promise((resolve12) => {
36706
+ await new Promise((resolve13) => {
36118
36707
  let settled = false;
36119
36708
  const finish = () => {
36120
36709
  if (settled) return;
36121
36710
  settled = true;
36122
36711
  clearTimeout(timer);
36123
- resolve12();
36712
+ resolve13();
36124
36713
  };
36125
36714
  child.once("exit", finish);
36126
36715
  const timer = setTimeout(finish, milliseconds);
@@ -36284,8 +36873,8 @@ function createManagedCompanionTunnel({
36284
36873
  child = spawned;
36285
36874
  const cancellationController = new AbortController();
36286
36875
  let resolveCancellation;
36287
- const cancellation = new Promise((resolve12) => {
36288
- resolveCancellation = resolve12;
36876
+ const cancellation = new Promise((resolve13) => {
36877
+ resolveCancellation = resolve13;
36289
36878
  });
36290
36879
  let cancelled = false;
36291
36880
  attemptHandle = {
@@ -36301,8 +36890,8 @@ function createManagedCompanionTunnel({
36301
36890
  let terminated = false;
36302
36891
  let expectedStop = false;
36303
36892
  let resolveExit;
36304
- const exit = new Promise((resolve12) => {
36305
- resolveExit = resolve12;
36893
+ const exit = new Promise((resolve13) => {
36894
+ resolveExit = resolve13;
36306
36895
  });
36307
36896
  const onTerminated = () => {
36308
36897
  if (terminated) return;
@@ -36336,8 +36925,8 @@ function createManagedCompanionTunnel({
36336
36925
  }
36337
36926
  if (Date.now() >= deadline) break;
36338
36927
  await Promise.race([
36339
- new Promise((resolve12) => {
36340
- const timer = setTimeout(resolve12, verifyIntervalMs);
36928
+ new Promise((resolve13) => {
36929
+ const timer = setTimeout(resolve13, verifyIntervalMs);
36341
36930
  timer.unref?.();
36342
36931
  }),
36343
36932
  exit,
@@ -37337,14 +37926,14 @@ function explainTailscaleFailure(reason) {
37337
37926
  }
37338
37927
  }
37339
37928
  function run(cli, args, timeoutMs) {
37340
- return new Promise((resolve12) => {
37929
+ return new Promise((resolve13) => {
37341
37930
  execFile(
37342
37931
  cli,
37343
37932
  args,
37344
37933
  { timeout: timeoutMs, killSignal: "SIGKILL", maxBuffer: 16 * 1024 * 1024, env: { ...process.env, PATH: searchPath() } },
37345
37934
  (error51, stdout2, stderr) => {
37346
37935
  const code = error51 && "code" in error51 && typeof error51.code === "number" ? error51.code : error51 ? null : 0;
37347
- resolve12({ ok: !error51, stdout: String(stdout2 ?? ""), stderr: String(stderr ?? ""), code });
37936
+ resolve13({ ok: !error51, stdout: String(stdout2 ?? ""), stderr: String(stderr ?? ""), code });
37348
37937
  }
37349
37938
  );
37350
37939
  });
@@ -37761,7 +38350,7 @@ function parseArgs(argv, env = process.env) {
37761
38350
  const options = {
37762
38351
  command: command === "--help" || command === "-h" ? "help" : command,
37763
38352
  port: Number(env.OMB_PORT || 8799),
37764
- dataDir: env.OMB_DATA_DIR || join32(homedir23(), ".openmausbot"),
38353
+ dataDir: env.OMB_DATA_DIR || join34(homedir24(), ".openmausbot"),
37765
38354
  tailscale: false,
37766
38355
  tunnel: false,
37767
38356
  client: false,
@@ -37780,7 +38369,7 @@ function parseArgs(argv, env = process.env) {
37780
38369
  };
37781
38370
  try {
37782
38371
  if (arg === "--port") options.port = Number(value());
37783
- else if (arg === "--data-dir") options.dataDir = resolve11(value());
38372
+ else if (arg === "--data-dir") options.dataDir = resolve12(value());
37784
38373
  else if (arg === "--label") options.label = value();
37785
38374
  else if (arg === "--public-url") options.publicUrl = value().replace(/\/+$/, "");
37786
38375
  else if (arg === "--tailscale") options.tailscale = true;
@@ -37891,7 +38480,7 @@ function defaultIo() {
37891
38480
  }
37892
38481
  function serverVersion(here = HERE2) {
37893
38482
  try {
37894
- const parsed = JSON.parse(readFileSync20(resolve11(here, "..", "package.json"), "utf8"));
38483
+ const parsed = JSON.parse(readFileSync20(resolve12(here, "..", "package.json"), "utf8"));
37895
38484
  const version2 = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "version") : void 0;
37896
38485
  return typeof version2 === "string" && version2 ? version2 : "0.0.0";
37897
38486
  } catch {
@@ -37916,7 +38505,7 @@ async function isWorkspaceRunning(options) {
37916
38505
  try {
37917
38506
  const { status, body } = await api(options.port, "/api/health");
37918
38507
  if (status !== 200 || body?.app !== "openmausbot") return false;
37919
- const expected = readFileSync20(join32(options.dataDir, "environment-id"), "utf8").trim();
38508
+ const expected = readFileSync20(join34(options.dataDir, "environment-id"), "utf8").trim();
37920
38509
  const descriptor = await api(options.port, "/.well-known/openmausbot/environment");
37921
38510
  return /^[0-9a-f-]{36}$/i.test(expected) && descriptor.status === 200 && descriptor.body?.environmentId === expected;
37922
38511
  } catch {
@@ -38116,9 +38705,9 @@ async function runStatus(options, io = defaultIo()) {
38116
38705
  return code;
38117
38706
  }
38118
38707
  async function runAccess(options, io = defaultIo()) {
38119
- const file2 = join32(options.dataDir, "config.json");
38708
+ const file2 = join34(options.dataDir, "config.json");
38120
38709
  let raw = {};
38121
- if (existsSync16(file2)) {
38710
+ if (existsSync17(file2)) {
38122
38711
  try {
38123
38712
  const parsed = JSON.parse(readFileSync20(file2, "utf8"));
38124
38713
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("not an object");
@@ -38134,7 +38723,7 @@ async function runAccess(options, io = defaultIo()) {
38134
38723
  const members = list(Reflect.get(current, "members"));
38135
38724
  const overridden = process.env.OMB_SIGNIN_EMAILS !== void 0 || process.env.OMB_SIGNIN_MEMBER_EMAILS !== void 0;
38136
38725
  const write = (next) => {
38137
- mkdirSync14(options.dataDir, { recursive: true, mode: 448 });
38726
+ mkdirSync15(options.dataDir, { recursive: true, mode: 448 });
38138
38727
  writeFileAtomic(file2, `${JSON.stringify({ ...raw, signIn: next }, null, 2)}
38139
38728
  `, { mode: 384 });
38140
38729
  };
@@ -38268,16 +38857,16 @@ async function runBrowser(options, io = defaultIo()) {
38268
38857
  return 0;
38269
38858
  }
38270
38859
  function serverEntry(here = HERE2) {
38271
- const bundled = join32(here, "index.js");
38272
- const root = resolve11(here, "..");
38273
- if (existsSync16(bundled)) {
38274
- const staticDir2 = [join32(root, "dist"), join32(here, "..", "ui")].find((d) => existsSync16(join32(d, "index.html"))) ?? null;
38275
- const skillsDir = existsSync16(join32(root, "skills")) ? join32(root, "skills") : null;
38860
+ const bundled = join34(here, "index.js");
38861
+ const root = resolve12(here, "..");
38862
+ if (existsSync17(bundled)) {
38863
+ const staticDir2 = [join34(root, "dist"), join34(here, "..", "ui")].find((d) => existsSync17(join34(d, "index.html"))) ?? null;
38864
+ const skillsDir = existsSync17(join34(root, "skills")) ? join34(root, "skills") : null;
38276
38865
  return { command: process.execPath, args: [bundled], staticDir: staticDir2, skillsDir };
38277
38866
  }
38278
- const source = join32(here, "index.ts");
38279
- const staticDir = existsSync16(join32(root, "dist", "index.html")) ? join32(root, "dist") : null;
38280
- return { command: process.execPath, args: ["--experimental-strip-types", source], staticDir, skillsDir: existsSync16(join32(root, "skills")) ? join32(root, "skills") : null };
38867
+ const source = join34(here, "index.ts");
38868
+ const staticDir = existsSync17(join34(root, "dist", "index.html")) ? join34(root, "dist") : null;
38869
+ return { command: process.execPath, args: ["--experimental-strip-types", source], staticDir, skillsDir: existsSync17(join34(root, "skills")) ? join34(root, "skills") : null };
38281
38870
  }
38282
38871
  async function planTunnel(options, log) {
38283
38872
  let access2 = null;
@@ -38377,9 +38966,9 @@ async function runServe(options, log = console.log) {
38377
38966
  let child;
38378
38967
  try {
38379
38968
  if (options.guided) {
38380
- const logsDir = join32(options.dataDir, "logs");
38381
- mkdirSync14(logsDir, { recursive: true, mode: 448 });
38382
- logPath = join32(logsDir, `server-${Date.now()}-${process.pid}.log`);
38969
+ const logsDir = join34(options.dataDir, "logs");
38970
+ mkdirSync15(logsDir, { recursive: true, mode: 448 });
38971
+ logPath = join34(logsDir, `server-${Date.now()}-${process.pid}.log`);
38383
38972
  logFd = openSync3(logPath, "wx", 384);
38384
38973
  log("\nStarting your workspace\u2026");
38385
38974
  }
@@ -38571,7 +39160,7 @@ async function runOnboardingCommand(options, io = defaultIo(), startServer = run
38571
39160
  }
38572
39161
  if (options.command === "setup") {
38573
39162
  io.log("\nAll set. Start with: openmausbot (or npx openmausbot without a global install).");
38574
- if (options.dataDir !== join32(homedir23(), ".openmausbot") || options.port !== 8799) {
39163
+ if (options.dataDir !== join34(homedir24(), ".openmausbot") || options.port !== 8799) {
38575
39164
  io.log(`Use the same --data-dir (${options.dataDir}) and --port (${options.port}) options when starting.`);
38576
39165
  }
38577
39166
  return 0;