openmausbot 0.1.68 → 0.1.69

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.
@@ -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
@@ -18679,12 +18723,12 @@ function describeSpawnFailure(err, cli) {
18679
18723
  function killCliTree(child, timeoutMs = 5e3) {
18680
18724
  const pid = child.pid;
18681
18725
  if (!pid || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);
18682
- return new Promise((resolve12) => {
18726
+ return new Promise((resolve13) => {
18683
18727
  let timer;
18684
18728
  const done = (stopped) => {
18685
18729
  clearTimeout(timer);
18686
18730
  child.off("close", closed);
18687
- resolve12(stopped);
18731
+ resolve13(stopped);
18688
18732
  };
18689
18733
  const closed = () => done(true);
18690
18734
  child.once("close", closed);
@@ -18909,8 +18953,10 @@ var init_registry = __esm({
18909
18953
  access: driver?.metadata.access ?? "subscription",
18910
18954
  install: driver?.install,
18911
18955
  authentication: inst.startAuthentication ? {
18912
- method: inst.getAuthentication && inst.completeAuthentication ? "paste-code" : inst.getAuthentication ? "device-code" : "browser"
18956
+ method: inst.getAuthentication && inst.completeAuthentication ? "paste-code" : inst.getAuthentication ? "device-code" : "browser",
18913
18957
  // a link and a callback URL (managed engines)
18958
+ // the browser may remove the stored sign-in to switch accounts
18959
+ signOut: inst.signOut !== void 0
18914
18960
  } : void 0,
18915
18961
  cli: this.cliByInstance.get(inst.instanceId),
18916
18962
  cliDefault: cliDefaultOf(driver),
@@ -19625,7 +19671,7 @@ function createAcpDriver(support11) {
19625
19671
  }
19626
19672
  appendNative(threadId, { dir: "out", source: SOURCE, msg: nativeLogMessage(obj) });
19627
19673
  };
19628
- const request = (method, params, timeoutMs) => new Promise((resolve12, reject) => {
19674
+ const request = (method, params, timeoutMs) => new Promise((resolve13, reject) => {
19629
19675
  const id = nextId++;
19630
19676
  let timer = null;
19631
19677
  if (timeoutMs) {
@@ -19635,7 +19681,7 @@ function createAcpDriver(support11) {
19635
19681
  }, timeoutMs);
19636
19682
  timer.unref?.();
19637
19683
  }
19638
- rpcPending.set(id, { resolve: resolve12, reject, timer });
19684
+ rpcPending.set(id, { resolve: resolve13, reject, timer });
19639
19685
  send({ jsonrpc: "2.0", id, method, params });
19640
19686
  });
19641
19687
  const stop = () => killCliTree(child);
@@ -20071,12 +20117,12 @@ ${turn.text}` : turn.text;
20071
20117
  const snapshot = async () => {
20072
20118
  const env = childEnv();
20073
20119
  if (support11.snapshot) return support11.snapshot(env, config2, instanceId);
20074
- const version2 = await new Promise((resolve12) => {
20120
+ const version2 = await new Promise((resolve13) => {
20075
20121
  execCli(
20076
20122
  config2.cli,
20077
20123
  ["--version"],
20078
20124
  { timeout: 8e3, env },
20079
- (err, stdout2) => resolve12(err ? null : stdout2.trim())
20125
+ (err, stdout2) => resolve13(err ? null : stdout2.trim())
20080
20126
  );
20081
20127
  });
20082
20128
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
@@ -20466,14 +20512,14 @@ var init_antigravity_acp = __esm({
20466
20512
  this.child.stderr.setEncoding("utf8");
20467
20513
  this.child.stderr.on("data", (chunk) => this.consumeDiagnostics(chunk));
20468
20514
  this.child.once("error", (error51) => this.failAll(error51));
20469
- this.exited = new Promise((resolve12) => {
20515
+ this.exited = new Promise((resolve13) => {
20470
20516
  this.child.once("close", (code, signal) => {
20471
20517
  this.noteStartupDiagnostic(this.diagnosticBuffer);
20472
20518
  this.diagnosticBuffer = "";
20473
20519
  if (!this.closed) this.failAll(new Error(
20474
20520
  `Antigravity ACP exited ${code ?? signal ?? "unexpectedly"}.${this.nativeStartupHint ? ` ${this.nativeStartupHint}` : ""}`
20475
20521
  ));
20476
- resolve12();
20522
+ resolve13();
20477
20523
  });
20478
20524
  });
20479
20525
  }
@@ -20579,8 +20625,8 @@ var init_antigravity_acp = __esm({
20579
20625
  async closeAndWait(timeoutMs = 5e3) {
20580
20626
  this.close();
20581
20627
  let timer;
20582
- const timedOut = new Promise((resolve12) => {
20583
- timer = setTimeout(() => resolve12(false), timeoutMs);
20628
+ const timedOut = new Promise((resolve13) => {
20629
+ timer = setTimeout(() => resolve13(false), timeoutMs);
20584
20630
  timer.unref?.();
20585
20631
  });
20586
20632
  try {
@@ -21089,7 +21135,7 @@ var init_antigravity_runtime = __esm({
21089
21135
  FREE_SPACE_MARGIN = 256 * 1024 * 1024;
21090
21136
  DOWNLOAD_TIMEOUT_MS2 = 45 * 6e4;
21091
21137
  STAGING_PREFIX = ".install-";
21092
- wait = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
21138
+ wait = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
21093
21139
  INSTALL_RECORD = ".install-complete.json";
21094
21140
  AntigravitySetupError = class extends Error {
21095
21141
  status = 409;
@@ -21803,13 +21849,13 @@ function computeBackoff(attempt, random = Math.random) {
21803
21849
  function interruptibleDelay(ms, signal) {
21804
21850
  let timer = null;
21805
21851
  let onCancel = null;
21806
- const promise2 = new Promise((resolve12) => {
21807
- timer = setTimeout(() => resolve12("elapsed"), Math.max(1, ms));
21852
+ const promise2 = new Promise((resolve13) => {
21853
+ timer = setTimeout(() => resolve13("elapsed"), Math.max(1, ms));
21808
21854
  timer.unref?.();
21809
- if (signal?.aborted) return resolve12("cancelled");
21855
+ if (signal?.aborted) return resolve13("cancelled");
21810
21856
  onCancel = () => {
21811
21857
  clearTimeout(timer);
21812
- resolve12("cancelled");
21858
+ resolve13("cancelled");
21813
21859
  };
21814
21860
  signal?.addEventListener("abort", onCancel, { once: true });
21815
21861
  });
@@ -21863,24 +21909,24 @@ import { createServer as createNetServer } from "node:net";
21863
21909
  import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
21864
21910
  import { join as join16, dirname as dirname8, isAbsolute as isAbsolute4, normalize } from "node:path";
21865
21911
  function claudeAuthStatus(cli, env, run3 = execCli) {
21866
- return new Promise((resolve12) => {
21912
+ return new Promise((resolve13) => {
21867
21913
  run3(cli, ["auth", "status", "--json"], { timeout: 8e3, maxBuffer: 65536, env }, (_error, stdout2) => {
21868
21914
  try {
21869
21915
  const status = JSON.parse(stdout2);
21870
21916
  if (!status || typeof status !== "object" || !("loggedIn" in status) || status.loggedIn !== true) {
21871
- return resolve12({ authenticated: false });
21917
+ return resolve13({ authenticated: false });
21872
21918
  }
21873
21919
  const identity = status;
21874
21920
  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
21921
  const candidateEmail = boundedText(identity.email, 254);
21876
21922
  const email3 = candidateEmail && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(candidateEmail) ? candidateEmail : void 0;
21877
21923
  const organization = boundedText(identity.orgName, 160);
21878
- resolve12({
21924
+ resolve13({
21879
21925
  authenticated: true,
21880
21926
  ...email3 || organization ? { account: { ...email3 ? { email: email3 } : {}, ...organization ? { organization } : {} } } : {}
21881
21927
  });
21882
21928
  } catch {
21883
- resolve12({ authenticated: false });
21929
+ resolve13({ authenticated: false });
21884
21930
  }
21885
21931
  });
21886
21932
  });
@@ -22071,9 +22117,9 @@ async function createPermissionBroker(opts) {
22071
22117
  unlinkSync3(candidate);
22072
22118
  } catch {
22073
22119
  }
22074
- let outcome = await new Promise((resolve12) => {
22075
- attempt.once("listening", () => resolve12("listening"));
22076
- attempt.once("error", (error51) => resolve12(error51));
22120
+ let outcome = await new Promise((resolve13) => {
22121
+ attempt.once("listening", () => resolve13("listening"));
22122
+ attempt.once("error", (error51) => resolve13(error51));
22077
22123
  attempt.listen(candidate);
22078
22124
  });
22079
22125
  if (outcome === "listening" && process.platform !== "win32") {
@@ -22330,19 +22376,19 @@ var init_claude = __esm({
22330
22376
  };
22331
22377
  const writeUser = (s, threadId, promptMsg) => {
22332
22378
  if (!s.child.stdin.writable || s.child.stdin.destroyed) return Promise.resolve(false);
22333
- return new Promise((resolve12) => {
22379
+ return new Promise((resolve13) => {
22334
22380
  try {
22335
22381
  s.child.stdin.write(JSON.stringify(promptMsg) + "\n", (error51) => {
22336
- if (error51) return resolve12(false);
22382
+ if (error51) return resolve13(false);
22337
22383
  appendNative(threadId, {
22338
22384
  dir: "out",
22339
22385
  source: "claude.sdk.message",
22340
22386
  msg: diagnosticClaudeUserMessage(promptMsg)
22341
22387
  });
22342
- resolve12(true);
22388
+ resolve13(true);
22343
22389
  });
22344
22390
  } catch {
22345
- resolve12(false);
22391
+ resolve13(false);
22346
22392
  }
22347
22393
  });
22348
22394
  };
@@ -22832,19 +22878,19 @@ var init_claude = __esm({
22832
22878
  } });
22833
22879
  const snapshot = async () => {
22834
22880
  const env = environment();
22835
- const version2 = await new Promise((resolve12) => {
22881
+ const version2 = await new Promise((resolve13) => {
22836
22882
  execCli(
22837
22883
  config2.cli,
22838
22884
  ["--version"],
22839
22885
  { timeout: 8e3, env },
22840
- (err, stdout2) => resolve12(err ? null : stdout2.trim())
22886
+ (err, stdout2) => resolve13(err ? null : stdout2.trim())
22841
22887
  );
22842
22888
  });
22843
22889
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
22844
22890
  const auth = await claudeAuthStatus(config2.cli, env);
22845
22891
  return { state: "available", version: version2, ...auth, billing: "subscription" };
22846
22892
  };
22847
- const generateReview = (prompt, signal) => new Promise((resolve12, reject) => {
22893
+ const generateReview = (prompt, signal) => new Promise((resolve13, reject) => {
22848
22894
  const child = spawnCli(
22849
22895
  config2.cli,
22850
22896
  ["-p", "--model", "claude-haiku-4-5", "--output-format", "text"],
@@ -22862,7 +22908,7 @@ var init_claude = __esm({
22862
22908
  clearTimeout(timer);
22863
22909
  signal?.removeEventListener("abort", onAbort);
22864
22910
  if (error51) reject(error51);
22865
- else resolve12(stdout2.trim());
22911
+ else resolve13(stdout2.trim());
22866
22912
  };
22867
22913
  const onAbort = () => {
22868
22914
  killCliTree(child);
@@ -22977,7 +23023,7 @@ function decodeCodexSelection(id) {
22977
23023
  return { model: id, modelProvider: MODEL_ID2.test(id) ? OFFICIAL_CODEX_PROVIDER : null };
22978
23024
  }
22979
23025
  function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
22980
- return new Promise((resolve12) => {
23026
+ return new Promise((resolve13) => {
22981
23027
  const child = spawnCli(cli, ["app-server"], {
22982
23028
  cwd: homedir10(),
22983
23029
  env,
@@ -22994,7 +23040,7 @@ function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
22994
23040
  settled = true;
22995
23041
  clearTimeout(timer);
22996
23042
  killCliTree(child);
22997
- resolve12(catalog);
23043
+ resolve13(catalog);
22998
23044
  };
22999
23045
  const request = (method, params, kind) => {
23000
23046
  const id = nextId++;
@@ -23405,6 +23451,7 @@ var init_codex_device_auth = __esm({
23405
23451
  authenticatingHomes2 = /* @__PURE__ */ new Set();
23406
23452
  CodexDeviceAuthController = class {
23407
23453
  flow = null;
23454
+ command = null;
23408
23455
  disposed = false;
23409
23456
  options;
23410
23457
  constructor(options) {
@@ -23480,12 +23527,92 @@ var init_codex_device_auth = __esm({
23480
23527
  if (this.flow?.status.phase === "waiting") this.finish(this.flow, "cancelled", "ChatGPT sign-in cancelled.");
23481
23528
  await this.flow?.stopping;
23482
23529
  if (this.flow?.terminationFailed) throw new Error(this.flow.status.message);
23530
+ if (this.command && !await this.stopChild(this.command)) {
23531
+ throw new Error("Codex could not be stopped on this server. Ask the server administrator to stop the account command before trying again.");
23532
+ }
23483
23533
  }
23484
23534
  async dispose() {
23485
23535
  this.disposed = true;
23486
23536
  await this.cancel();
23487
23537
  this.flow = null;
23488
23538
  }
23539
+ /** Remove the ChatGPT sign-in Codex stores for this server account so a
23540
+ * different account can connect. A sign-in in progress is never pulled
23541
+ * away underneath the browser completing it. */
23542
+ async signOut() {
23543
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
23544
+ if (this.flow?.status.phase === "waiting") throw new Error("Finish or cancel the ChatGPT sign-in in progress before signing out.");
23545
+ await this.flow?.stopping;
23546
+ if (this.disposed) throw new Error("This provider was removed. Refresh Settings before signing out.");
23547
+ const env = this.options.environment();
23548
+ const home = env.HOME || env.USERPROFILE || homedir11();
23549
+ if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
23550
+ throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing out.");
23551
+ }
23552
+ const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join19(home, ".codex")));
23553
+ if (authenticatingHomes2.has(homeKey)) {
23554
+ throw new Error("A ChatGPT sign-in is running for this server account. Finish or cancel it before signing out.");
23555
+ }
23556
+ authenticatingHomes2.add(homeKey);
23557
+ try {
23558
+ const before = await this.exec(["login", "status"], env, home);
23559
+ if (before.code === 1 && /^not logged in\b/im.test(before.output)) return;
23560
+ if (before.code !== 0 || !/^logged in.*chatgpt\b/im.test(before.output)) {
23561
+ 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.");
23562
+ }
23563
+ const logout = await this.exec(["logout"], env, home);
23564
+ 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.");
23565
+ const status = await this.exec(["login", "status"], env, home);
23566
+ if (status.code !== 1 || !/^not logged in\b/im.test(status.output)) {
23567
+ throw new Error("Codex still reports a sign-in on this server. Update Codex and check its login status before trying again.");
23568
+ }
23569
+ } finally {
23570
+ const child = this.command;
23571
+ if (child && child.exitCode === null && child.signalCode === null) {
23572
+ child.once("close", () => authenticatingHomes2.delete(homeKey));
23573
+ } else authenticatingHomes2.delete(homeKey);
23574
+ }
23575
+ }
23576
+ /** One bounded, non-interactive Codex command. Its output stays here;
23577
+ * callers see an exit code and a status-line match, never the text. */
23578
+ exec(args, env, cwd) {
23579
+ return new Promise((resolveExec, rejectExec) => {
23580
+ if (this.disposed) {
23581
+ rejectExec(new Error("This provider was removed. Refresh Settings before signing out."));
23582
+ return;
23583
+ }
23584
+ let child;
23585
+ try {
23586
+ child = spawnCli(this.options.cli, args, { env: { ...env, NO_COLOR: "1" }, cwd, stdio: ["pipe", "pipe", "pipe"] });
23587
+ } catch {
23588
+ rejectExec(new Error("Codex could not start on this server. Install or update the configured Codex CLI, then try again."));
23589
+ return;
23590
+ }
23591
+ this.command = child;
23592
+ child.stdin.end();
23593
+ let output = "";
23594
+ const receive = (chunk) => {
23595
+ if (output.length < MAX_OUTPUT2) output += chunk.toString("utf8").slice(0, MAX_OUTPUT2 - output.length);
23596
+ };
23597
+ child.stdout.on("data", receive);
23598
+ child.stderr.on("data", receive);
23599
+ const timer = setTimeout(() => {
23600
+ void this.stopChild(child).catch(() => false).then((stopped) => {
23601
+ 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."));
23602
+ });
23603
+ }, this.options.startupTimeoutMs ?? 3e4);
23604
+ timer.unref();
23605
+ child.once("error", (error51) => {
23606
+ clearTimeout(timer);
23607
+ 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."));
23608
+ });
23609
+ child.once("close", (code) => {
23610
+ clearTimeout(timer);
23611
+ if (this.command === child) this.command = null;
23612
+ resolveExec({ code, output: stripVTControlCharacters4(output) });
23613
+ });
23614
+ });
23615
+ }
23489
23616
  run(flow, args, env, cwd, done, parsePrompt = false) {
23490
23617
  if (flow.status.phase !== "waiting") return;
23491
23618
  let child;
@@ -23540,7 +23667,7 @@ var init_codex_device_auth = __esm({
23540
23667
  if (phase === "succeeded") flow.resolve({ ...flow.status, phase });
23541
23668
  else flow.reject(new Error(message2 ?? "ChatGPT sign-in did not finish."));
23542
23669
  }
23543
- flow.stopping = this.stopChild(flow).catch(() => false).then((stopped) => {
23670
+ flow.stopping = this.stopChild(flow.child).catch(() => false).then((stopped) => {
23544
23671
  const release = () => authenticatingHomes2.delete(flow.homeKey);
23545
23672
  if (stopped) {
23546
23673
  release();
@@ -23555,8 +23682,7 @@ var init_codex_device_auth = __esm({
23555
23682
  if (phase === "succeeded") void this.options.onAuthenticated?.().catch(() => {
23556
23683
  });
23557
23684
  }
23558
- async stopChild(flow) {
23559
- const child = flow.child;
23685
+ async stopChild(child) {
23560
23686
  if (!child || await killCliTree(child, this.options.terminateTimeoutMs ?? 1500)) return true;
23561
23687
  if (process.platform !== "win32" && child.pid) {
23562
23688
  try {
@@ -23580,9 +23706,122 @@ var init_codex_device_auth = __esm({
23580
23706
  }
23581
23707
  });
23582
23708
 
23709
+ // server/drivers/codex-identity.ts
23710
+ import { homedir as homedir12 } from "node:os";
23711
+ import { isAbsolute as isAbsolute6, join as join20, resolve as resolve9 } from "node:path";
23712
+ function codexHome2(env) {
23713
+ if (env.CODEX_HOME) return isAbsolute6(env.CODEX_HOME) ? resolve9(env.CODEX_HOME) : null;
23714
+ const home = env.HOME || env.USERPROFILE || homedir12();
23715
+ return isAbsolute6(home) ? join20(home, ".codex") : null;
23716
+ }
23717
+ async function codexAccountEmail(cli, env, timeoutMs = 3e3) {
23718
+ const cwd = env.HOME || env.USERPROFILE || homedir12();
23719
+ if (!isAbsolute6(cwd) || !codexHome2(env)) return null;
23720
+ return new Promise((resolveEmail) => {
23721
+ let child;
23722
+ try {
23723
+ child = spawnCli(cli, ["app-server"], { cwd, env, stdio: ["pipe", "pipe", "pipe"] });
23724
+ } catch {
23725
+ resolveEmail(null);
23726
+ return;
23727
+ }
23728
+ let finishing = false;
23729
+ let buffer = "";
23730
+ let outputBytes = 0;
23731
+ let initialized = false;
23732
+ const finish = async (email3) => {
23733
+ if (finishing) return;
23734
+ finishing = true;
23735
+ clearTimeout(timer);
23736
+ let stopped = await killCliTree(child, 1e3);
23737
+ if (!stopped && child.pid) {
23738
+ try {
23739
+ if (process.platform === "win32") child.kill("SIGKILL");
23740
+ else process.kill(-child.pid, "SIGKILL");
23741
+ } catch {
23742
+ try {
23743
+ child.kill("SIGKILL");
23744
+ } catch {
23745
+ }
23746
+ }
23747
+ stopped = await killCliTree(child, 1e3);
23748
+ }
23749
+ resolveEmail(stopped ? email3 : null);
23750
+ };
23751
+ const timer = setTimeout(() => {
23752
+ void finish(null);
23753
+ }, timeoutMs);
23754
+ timer.unref();
23755
+ const send = (message2) => {
23756
+ try {
23757
+ child.stdin.write(`${JSON.stringify(message2)}
23758
+ `);
23759
+ } catch {
23760
+ void finish(null);
23761
+ }
23762
+ };
23763
+ child.stdin.on("error", () => {
23764
+ void finish(null);
23765
+ });
23766
+ child.stderr.resume();
23767
+ child.on("error", () => {
23768
+ void finish(null);
23769
+ });
23770
+ child.on("close", () => {
23771
+ void finish(null);
23772
+ });
23773
+ child.stdout.setEncoding("utf8");
23774
+ child.stdout.on("data", (chunk) => {
23775
+ if (finishing) return;
23776
+ outputBytes += Buffer.byteLength(chunk);
23777
+ if (outputBytes > MAX_OUTPUT3) {
23778
+ void finish(null);
23779
+ return;
23780
+ }
23781
+ buffer += chunk;
23782
+ let newline;
23783
+ while (!finishing && (newline = buffer.indexOf("\n")) !== -1) {
23784
+ const line = buffer.slice(0, newline);
23785
+ buffer = buffer.slice(newline + 1);
23786
+ if (!line.trim()) continue;
23787
+ let message2;
23788
+ try {
23789
+ message2 = JSON.parse(line);
23790
+ } catch {
23791
+ void finish(null);
23792
+ return;
23793
+ }
23794
+ if (!initialized && message2?.id === 1) {
23795
+ if (message2.error || !message2.result) {
23796
+ void finish(null);
23797
+ return;
23798
+ }
23799
+ initialized = true;
23800
+ send({ method: "initialized", params: {} });
23801
+ send({ id: 2, method: "account/read", params: { refreshToken: false } });
23802
+ } else if (initialized && message2?.id === 2) {
23803
+ const account = message2.error ? null : message2.result?.account;
23804
+ const email3 = account?.type === "chatgpt" ? account.email : null;
23805
+ void finish(typeof email3 === "string" && email3.length <= 254 && EMAIL.test(email3) && !/[\p{Cc}\p{Cf}]/u.test(email3) ? email3 : null);
23806
+ }
23807
+ }
23808
+ });
23809
+ send({ id: 1, method: "initialize", params: { clientInfo: { name: "openmausbot", version: "1" } } });
23810
+ });
23811
+ }
23812
+ var MAX_OUTPUT3, EMAIL;
23813
+ var init_codex_identity = __esm({
23814
+ "server/drivers/codex-identity.ts"() {
23815
+ "use strict";
23816
+ init_procs();
23817
+ MAX_OUTPUT3 = 16384;
23818
+ EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
23819
+ }
23820
+ });
23821
+
23583
23822
  // server/drivers/codex.ts
23584
23823
  import { existsSync as existsSync7 } from "node:fs";
23585
- import { homedir as homedir12 } from "node:os";
23824
+ import { homedir as homedir13 } from "node:os";
23586
23825
  function codexPredatesAstra(version2) {
23587
23826
  const value = version2.trim();
23588
23827
  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);
@@ -23852,6 +24091,7 @@ var init_codex = __esm({
23852
24091
  init_native();
23853
24092
  init_codex_instructions();
23854
24093
  init_codex_device_auth();
24094
+ init_codex_identity();
23855
24095
  init_codex_catalog();
23856
24096
  DRIVER_KIND3 = "codex";
23857
24097
  ASTRA_MODEL_ID = "gpt-6-astra";
@@ -23985,7 +24225,7 @@ var init_codex = __esm({
23985
24225
  );
23986
24226
  }
23987
24227
  const child = spawnCli(config2.cli, appServerArgs, {
23988
- cwd: turn.cwd ?? homedir12(),
24228
+ cwd: turn.cwd ?? homedir13(),
23989
24229
  env,
23990
24230
  stdio: ["pipe", "pipe", "pipe"]
23991
24231
  });
@@ -24013,7 +24253,7 @@ var init_codex = __esm({
24013
24253
  msg: codexNativeLogMessage(obj)
24014
24254
  });
24015
24255
  };
24016
- const request = (method, params, timeoutMs = 6e4) => new Promise((resolve12, reject) => {
24256
+ const request = (method, params, timeoutMs = 6e4) => new Promise((resolve13, reject) => {
24017
24257
  const id = nextId++;
24018
24258
  if (method === "config/read") sensitiveResponseIds.add(id);
24019
24259
  const timer = setTimeout(() => {
@@ -24023,7 +24263,7 @@ var init_codex = __esm({
24023
24263
  rpcPending.set(id, {
24024
24264
  resolve: (v) => {
24025
24265
  clearTimeout(timer);
24026
- resolve12(v);
24266
+ resolve13(v);
24027
24267
  },
24028
24268
  reject: (e) => {
24029
24269
  clearTimeout(timer);
@@ -24291,7 +24531,7 @@ var init_codex = __esm({
24291
24531
  let effectiveConfig;
24292
24532
  try {
24293
24533
  const configured = await request("config/read", {
24294
- cwd: turn.cwd ?? homedir12(),
24534
+ cwd: turn.cwd ?? homedir13(),
24295
24535
  includeLayers: false
24296
24536
  });
24297
24537
  effectiveConfig = configured?.config;
@@ -24335,7 +24575,7 @@ var init_codex = __esm({
24335
24575
  const selection = decodeCodexSelection(turn.model);
24336
24576
  const startThread = () => request("thread/start", {
24337
24577
  developerInstructions,
24338
- cwd: turn.cwd ?? homedir12(),
24578
+ cwd: turn.cwd ?? homedir13(),
24339
24579
  model: selection.model,
24340
24580
  ...selection.modelProvider ? { modelProvider: selection.modelProvider } : {},
24341
24581
  ...approvalParams.thread,
@@ -24402,8 +24642,8 @@ var init_codex = __esm({
24402
24642
  void settle(false, "shutdown_timeout");
24403
24643
  return;
24404
24644
  }
24405
- await new Promise((resolve12) => {
24406
- const timer = setTimeout(resolve12, Math.max(1, Math.round(delayMs * retryScale)));
24645
+ await new Promise((resolve13) => {
24646
+ const timer = setTimeout(resolve13, Math.max(1, Math.round(delayMs * retryScale)));
24407
24647
  timer.unref?.();
24408
24648
  });
24409
24649
  if (!stopRequested) {
@@ -24431,28 +24671,30 @@ var init_codex = __esm({
24431
24671
  };
24432
24672
  const snapshot = async () => {
24433
24673
  const env = childEnv();
24434
- const version2 = await new Promise((resolve12) => {
24674
+ const version2 = await new Promise((resolve13) => {
24435
24675
  execCli(
24436
24676
  config2.cli,
24437
24677
  ["--version"],
24438
24678
  { timeout: 8e3, env },
24439
- (err, stdout2) => resolve12(err ? null : stdout2.trim())
24679
+ (err, stdout2) => resolve13(err ? null : stdout2.trim())
24440
24680
  );
24441
24681
  });
24442
24682
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
24443
- const authenticated = await new Promise((resolve12) => {
24683
+ const authenticated = await new Promise((resolve13) => {
24444
24684
  execCli(
24445
24685
  config2.cli,
24446
24686
  ["login", "status"],
24447
24687
  { timeout: 8e3, env },
24448
- (err, stdout2, stderr) => resolve12(!err && /^logged in\b/im.test(`${stdout2}
24688
+ (err, stdout2, stderr) => resolve13(!err && /^logged in\b/im.test(`${stdout2}
24449
24689
  ${stderr ?? ""}`))
24450
24690
  );
24451
24691
  });
24692
+ const email3 = authenticated ? await codexAccountEmail(config2.cli, env) : null;
24452
24693
  return {
24453
24694
  state: "available",
24454
24695
  version: version2,
24455
24696
  authenticated,
24697
+ ...email3 ? { account: { email: email3 } } : {},
24456
24698
  update: codexAstraUpdate(version2, models, config2.cli),
24457
24699
  billing: "subscription"
24458
24700
  };
@@ -24469,6 +24711,7 @@ ${stderr ?? ""}`))
24469
24711
  startAuthentication: () => authentication.start(),
24470
24712
  getAuthentication: (flowId) => authentication.get(flowId),
24471
24713
  cancelAuthentication: () => authentication.cancel(),
24714
+ signOut: () => authentication.signOut(),
24472
24715
  snapshot,
24473
24716
  adapter: {
24474
24717
  provider: DRIVER_KIND3,
@@ -24793,11 +25036,11 @@ var init_grok = __esm({
24793
25036
 
24794
25037
  // server/drivers/acp/grok.ts
24795
25038
  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";
25039
+ import { homedir as homedir14 } from "node:os";
25040
+ import { join as join21 } from "node:path";
24798
25041
  function grokHome(env) {
24799
25042
  if (env.GROK_HOME) return env.GROK_HOME;
24800
- return join20(env.HOME || env.USERPROFILE || homedir13(), ".grok");
25043
+ return join21(env.HOME || env.USERPROFILE || homedir14(), ".grok");
24801
25044
  }
24802
25045
  function unquote2(raw) {
24803
25046
  const value = raw.trim();
@@ -24807,7 +25050,7 @@ function unquote2(raw) {
24807
25050
  return value;
24808
25051
  }
24809
25052
  function readGrokModelCatalog(env = process.env) {
24810
- const path3 = join20(grokHome(env), "config.toml");
25053
+ const path3 = join21(grokHome(env), "config.toml");
24811
25054
  let text2 = "";
24812
25055
  try {
24813
25056
  text2 = readFileSync9(path3, "utf8");
@@ -24880,7 +25123,7 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
24880
25123
  if (!inject) return modelId;
24881
25124
  const host = localHost(inject.host);
24882
25125
  if (!host) return modelId;
24883
- const path3 = join20(grokHome(env), "config.toml");
25126
+ const path3 = join21(grokHome(env), "config.toml");
24884
25127
  let text2 = "";
24885
25128
  try {
24886
25129
  text2 = readFileSync9(path3, "utf8");
@@ -25015,7 +25258,7 @@ var init_grok2 = __esm({
25015
25258
  // an unauthenticated CLI is a user action, not something to paper over.
25016
25259
  pickAuthMethod: (methods) => methods.some((m) => m.id === "cached_token") ? "cached_token" : null,
25017
25260
  authFailure: "fail",
25018
- isAuthenticated: () => existsSync8(join20(homedir13(), ".grok", "auth.json")),
25261
+ isAuthenticated: () => existsSync8(join21(homedir14(), ".grok", "auth.json")),
25019
25262
  // `--append-system-prompt`/`--rules` are accepted by the CLI but do NOT
25020
25263
  // reach the agent-stdio system prompt (verified against 1.0.0), so the
25021
25264
  // persona is prepended codex-style.
@@ -25029,11 +25272,11 @@ ${turn.text}` : turn.text
25029
25272
 
25030
25273
  // server/drivers/acp/gemini.ts
25031
25274
  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";
25275
+ import { homedir as homedir15 } from "node:os";
25276
+ import { join as join22 } from "node:path";
25034
25277
  function liveOauthCredential() {
25035
25278
  try {
25036
- const creds = JSON.parse(readFileSync10(join21(homedir14(), ".gemini", "oauth_creds.json"), "utf8"));
25279
+ const creds = JSON.parse(readFileSync10(join22(homedir15(), ".gemini", "oauth_creds.json"), "utf8"));
25037
25280
  if (typeof creds.access_token !== "string" || creds.access_token.trim().length === 0) return false;
25038
25281
  const hasRefresh = typeof creds.refresh_token === "string" && creds.refresh_token.trim().length > 0;
25039
25282
  if (creds.expiry_date !== void 0) {
@@ -25046,7 +25289,7 @@ function liveOauthCredential() {
25046
25289
  }
25047
25290
  }
25048
25291
  function geminiIsAuthenticated(env) {
25049
- return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync9(join21(homedir14(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
25292
+ return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync9(join22(homedir15(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
25050
25293
  }
25051
25294
  var AUTH_PREFERENCE, nonBlank, support3, GeminiAgentDriver;
25052
25295
  var init_gemini = __esm({
@@ -25089,16 +25332,16 @@ ${turn.text}` : turn.text
25089
25332
 
25090
25333
  // server/drivers/acp/kimi.ts
25091
25334
  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";
25335
+ import { homedir as homedir16 } from "node:os";
25336
+ import { join as join23 } from "node:path";
25094
25337
  function isLocalInjectAlias(slug) {
25095
25338
  return LOCAL_PROVIDER_PREFIXES.some((prefix) => slug.startsWith(prefix));
25096
25339
  }
25097
25340
  function kimiDataRoot(env) {
25098
- return env.KIMI_CODE_HOME || join22(env.HOME || env.USERPROFILE || homedir15(), ".kimi-code");
25341
+ return env.KIMI_CODE_HOME || join23(env.HOME || env.USERPROFILE || homedir16(), ".kimi-code");
25099
25342
  }
25100
25343
  function credentialsPath(env) {
25101
- return join22(kimiDataRoot(env), "credentials", "kimi-code.json");
25344
+ return join23(kimiDataRoot(env), "credentials", "kimi-code.json");
25102
25345
  }
25103
25346
  function quoteToml2(value) {
25104
25347
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
@@ -25386,7 +25629,7 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
25386
25629
  const alias = `${inject.host}/${inject.model.replace(/\//g, "-")}`;
25387
25630
  const dataRoot = kimiDataRoot(env);
25388
25631
  mkdirSync7(dataRoot, { recursive: true });
25389
- const path3 = join22(dataRoot, "config.toml");
25632
+ const path3 = join23(dataRoot, "config.toml");
25390
25633
  let text2 = "";
25391
25634
  try {
25392
25635
  text2 = readFileSync11(path3, "utf8");
@@ -25451,7 +25694,7 @@ function readKimiModelCatalog(env) {
25451
25694
  const dataRoot = kimiDataRoot(env);
25452
25695
  let text2 = "";
25453
25696
  try {
25454
- text2 = readFileSync11(join22(dataRoot, "config.toml"), "utf8");
25697
+ text2 = readFileSync11(join23(dataRoot, "config.toml"), "utf8");
25455
25698
  } catch {
25456
25699
  return STATIC_KIMI_MODELS;
25457
25700
  }
@@ -25571,18 +25814,18 @@ ${turn.text}` : turn.text
25571
25814
 
25572
25815
  // server/drivers/acp/droid.ts
25573
25816
  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";
25817
+ import { homedir as homedir17 } from "node:os";
25818
+ import { join as join24 } from "node:path";
25576
25819
  function authFilePaths(env) {
25577
- const home = env.FACTORY_HOME_OVERRIDE || env.HOME || homedir16();
25578
- return AUTH_FILES.map((name) => join23(home, ".factory", name));
25820
+ const home = env.FACTORY_HOME_OVERRIDE || env.HOME || homedir17();
25821
+ return AUTH_FILES.map((name) => join24(home, ".factory", name));
25579
25822
  }
25580
25823
  function droidInjectId(host, model) {
25581
25824
  const safe = `${host}-${model}`.replace(/[^a-zA-Z0-9._+-]+/g, "-").replace(/-+/g, "-");
25582
25825
  return `${INJECT_ID_PREFIX}${safe}`;
25583
25826
  }
25584
25827
  function factoryHome(env) {
25585
- return env.FACTORY_HOME_OVERRIDE || env.HOME || env.USERPROFILE || homedir16();
25828
+ return env.FACTORY_HOME_OVERRIDE || env.HOME || env.USERPROFILE || homedir17();
25586
25829
  }
25587
25830
  function ensureDroidInjectModel(modelId, env = process.env) {
25588
25831
  const inject = decodeInjectId(modelId);
@@ -25590,9 +25833,9 @@ function ensureDroidInjectModel(modelId, env = process.env) {
25590
25833
  const host = localHost(inject.host);
25591
25834
  if (!host) return modelId;
25592
25835
  const id = droidInjectId(inject.host, inject.model);
25593
- const dir = join23(factoryHome(env), ".factory");
25836
+ const dir = join24(factoryHome(env), ".factory");
25594
25837
  mkdirSync8(dir, { recursive: true });
25595
- const path3 = join23(dir, "settings.json");
25838
+ const path3 = join24(dir, "settings.json");
25596
25839
  let settings2 = {};
25597
25840
  try {
25598
25841
  settings2 = JSON.parse(readFileSync12(path3, "utf8"));
@@ -25632,7 +25875,7 @@ function applyDroidLocalAuthEnv(env, modelId) {
25632
25875
  env.FACTORY_API_KEY = "openmausbot-local";
25633
25876
  }
25634
25877
  function readSettings(env) {
25635
- return JSON.parse(readFileSync12(join23(factoryHome(env), ".factory", "settings.json"), "utf8"));
25878
+ return JSON.parse(readFileSync12(join24(factoryHome(env), ".factory", "settings.json"), "utf8"));
25636
25879
  }
25637
25880
  async function resolveModels(env) {
25638
25881
  let catalog = MODELS3;
@@ -25901,10 +26144,10 @@ function decodeCursorAuthText(text2) {
25901
26144
  return null;
25902
26145
  }
25903
26146
  function execText(run3, cli, args, env) {
25904
- return new Promise((resolve12) => {
26147
+ return new Promise((resolve13) => {
25905
26148
  run3(cli, args, { timeout: EXEC_TIMEOUT_MS, env }, (err, stdout2) => {
25906
- if (err) return resolve12(null);
25907
- resolve12(String(stdout2 ?? ""));
26149
+ if (err) return resolve13(null);
26150
+ resolve13(String(stdout2 ?? ""));
25908
26151
  });
25909
26152
  });
25910
26153
  }
@@ -26023,8 +26266,8 @@ ${turn.text}` : turn.text
26023
26266
 
26024
26267
  // server/drivers/acp/opencode-go.ts
26025
26268
  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";
26269
+ import { homedir as homedir18 } from "node:os";
26270
+ import { join as join25 } from "node:path";
26028
26271
  function labelForModel(id) {
26029
26272
  return id.split(/[-_.]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
26030
26273
  }
@@ -26098,7 +26341,7 @@ function parseOpenCodeModelsOutput(stdout2) {
26098
26341
  return { default: (preferred ?? options[0]).id, options };
26099
26342
  }
26100
26343
  function runOpenCodeModels(cli, environment, verbose) {
26101
- return new Promise((resolve12, reject) => {
26344
+ return new Promise((resolve13, reject) => {
26102
26345
  execCli(
26103
26346
  cli,
26104
26347
  ["models", ...verbose ? ["--verbose"] : []],
@@ -26108,7 +26351,7 @@ function runOpenCodeModels(cli, environment, verbose) {
26108
26351
  reject(new Error(stderr?.trim() || error51.message, { cause: error51 }));
26109
26352
  return;
26110
26353
  }
26111
- resolve12(stdout2);
26354
+ resolve13(stdout2);
26112
26355
  }
26113
26356
  );
26114
26357
  });
@@ -26124,8 +26367,8 @@ async function discoverOpenCodeModels(environment, cli = "opencode") {
26124
26367
  }
26125
26368
  }
26126
26369
  function opencodeConfigDir(env) {
26127
- const home = env.HOME || env.USERPROFILE || homedir17();
26128
- return join24(env.XDG_CONFIG_HOME || join24(home, ".config"), "opencode");
26370
+ const home = env.HOME || env.USERPROFILE || homedir18();
26371
+ return join25(env.XDG_CONFIG_HOME || join25(home, ".config"), "opencode");
26129
26372
  }
26130
26373
  function ensureOpenCodeInjectModel(modelId, env = process.env) {
26131
26374
  const inject = decodeInjectId(modelId);
@@ -26135,7 +26378,7 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
26135
26378
  const native = `${inject.host}/${inject.model}`;
26136
26379
  const dir = opencodeConfigDir(env);
26137
26380
  mkdirSync9(dir, { recursive: true });
26138
- const path3 = join24(dir, "opencode.json");
26381
+ const path3 = join25(dir, "opencode.json");
26139
26382
  let config2 = { $schema: "https://opencode.ai/config.json" };
26140
26383
  if (existsSync12(path3)) {
26141
26384
  try {
@@ -26171,12 +26414,12 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
26171
26414
  return native;
26172
26415
  }
26173
26416
  function storedAuthPaths(env) {
26174
- const home = env.HOME || env.USERPROFILE || homedir17();
26417
+ const home = env.HOME || env.USERPROFILE || homedir18();
26175
26418
  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") : ""
26419
+ env.XDG_DATA_HOME || join25(home, ".local", "share"),
26420
+ process.platform === "darwin" ? join25(home, "Library", "Application Support") : process.platform === "win32" ? env.LOCALAPPDATA || join25(home, "AppData", "Local") : ""
26178
26421
  ].filter(Boolean);
26179
- return [...new Set(roots)].map((root) => join24(root, "opencode", "auth.json"));
26422
+ return [...new Set(roots)].map((root) => join25(root, "opencode", "auth.json"));
26180
26423
  }
26181
26424
  function usableAuthEntry(parsed) {
26182
26425
  return Object.values(parsed).some((auth) => {
@@ -26307,10 +26550,96 @@ ${turn.text}` : turn.text
26307
26550
 
26308
26551
  // server/drivers/acp/qwen.ts
26309
26552
  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";
26553
+ import { createHash as createHash7 } from "node:crypto";
26554
+ import { homedir as homedir19 } from "node:os";
26555
+ import { join as join26 } from "node:path";
26312
26556
  function qwenHome(env) {
26313
- return join25(env.HOME || env.USERPROFILE || homedir18(), ".qwen");
26557
+ const home = process.platform === "win32" ? env.USERPROFILE || env.HOME || homedir19() : env.HOME || env.USERPROFILE || homedir19();
26558
+ return join26(home, ".qwen");
26559
+ }
26560
+ function isRecord(value) {
26561
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
26562
+ }
26563
+ function qwenModelLabel(id, name) {
26564
+ if (!name || name.toLocaleLowerCase().endsWith(id.toLocaleLowerCase())) return id;
26565
+ return `${id} \u2014 ${name}`;
26566
+ }
26567
+ function readQwenRoutes(env) {
26568
+ let settings2;
26569
+ try {
26570
+ settings2 = JSON.parse(readFileSync14(join26(qwenHome(env), "settings.json"), "utf8"));
26571
+ } catch {
26572
+ return [];
26573
+ }
26574
+ if (!isRecord(settings2) || !isRecord(settings2.modelProviders)) return [];
26575
+ const routes = [];
26576
+ const seen = /* @__PURE__ */ new Set();
26577
+ const mappings = isRecord(settings2.providerProtocol) ? settings2.providerProtocol : {};
26578
+ for (const [provider, rows] of Object.entries(settings2.modelProviders)) {
26579
+ const protocol = Object.hasOwn(mappings, provider) ? mappings[provider] : provider;
26580
+ if (typeof protocol !== "string" || !PROTOCOLS.has(protocol) || !Array.isArray(rows)) continue;
26581
+ for (const row of rows) {
26582
+ if (!isRecord(row) || typeof row.id !== "string") continue;
26583
+ const model = row.id;
26584
+ if (!model.trim()) continue;
26585
+ if (row.baseUrl !== void 0 && typeof row.baseUrl !== "string") continue;
26586
+ const baseUrl = typeof row.baseUrl === "string" && row.baseUrl ? row.baseUrl : void 0;
26587
+ if (baseUrl) {
26588
+ try {
26589
+ new URL(baseUrl);
26590
+ } catch {
26591
+ throw new Error("A Qwen model has an invalid endpoint. Fix its baseUrl in Qwen settings and refresh models.");
26592
+ }
26593
+ }
26594
+ const identity = JSON.stringify([protocol, model, baseUrl ?? null]);
26595
+ if (seen.has(identity)) continue;
26596
+ seen.add(identity);
26597
+ if (row.imageOnly === true || row.voiceOnly === true || row.fastOnly === true) continue;
26598
+ routes.push({
26599
+ id: `${model}(${protocol})`,
26600
+ model,
26601
+ provider,
26602
+ protocol,
26603
+ baseUrl,
26604
+ label: typeof row.name === "string" && row.name ? row.name : model,
26605
+ envKey: typeof row.envKey === "string" ? row.envKey : void 0
26606
+ });
26607
+ }
26608
+ }
26609
+ const counts = /* @__PURE__ */ new Map();
26610
+ for (const route of routes) counts.set(route.id, (counts.get(route.id) ?? 0) + 1);
26611
+ for (const route of routes) {
26612
+ if (counts.get(route.id) === 1) continue;
26613
+ const endpoint = route.baseUrl ?? (route.protocol === "openai" ? "https://api.openai.com/v1" : "");
26614
+ let publicEndpoint = null;
26615
+ if (endpoint) {
26616
+ try {
26617
+ const url2 = new URL(endpoint);
26618
+ url2.username = "";
26619
+ url2.password = "";
26620
+ url2.search = "";
26621
+ url2.hash = "";
26622
+ publicEndpoint = url2.href;
26623
+ } catch {
26624
+ throw new Error("A Qwen model has an invalid endpoint. Fix its baseUrl in Qwen settings and refresh models.");
26625
+ }
26626
+ }
26627
+ const identity = [route.id, route.label, route.envKey ?? null, route.baseUrl === void 0, publicEndpoint];
26628
+ route.id = `qwen-route:v1:${createHash7("sha256").update(JSON.stringify(identity)).digest("base64url").slice(0, 16)}`;
26629
+ }
26630
+ if (new Set(routes.map((route) => route.id)).size !== routes.length) {
26631
+ throw new Error("Qwen has indistinguishable model routes. Give them distinct names, envKey values, or public endpoints in Qwen settings.");
26632
+ }
26633
+ return routes;
26634
+ }
26635
+ function readQwenModelCatalog(env = process.env) {
26636
+ const options = readQwenRoutes(env).map(({ id, model, label, provider }) => ({
26637
+ id,
26638
+ label: qwenModelLabel(model, label),
26639
+ custom: true,
26640
+ provider
26641
+ }));
26642
+ return { default: options[0]?.id ?? "", options };
26314
26643
  }
26315
26644
  function envKeyFor(hostId) {
26316
26645
  return `OPENMAUSBOT_QWEN_${hostId.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
@@ -26322,7 +26651,7 @@ function ensureQwenInjectModel(modelId, env = process.env) {
26322
26651
  if (!host) return modelId;
26323
26652
  const dir = qwenHome(env);
26324
26653
  mkdirSync10(dir, { recursive: true });
26325
- const path3 = join25(dir, "settings.json");
26654
+ const path3 = join26(dir, "settings.json");
26326
26655
  let settings2 = {};
26327
26656
  if (existsSync13(path3)) {
26328
26657
  try {
@@ -26359,23 +26688,54 @@ function ensureQwenInjectModel(modelId, env = process.env) {
26359
26688
  return inject.model;
26360
26689
  }
26361
26690
  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;
26691
+ const catalog = await mergeLocalInject(readQwenModelCatalog(env), env);
26692
+ const routes = readQwenRoutes(env);
26693
+ const replacements = /* @__PURE__ */ new Map();
26694
+ for (const option of catalog.options) {
26695
+ const injected = decodeInjectId(option.id);
26696
+ if (!injected) continue;
26697
+ const endpoint = localHost(injected.host)?.baseUrl;
26698
+ for (const route of routes) {
26699
+ if (route.protocol === "openai" && route.model === injected.model && route.baseUrl === endpoint) {
26700
+ replacements.set(route.id, option.id);
26701
+ }
26702
+ }
26703
+ }
26704
+ const options = catalog.options.filter((option) => !replacements.has(option.id));
26705
+ const preferred = replacements.get(catalog.default) ?? catalog.default;
26706
+ return { default: options.some((option) => option.id === preferred) ? preferred : options[0]?.id ?? "", options };
26707
+ }
26708
+ function resolveQwenTurnModel(model, env) {
26709
+ if (!model) return model;
26710
+ const injected = decodeInjectId(model);
26711
+ if (injected) ensureQwenInjectModel(model, env);
26712
+ const routes = readQwenRoutes(env);
26713
+ if (injected) {
26714
+ const route = routes.find((row) => row.protocol === "openai" && row.model === injected.model && row.baseUrl === localHost(injected.host)?.baseUrl);
26715
+ if (!route) throw new Error("Qwen could not configure this local model. Refresh models and select it again.");
26716
+ return route.id;
26717
+ }
26718
+ if (routes.some((route) => route.id === model)) return model;
26719
+ const matches = routes.filter((route) => route.model === model);
26720
+ if (matches.length > 1) throw new Error("This Qwen model has multiple providers. Refresh models and select the intended provider again.");
26721
+ if (!matches.length) throw new Error("This Qwen model is no longer configured. Refresh models and select it again.");
26722
+ return matches[0].id;
26723
+ }
26724
+ var EMPTY, PROTOCOLS, support8, QwenAgentDriver;
26366
26725
  var init_qwen = __esm({
26367
26726
  "server/drivers/acp/qwen.ts"() {
26368
26727
  "use strict";
26369
26728
  init_local_inject();
26370
26729
  init_core3();
26371
26730
  EMPTY = { default: "", options: [] };
26731
+ PROTOCOLS = /* @__PURE__ */ new Set(["openai", "anthropic", "gemini", "vertex-ai"]);
26372
26732
  support8 = {
26373
26733
  driverKind: "qwenAgent",
26374
26734
  displayName: "Qwen",
26375
26735
  access: "custom",
26376
26736
  models: EMPTY,
26377
26737
  resolveModels: resolveModels2,
26378
- resolveTurnModel: (model, env) => model ? ensureQwenInjectModel(model, env) : model,
26738
+ resolveTurnModel: resolveQwenTurnModel,
26379
26739
  defaultCli: "qwen",
26380
26740
  nativeSource: "qwen.acp",
26381
26741
  loginNote: "Qwen Code CLI is not installed",
@@ -26387,7 +26747,10 @@ var init_qwen = __esm({
26387
26747
  },
26388
26748
  docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/overview/"
26389
26749
  },
26390
- spawnArgs: (_config, turn) => ["--acp", ...turn.model ? ["-m", turn.model] : []],
26750
+ // A raw -m only changes the model within the saved provider. ACP switches
26751
+ // the complete route and confirms it before any prompt leaves OMB.
26752
+ spawnArgs: () => ["--acp"],
26753
+ selectModel: { configId: "model" },
26391
26754
  pickAuthMethod: () => null,
26392
26755
  authFailure: "continue",
26393
26756
  isAuthenticated: () => true,
@@ -33288,8 +33651,8 @@ var init_browser = __esm({
33288
33651
  // server/drivers/acp/hermes.ts
33289
33652
  import { spawn as spawn5 } from "node:child_process";
33290
33653
  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";
33654
+ import { homedir as homedir20 } from "node:os";
33655
+ import { join as join27 } from "node:path";
33293
33656
  function bindHermesScreenshotCompat(env, modelId) {
33294
33657
  delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT];
33295
33658
  delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL];
@@ -33299,7 +33662,7 @@ function bindHermesScreenshotCompat(env, modelId) {
33299
33662
  env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL] = inject.model;
33300
33663
  }
33301
33664
  function hermesHome(env) {
33302
- return env.HERMES_HOME || join26(env.HOME || env.USERPROFILE || homedir19(), ".hermes");
33665
+ return env.HERMES_HOME || join27(env.HOME || env.USERPROFILE || homedir20(), ".hermes");
33303
33666
  }
33304
33667
  function quoteYaml(value) {
33305
33668
  if (/^[\w./:+-]+$/.test(value)) return value;
@@ -33341,7 +33704,7 @@ function ensureHermesInjectProvider(modelId, env = process.env) {
33341
33704
  if (!host) return modelId;
33342
33705
  const dir = hermesHome(env);
33343
33706
  mkdirSync11(dir, { recursive: true });
33344
- const path3 = join26(dir, "config.yaml");
33707
+ const path3 = join27(dir, "config.yaml");
33345
33708
  let text2 = "";
33346
33709
  try {
33347
33710
  text2 = readFileSync15(path3, "utf8");
@@ -33412,13 +33775,13 @@ function hermesConfiguredModel(env = process.env) {
33412
33775
  const dir = hermesHome(env);
33413
33776
  let secrets = "";
33414
33777
  try {
33415
- secrets = readFileSync15(join26(dir, ".env"), "utf8");
33778
+ secrets = readFileSync15(join27(dir, ".env"), "utf8");
33416
33779
  } catch {
33417
33780
  }
33418
33781
  const hasHostedProviderKey = HERMES_HOSTED_PROVIDER_KEYS.some((name) => nonEmptyDotenvValue(secrets, name));
33419
33782
  let configuredDefault = null;
33420
33783
  try {
33421
- configuredDefault = hermesConfigDefault(readFileSync15(join26(dir, "config.yaml"), "utf8"));
33784
+ configuredDefault = hermesConfigDefault(readFileSync15(join27(dir, "config.yaml"), "utf8"));
33422
33785
  } catch {
33423
33786
  }
33424
33787
  const configuredProvider = configuredDefault?.provider.toLowerCase() ?? "";
@@ -33434,12 +33797,12 @@ function hermesConfiguredModel(env = process.env) {
33434
33797
  };
33435
33798
  }
33436
33799
  async function fetchHermesAcpModels(cli, env) {
33437
- return await new Promise((resolve12) => {
33800
+ return await new Promise((resolve13) => {
33438
33801
  let child;
33439
33802
  try {
33440
33803
  child = spawn5(cli, ["acp"], { stdio: ["pipe", "pipe", "ignore"], env });
33441
33804
  } catch {
33442
- return resolve12([]);
33805
+ return resolve13([]);
33443
33806
  }
33444
33807
  let settled = false;
33445
33808
  let timer;
@@ -33460,7 +33823,7 @@ async function fetchHermesAcpModels(cli, env) {
33460
33823
  }
33461
33824
  } catch {
33462
33825
  }
33463
- resolve12(out);
33826
+ resolve13(out);
33464
33827
  };
33465
33828
  timer = setTimeout(() => done([]), 5e3);
33466
33829
  child.once("error", () => done([]));
@@ -33503,7 +33866,7 @@ async function fetchHermesAcpModels(cli, env) {
33503
33866
  }
33504
33867
  if (msg?.id === initId) {
33505
33868
  if (!msg.result) return done([]);
33506
- sessionId = send("session/new", { cwd: env.HOME || env.USERPROFILE || homedir19(), mcpServers: [] });
33869
+ sessionId = send("session/new", { cwd: env.HOME || env.USERPROFILE || homedir20(), mcpServers: [] });
33507
33870
  } else if (sessionId && msg?.id === sessionId) {
33508
33871
  const list = Array.isArray(msg.result?.models?.availableModels) ? msg.result.models.availableModels : [];
33509
33872
  done(
@@ -33739,8 +34102,8 @@ var init_openai_compat = __esm({
33739
34102
 
33740
34103
  // server/drivers/pi.ts
33741
34104
  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";
34105
+ import { homedir as homedir21, tmpdir as tmpdir4 } from "node:os";
34106
+ import { join as join28 } from "node:path";
33744
34107
  function readPiPromptImages(turn) {
33745
34108
  return (turn.images ?? []).map((image) => ({
33746
34109
  type: "image",
@@ -33847,7 +34210,7 @@ async function applyPiLocalCatalog(catalog, env = process.env, fetchImpl = fetch
33847
34210
  return preferPiInjectRows(await mergeLocalInject(catalog, env, fetchImpl));
33848
34211
  }
33849
34212
  function piAgentDir(env) {
33850
- return join27(env.HOME || env.USERPROFILE || homedir20(), ".pi", "agent");
34213
+ return join28(env.HOME || env.USERPROFILE || homedir21(), ".pi", "agent");
33851
34214
  }
33852
34215
  function ensurePiInjectModel(modelId, env = process.env) {
33853
34216
  const split = splitPiModel(modelId);
@@ -33858,7 +34221,7 @@ function ensurePiInjectModel(modelId, env = process.env) {
33858
34221
  if (!host) return split;
33859
34222
  const dir = piAgentDir(env);
33860
34223
  mkdirSync12(dir, { recursive: true });
33861
- const path3 = join27(dir, "models.json");
34224
+ const path3 = join28(dir, "models.json");
33862
34225
  let root = { providers: {} };
33863
34226
  if (existsSync14(path3)) {
33864
34227
  try {
@@ -33912,7 +34275,7 @@ function ensurePiInjectModel(modelId, env = process.env) {
33912
34275
  return split;
33913
34276
  }
33914
34277
  function readPiDefaultModel(env) {
33915
- const home = env.HOME || env.USERPROFILE || homedir20();
34278
+ const home = env.HOME || env.USERPROFILE || homedir21();
33916
34279
  try {
33917
34280
  const s = JSON.parse(readFileSync16(`${home}/.pi/agent/settings.json`, "utf8"));
33918
34281
  return s.defaultProvider && s.defaultModel ? `${s.defaultProvider}/${s.defaultModel}` : "";
@@ -33922,7 +34285,7 @@ function readPiDefaultModel(env) {
33922
34285
  }
33923
34286
  async function fetchPiModels(cli, env) {
33924
34287
  const child = spawnCli(cli, PI_ARGS, { stdio: ["pipe", "pipe", "pipe"], env });
33925
- return new Promise((resolve12) => {
34288
+ return new Promise((resolve13) => {
33926
34289
  let buf = "";
33927
34290
  let done = false;
33928
34291
  const fallbackDefault = readPiDefaultModel(env);
@@ -33933,7 +34296,7 @@ async function fetchPiModels(cli, env) {
33933
34296
  killCliTree(child);
33934
34297
  } catch {
33935
34298
  }
33936
- resolve12(catalog);
34299
+ resolve13(catalog);
33937
34300
  };
33938
34301
  const timer = setTimeout(() => finish({ default: "", options: [] }), 15e3);
33939
34302
  timer.unref?.();
@@ -34060,9 +34423,9 @@ var init_pi = __esm({
34060
34423
  const mcpServers = buildMcpServers(turn);
34061
34424
  let mcpTempDir = null;
34062
34425
  if (mcpServers) {
34063
- mcpTempDir = mkdtempSync3(join27(tmpdir4(), "omb-pi-mcp-"));
34426
+ mcpTempDir = mkdtempSync3(join28(tmpdir4(), "omb-pi-mcp-"));
34064
34427
  try {
34065
- writeFileSync12(join27(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
34428
+ writeFileSync12(join28(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
34066
34429
  } catch (err) {
34067
34430
  try {
34068
34431
  rmSync3(mcpTempDir, { recursive: true, force: true });
@@ -34080,7 +34443,7 @@ var init_pi = __esm({
34080
34443
  env: piEnvironment({
34081
34444
  ...process.env,
34082
34445
  ...input.environment,
34083
- ...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join27(mcpTempDir, "mcp.json") } : {}
34446
+ ...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join28(mcpTempDir, "mcp.json") } : {}
34084
34447
  })
34085
34448
  });
34086
34449
  } catch (err) {
@@ -34103,13 +34466,13 @@ var init_pi = __esm({
34103
34466
  }
34104
34467
  responseWaiters.clear();
34105
34468
  };
34106
- const awaitResponse = (command, timeoutMs = 2e4) => new Promise((resolve12, reject) => {
34469
+ const awaitResponse = (command, timeoutMs = 2e4) => new Promise((resolve13, reject) => {
34107
34470
  const timer = setTimeout(() => {
34108
34471
  responseWaiters.delete(command);
34109
34472
  reject(new Error(`pi ${command} timed out`));
34110
34473
  }, timeoutMs);
34111
34474
  timer.unref?.();
34112
- responseWaiters.set(command, { resolve: resolve12, reject, timer });
34475
+ responseWaiters.set(command, { resolve: resolve13, reject, timer });
34113
34476
  });
34114
34477
  child.stdin.on("error", () => rejectWaiters(new Error("pi stdin closed")));
34115
34478
  const send = (obj) => {
@@ -34317,7 +34680,7 @@ ${turn.text}` : turn.text;
34317
34680
  return { turnId };
34318
34681
  };
34319
34682
  const snapshot = async () => {
34320
- const version2 = await new Promise((resolve12) => {
34683
+ const version2 = await new Promise((resolve13) => {
34321
34684
  const child = spawnCli(config2.cli, ["--version"], {
34322
34685
  stdio: ["ignore", "pipe", "pipe"],
34323
34686
  env: piEnvironment({ ...process.env, ...input.environment })
@@ -34330,16 +34693,16 @@ ${turn.text}` : turn.text;
34330
34693
  killCliTree(child);
34331
34694
  } catch {
34332
34695
  }
34333
- resolve12(null);
34696
+ resolve13(null);
34334
34697
  }, 8e3);
34335
34698
  timer.unref?.();
34336
34699
  child.on("error", () => {
34337
34700
  clearTimeout(timer);
34338
- resolve12(null);
34701
+ resolve13(null);
34339
34702
  });
34340
34703
  child.on("close", () => {
34341
34704
  clearTimeout(timer);
34342
- resolve12(out.trim() || null);
34705
+ resolve13(out.trim() || null);
34343
34706
  });
34344
34707
  });
34345
34708
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
@@ -34418,15 +34781,15 @@ ${turn.text}` : turn.text;
34418
34781
 
34419
34782
  // server/drivers/minimax.ts
34420
34783
  import { readFileSync as readFileSync17 } from "node:fs";
34421
- import { homedir as homedir21 } from "node:os";
34422
- import { join as join28 } from "node:path";
34784
+ import { homedir as homedir22 } from "node:os";
34785
+ import { join as join29 } from "node:path";
34423
34786
  function normalizedApiUrl(value) {
34424
34787
  const root = value.trim().replace(/\/+$/, "");
34425
34788
  return root.endsWith("/v1") ? root : `${root}/v1`;
34426
34789
  }
34427
- function loadLocalMiniMaxConfig(home = homedir21()) {
34790
+ function loadLocalMiniMaxConfig(home = homedir22()) {
34428
34791
  try {
34429
- const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join28(home, ".mmx", "config.json"), "utf8")));
34792
+ const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join29(home, ".mmx", "config.json"), "utf8")));
34430
34793
  const configuredUrl = raw.base_url?.trim() ? raw.base_url : raw.region === "cn" ? CN_URL : DEFAULT_URL2;
34431
34794
  return {
34432
34795
  apiKey: raw.api_key?.trim() ?? "",
@@ -34694,7 +35057,7 @@ __export(cli_setup_exports, {
34694
35057
  });
34695
35058
  import { spawn as spawn6 } from "node:child_process";
34696
35059
  import { readFileSync as readFileSync18 } from "node:fs";
34697
- import { join as join29, resolve as resolve9 } from "node:path";
35060
+ import { join as join30, resolve as resolve10 } from "node:path";
34698
35061
  import { randomUUID as randomUUID10 } from "node:crypto";
34699
35062
  async function inspect(id, entry) {
34700
35063
  const registry2 = new ProviderRegistry(BUILT_IN_DRIVERS);
@@ -34727,11 +35090,11 @@ async function runSetupCli(cli, args, environment = {}) {
34727
35090
  resetPathCache();
34728
35091
  }
34729
35092
  function assertDataDir(dataDir) {
34730
- if (resolve9(dataDir) !== resolve9(DATA_DIR)) throw new Error("Setup data directory mismatch. Restart the CLI with --data-dir.");
35093
+ if (resolve10(dataDir) !== resolve10(DATA_DIR)) throw new Error("Setup data directory mismatch. Restart the CLI with --data-dir.");
34731
35094
  }
34732
35095
  function checkStoredConfig(dataDir) {
34733
35096
  try {
34734
- parseStoredConfig(JSON.parse(readFileSync18(join29(dataDir, "config.json"), "utf8")));
35097
+ parseStoredConfig(JSON.parse(readFileSync18(join30(dataDir, "config.json"), "utf8")));
34735
35098
  } catch (error51) {
34736
35099
  if (error51.code === "ENOENT") return;
34737
35100
  throw new Error("Existing config.json could not be read or validated. Setup has not changed it; repair it before continuing.");
@@ -35009,7 +35372,7 @@ var init_browser_engine_release = __esm({
35009
35372
  });
35010
35373
 
35011
35374
  // server/browser-bundle-release.ts
35012
- import { join as join30 } from "node:path";
35375
+ import { join as join31 } from "node:path";
35013
35376
  function browserBundleSpec(target) {
35014
35377
  if (!Object.hasOwn(CHROME_ASSETS, target)) throw new Error(`Unsupported desktop browser target: ${target}`);
35015
35378
  const pinned = CHROME_ASSETS[target];
@@ -35045,10 +35408,10 @@ function browserBundlePaths(bundleDirectory, target) {
35045
35408
  const spec = browserBundleSpec(target);
35046
35409
  return {
35047
35410
  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")
35411
+ manifest: join31(bundleDirectory, "manifest.json"),
35412
+ engine: join31(bundleDirectory, spec.engine.executable),
35413
+ chrome: join31(bundleDirectory, spec.chrome.executable),
35414
+ licenses: join31(bundleDirectory, "licenses")
35052
35415
  };
35053
35416
  }
35054
35417
  var CHROME_VERSION, CHROME_ASSETS;
@@ -35102,23 +35465,23 @@ __export(browser_engine_exports, {
35102
35465
  resolveAgentBrowserBinary: () => resolveAgentBrowserBinary
35103
35466
  });
35104
35467
  import { spawn as spawn7 } from "node:child_process";
35105
- import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
35468
+ import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
35106
35469
  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";
35470
+ import { homedir as homedir23, tmpdir as tmpdir5 } from "node:os";
35471
+ import { delimiter as delimiter6, dirname as dirname10, join as join32, resolve as resolve11 } from "node:path";
35109
35472
  function browserRestoreKey(session) {
35110
35473
  if (!/^[A-Za-z0-9_-]{1,96}$/.test(session)) throw new Error("Invalid browser session.");
35111
- return `omb-${createHash7("sha256").update(session).digest("hex")}`;
35474
+ return `omb-${createHash8("sha256").update(session).digest("hex")}`;
35112
35475
  }
35113
35476
  function browserSessionsDirectory(env) {
35114
35477
  const namespace = env.AGENT_BROWSER_NAMESPACE;
35115
35478
  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");
35479
+ const home = (process.platform === "win32" ? env.USERPROFILE : env.HOME) || homedir23();
35480
+ const stateRoot = namespace ? join32(home, ".agent-browser", "namespaces", namespace, "state") : join32(home, ".agent-browser");
35481
+ return join32(stateRoot, "sessions");
35119
35482
  }
35120
35483
  function managedBrowserConfigPath(env) {
35121
- return join31(browserSessionsDirectory(env), "..", "omb-managed-config.json");
35484
+ return join32(browserSessionsDirectory(env), "..", "omb-managed-config.json");
35122
35485
  }
35123
35486
  function ensureManagedBrowserConfig(env) {
35124
35487
  const path3 = managedBrowserConfigPath(env);
@@ -35191,7 +35554,7 @@ async function closeBrowserSession(binaryPath, env, timeoutMs = 15e3) {
35191
35554
  } catch {
35192
35555
  return false;
35193
35556
  }
35194
- await new Promise((resolve12) => setTimeout(resolve12, Math.min(25, Math.max(1, deadline - Date.now()))));
35557
+ await new Promise((resolve13) => setTimeout(resolve13, Math.min(25, Math.max(1, deadline - Date.now()))));
35195
35558
  }
35196
35559
  return false;
35197
35560
  }
@@ -35205,11 +35568,11 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35205
35568
  ensureManagedBrowserConfig(env);
35206
35569
  if (options.persistent === false) return;
35207
35570
  const directory = browserSessionsDirectory(env);
35208
- const key = join31(directory, session);
35571
+ const key = join32(directory, session);
35209
35572
  let pending = preparedBrowserSessions.get(key);
35210
35573
  if (!pending) {
35211
35574
  pending = (async () => {
35212
- const targetBase = join31(directory, `${restoreKey}-${session}`);
35575
+ const targetBase = join32(directory, `${restoreKey}-${session}`);
35213
35576
  const hasTarget = () => existsSync15(`${targetBase}.json.enc`) || existsSync15(`${targetBase}.json`);
35214
35577
  if (hasTarget()) return;
35215
35578
  check2();
@@ -35219,7 +35582,7 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35219
35582
  check2();
35220
35583
  if (hasTarget()) return;
35221
35584
  const candidates = [".json.enc", ".json"].flatMap((suffix) => {
35222
- const path3 = join31(directory, `${session}-${session}${suffix}`);
35585
+ const path3 = join32(directory, `${session}-${session}${suffix}`);
35223
35586
  try {
35224
35587
  const stat4 = statSync3(path3);
35225
35588
  if (!stat4.isFile()) throw new Error("Saved browser state is not a file.");
@@ -35254,14 +35617,14 @@ function isMusl(platform = process.platform, exists = existsSync15) {
35254
35617
  }
35255
35618
  function pinnedBinaryPath(dataDir = DATA_DIR, platform = process.platform, arch = process.arch) {
35256
35619
  const version2 = agentBrowserReleaseVersion(resolveAgentBrowserReleaseAsset(platform, arch));
35257
- return join31(dataDir, ENGINE_DIR, version2, executableName(platform));
35620
+ return join32(dataDir, ENGINE_DIR, version2, executableName(platform));
35258
35621
  }
35259
35622
  function onPath(env, platform, exists) {
35260
35623
  const pathValue = platform === "win32" ? Object.entries(env).findLast(([key]) => key.toUpperCase() === "PATH")?.[1] : env.PATH;
35261
35624
  for (const part of (pathValue ?? "").split(delimiter6)) {
35262
35625
  const dir = part.trim().replace(/^"|"$/gu, "");
35263
35626
  if (!dir) continue;
35264
- const candidate = resolve10(dir, executableName(platform));
35627
+ const candidate = resolve11(dir, executableName(platform));
35265
35628
  if (exists(candidate)) return candidate;
35266
35629
  }
35267
35630
  return null;
@@ -35270,7 +35633,7 @@ function packagedBrowser(options) {
35270
35633
  const resources = (options.env ?? process.env).OMB_RESOURCES_PATH;
35271
35634
  if (!resources) return null;
35272
35635
  try {
35273
- return browserBundlePaths(join31(resolve10(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
35636
+ return browserBundlePaths(join32(resolve11(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
35274
35637
  } catch {
35275
35638
  return null;
35276
35639
  }
@@ -35283,7 +35646,7 @@ function resolveAgentBrowserBinary(options = {}) {
35283
35646
  const platform = options.platform ?? process.platform;
35284
35647
  const exists = options.exists ?? existsSync15;
35285
35648
  const override = env.OMB_AGENT_BROWSER_PATH?.trim();
35286
- if (override) return resolve10(override) && exists(resolve10(override)) ? resolve10(override) : null;
35649
+ if (override) return resolve11(override) && exists(resolve11(override)) ? resolve11(override) : null;
35287
35650
  const bundle = packagedBrowser(options);
35288
35651
  if (bundle && exists(bundle.directory)) return completePackage(bundle, exists) ? bundle.engine : null;
35289
35652
  const pinned = pinnedBinaryPath(options.dataDir, platform, options.arch);
@@ -35295,7 +35658,7 @@ async function installAgentBrowserBinary(options = {}) {
35295
35658
  const asset = options.asset ?? resolveAgentBrowserReleaseAsset(platform, options.arch ?? process.arch, options.musl ?? isMusl(platform));
35296
35659
  if (!asset) throw new Error(`agent-browser publishes no build for ${platform}-${options.arch ?? process.arch}.`);
35297
35660
  const destination = pinnedBinaryPath(options.dataDir, platform, options.arch);
35298
- const directory = join31(destination, "..");
35661
+ const directory = join32(destination, "..");
35299
35662
  mkdirSync13(directory, { recursive: true, mode: 448 });
35300
35663
  const url2 = agentBrowserReleaseUrl(asset);
35301
35664
  options.log?.(`downloading agent-browser ${agentBrowserReleaseVersion(asset)} (${Math.round(asset.bytes / 1024 / 1024)} MB, digest pinned)`);
@@ -35311,7 +35674,7 @@ async function installAgentBrowserBinary(options = {}) {
35311
35674
  clearTimeout(timer);
35312
35675
  }
35313
35676
  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");
35677
+ const digest2 = createHash8("sha256").update(body).digest("hex");
35315
35678
  if (digest2 !== asset.sha256) throw new Error("the agent-browser download failed its SHA-256 check; nothing was installed");
35316
35679
  const staging = `${destination}.${randomBytes3(6).toString("hex")}.part`;
35317
35680
  writeFileSync13(staging, body, { mode: 493 });
@@ -35321,7 +35684,7 @@ async function installAgentBrowserBinary(options = {}) {
35321
35684
  }
35322
35685
  function ensureChrome(binaryPath, options = {}) {
35323
35686
  const bundle = packagedBrowser(options);
35324
- if (!options.withDeps && bundle && resolve10(binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
35687
+ if (!options.withDeps && bundle && resolve11(binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
35325
35688
  options.log?.("agent-browser: the bundled browser is ready; no download needed");
35326
35689
  return Promise.resolve();
35327
35690
  }
@@ -35347,7 +35710,7 @@ function ensureChrome(binaryPath, options = {}) {
35347
35710
  });
35348
35711
  }
35349
35712
  function browserEngineEncryptionKey(dataDir = DATA_DIR) {
35350
- const file2 = join31(dataDir, KEY_FILE);
35713
+ const file2 = join32(dataDir, KEY_FILE);
35351
35714
  try {
35352
35715
  const existing = readFileSync19(file2, "utf8").trim();
35353
35716
  if (/^[0-9a-f]{64}$/u.test(existing)) return existing;
@@ -35401,13 +35764,13 @@ function agentBrowserIntegration(input) {
35401
35764
  if (sourceEnv[name]) env[name] = sourceEnv[name];
35402
35765
  }
35403
35766
  const bundle = packagedBrowser({ env: sourceEnv });
35404
- if (!env.AGENT_BROWSER_EXECUTABLE_PATH && bundle && resolve10(input.binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
35767
+ if (!env.AGENT_BROWSER_EXECUTABLE_PATH && bundle && resolve11(input.binaryPath) === bundle.engine && completePackage(bundle, existsSync15)) {
35405
35768
  env.AGENT_BROWSER_EXECUTABLE_PATH = bundle.chrome;
35406
35769
  }
35407
35770
  return { command: input.binaryPath, args: ["mcp", "--tools", "core", "--no-webmcp"], env };
35408
35771
  }
35409
35772
  function agentBrowserFrame(input) {
35410
- const file2 = join31(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
35773
+ const file2 = join32(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
35411
35774
  return new Promise((settle, fail) => {
35412
35775
  const child = spawn7(input.binaryPath, ["screenshot", file2], {
35413
35776
  env: browserRuntimeEnv(input.env),
@@ -35477,8 +35840,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
35477
35840
  }
35478
35841
  };
35479
35842
  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");
35843
+ for (const base2 of bases) for (const suffix of [".json", ".json.enc", ".json.previous", ".json.enc.previous"]) remove(join32(directory, base2 + suffix));
35844
+ const pendingDirectory = join32(directory, ".tmp");
35482
35845
  let pendingFiles = [];
35483
35846
  try {
35484
35847
  pendingFiles = readdirSync3(pendingDirectory);
@@ -35486,8 +35849,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
35486
35849
  if (error51.code !== "ENOENT") throw error51;
35487
35850
  }
35488
35851
  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));
35852
+ for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(join32(pendingDirectory, name));
35853
+ preparedBrowserSessions.delete(join32(directory, session));
35491
35854
  return true;
35492
35855
  } catch {
35493
35856
  return false;
@@ -35515,8 +35878,8 @@ var init_browser_engine = __esm({
35515
35878
  var import_qrcode_terminal = __toESM(require_main(), 1);
35516
35879
  import { spawn as spawn8 } from "node:child_process";
35517
35880
  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";
35881
+ import { homedir as homedir24 } from "node:os";
35882
+ import { dirname as dirname11, join as join33, resolve as resolve12 } from "node:path";
35520
35883
  import { createInterface as createInterface2 } from "node:readline/promises";
35521
35884
  import { fileURLToPath as fileURLToPath3 } from "node:url";
35522
35885
 
@@ -36114,13 +36477,13 @@ function writePrivateToken(runtimeRoot2, token, { fileSystem, processId, identif
36114
36477
  }
36115
36478
  async function waitForExit(child, milliseconds) {
36116
36479
  if (child.exitCode !== null || child.signalCode !== null) return;
36117
- await new Promise((resolve12) => {
36480
+ await new Promise((resolve13) => {
36118
36481
  let settled = false;
36119
36482
  const finish = () => {
36120
36483
  if (settled) return;
36121
36484
  settled = true;
36122
36485
  clearTimeout(timer);
36123
- resolve12();
36486
+ resolve13();
36124
36487
  };
36125
36488
  child.once("exit", finish);
36126
36489
  const timer = setTimeout(finish, milliseconds);
@@ -36284,8 +36647,8 @@ function createManagedCompanionTunnel({
36284
36647
  child = spawned;
36285
36648
  const cancellationController = new AbortController();
36286
36649
  let resolveCancellation;
36287
- const cancellation = new Promise((resolve12) => {
36288
- resolveCancellation = resolve12;
36650
+ const cancellation = new Promise((resolve13) => {
36651
+ resolveCancellation = resolve13;
36289
36652
  });
36290
36653
  let cancelled = false;
36291
36654
  attemptHandle = {
@@ -36301,8 +36664,8 @@ function createManagedCompanionTunnel({
36301
36664
  let terminated = false;
36302
36665
  let expectedStop = false;
36303
36666
  let resolveExit;
36304
- const exit = new Promise((resolve12) => {
36305
- resolveExit = resolve12;
36667
+ const exit = new Promise((resolve13) => {
36668
+ resolveExit = resolve13;
36306
36669
  });
36307
36670
  const onTerminated = () => {
36308
36671
  if (terminated) return;
@@ -36336,8 +36699,8 @@ function createManagedCompanionTunnel({
36336
36699
  }
36337
36700
  if (Date.now() >= deadline) break;
36338
36701
  await Promise.race([
36339
- new Promise((resolve12) => {
36340
- const timer = setTimeout(resolve12, verifyIntervalMs);
36702
+ new Promise((resolve13) => {
36703
+ const timer = setTimeout(resolve13, verifyIntervalMs);
36341
36704
  timer.unref?.();
36342
36705
  }),
36343
36706
  exit,
@@ -37337,14 +37700,14 @@ function explainTailscaleFailure(reason) {
37337
37700
  }
37338
37701
  }
37339
37702
  function run(cli, args, timeoutMs) {
37340
- return new Promise((resolve12) => {
37703
+ return new Promise((resolve13) => {
37341
37704
  execFile(
37342
37705
  cli,
37343
37706
  args,
37344
37707
  { timeout: timeoutMs, killSignal: "SIGKILL", maxBuffer: 16 * 1024 * 1024, env: { ...process.env, PATH: searchPath() } },
37345
37708
  (error51, stdout2, stderr) => {
37346
37709
  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 });
37710
+ resolve13({ ok: !error51, stdout: String(stdout2 ?? ""), stderr: String(stderr ?? ""), code });
37348
37711
  }
37349
37712
  );
37350
37713
  });
@@ -37761,7 +38124,7 @@ function parseArgs(argv, env = process.env) {
37761
38124
  const options = {
37762
38125
  command: command === "--help" || command === "-h" ? "help" : command,
37763
38126
  port: Number(env.OMB_PORT || 8799),
37764
- dataDir: env.OMB_DATA_DIR || join32(homedir23(), ".openmausbot"),
38127
+ dataDir: env.OMB_DATA_DIR || join33(homedir24(), ".openmausbot"),
37765
38128
  tailscale: false,
37766
38129
  tunnel: false,
37767
38130
  client: false,
@@ -37780,7 +38143,7 @@ function parseArgs(argv, env = process.env) {
37780
38143
  };
37781
38144
  try {
37782
38145
  if (arg === "--port") options.port = Number(value());
37783
- else if (arg === "--data-dir") options.dataDir = resolve11(value());
38146
+ else if (arg === "--data-dir") options.dataDir = resolve12(value());
37784
38147
  else if (arg === "--label") options.label = value();
37785
38148
  else if (arg === "--public-url") options.publicUrl = value().replace(/\/+$/, "");
37786
38149
  else if (arg === "--tailscale") options.tailscale = true;
@@ -37891,7 +38254,7 @@ function defaultIo() {
37891
38254
  }
37892
38255
  function serverVersion(here = HERE2) {
37893
38256
  try {
37894
- const parsed = JSON.parse(readFileSync20(resolve11(here, "..", "package.json"), "utf8"));
38257
+ const parsed = JSON.parse(readFileSync20(resolve12(here, "..", "package.json"), "utf8"));
37895
38258
  const version2 = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "version") : void 0;
37896
38259
  return typeof version2 === "string" && version2 ? version2 : "0.0.0";
37897
38260
  } catch {
@@ -37916,7 +38279,7 @@ async function isWorkspaceRunning(options) {
37916
38279
  try {
37917
38280
  const { status, body } = await api(options.port, "/api/health");
37918
38281
  if (status !== 200 || body?.app !== "openmausbot") return false;
37919
- const expected = readFileSync20(join32(options.dataDir, "environment-id"), "utf8").trim();
38282
+ const expected = readFileSync20(join33(options.dataDir, "environment-id"), "utf8").trim();
37920
38283
  const descriptor = await api(options.port, "/.well-known/openmausbot/environment");
37921
38284
  return /^[0-9a-f-]{36}$/i.test(expected) && descriptor.status === 200 && descriptor.body?.environmentId === expected;
37922
38285
  } catch {
@@ -38116,7 +38479,7 @@ async function runStatus(options, io = defaultIo()) {
38116
38479
  return code;
38117
38480
  }
38118
38481
  async function runAccess(options, io = defaultIo()) {
38119
- const file2 = join32(options.dataDir, "config.json");
38482
+ const file2 = join33(options.dataDir, "config.json");
38120
38483
  let raw = {};
38121
38484
  if (existsSync16(file2)) {
38122
38485
  try {
@@ -38268,16 +38631,16 @@ async function runBrowser(options, io = defaultIo()) {
38268
38631
  return 0;
38269
38632
  }
38270
38633
  function serverEntry(here = HERE2) {
38271
- const bundled = join32(here, "index.js");
38272
- const root = resolve11(here, "..");
38634
+ const bundled = join33(here, "index.js");
38635
+ const root = resolve12(here, "..");
38273
38636
  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;
38637
+ const staticDir2 = [join33(root, "dist"), join33(here, "..", "ui")].find((d) => existsSync16(join33(d, "index.html"))) ?? null;
38638
+ const skillsDir = existsSync16(join33(root, "skills")) ? join33(root, "skills") : null;
38276
38639
  return { command: process.execPath, args: [bundled], staticDir: staticDir2, skillsDir };
38277
38640
  }
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 };
38641
+ const source = join33(here, "index.ts");
38642
+ const staticDir = existsSync16(join33(root, "dist", "index.html")) ? join33(root, "dist") : null;
38643
+ return { command: process.execPath, args: ["--experimental-strip-types", source], staticDir, skillsDir: existsSync16(join33(root, "skills")) ? join33(root, "skills") : null };
38281
38644
  }
38282
38645
  async function planTunnel(options, log) {
38283
38646
  let access2 = null;
@@ -38377,9 +38740,9 @@ async function runServe(options, log = console.log) {
38377
38740
  let child;
38378
38741
  try {
38379
38742
  if (options.guided) {
38380
- const logsDir = join32(options.dataDir, "logs");
38743
+ const logsDir = join33(options.dataDir, "logs");
38381
38744
  mkdirSync14(logsDir, { recursive: true, mode: 448 });
38382
- logPath = join32(logsDir, `server-${Date.now()}-${process.pid}.log`);
38745
+ logPath = join33(logsDir, `server-${Date.now()}-${process.pid}.log`);
38383
38746
  logFd = openSync3(logPath, "wx", 384);
38384
38747
  log("\nStarting your workspace\u2026");
38385
38748
  }
@@ -38571,7 +38934,7 @@ async function runOnboardingCommand(options, io = defaultIo(), startServer = run
38571
38934
  }
38572
38935
  if (options.command === "setup") {
38573
38936
  io.log("\nAll set. Start with: openmausbot (or npx openmausbot without a global install).");
38574
- if (options.dataDir !== join32(homedir23(), ".openmausbot") || options.port !== 8799) {
38937
+ if (options.dataDir !== join33(homedir24(), ".openmausbot") || options.port !== 8799) {
38575
38938
  io.log(`Use the same --data-dir (${options.dataDir}) and --port (${options.port}) options when starting.`);
38576
38939
  }
38577
38940
  return 0;