openmausbot 0.1.70 → 0.1.71

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 (56) hide show
  1. package/dist/assets/{index-D1RGhLUK.js → index-CJtyBonr.js} +1 -1
  2. package/dist/assets/index-CYLdYtYp.css +1 -0
  3. package/dist/assets/index-Di4ovwu5.js +289 -0
  4. package/dist/index.html +2 -2
  5. package/dist-server/container-mcp.js +4 -2
  6. package/dist-server/drivers/agents-proxy.js +202 -16
  7. package/dist-server/drivers/pi-mcp-extension.ts +1 -1
  8. package/dist-server/index.js +2258 -834
  9. package/dist-server/local-computer.js +2 -1
  10. package/dist-server/mcp-gate.js +543 -0
  11. package/dist-server/mcp-server.js +38 -0
  12. package/dist-server/openmausbot.js +416 -130
  13. package/dist-server/pair-cli.js +416 -130
  14. package/dist-server/proxy-paths.js +1 -0
  15. package/dist-server/server/agent-tool-policy.js +29 -0
  16. package/dist-server/server/bot-package.js +55 -2
  17. package/dist-server/server/browser-live.js +12 -7
  18. package/dist-server/server/config.js +40 -4
  19. package/dist-server/server/drivers/acp/core.js +2 -0
  20. package/dist-server/server/drivers/acp/cursor.js +1 -1
  21. package/dist-server/server/drivers/acp/grok.js +5 -1
  22. package/dist-server/server/drivers/agents-proxy.js +195 -16
  23. package/dist-server/server/drivers/boxagent.js +1 -1
  24. package/dist-server/server/drivers/claude.js +288 -17
  25. package/dist-server/server/drivers/codex.js +13 -4
  26. package/dist-server/server/drivers/pi.js +1 -1
  27. package/dist-server/server/harness/bus.js +1 -1
  28. package/dist-server/server/index.js +520 -193
  29. package/dist-server/server/local-computer.js +1 -1
  30. package/dist-server/server/mcp-gate-config.js +56 -0
  31. package/dist-server/server/mcp-gate.js +227 -0
  32. package/dist-server/server/mcp-trim.js +182 -0
  33. package/dist-server/server/memory-journal.js +440 -0
  34. package/dist-server/server/memory-store.js +308 -0
  35. package/dist-server/server/message-db.js +90 -3
  36. package/dist-server/server/package-export.js +25 -0
  37. package/dist-server/server/peer-approval.js +1 -1
  38. package/dist-server/server/proxy-paths.js +1 -0
  39. package/dist-server/server/redact.js +15 -0
  40. package/dist-server/server/resume-recovery.js +46 -0
  41. package/dist-server/server/screen-frame-gate.js +9 -6
  42. package/dist-server/server/skill-library.js +5 -5
  43. package/dist-server/server/store.js +7 -3
  44. package/dist-server/server/system-prompt.js +13 -1
  45. package/dist-server/server/team-backup.js +35 -0
  46. package/dist-server/server/tool-summary.js +39 -0
  47. package/dist-server/server/tts/speech-text.js +3 -1
  48. package/dist-server/server/turn-context.js +18 -0
  49. package/dist-server/server/workspace.js +321 -22
  50. package/dist-server/shared/approval-mode.js +1 -1
  51. package/dist-server/shared/team-backup.js +13 -2
  52. package/dist-server/vps-container-mcp.js +4 -2
  53. package/package.json +1 -1
  54. package/skills/create-verification-skill/SKILL.md +2 -3
  55. package/dist/assets/index-B2F__IRS.css +0 -1
  56. package/dist/assets/index-CLj3t5Ba.js +0 -280
@@ -1181,7 +1181,7 @@ var init_dist = __esm({
1181
1181
  MODIFIER_RE = new RegExp("\\p{M}+", "gu");
1182
1182
  NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
1183
1183
  getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
1184
- const LIMIT = truncationOptions.limit ?? Infinity;
1184
+ const LIMIT2 = truncationOptions.limit ?? Infinity;
1185
1185
  const ELLIPSIS = truncationOptions.ellipsis ?? "";
1186
1186
  const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
1187
1187
  const ANSI_WIDTH = 0;
@@ -1205,7 +1205,7 @@ var init_dist = __esm({
1205
1205
  let lengthExtra = 0;
1206
1206
  let truncationEnabled = false;
1207
1207
  let truncationIndex = length;
1208
- let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
1208
+ let truncationLimit = Math.max(0, LIMIT2 - ELLIPSIS_WIDTH);
1209
1209
  let unmatchedStart = 0;
1210
1210
  let unmatchedEnd = 0;
1211
1211
  let width = 0;
@@ -1226,7 +1226,7 @@ var init_dist = __esm({
1226
1226
  if (width + widthExtra > truncationLimit) {
1227
1227
  truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
1228
1228
  }
1229
- if (width + widthExtra > LIMIT) {
1229
+ if (width + widthExtra > LIMIT2) {
1230
1230
  truncationEnabled = true;
1231
1231
  break outer;
1232
1232
  }
@@ -1247,7 +1247,7 @@ var init_dist = __esm({
1247
1247
  if (width + widthExtra > truncationLimit) {
1248
1248
  truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
1249
1249
  }
1250
- if (width + widthExtra > LIMIT) {
1250
+ if (width + widthExtra > LIMIT2) {
1251
1251
  truncationEnabled = true;
1252
1252
  break outer;
1253
1253
  }
@@ -1264,7 +1264,7 @@ var init_dist = __esm({
1264
1264
  width: truncationEnabled ? truncationLimit : width,
1265
1265
  index: truncationEnabled ? truncationIndex : length,
1266
1266
  truncated: truncationEnabled,
1267
- ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
1267
+ ellipsed: truncationEnabled && LIMIT2 >= ELLIPSIS_WIDTH
1268
1268
  };
1269
1269
  };
1270
1270
  dist_default = getStringTruncatedWidth;
@@ -17964,8 +17964,9 @@ var init_config = __esm({
17964
17964
  });
17965
17965
  });
17966
17966
  featureConfigSchema = external_exports.object({
17967
- /** Experimental desktop workflow recorder. Hidden unless explicitly enabled. */
17968
- skillRecorder: external_exports.boolean().optional(),
17967
+ /** Bots may draft skills (skill_manage, /learn) for your review. Off unless
17968
+ * explicitly enabled. */
17969
+ skillAuthoring: external_exports.boolean().optional(),
17969
17970
  /** Show each tool run in the transcript. Off unless explicitly enabled. */
17970
17971
  showToolCalls: external_exports.boolean().optional(),
17971
17972
  /** Experimental built-in browser. Off until explicitly enabled; each bot
@@ -19437,6 +19438,7 @@ var init_proxy_paths = __esm({
19437
19438
  agents: resolveProxy("drivers/agents-proxy"),
19438
19439
  dweb: resolveProxy("drivers/dweb-proxy"),
19439
19440
  connectors: resolveProxy("connector-proxy"),
19441
+ mcpGate: resolveProxy("mcp-gate"),
19440
19442
  phone: resolveProxy("drivers/phone-proxy"),
19441
19443
  // Loaded by the external `pi` process via `-e`, not by this server — but
19442
19444
  // resolved through the same single source of truth so the packaged layout
@@ -19506,6 +19508,9 @@ ${close}`);
19506
19508
  for (const re of KEY_PREFIXES) out = out.replace(re, (m) => mask(m));
19507
19509
  out = out.replace(BEARER, (_m, lead, tok) => `${lead}${mask(tok)}`);
19508
19510
  out = out.replace(KEY_VALUE, (_m, key, sep, quote, value) => `${key}${sep}${quote}${mask(value)}${quote}`);
19511
+ out = out.replace(KEY_SUFFIX_ASSIGNMENT, (_m, key, sep, quote, value) => `${key}${sep}${quote}${mask(value)}${quote}`);
19512
+ out = out.replace(SECRET_FLAG, (_m, flag, quote, value) => `${flag}${quote}${mask(value)}${quote}`);
19513
+ out = out.replace(URL_USERINFO, (_m, lead, secret, at) => `${lead}${mask(secret)}${at}`);
19509
19514
  return out;
19510
19515
  }
19511
19516
  function redactSecrets(input, depth = 0) {
@@ -19530,7 +19535,7 @@ function redactSecrets(input, depth = 0) {
19530
19535
  }
19531
19536
  return out;
19532
19537
  }
19533
- var SECRET_KEY_PARTS, REDACTION_MARKER, mask, KEY_PREFIXES, BEARER, PEM_BLOCK, KEY_VALUE;
19538
+ var SECRET_KEY_PARTS, REDACTION_MARKER, mask, KEY_PREFIXES, BEARER, PEM_BLOCK, KEY_VALUE, KEY_SUFFIX_ASSIGNMENT, SECRET_FLAG, URL_USERINFO;
19534
19539
  var init_redact = __esm({
19535
19540
  "server/redact.ts"() {
19536
19541
  "use strict";
@@ -19540,6 +19545,12 @@ var init_redact = __esm({
19540
19545
  KEY_PREFIXES = [
19541
19546
  /\bsk-(?:ant-|proj-|live-|test-)?[A-Za-z0-9_-]{16,}/g,
19542
19547
  // anthropic / openai / stripe
19548
+ /\bxai-[A-Za-z0-9_-]{20,}/g,
19549
+ // xai (grok)
19550
+ /\bgsk_[A-Za-z0-9]{40,}/g,
19551
+ // groq
19552
+ /\bhf_[A-Za-z0-9]{30,}/g,
19553
+ // hugging face
19543
19554
  /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}/g,
19544
19555
  // github classic
19545
19556
  /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
@@ -19558,6 +19569,9 @@ var init_redact = __esm({
19558
19569
  BEARER = /(\bBearer\s+)([A-Za-z0-9._~+/=-]{12,})/g;
19559
19570
  PEM_BLOCK = /(-----BEGIN [A-Z ]*PRIVATE KEY-----)([\s\S]*?)(-----END [A-Z ]*PRIVATE KEY-----)/g;
19560
19571
  KEY_VALUE = /\b((?:[A-Za-z0-9_-]*_)?(?:api[_-]?key|apikey|secret|token|password|passwd|authorization|auth[_-]?token|access[_-]?key|private[_-]?key)s?)(["']?\s*[=:]\s*)(["']?)([A-Za-z0-9._~+/=-]{8,})\3/gi;
19572
+ KEY_SUFFIX_ASSIGNMENT = /\b([A-Za-z][A-Za-z0-9_-]*[_-]key)s?(=)(["']?)([A-Za-z0-9._~+/=-]+)\3/gi;
19573
+ SECRET_FLAG = /(--(?:token|password|passwd|api-key|apikey|secret|access-key|auth-token)(?:=|\s+))(["']?)(?!-)([A-Za-z0-9._~+/=-]+)\2/gi;
19574
+ URL_USERINFO = /(\b[a-z][a-z0-9+.-]*:\/\/[^\s/:@'"]+:)([^\s/@'"«»]+)(@)/gi;
19561
19575
  }
19562
19576
  });
19563
19577
 
@@ -19582,6 +19596,36 @@ var init_native = __esm({
19582
19596
  }
19583
19597
  });
19584
19598
 
19599
+ // server/tool-summary.ts
19600
+ function fieldsOf(input) {
19601
+ if (input === null || typeof input !== "object" || Array.isArray(input)) return void 0;
19602
+ return input;
19603
+ }
19604
+ function commandSummary(input) {
19605
+ const command = fieldsOf(input)?.command;
19606
+ if (typeof command !== "string") return void 0;
19607
+ return cut(command.replace(/\s*[\r\n]+\s*/g, " "), LIMIT);
19608
+ }
19609
+ function askInputSummary(input) {
19610
+ const fields = fieldsOf(input);
19611
+ if (!fields) return void 0;
19612
+ if (typeof fields.question === "string") return cut(fields.question, QUESTION_LIMIT);
19613
+ if (typeof fields.command === "string") return cut(fields.command, LIMIT);
19614
+ if (typeof fields.url === "string") return cut(fields.url, LIMIT);
19615
+ const text2 = JSON.stringify(fields);
19616
+ return text2 === "{}" ? void 0 : cut(text2, LIMIT);
19617
+ }
19618
+ var QUESTION_LIMIT, LIMIT, cut;
19619
+ var init_tool_summary = __esm({
19620
+ "server/tool-summary.ts"() {
19621
+ "use strict";
19622
+ init_redact();
19623
+ QUESTION_LIMIT = 300;
19624
+ LIMIT = 200;
19625
+ cut = (text2, limit) => redactSecretsInText(text2).trim().slice(0, limit);
19626
+ }
19627
+ });
19628
+
19585
19629
  // server/drivers/acp/core.ts
19586
19630
  import { homedir as homedir7 } from "node:os";
19587
19631
  import { lstat, mkdir, readFile, realpath, stat, writeFile } from "node:fs/promises";
@@ -20026,7 +20070,8 @@ function createAcpDriver(support11) {
20026
20070
  type: "item.started",
20027
20071
  itemType: "tool",
20028
20072
  itemId: u4.toolCallId,
20029
- title: String(u4.rawInput?.command ?? u4.title ?? "tool").slice(0, 80)
20073
+ title: String(u4.rawInput?.command ?? u4.title ?? "tool").slice(0, 80),
20074
+ summary: commandSummary(u4.rawInput)
20030
20075
  });
20031
20076
  break;
20032
20077
  }
@@ -20336,6 +20381,7 @@ var init_core3 = __esm({
20336
20381
  init_env_path();
20337
20382
  init_approval_mode();
20338
20383
  init_native();
20384
+ init_tool_summary();
20339
20385
  init_proxy_paths();
20340
20386
  COMPUTER_PROXY_PATH = SPAWNED_PROXIES.computer;
20341
20387
  envOr = (key, fallback) => Number(process.env[key] ?? fallback);
@@ -21480,7 +21526,7 @@ var init_boxagent = __esm({
21480
21526
  const listeners = /* @__PURE__ */ new Set();
21481
21527
  const active = /* @__PURE__ */ new Map();
21482
21528
  const emit = (event) => {
21483
- for (const l of [...listeners]) l(event);
21529
+ for (const l of Array.from(listeners)) l(event);
21484
21530
  };
21485
21531
  const base2 = (threadId, turnId) => ({
21486
21532
  eventId: newEventId(),
@@ -21670,6 +21716,27 @@ var init_boxagent = __esm({
21670
21716
  }
21671
21717
  });
21672
21718
 
21719
+ // server/resume-recovery.ts
21720
+ function classifyResumeFailure(state) {
21721
+ if (state.producedOutput || state.promptSubmitted) return "after-accept";
21722
+ if (state.attempted && state.rejected) return "before-accept";
21723
+ return "unknown";
21724
+ }
21725
+ function mayReplay(failure) {
21726
+ return failure === "before-accept";
21727
+ }
21728
+ function recoveryPromptFor(input) {
21729
+ if (!mayReplay(input.failure)) return { text: input.currentText, replayed: false };
21730
+ const replay = input.recoveryText?.trim();
21731
+ if (!replay || replay === input.currentText.trim()) return { text: input.currentText, replayed: false };
21732
+ return { text: replay, replayed: true };
21733
+ }
21734
+ var init_resume_recovery = __esm({
21735
+ "server/resume-recovery.ts"() {
21736
+ "use strict";
21737
+ }
21738
+ });
21739
+
21673
21740
  // server/drivers/claude-login-auth.ts
21674
21741
  import { randomUUID as randomUUID8 } from "node:crypto";
21675
21742
  import { realpathSync } from "node:fs";
@@ -22040,6 +22107,53 @@ var init_claude_login_auth = __esm({
22040
22107
  }
22041
22108
  });
22042
22109
 
22110
+ // server/mcp-trim.ts
22111
+ var DEFAULT_RESULT_BUDGET;
22112
+ var init_mcp_trim = __esm({
22113
+ "server/mcp-trim.ts"() {
22114
+ "use strict";
22115
+ DEFAULT_RESULT_BUDGET = 8e3;
22116
+ }
22117
+ });
22118
+
22119
+ // server/mcp-gate-config.ts
22120
+ import { join as join17 } from "node:path";
22121
+ function resultBudget(env = process.env) {
22122
+ const raw = env.OMB_MCP_RESULT_BUDGET;
22123
+ if (raw === void 0 || raw === "") return DEFAULT_RESULT_BUDGET;
22124
+ const parsed = Number(raw);
22125
+ return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : DEFAULT_RESULT_BUDGET;
22126
+ }
22127
+ function spillDir(threadId) {
22128
+ return join17(DATA_DIR, "tool-results", threadId.replace(/[^A-Za-z0-9_-]/g, "-").slice(0, 80) || "thread");
22129
+ }
22130
+ function gateServer(input) {
22131
+ const { name, server, budget } = input;
22132
+ if (budget <= 0) return null;
22133
+ if (!server || typeof server !== "object" || Array.isArray(server)) return null;
22134
+ const spec = server;
22135
+ if (typeof spec.command !== "string" || !spec.command) return null;
22136
+ return {
22137
+ command: input.execPath ?? process.execPath,
22138
+ args: [SPAWNED_PROXIES.mcpGate],
22139
+ env: {
22140
+ ...input.nodeEnv,
22141
+ OMB_GATE_NAME: name,
22142
+ OMB_GATE_UPSTREAM: JSON.stringify({ command: spec.command, args: spec.args ?? [], env: spec.env ?? {} }),
22143
+ OMB_GATE_SPILL_DIR: spillDir(input.threadId),
22144
+ OMB_GATE_BUDGET: String(budget)
22145
+ }
22146
+ };
22147
+ }
22148
+ var init_mcp_gate_config = __esm({
22149
+ "server/mcp-gate-config.ts"() {
22150
+ "use strict";
22151
+ init_config();
22152
+ init_mcp_trim();
22153
+ init_proxy_paths();
22154
+ }
22155
+ });
22156
+
22043
22157
  // server/drivers/retry.ts
22044
22158
  function classifyError(err) {
22045
22159
  const text2 = messageOf(err);
@@ -22128,7 +22242,7 @@ import { createHash as createHash5, randomBytes as randomBytes2 } from "node:cry
22128
22242
  import { chmodSync as chmodSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
22129
22243
  import { createServer as createNetServer } from "node:net";
22130
22244
  import { homedir as homedir9, tmpdir as tmpdir3 } from "node:os";
22131
- import { join as join17, dirname as dirname8, isAbsolute as isAbsolute4, normalize } from "node:path";
22245
+ import { join as join18, dirname as dirname8, isAbsolute as isAbsolute4, normalize } from "node:path";
22132
22246
  function claudeAuthStatus(cli, env, run3 = execCli) {
22133
22247
  return new Promise((resolve13) => {
22134
22248
  run3(cli, ["auth", "status", "--json"], { timeout: 8e3, maxBuffer: 65536, env }, (_error, stdout2) => {
@@ -22154,8 +22268,8 @@ function claudeAuthStatus(cli, env, run3 = execCli) {
22154
22268
  }
22155
22269
  function resolveClaudeConfigDir(configDir, env = process.env) {
22156
22270
  const home = env.HOME || env.USERPROFILE || homedir9();
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;
22271
+ const configured = configDir?.trim() || env.CLAUDE_CONFIG_DIR?.trim() || join18(home, ".claude");
22272
+ const expanded = configured === "~" ? home : configured.startsWith("~/") ? join18(home, configured.slice(2)) : configured;
22159
22273
  if (!isAbsolute4(expanded) || /[\p{Cc}\p{Cf}]/u.test(expanded)) {
22160
22274
  throw new Error("claude: configDir must be an absolute path or start with ~/");
22161
22275
  }
@@ -22184,6 +22298,57 @@ function claudeEnvironment(model, source = process.env, configDir, instanceEnvir
22184
22298
  if (!applied.injected) delete env.ANTHROPIC_API_KEY;
22185
22299
  return env;
22186
22300
  }
22301
+ function inheritsUserConfig(env) {
22302
+ return env.OMB_CLAUDE_INHERIT_USER_CONFIG === "1";
22303
+ }
22304
+ function projectMcpServers(cwd) {
22305
+ let parsed;
22306
+ try {
22307
+ parsed = JSON.parse(readFileSync6(join18(cwd, ".mcp.json"), "utf8"));
22308
+ } catch {
22309
+ return {};
22310
+ }
22311
+ const servers = parsed?.mcpServers;
22312
+ if (!servers || typeof servers !== "object" || Array.isArray(servers)) return {};
22313
+ const out = {};
22314
+ for (const [name, server] of Object.entries(servers)) {
22315
+ if (server && typeof server === "object" && !Array.isArray(server)) out[name] = server;
22316
+ }
22317
+ return out;
22318
+ }
22319
+ function autoCompactWindow(env) {
22320
+ const raw = (env.OMB_CLAUDE_AUTOCOMPACT ?? "").trim().toLowerCase();
22321
+ if (raw === "off") return null;
22322
+ if (raw === "auto") return "auto";
22323
+ const parsed = raw ? Number(raw) : DEFAULT_AUTOCOMPACT_TOKENS;
22324
+ if (!Number.isFinite(parsed) || parsed <= 0) return String(DEFAULT_AUTOCOMPACT_TOKENS);
22325
+ return String(Math.min(1e6, Math.max(1e5, Math.floor(parsed))));
22326
+ }
22327
+ function parseClaudeCliVersion(stdout2) {
22328
+ const match = /(\d+)\.(\d+)\.(\d+)/.exec(stdout2 ?? "");
22329
+ if (!match) return null;
22330
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
22331
+ }
22332
+ function versionAtLeast(installed, floor) {
22333
+ for (let i2 = 0; i2 < 3; i2 += 1) {
22334
+ if (installed[i2] !== floor[i2]) return installed[i2] > floor[i2];
22335
+ }
22336
+ return true;
22337
+ }
22338
+ function claudeCliSupports(version2, flag) {
22339
+ return version2 === null || versionAtLeast(version2, CLAUDE_FLAG_FLOORS[flag]);
22340
+ }
22341
+ function claudeCliUpdate(version2, cli) {
22342
+ const parsed = parseClaudeCliVersion(version2);
22343
+ if (!parsed || versionAtLeast(parsed, CLAUDE_CONTEXT_CONTROL_MIN_VERSION)) return void 0;
22344
+ const floor = CLAUDE_CONTEXT_CONTROL_MIN_VERSION.join(".");
22345
+ const missing = Object.keys(CLAUDE_FLAG_FLOORS).filter((flag) => !claudeCliSupports(parsed, flag));
22346
+ return {
22347
+ title: "Update Claude Code for context controls",
22348
+ message: `Claude Code ${parsed.join(".")} predates ${floor}, so bots run without ${missing.join(", ")}: no compaction window picked by OpenMausBot` + (missing.includes("--setting-sources") ? ", and bots still see this machine's own Claude Code setup" : "") + ". Update it, then refresh Engines.",
22349
+ command: cli === "claude" ? "claude update" : `${cli} update`
22350
+ };
22351
+ }
22187
22352
  async function resolveClaudeTurnModel(model, env) {
22188
22353
  if (!model || decodeInjectId(model) || STATIC_CLAUDE_MODELS.options.some((option) => option.id === model)) {
22189
22354
  return model;
@@ -22207,7 +22372,7 @@ function extrasFromUnknown(value) {
22207
22372
  function readClaudeModelCatalog(env = process.env) {
22208
22373
  let settings2 = {};
22209
22374
  try {
22210
- settings2 = JSON.parse(readFileSync6(join17(resolveClaudeConfigDir(void 0, env), "settings.json"), "utf8"));
22375
+ settings2 = JSON.parse(readFileSync6(join18(resolveClaudeConfigDir(void 0, env), "settings.json"), "utf8"));
22211
22376
  } catch {
22212
22377
  return STATIC_CLAUDE_MODELS;
22213
22378
  }
@@ -22241,12 +22406,7 @@ function systemEndedReply(kind) {
22241
22406
  return kind === "question" ? { behavior: "answer", message: "OpenMausBot: the turn is ending \u2014 wrap up." } : { behavior: "deny", message: "OpenMausBot: the turn ended" };
22242
22407
  }
22243
22408
  function askSummary(ask) {
22244
- const input = ask.input ?? {};
22245
- if (typeof input.question === "string") return input.question.slice(0, 300);
22246
- if (typeof input.command === "string") return input.command.slice(0, 200);
22247
- if (typeof input.url === "string") return input.url.slice(0, 200);
22248
- const text2 = JSON.stringify(input);
22249
- return text2 === "{}" ? ask.tool ?? "tool" : text2.slice(0, 200);
22409
+ return askInputSummary(ask.input) ?? ask.tool ?? "tool";
22250
22410
  }
22251
22411
  function permissionSocketPath(threadId) {
22252
22412
  const prefix = threadId.replace(/[^\w-]/g, "").slice(0, 4);
@@ -22257,7 +22417,7 @@ function brokerSocketCandidates(threadId) {
22257
22417
  const base2 = permissionSocketPath(threadId);
22258
22418
  if (process.platform !== "win32") {
22259
22419
  const scope = createHash5("sha256").update(`${DATA_DIR}\0${process.pid}\0${threadId}`).digest("hex").slice(0, 16);
22260
- return [base2, join17(tmpdir3(), `omb-perm-${scope}.sock`)];
22420
+ return [base2, join18(tmpdir3(), `omb-perm-${scope}.sock`)];
22261
22421
  }
22262
22422
  return [
22263
22423
  base2,
@@ -22380,7 +22540,7 @@ async function createPermissionBroker(opts) {
22380
22540
  }
22381
22541
  if (!server) throw new Error("claude: permission broker could not bind a local socket");
22382
22542
  const drain = () => {
22383
- for (const p of [...pending.values()]) {
22543
+ for (const p of Array.from(pending.values())) {
22384
22544
  const { behavior, message: message2 } = systemEndedReply(p.ask.kind);
22385
22545
  p.finish(behavior, message2, "system");
22386
22546
  }
@@ -22455,6 +22615,17 @@ function firstText(content) {
22455
22615
  }
22456
22616
  return "";
22457
22617
  }
22618
+ function withVolatileNote(text2, volatile) {
22619
+ const body = volatile.trim() ? `This part of your instructions changed since this session started. It replaces the earlier copy:
22620
+
22621
+ ${volatile.trim()}` : "The notes that were in your instructions when this session started have been cleared.";
22622
+ const note = `<system-reminder>
22623
+ ${body}
22624
+ </system-reminder>`;
22625
+ return text2 ? `${note}
22626
+
22627
+ ${text2}` : note;
22628
+ }
22458
22629
  function claudeUserMessage(text2, images) {
22459
22630
  if (!images?.length) return { type: "user", message: { role: "user", content: text2 } };
22460
22631
  const content = images.map((image) => ({
@@ -22486,16 +22657,19 @@ function diagnosticClaudeUserMessage(message2) {
22486
22657
  }
22487
22658
  };
22488
22659
  }
22489
- var CLAUDE_ACCOUNT_ENV_KEYS, DRIVER_KIND2, STATIC_CLAUDE_MODELS, CLAUDE_MODEL_ID, PROXY_PATH, PERM_PROXY_PATH, DWEB_PROXY_PATH, NODE_ENV_FLAG, DENY_TIMEOUT_NOTE, QUESTION_TIMEOUT_NOTE, DUPLICATE_ASK_ID_NOTE, ClaudeDriver;
22660
+ var CLAUDE_ACCOUNT_ENV_KEYS, DEFAULT_AUTOCOMPACT_TOKENS, CLAUDE_FLAG_FLOORS, CLAUDE_CONTEXT_CONTROL_MIN_VERSION, DRIVER_KIND2, STATIC_CLAUDE_MODELS, CLAUDE_MODEL_ID, PROXY_PATH, PERM_PROXY_PATH, DWEB_PROXY_PATH, NODE_ENV_FLAG, DENY_TIMEOUT_NOTE, QUESTION_TIMEOUT_NOTE, DUPLICATE_ASK_ID_NOTE, ClaudeDriver;
22490
22661
  var init_claude = __esm({
22491
22662
  "server/drivers/claude.ts"() {
22492
22663
  "use strict";
22493
22664
  init_config();
22494
22665
  init_env_path();
22495
22666
  init_procs();
22667
+ init_resume_recovery();
22496
22668
  init_claude_login_auth();
22497
22669
  init_container_computer();
22670
+ init_mcp_gate_config();
22498
22671
  init_contracts();
22672
+ init_tool_summary();
22499
22673
  init_retry();
22500
22674
  init_local_inject();
22501
22675
  init_native();
@@ -22514,6 +22688,13 @@ var init_claude = __esm({
22514
22688
  "CLAUDE_CODE_USE_VERTEX",
22515
22689
  "CLAUDE_CODE_USE_FOUNDRY"
22516
22690
  ];
22691
+ DEFAULT_AUTOCOMPACT_TOKENS = 2e5;
22692
+ CLAUDE_FLAG_FLOORS = {
22693
+ "--strict-mcp-config": [1, 0, 60],
22694
+ "--setting-sources": [1, 0, 122],
22695
+ "--autocompact": [2, 1, 122]
22696
+ };
22697
+ CLAUDE_CONTEXT_CONTROL_MIN_VERSION = CLAUDE_FLAG_FLOORS["--autocompact"];
22517
22698
  DRIVER_KIND2 = "claudeAgent";
22518
22699
  STATIC_CLAUDE_MODELS = {
22519
22700
  default: "claude-sonnet-5",
@@ -22564,6 +22745,7 @@ var init_claude = __esm({
22564
22745
  }
22565
22746
  };
22566
22747
  await refreshModels();
22748
+ let cliVersion = null;
22567
22749
  const listeners = /* @__PURE__ */ new Set();
22568
22750
  const active = /* @__PURE__ */ new Map();
22569
22751
  const sessions = /* @__PURE__ */ new Map();
@@ -22614,7 +22796,7 @@ var init_claude = __esm({
22614
22796
  });
22615
22797
  };
22616
22798
  const emit = (event) => {
22617
- for (const l of [...listeners]) l(event);
22799
+ for (const l of Array.from(listeners)) l(event);
22618
22800
  };
22619
22801
  const base2 = (threadId, turnId) => ({
22620
22802
  eventId: newEventId(),
@@ -22660,6 +22842,15 @@ var init_claude = __esm({
22660
22842
  args.push("--disallowedTools", config2.disallowedTools.join(","));
22661
22843
  }
22662
22844
  const turnEnvironment = environment();
22845
+ const isolated = !inheritsUserConfig(turnEnvironment);
22846
+ if (isolated) {
22847
+ if (claudeCliSupports(cliVersion, "--strict-mcp-config")) args.push("--strict-mcp-config");
22848
+ if (claudeCliSupports(cliVersion, "--setting-sources")) args.push("--setting-sources", "project");
22849
+ }
22850
+ const compactWindow = autoCompactWindow(turnEnvironment);
22851
+ if (compactWindow && claudeCliSupports(cliVersion, "--autocompact")) {
22852
+ args.push("--autocompact", compactWindow);
22853
+ }
22663
22854
  const turnModel = await resolveClaudeTurnModel(turn.model, turnEnvironment);
22664
22855
  const injected = applyClaudeInject({ ...turnEnvironment }, turnModel);
22665
22856
  if (injected.model) args.push("--model", injected.model);
@@ -22710,9 +22901,23 @@ var init_claude = __esm({
22710
22901
  };
22711
22902
  allowed.push("mcp__dweb");
22712
22903
  }
22904
+ const botOwned = /* @__PURE__ */ new Set();
22713
22905
  for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
22714
22906
  if (name in mcpServers) continue;
22715
22907
  mcpServers[name] = { ...server };
22908
+ botOwned.add(name);
22909
+ }
22910
+ if (isolated && turn.cwd) {
22911
+ for (const [name, server] of Object.entries(projectMcpServers(turn.cwd))) {
22912
+ if (name in mcpServers) continue;
22913
+ mcpServers[name] = server;
22914
+ botOwned.add(name);
22915
+ }
22916
+ }
22917
+ const budget = resultBudget(turnEnvironment);
22918
+ for (const name of botOwned) {
22919
+ const gated = gateServer({ name, server: mcpServers[name], threadId, budget, nodeEnv: NODE_ENV_FLAG });
22920
+ if (gated) mcpServers[name] = gated;
22716
22921
  }
22717
22922
  let broker;
22718
22923
  const socketPath = permissionSocketPath(threadId);
@@ -22723,7 +22928,7 @@ var init_claude = __esm({
22723
22928
  allowed.push("mcp__ogb");
22724
22929
  let mcpConfigPath = null;
22725
22930
  if (Object.keys(mcpServers).length) {
22726
- mcpConfigPath = join17(mkdtempSync2(join17(tmpdir3(), "omb-mcp-")), "mcp.json");
22931
+ mcpConfigPath = join18(mkdtempSync2(join18(tmpdir3(), "omb-mcp-")), "mcp.json");
22727
22932
  args.push("--mcp-config", mcpConfigPath);
22728
22933
  args.push("--allowedTools", allowed.join(","));
22729
22934
  }
@@ -22734,7 +22939,9 @@ var init_claude = __esm({
22734
22939
  const keyArgs = args.filter((a2, i2) => !privateFileFlags.has(a2) && !privateFileFlags.has(args[i2 - 1] ?? ""));
22735
22940
  const argsKey = JSON.stringify({
22736
22941
  args: keyArgs,
22737
- system: turn.system ?? null,
22942
+ // the volatile half is deliberately absent: it must not respawn a
22943
+ // healthy session (see Session.volatile)
22944
+ system: turn.systemStable ?? turn.system ?? null,
22738
22945
  mcpServers,
22739
22946
  cwd,
22740
22947
  model: injected.model ?? null,
@@ -22750,7 +22957,10 @@ var init_claude = __esm({
22750
22957
  killCliTree(live.child);
22751
22958
  }, turnId, broker: live.broker });
22752
22959
  emit({ ...base2(threadId, turnId), type: "turn.started" });
22753
- const written = await writeUser(live, threadId, promptMsg);
22960
+ const volatile = turn.systemVolatile ?? "";
22961
+ const message2 = volatile === live.volatile ? promptMsg : claudeUserMessage(withVolatileNote(turn.text, volatile), turn.images);
22962
+ live.volatile = volatile;
22963
+ const written = await writeUser(live, threadId, message2);
22754
22964
  if (!written) {
22755
22965
  active.delete(threadId);
22756
22966
  live.turn = null;
@@ -22791,7 +23001,7 @@ var init_claude = __esm({
22791
23001
  };
22792
23002
  try {
22793
23003
  if (turn.system) {
22794
- systemPromptPath = join17(mkdtempSync2(join17(tmpdir3(), "omb-system-")), "prompt.txt");
23004
+ systemPromptPath = join18(mkdtempSync2(join18(tmpdir3(), "omb-system-")), "prompt.txt");
22795
23005
  writeFileSync5(systemPromptPath, turn.system, { mode: 384 });
22796
23006
  args.push("--append-system-prompt-file", systemPromptPath);
22797
23007
  }
@@ -22857,7 +23067,9 @@ var init_claude = __esm({
22857
23067
  mcpConfigPath,
22858
23068
  systemPromptPath,
22859
23069
  argsKey,
23070
+ volatile: turn.systemVolatile ?? "",
22860
23071
  sessionId: sessionId ?? newSessionId,
23072
+ sawInit: false,
22861
23073
  turn: { turnId, settled: false, sawStreamDelta: false },
22862
23074
  idleTimer: null,
22863
23075
  closing: false,
@@ -22897,6 +23109,7 @@ var init_claude = __esm({
22897
23109
  switch (o.type) {
22898
23110
  case "system":
22899
23111
  if (o.subtype === "init") {
23112
+ session.sawInit = true;
22900
23113
  if (typeof o.session_id === "string") session.sessionId = o.session_id;
22901
23114
  emit({ ...base2(threadId, currentTurnId()), type: "session.started", sessionId: o.session_id, model: o.model });
22902
23115
  } else if (o.subtype === "thinking_tokens") {
@@ -22933,7 +23146,14 @@ var init_claude = __esm({
22933
23146
  }
22934
23147
  for (const b of Array.isArray(msg.content) ? msg.content : []) {
22935
23148
  if (b.type === "tool_use") {
22936
- emit({ ...base2(threadId, currentTurnId()), type: "item.started", itemType: "tool", itemId: b.id, title: b.name });
23149
+ emit({
23150
+ ...base2(threadId, currentTurnId()),
23151
+ type: "item.started",
23152
+ itemType: "tool",
23153
+ itemId: b.id,
23154
+ title: b.name,
23155
+ summary: commandSummary(b.input)
23156
+ });
22937
23157
  }
22938
23158
  }
22939
23159
  if (msg.usage) {
@@ -23056,6 +23276,56 @@ var init_claude = __esm({
23056
23276
  })();
23057
23277
  return;
23058
23278
  }
23279
+ const resumeFailure = classifyResumeFailure({
23280
+ attempted: Boolean(sessionId),
23281
+ rejected: !session.sawInit,
23282
+ promptSubmitted: session.sawInit,
23283
+ producedOutput: session.turn.sawStreamDelta
23284
+ });
23285
+ if (mayReplay(resumeFailure) && !retry.cancelled) {
23286
+ const recovery = recoveryPromptFor({
23287
+ recoveryText: turn.recoveryText,
23288
+ currentText: turn.text,
23289
+ failure: resumeFailure
23290
+ });
23291
+ session.broker?.close();
23292
+ session.broker = void 0;
23293
+ if (session.mcpConfigPath) {
23294
+ try {
23295
+ rmSync2(dirname8(session.mcpConfigPath), { recursive: true, force: true });
23296
+ } catch {
23297
+ }
23298
+ session.mcpConfigPath = null;
23299
+ }
23300
+ if (session.systemPromptPath) {
23301
+ removePrivateTempDir(session.systemPromptPath);
23302
+ session.systemPromptPath = null;
23303
+ }
23304
+ sessions.delete(threadId);
23305
+ session.turn = null;
23306
+ active.delete(threadId);
23307
+ emit({
23308
+ ...base2(threadId, turnId),
23309
+ type: "turn.retrying",
23310
+ attempt: retry.attempt + 1,
23311
+ delayMs: 0,
23312
+ reason: "resume_rejected"
23313
+ });
23314
+ void (async () => {
23315
+ try {
23316
+ await sendTurn({ ...turn, resumeCursor: void 0, recoveryText: void 0, text: recovery.text });
23317
+ } catch (e) {
23318
+ retryState.delete(threadId);
23319
+ emit({
23320
+ ...base2(threadId, turnId),
23321
+ type: "runtime.error",
23322
+ message: e instanceof Error ? e.message : String(e)
23323
+ });
23324
+ emit({ ...base2(threadId, turnId), type: "turn.completed", ok: false, stopReason: "exit_before_result", cost: null });
23325
+ }
23326
+ })();
23327
+ return;
23328
+ }
23059
23329
  retryState.delete(threadId);
23060
23330
  emit({
23061
23331
  ...base2(threadId, currentTurnId()),
@@ -23108,8 +23378,10 @@ var init_claude = __esm({
23108
23378
  );
23109
23379
  });
23110
23380
  if (!version2) return { state: "unavailable", reason: `\`${config2.cli}\` CLI not found` };
23381
+ cliVersion = parseClaudeCliVersion(version2);
23111
23382
  const auth = await claudeAuthStatus(config2.cli, env);
23112
- return { state: "available", version: version2, ...auth, billing: "subscription" };
23383
+ const update = claudeCliUpdate(version2, config2.cli);
23384
+ return { state: "available", version: version2, ...auth, ...update ? { update } : {}, billing: "subscription" };
23113
23385
  };
23114
23386
  const generateReview = (prompt, signal) => new Promise((resolve13, reject) => {
23115
23387
  const child = spawnCli(
@@ -23209,7 +23481,7 @@ var init_claude = __esm({
23209
23481
  hasSession: (threadId) => active.has(threadId),
23210
23482
  stopAll: async () => {
23211
23483
  for (const { stop } of active.values()) stop();
23212
- for (const threadId of [...sessions.keys()]) closeSession(threadId, "stopAll");
23484
+ for (const threadId of Array.from(sessions.keys())) closeSession(threadId, "stopAll");
23213
23485
  },
23214
23486
  onEvent: (listener) => {
23215
23487
  listeners.add(listener);
@@ -23223,7 +23495,7 @@ var init_claude = __esm({
23223
23495
  await login.dispose();
23224
23496
  } finally {
23225
23497
  for (const { stop } of active.values()) stop();
23226
- for (const threadId of [...sessions.keys()]) closeSession(threadId, "dispose");
23498
+ for (const threadId of Array.from(sessions.keys())) closeSession(threadId, "dispose");
23227
23499
  listeners.clear();
23228
23500
  }
23229
23501
  }
@@ -23236,7 +23508,7 @@ var init_claude = __esm({
23236
23508
  // server/drivers/codex-catalog.ts
23237
23509
  import { readdirSync as readdirSync2, readFileSync as readFileSync7 } from "node:fs";
23238
23510
  import { homedir as homedir10 } from "node:os";
23239
- import { basename as basename5, join as join18 } from "node:path";
23511
+ import { basename as basename5, join as join19 } from "node:path";
23240
23512
  function encodeCodexSelection(provider, model) {
23241
23513
  return `${provider}${SEP}${model}`;
23242
23514
  }
@@ -23352,7 +23624,7 @@ function readCodexAppServerModelCatalog(cli, env, timeoutMs = 8e3) {
23352
23624
  }
23353
23625
  function codexHome(env) {
23354
23626
  if (env.CODEX_HOME) return env.CODEX_HOME;
23355
- return join18(env.HOME || env.USERPROFILE || homedir10(), ".codex");
23627
+ return join19(env.HOME || env.USERPROFILE || homedir10(), ".codex");
23356
23628
  }
23357
23629
  function unquote(raw) {
23358
23630
  let value = raw.trim();
@@ -23438,11 +23710,11 @@ function niceLabel(model, provider, known, named) {
23438
23710
  }
23439
23711
  function collectCatalogNames(home) {
23440
23712
  const named = /* @__PURE__ */ new Map();
23441
- for (const file2 of listDir(join18(home, "model-catalogs"))) {
23713
+ for (const file2 of listDir(join19(home, "model-catalogs"))) {
23442
23714
  if (!file2.endsWith(".json")) continue;
23443
23715
  const provider = basename5(file2, ".json").replace(/-models$/, "");
23444
23716
  if (!PROVIDER_ID.test(provider)) continue;
23445
- const raw = readText(join18(home, "model-catalogs", file2));
23717
+ const raw = readText(join19(home, "model-catalogs", file2));
23446
23718
  if (!raw) continue;
23447
23719
  let parsed;
23448
23720
  try {
@@ -23494,7 +23766,7 @@ async function probeProviderModels(provider, env, fetchImpl) {
23494
23766
  async function readCodexModelCatalog(env = process.env, fetchImpl = fetch, cli) {
23495
23767
  const official = (cli ? await readCodexAppServerModelCatalog(cli, env) : null) ?? STATIC_CODEX_MODELS;
23496
23768
  const home = codexHome(env);
23497
- const mainText = readText(join18(home, "config.toml"));
23769
+ const mainText = readText(join19(home, "config.toml"));
23498
23770
  if (!mainText) return mergeLocalInject(official, env, fetchImpl);
23499
23771
  const main2 = parseCodexToml(mainText);
23500
23772
  const known = new Map(main2.providers.map((provider) => [provider.id, provider]));
@@ -23509,7 +23781,7 @@ async function readCodexModelCatalog(env = process.env, fetchImpl = fetch, cli)
23509
23781
  remember(main2.modelProvider, main2.model);
23510
23782
  for (const file2 of listDir(home)) {
23511
23783
  if (!file2.endsWith(".config.toml")) continue;
23512
- const profile = parseCodexToml(readText(join18(home, file2)) ?? "");
23784
+ const profile = parseCodexToml(readText(join19(home, file2)) ?? "");
23513
23785
  for (const provider of profile.providers) {
23514
23786
  if (!known.has(provider.id)) known.set(provider.id, provider);
23515
23787
  }
@@ -23576,7 +23848,7 @@ var init_codex_catalog = __esm({
23576
23848
  // server/drivers/codex-instructions.ts
23577
23849
  import { createHash as createHash6 } from "node:crypto";
23578
23850
  import { mkdirSync as mkdirSync7, readFileSync as readFileSync8 } from "node:fs";
23579
- import { join as join19 } from "node:path";
23851
+ import { join as join20 } from "node:path";
23580
23852
  function codexDeveloperInstructions(config2, botInstructions) {
23581
23853
  if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) {
23582
23854
  throw new Error("Codex returned no effective configuration; cannot safely update bot instructions.");
@@ -23590,8 +23862,8 @@ function codexDeveloperInstructions(config2, botInstructions) {
23590
23862
  ${configured}` : botInstructions;
23591
23863
  }
23592
23864
  async function syncCodexInstructions(key, nativeThreadId, instructions, resumed, request) {
23593
- const directory = join19(DATA_DIR, "codex-instructions");
23594
- const path3 = join19(directory, `${digest(JSON.stringify([key, nativeThreadId]))}.sha256`);
23865
+ const directory = join20(DATA_DIR, "codex-instructions");
23866
+ const path3 = join20(directory, `${digest(JSON.stringify([key, nativeThreadId]))}.sha256`);
23595
23867
  const fingerprint = digest(instructions);
23596
23868
  let previous;
23597
23869
  try {
@@ -23638,14 +23910,14 @@ var init_codex_instructions = __esm({
23638
23910
  import { randomUUID as randomUUID9 } from "node:crypto";
23639
23911
  import { realpathSync as realpathSync2 } from "node:fs";
23640
23912
  import { homedir as homedir11 } from "node:os";
23641
- import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute5, join as join20, resolve as resolve8 } from "node:path";
23913
+ import { basename as basename6, dirname as dirname9, isAbsolute as isAbsolute5, join as join21, resolve as resolve8 } from "node:path";
23642
23914
  import { stripVTControlCharacters as stripVTControlCharacters5 } from "node:util";
23643
23915
  function canonicalPath2(path3) {
23644
23916
  try {
23645
23917
  return realpathSync2(path3);
23646
23918
  } catch {
23647
23919
  const parent = dirname9(path3);
23648
- return parent === path3 ? path3 : join20(canonicalPath2(parent), basename6(path3));
23920
+ return parent === path3 ? path3 : join21(canonicalPath2(parent), basename6(path3));
23649
23921
  }
23650
23922
  }
23651
23923
  function codexDevicePrompt(output) {
@@ -23696,7 +23968,7 @@ var init_codex_device_auth = __esm({
23696
23968
  if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
23697
23969
  throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing in.");
23698
23970
  }
23699
- const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join20(home, ".codex")));
23971
+ const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join21(home, ".codex")));
23700
23972
  if (authenticatingHomes2.has(homeKey)) {
23701
23973
  throw new Error("A ChatGPT sign-in is already running for this server account. Finish or cancel it before starting another.");
23702
23974
  }
@@ -23775,7 +24047,7 @@ var init_codex_device_auth = __esm({
23775
24047
  if (!isAbsolute5(home) || env.CODEX_HOME && !isAbsolute5(env.CODEX_HOME)) {
23776
24048
  throw new Error("Use an absolute HOME and CODEX_HOME path for this server's Codex provider before signing out.");
23777
24049
  }
23778
- const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join20(home, ".codex")));
24050
+ const homeKey = canonicalPath2(resolve8(env.CODEX_HOME || join21(home, ".codex")));
23779
24051
  if (authenticatingHomes2.has(homeKey)) {
23780
24052
  throw new Error("A ChatGPT sign-in is running for this server account. Finish or cancel it before signing out.");
23781
24053
  }
@@ -23934,11 +24206,11 @@ var init_codex_device_auth = __esm({
23934
24206
 
23935
24207
  // server/drivers/codex-identity.ts
23936
24208
  import { homedir as homedir12 } from "node:os";
23937
- import { isAbsolute as isAbsolute6, join as join21, resolve as resolve9 } from "node:path";
24209
+ import { isAbsolute as isAbsolute6, join as join22, resolve as resolve9 } from "node:path";
23938
24210
  function codexHome2(env) {
23939
24211
  if (env.CODEX_HOME) return isAbsolute6(env.CODEX_HOME) ? resolve9(env.CODEX_HOME) : null;
23940
24212
  const home = env.HOME || env.USERPROFILE || homedir12();
23941
- return isAbsolute6(home) ? join21(home, ".codex") : null;
24213
+ return isAbsolute6(home) ? join22(home, ".codex") : null;
23942
24214
  }
23943
24215
  async function codexAccountEmail(cli, env, timeoutMs = 3e3) {
23944
24216
  const cwd = env.HOME || env.USERPROFILE || homedir12();
@@ -24315,6 +24587,7 @@ var init_codex = __esm({
24315
24587
  init_env_path();
24316
24588
  init_retry();
24317
24589
  init_native();
24590
+ init_tool_summary();
24318
24591
  init_codex_instructions();
24319
24592
  init_codex_device_auth();
24320
24593
  init_codex_identity();
@@ -24379,7 +24652,7 @@ var init_codex = __esm({
24379
24652
  const listeners = /* @__PURE__ */ new Set();
24380
24653
  const active = /* @__PURE__ */ new Map();
24381
24654
  const emit = (event) => {
24382
- for (const l of [...listeners]) l(event);
24655
+ for (const l of Array.from(listeners)) l(event);
24383
24656
  };
24384
24657
  const base2 = (threadId, turnId) => ({
24385
24658
  eventId: newEventId(),
@@ -24507,7 +24780,7 @@ var init_codex = __esm({
24507
24780
  const settle = async (ok, stopReason) => {
24508
24781
  if (state.settled) return;
24509
24782
  state.settled = true;
24510
- for (const finish of [...asks.values()]) finish("deny", "OpenMausBot: the turn ended", "system");
24783
+ for (const finish of Array.from(asks.values())) finish("deny", "OpenMausBot: the turn ended", "system");
24511
24784
  for (const p of rpcPending.values()) p.reject(new Error("turn settled"));
24512
24785
  rpcPending.clear();
24513
24786
  const complete = () => {
@@ -24618,7 +24891,16 @@ var init_codex = __esm({
24618
24891
  case "item/started": {
24619
24892
  const item = p.item ?? {};
24620
24893
  const title = item.type === "commandExecution" ? String(item.command ?? "shell") : item.type === "fileChange" ? "edit" : item.type === "mcpToolCall" ? item.tool ?? item.name ?? "mcp" : item.type === "webSearch" ? "web_search" : null;
24621
- if (title) emit({ ...base2(threadId, turnId), type: "item.started", itemType: "tool", itemId: item.id, title });
24894
+ if (title) {
24895
+ emit({
24896
+ ...base2(threadId, turnId),
24897
+ type: "item.started",
24898
+ itemType: "tool",
24899
+ itemId: item.id,
24900
+ title,
24901
+ summary: item.type === "commandExecution" ? commandSummary({ command: item.command }) : void 0
24902
+ });
24903
+ }
24622
24904
  break;
24623
24905
  }
24624
24906
  case "item/completed": {
@@ -25263,10 +25545,10 @@ var init_grok = __esm({
25263
25545
  // server/drivers/acp/grok.ts
25264
25546
  import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
25265
25547
  import { homedir as homedir14 } from "node:os";
25266
- import { join as join22 } from "node:path";
25548
+ import { join as join23 } from "node:path";
25267
25549
  function grokHome(env) {
25268
25550
  if (env.GROK_HOME) return env.GROK_HOME;
25269
- return join22(env.HOME || env.USERPROFILE || homedir14(), ".grok");
25551
+ return join23(env.HOME || env.USERPROFILE || homedir14(), ".grok");
25270
25552
  }
25271
25553
  function unquote2(raw) {
25272
25554
  const value = raw.trim();
@@ -25276,7 +25558,7 @@ function unquote2(raw) {
25276
25558
  return value;
25277
25559
  }
25278
25560
  function readGrokModelCatalog(env = process.env) {
25279
- const path3 = join22(grokHome(env), "config.toml");
25561
+ const path3 = join23(grokHome(env), "config.toml");
25280
25562
  let text2 = "";
25281
25563
  try {
25282
25564
  text2 = readFileSync9(path3, "utf8");
@@ -25349,7 +25631,7 @@ function ensureGrokInjectSlug(modelId, env = process.env) {
25349
25631
  if (!inject) return modelId;
25350
25632
  const host = localHost(inject.host);
25351
25633
  if (!host) return modelId;
25352
- const path3 = join22(grokHome(env), "config.toml");
25634
+ const path3 = join23(grokHome(env), "config.toml");
25353
25635
  let text2 = "";
25354
25636
  try {
25355
25637
  text2 = readFileSync9(path3, "utf8");
@@ -25453,9 +25735,13 @@ var init_grok2 = __esm({
25453
25735
  // and BEFORE `stdio` (`grok agent -m slug stdio`). Putting -m first is
25454
25736
  // accepted as a TUI option and then ignored, so ACP session/new keeps
25455
25737
  // [models].default (grok-4.6) and oMLX never sees a request.
25738
+ // Auto selects Grok's native classifier; if its feature gate is disabled,
25739
+ // residual requests still ask. Never replace it with bypassPermissions.
25740
+ // Verified: grok 1.0.3 --help and xai-org/grok-build@37949780,
25741
+ // crates/codegen/xai-grok-pager-bin/src/main.rs:1259-1273.
25456
25742
  spawnArgs: (config2, turn) => [
25457
25743
  "--permission-mode",
25458
- config2.fullAuto ? "bypassPermissions" : "default",
25744
+ config2.fullAuto ? "bypassPermissions" : turn.approvalMode === "auto" ? "auto" : "default",
25459
25745
  "agent",
25460
25746
  ...turn.model ? ["-m", turn.model] : [],
25461
25747
  // long form on purpose: `--effort` is documented as an alias, and an
@@ -25484,7 +25770,7 @@ var init_grok2 = __esm({
25484
25770
  // an unauthenticated CLI is a user action, not something to paper over.
25485
25771
  pickAuthMethod: (methods) => methods.some((m) => m.id === "cached_token") ? "cached_token" : null,
25486
25772
  authFailure: "fail",
25487
- isAuthenticated: () => existsSync9(join22(homedir14(), ".grok", "auth.json")),
25773
+ isAuthenticated: () => existsSync9(join23(homedir14(), ".grok", "auth.json")),
25488
25774
  // `--append-system-prompt`/`--rules` are accepted by the CLI but do NOT
25489
25775
  // reach the agent-stdio system prompt (verified against 1.0.0), so the
25490
25776
  // persona is prepended codex-style.
@@ -25499,10 +25785,10 @@ ${turn.text}` : turn.text
25499
25785
  // server/drivers/acp/gemini.ts
25500
25786
  import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
25501
25787
  import { homedir as homedir15 } from "node:os";
25502
- import { join as join23 } from "node:path";
25788
+ import { join as join24 } from "node:path";
25503
25789
  function liveOauthCredential() {
25504
25790
  try {
25505
- const creds = JSON.parse(readFileSync10(join23(homedir15(), ".gemini", "oauth_creds.json"), "utf8"));
25791
+ const creds = JSON.parse(readFileSync10(join24(homedir15(), ".gemini", "oauth_creds.json"), "utf8"));
25506
25792
  if (typeof creds.access_token !== "string" || creds.access_token.trim().length === 0) return false;
25507
25793
  const hasRefresh = typeof creds.refresh_token === "string" && creds.refresh_token.trim().length > 0;
25508
25794
  if (creds.expiry_date !== void 0) {
@@ -25515,7 +25801,7 @@ function liveOauthCredential() {
25515
25801
  }
25516
25802
  }
25517
25803
  function geminiIsAuthenticated(env) {
25518
- return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync10(join23(homedir15(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
25804
+ return nonBlank(env.GEMINI_API_KEY) || nonBlank(env.GOOGLE_API_KEY) || existsSync10(join24(homedir15(), ".gemini", "oauth_creds.json")) && liveOauthCredential();
25519
25805
  }
25520
25806
  var AUTH_PREFERENCE, nonBlank, support3, GeminiAgentDriver;
25521
25807
  var init_gemini = __esm({
@@ -25559,15 +25845,15 @@ ${turn.text}` : turn.text
25559
25845
  // server/drivers/acp/kimi.ts
25560
25846
  import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
25561
25847
  import { homedir as homedir16 } from "node:os";
25562
- import { join as join24 } from "node:path";
25848
+ import { join as join25 } from "node:path";
25563
25849
  function isLocalInjectAlias(slug) {
25564
25850
  return LOCAL_PROVIDER_PREFIXES.some((prefix) => slug.startsWith(prefix));
25565
25851
  }
25566
25852
  function kimiDataRoot(env) {
25567
- return env.KIMI_CODE_HOME || join24(env.HOME || env.USERPROFILE || homedir16(), ".kimi-code");
25853
+ return env.KIMI_CODE_HOME || join25(env.HOME || env.USERPROFILE || homedir16(), ".kimi-code");
25568
25854
  }
25569
25855
  function credentialsPath(env) {
25570
- return join24(kimiDataRoot(env), "credentials", "kimi-code.json");
25856
+ return join25(kimiDataRoot(env), "credentials", "kimi-code.json");
25571
25857
  }
25572
25858
  function quoteToml2(value) {
25573
25859
  return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
@@ -25855,7 +26141,7 @@ function ensureKimiInjectAlias(modelId, env = process.env) {
25855
26141
  const alias = `${inject.host}/${inject.model.replace(/\//g, "-")}`;
25856
26142
  const dataRoot = kimiDataRoot(env);
25857
26143
  mkdirSync8(dataRoot, { recursive: true });
25858
- const path3 = join24(dataRoot, "config.toml");
26144
+ const path3 = join25(dataRoot, "config.toml");
25859
26145
  let text2 = "";
25860
26146
  try {
25861
26147
  text2 = readFileSync11(path3, "utf8");
@@ -25920,7 +26206,7 @@ function readKimiModelCatalog(env) {
25920
26206
  const dataRoot = kimiDataRoot(env);
25921
26207
  let text2 = "";
25922
26208
  try {
25923
- text2 = readFileSync11(join24(dataRoot, "config.toml"), "utf8");
26209
+ text2 = readFileSync11(join25(dataRoot, "config.toml"), "utf8");
25924
26210
  } catch {
25925
26211
  return STATIC_KIMI_MODELS;
25926
26212
  }
@@ -26041,10 +26327,10 @@ ${turn.text}` : turn.text
26041
26327
  // server/drivers/acp/droid.ts
26042
26328
  import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
26043
26329
  import { homedir as homedir17 } from "node:os";
26044
- import { join as join25 } from "node:path";
26330
+ import { join as join26 } from "node:path";
26045
26331
  function authFilePaths(env) {
26046
26332
  const home = env.FACTORY_HOME_OVERRIDE || env.HOME || homedir17();
26047
- return AUTH_FILES.map((name) => join25(home, ".factory", name));
26333
+ return AUTH_FILES.map((name) => join26(home, ".factory", name));
26048
26334
  }
26049
26335
  function droidInjectId(host, model) {
26050
26336
  const safe = `${host}-${model}`.replace(/[^a-zA-Z0-9._+-]+/g, "-").replace(/-+/g, "-");
@@ -26059,9 +26345,9 @@ function ensureDroidInjectModel(modelId, env = process.env) {
26059
26345
  const host = localHost(inject.host);
26060
26346
  if (!host) return modelId;
26061
26347
  const id = droidInjectId(inject.host, inject.model);
26062
- const dir = join25(factoryHome(env), ".factory");
26348
+ const dir = join26(factoryHome(env), ".factory");
26063
26349
  mkdirSync9(dir, { recursive: true });
26064
- const path3 = join25(dir, "settings.json");
26350
+ const path3 = join26(dir, "settings.json");
26065
26351
  let settings2 = {};
26066
26352
  try {
26067
26353
  settings2 = JSON.parse(readFileSync12(path3, "utf8"));
@@ -26101,7 +26387,7 @@ function applyDroidLocalAuthEnv(env, modelId) {
26101
26387
  env.FACTORY_API_KEY = "openmausbot-local";
26102
26388
  }
26103
26389
  function readSettings(env) {
26104
- return JSON.parse(readFileSync12(join25(factoryHome(env), ".factory", "settings.json"), "utf8"));
26390
+ return JSON.parse(readFileSync12(join26(factoryHome(env), ".factory", "settings.json"), "utf8"));
26105
26391
  }
26106
26392
  async function resolveModels(env) {
26107
26393
  let catalog = MODELS3;
@@ -26312,7 +26598,7 @@ function decodeCursorModelText(text2) {
26312
26598
  for (const raw of text2.split(/\r?\n/)) {
26313
26599
  const line = raw.trim();
26314
26600
  if (!line || line.startsWith("#") || /^available\s+models?\b/i.test(line) || /^models?\b/i.test(line)) continue;
26315
- const stripped = line.replace(/^[\s*•\-]+\s*/, "");
26601
+ const stripped = line.replace(/^[\s*•-]+\s*/, "");
26316
26602
  const parts = stripped.split(/\s+[—–|:]\s+|\s+-\s+|\s{2,}/);
26317
26603
  const id = (parts[0] ?? "").trim();
26318
26604
  const rawLabel = parts.slice(1).join(" ").trim();
@@ -26493,7 +26779,7 @@ ${turn.text}` : turn.text
26493
26779
  // server/drivers/acp/opencode-go.ts
26494
26780
  import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
26495
26781
  import { homedir as homedir18 } from "node:os";
26496
- import { join as join26 } from "node:path";
26782
+ import { join as join27 } from "node:path";
26497
26783
  function labelForModel(id) {
26498
26784
  return id.split(/[-_.]+/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
26499
26785
  }
@@ -26594,7 +26880,7 @@ async function discoverOpenCodeModels(environment, cli = "opencode") {
26594
26880
  }
26595
26881
  function opencodeConfigDir(env) {
26596
26882
  const home = env.HOME || env.USERPROFILE || homedir18();
26597
- return join26(env.XDG_CONFIG_HOME || join26(home, ".config"), "opencode");
26883
+ return join27(env.XDG_CONFIG_HOME || join27(home, ".config"), "opencode");
26598
26884
  }
26599
26885
  function ensureOpenCodeInjectModel(modelId, env = process.env) {
26600
26886
  const inject = decodeInjectId(modelId);
@@ -26604,7 +26890,7 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
26604
26890
  const native = `${inject.host}/${inject.model}`;
26605
26891
  const dir = opencodeConfigDir(env);
26606
26892
  mkdirSync10(dir, { recursive: true });
26607
- const path3 = join26(dir, "opencode.json");
26893
+ const path3 = join27(dir, "opencode.json");
26608
26894
  let config2 = { $schema: "https://opencode.ai/config.json" };
26609
26895
  if (existsSync13(path3)) {
26610
26896
  try {
@@ -26642,10 +26928,10 @@ function ensureOpenCodeInjectModel(modelId, env = process.env) {
26642
26928
  function storedAuthPaths(env) {
26643
26929
  const home = env.HOME || env.USERPROFILE || homedir18();
26644
26930
  const roots = [
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") : ""
26931
+ env.XDG_DATA_HOME || join27(home, ".local", "share"),
26932
+ process.platform === "darwin" ? join27(home, "Library", "Application Support") : process.platform === "win32" ? env.LOCALAPPDATA || join27(home, "AppData", "Local") : ""
26647
26933
  ].filter(Boolean);
26648
- return [...new Set(roots)].map((root) => join26(root, "opencode", "auth.json"));
26934
+ return [...new Set(roots)].map((root) => join27(root, "opencode", "auth.json"));
26649
26935
  }
26650
26936
  function usableAuthEntry(parsed) {
26651
26937
  return Object.values(parsed).some((auth) => {
@@ -26778,10 +27064,10 @@ ${turn.text}` : turn.text
26778
27064
  import { chmodSync as chmodSync4, existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
26779
27065
  import { createHash as createHash7 } from "node:crypto";
26780
27066
  import { homedir as homedir19 } from "node:os";
26781
- import { join as join27 } from "node:path";
27067
+ import { join as join28 } from "node:path";
26782
27068
  function qwenHome(env) {
26783
27069
  const home = process.platform === "win32" ? env.USERPROFILE || env.HOME || homedir19() : env.HOME || env.USERPROFILE || homedir19();
26784
- return join27(home, ".qwen");
27070
+ return join28(home, ".qwen");
26785
27071
  }
26786
27072
  function isRecord(value) {
26787
27073
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -26793,7 +27079,7 @@ function qwenModelLabel(id, name) {
26793
27079
  function readQwenRoutes(env) {
26794
27080
  let settings2;
26795
27081
  try {
26796
- settings2 = JSON.parse(readFileSync14(join27(qwenHome(env), "settings.json"), "utf8"));
27082
+ settings2 = JSON.parse(readFileSync14(join28(qwenHome(env), "settings.json"), "utf8"));
26797
27083
  } catch {
26798
27084
  return [];
26799
27085
  }
@@ -26877,7 +27163,7 @@ function ensureQwenInjectModel(modelId, env = process.env) {
26877
27163
  if (!host) return modelId;
26878
27164
  const dir = qwenHome(env);
26879
27165
  mkdirSync11(dir, { recursive: true });
26880
- const path3 = join27(dir, "settings.json");
27166
+ const path3 = join28(dir, "settings.json");
26881
27167
  let settings2 = {};
26882
27168
  if (existsSync14(path3)) {
26883
27169
  try {
@@ -33878,7 +34164,7 @@ var init_browser = __esm({
33878
34164
  import { spawn as spawn5 } from "node:child_process";
33879
34165
  import { mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
33880
34166
  import { homedir as homedir20 } from "node:os";
33881
- import { join as join28 } from "node:path";
34167
+ import { join as join29 } from "node:path";
33882
34168
  function bindHermesScreenshotCompat(env, modelId) {
33883
34169
  delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT];
33884
34170
  delete env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL];
@@ -33888,7 +34174,7 @@ function bindHermesScreenshotCompat(env, modelId) {
33888
34174
  env[HERMES_OPENMAUS_SCREENSHOT_COMPAT_MODEL] = inject.model;
33889
34175
  }
33890
34176
  function hermesHome(env) {
33891
- return env.HERMES_HOME || join28(env.HOME || env.USERPROFILE || homedir20(), ".hermes");
34177
+ return env.HERMES_HOME || join29(env.HOME || env.USERPROFILE || homedir20(), ".hermes");
33892
34178
  }
33893
34179
  function quoteYaml(value) {
33894
34180
  if (/^[\w./:+-]+$/.test(value)) return value;
@@ -33930,7 +34216,7 @@ function ensureHermesInjectProvider(modelId, env = process.env) {
33930
34216
  if (!host) return modelId;
33931
34217
  const dir = hermesHome(env);
33932
34218
  mkdirSync12(dir, { recursive: true });
33933
- const path3 = join28(dir, "config.yaml");
34219
+ const path3 = join29(dir, "config.yaml");
33934
34220
  let text2 = "";
33935
34221
  try {
33936
34222
  text2 = readFileSync15(path3, "utf8");
@@ -34001,13 +34287,13 @@ function hermesConfiguredModel(env = process.env) {
34001
34287
  const dir = hermesHome(env);
34002
34288
  let secrets = "";
34003
34289
  try {
34004
- secrets = readFileSync15(join28(dir, ".env"), "utf8");
34290
+ secrets = readFileSync15(join29(dir, ".env"), "utf8");
34005
34291
  } catch {
34006
34292
  }
34007
34293
  const hasHostedProviderKey = HERMES_HOSTED_PROVIDER_KEYS.some((name) => nonEmptyDotenvValue(secrets, name));
34008
34294
  let configuredDefault = null;
34009
34295
  try {
34010
- configuredDefault = hermesConfigDefault(readFileSync15(join28(dir, "config.yaml"), "utf8"));
34296
+ configuredDefault = hermesConfigDefault(readFileSync15(join29(dir, "config.yaml"), "utf8"));
34011
34297
  } catch {
34012
34298
  }
34013
34299
  const configuredProvider = configuredDefault?.provider.toLowerCase() ?? "";
@@ -34329,7 +34615,7 @@ var init_openai_compat = __esm({
34329
34615
  // server/drivers/pi.ts
34330
34616
  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
34617
  import { homedir as homedir21, tmpdir as tmpdir4 } from "node:os";
34332
- import { join as join29 } from "node:path";
34618
+ import { join as join30 } from "node:path";
34333
34619
  function readPiPromptImages(turn) {
34334
34620
  return (turn.images ?? []).map((image) => ({
34335
34621
  type: "image",
@@ -34436,7 +34722,7 @@ async function applyPiLocalCatalog(catalog, env = process.env, fetchImpl = fetch
34436
34722
  return preferPiInjectRows(await mergeLocalInject(catalog, env, fetchImpl));
34437
34723
  }
34438
34724
  function piAgentDir(env) {
34439
- return join29(env.HOME || env.USERPROFILE || homedir21(), ".pi", "agent");
34725
+ return join30(env.HOME || env.USERPROFILE || homedir21(), ".pi", "agent");
34440
34726
  }
34441
34727
  function ensurePiInjectModel(modelId, env = process.env) {
34442
34728
  const split = splitPiModel(modelId);
@@ -34447,7 +34733,7 @@ function ensurePiInjectModel(modelId, env = process.env) {
34447
34733
  if (!host) return split;
34448
34734
  const dir = piAgentDir(env);
34449
34735
  mkdirSync13(dir, { recursive: true });
34450
- const path3 = join29(dir, "models.json");
34736
+ const path3 = join30(dir, "models.json");
34451
34737
  let root = { providers: {} };
34452
34738
  if (existsSync15(path3)) {
34453
34739
  try {
@@ -34621,7 +34907,7 @@ var init_pi = __esm({
34621
34907
  const listeners = /* @__PURE__ */ new Set();
34622
34908
  const active = /* @__PURE__ */ new Map();
34623
34909
  const emit = (event) => {
34624
- for (const l of [...listeners]) l(event);
34910
+ for (const l of Array.from(listeners)) l(event);
34625
34911
  };
34626
34912
  const base2 = (threadId, turnId) => ({
34627
34913
  eventId: newEventId(),
@@ -34649,9 +34935,9 @@ var init_pi = __esm({
34649
34935
  const mcpServers = buildMcpServers(turn);
34650
34936
  let mcpTempDir = null;
34651
34937
  if (mcpServers) {
34652
- mcpTempDir = mkdtempSync3(join29(tmpdir4(), "omb-pi-mcp-"));
34938
+ mcpTempDir = mkdtempSync3(join30(tmpdir4(), "omb-pi-mcp-"));
34653
34939
  try {
34654
- writeFileSync12(join29(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
34940
+ writeFileSync12(join30(mcpTempDir, "mcp.json"), JSON.stringify({ mcpServers }), { mode: 384 });
34655
34941
  } catch (err) {
34656
34942
  try {
34657
34943
  rmSync3(mcpTempDir, { recursive: true, force: true });
@@ -34669,7 +34955,7 @@ var init_pi = __esm({
34669
34955
  env: piEnvironment({
34670
34956
  ...process.env,
34671
34957
  ...input.environment,
34672
- ...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join29(mcpTempDir, "mcp.json") } : {}
34958
+ ...mcpServers && mcpTempDir ? { OMB_MCP_CONFIG: join30(mcpTempDir, "mcp.json") } : {}
34673
34959
  })
34674
34960
  });
34675
34961
  } catch (err) {
@@ -35008,14 +35294,14 @@ ${turn.text}` : turn.text;
35008
35294
  // server/drivers/minimax.ts
35009
35295
  import { readFileSync as readFileSync17 } from "node:fs";
35010
35296
  import { homedir as homedir22 } from "node:os";
35011
- import { join as join30 } from "node:path";
35297
+ import { join as join31 } from "node:path";
35012
35298
  function normalizedApiUrl(value) {
35013
35299
  const root = value.trim().replace(/\/+$/, "");
35014
35300
  return root.endsWith("/v1") ? root : `${root}/v1`;
35015
35301
  }
35016
35302
  function loadLocalMiniMaxConfig(home = homedir22()) {
35017
35303
  try {
35018
- const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join30(home, ".mmx", "config.json"), "utf8")));
35304
+ const raw = localConfigSchema.parse(JSON.parse(readFileSync17(join31(home, ".mmx", "config.json"), "utf8")));
35019
35305
  const configuredUrl = raw.base_url?.trim() ? raw.base_url : raw.region === "cn" ? CN_URL : DEFAULT_URL2;
35020
35306
  return {
35021
35307
  apiKey: raw.api_key?.trim() ?? "",
@@ -35283,7 +35569,7 @@ __export(cli_setup_exports, {
35283
35569
  });
35284
35570
  import { spawn as spawn6 } from "node:child_process";
35285
35571
  import { readFileSync as readFileSync18 } from "node:fs";
35286
- import { join as join31, resolve as resolve10 } from "node:path";
35572
+ import { join as join32, resolve as resolve10 } from "node:path";
35287
35573
  import { randomUUID as randomUUID10 } from "node:crypto";
35288
35574
  async function inspect(id, entry) {
35289
35575
  const registry2 = new ProviderRegistry(BUILT_IN_DRIVERS);
@@ -35320,7 +35606,7 @@ function assertDataDir(dataDir) {
35320
35606
  }
35321
35607
  function checkStoredConfig(dataDir) {
35322
35608
  try {
35323
- parseStoredConfig(JSON.parse(readFileSync18(join31(dataDir, "config.json"), "utf8")));
35609
+ parseStoredConfig(JSON.parse(readFileSync18(join32(dataDir, "config.json"), "utf8")));
35324
35610
  } catch (error51) {
35325
35611
  if (error51.code === "ENOENT") return;
35326
35612
  throw new Error("Existing config.json could not be read or validated. Setup has not changed it; repair it before continuing.");
@@ -35598,7 +35884,7 @@ var init_browser_engine_release = __esm({
35598
35884
  });
35599
35885
 
35600
35886
  // server/browser-bundle-release.ts
35601
- import { join as join32 } from "node:path";
35887
+ import { join as join33 } from "node:path";
35602
35888
  function browserBundleSpec(target) {
35603
35889
  if (!Object.hasOwn(CHROME_ASSETS, target)) throw new Error(`Unsupported desktop browser target: ${target}`);
35604
35890
  const pinned = CHROME_ASSETS[target];
@@ -35634,10 +35920,10 @@ function browserBundlePaths(bundleDirectory, target) {
35634
35920
  const spec = browserBundleSpec(target);
35635
35921
  return {
35636
35922
  directory: bundleDirectory,
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")
35923
+ manifest: join33(bundleDirectory, "manifest.json"),
35924
+ engine: join33(bundleDirectory, spec.engine.executable),
35925
+ chrome: join33(bundleDirectory, spec.chrome.executable),
35926
+ licenses: join33(bundleDirectory, "licenses")
35641
35927
  };
35642
35928
  }
35643
35929
  var CHROME_VERSION, CHROME_ASSETS;
@@ -35694,7 +35980,7 @@ import { spawn as spawn7 } from "node:child_process";
35694
35980
  import { createHash as createHash8, randomBytes as randomBytes3, randomUUID as randomUUID11 } from "node:crypto";
35695
35981
  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
35982
  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";
35983
+ import { delimiter as delimiter6, dirname as dirname10, join as join34, resolve as resolve11 } from "node:path";
35698
35984
  function browserRestoreKey(session) {
35699
35985
  if (!/^[A-Za-z0-9_-]{1,96}$/.test(session)) throw new Error("Invalid browser session.");
35700
35986
  return `omb-${createHash8("sha256").update(session).digest("hex")}`;
@@ -35703,11 +35989,11 @@ function browserSessionsDirectory(env) {
35703
35989
  const namespace = env.AGENT_BROWSER_NAMESPACE;
35704
35990
  if (namespace && !/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(namespace)) throw new Error("Invalid browser namespace.");
35705
35991
  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");
35992
+ const stateRoot = namespace ? join34(home, ".agent-browser", "namespaces", namespace, "state") : join34(home, ".agent-browser");
35993
+ return join34(stateRoot, "sessions");
35708
35994
  }
35709
35995
  function managedBrowserConfigPath(env) {
35710
- return join33(browserSessionsDirectory(env), "..", "omb-managed-config.json");
35996
+ return join34(browserSessionsDirectory(env), "..", "omb-managed-config.json");
35711
35997
  }
35712
35998
  function ensureManagedBrowserConfig(env) {
35713
35999
  const path3 = managedBrowserConfigPath(env);
@@ -35794,11 +36080,11 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35794
36080
  ensureManagedBrowserConfig(env);
35795
36081
  if (options.persistent === false) return;
35796
36082
  const directory = browserSessionsDirectory(env);
35797
- const key = join33(directory, session);
36083
+ const key = join34(directory, session);
35798
36084
  let pending = preparedBrowserSessions.get(key);
35799
36085
  if (!pending) {
35800
36086
  pending = (async () => {
35801
- const targetBase = join33(directory, `${restoreKey}-${session}`);
36087
+ const targetBase = join34(directory, `${restoreKey}-${session}`);
35802
36088
  const hasTarget = () => existsSync16(`${targetBase}.json.enc`) || existsSync16(`${targetBase}.json`);
35803
36089
  if (hasTarget()) return;
35804
36090
  check2();
@@ -35808,7 +36094,7 @@ async function prepareBrowserSessionState(binaryPath, session, options = {}) {
35808
36094
  check2();
35809
36095
  if (hasTarget()) return;
35810
36096
  const candidates = [".json.enc", ".json"].flatMap((suffix) => {
35811
- const path3 = join33(directory, `${session}-${session}${suffix}`);
36097
+ const path3 = join34(directory, `${session}-${session}${suffix}`);
35812
36098
  try {
35813
36099
  const stat4 = statSync3(path3);
35814
36100
  if (!stat4.isFile()) throw new Error("Saved browser state is not a file.");
@@ -35843,7 +36129,7 @@ function isMusl(platform = process.platform, exists = existsSync16) {
35843
36129
  }
35844
36130
  function pinnedBinaryPath(dataDir = DATA_DIR, platform = process.platform, arch = process.arch) {
35845
36131
  const version2 = agentBrowserReleaseVersion(resolveAgentBrowserReleaseAsset(platform, arch));
35846
- return join33(dataDir, ENGINE_DIR, version2, executableName(platform));
36132
+ return join34(dataDir, ENGINE_DIR, version2, executableName(platform));
35847
36133
  }
35848
36134
  function onPath(env, platform, exists) {
35849
36135
  const pathValue = platform === "win32" ? Object.entries(env).findLast(([key]) => key.toUpperCase() === "PATH")?.[1] : env.PATH;
@@ -35859,7 +36145,7 @@ function packagedBrowser(options) {
35859
36145
  const resources = (options.env ?? process.env).OMB_RESOURCES_PATH;
35860
36146
  if (!resources) return null;
35861
36147
  try {
35862
- return browserBundlePaths(join33(resolve11(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
36148
+ return browserBundlePaths(join34(resolve11(resources), "browser-engine"), `${options.platform ?? process.platform}-${options.arch ?? process.arch}`);
35863
36149
  } catch {
35864
36150
  return null;
35865
36151
  }
@@ -35884,7 +36170,7 @@ async function installAgentBrowserBinary(options = {}) {
35884
36170
  const asset = options.asset ?? resolveAgentBrowserReleaseAsset(platform, options.arch ?? process.arch, options.musl ?? isMusl(platform));
35885
36171
  if (!asset) throw new Error(`agent-browser publishes no build for ${platform}-${options.arch ?? process.arch}.`);
35886
36172
  const destination = pinnedBinaryPath(options.dataDir, platform, options.arch);
35887
- const directory = join33(destination, "..");
36173
+ const directory = join34(destination, "..");
35888
36174
  mkdirSync14(directory, { recursive: true, mode: 448 });
35889
36175
  const url2 = agentBrowserReleaseUrl(asset);
35890
36176
  options.log?.(`downloading agent-browser ${agentBrowserReleaseVersion(asset)} (${Math.round(asset.bytes / 1024 / 1024)} MB, digest pinned)`);
@@ -35936,7 +36222,7 @@ function ensureChrome(binaryPath, options = {}) {
35936
36222
  });
35937
36223
  }
35938
36224
  function browserEngineEncryptionKey(dataDir = DATA_DIR) {
35939
- const file2 = join33(dataDir, KEY_FILE);
36225
+ const file2 = join34(dataDir, KEY_FILE);
35940
36226
  try {
35941
36227
  const existing = readFileSync19(file2, "utf8").trim();
35942
36228
  if (/^[0-9a-f]{64}$/u.test(existing)) return existing;
@@ -35996,7 +36282,7 @@ function agentBrowserIntegration(input) {
35996
36282
  return { command: input.binaryPath, args: ["mcp", "--tools", "core", "--no-webmcp"], env };
35997
36283
  }
35998
36284
  function agentBrowserFrame(input) {
35999
- const file2 = join33(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
36285
+ const file2 = join34(tmpdir5(), `openmausbot-browser-${randomUUID11()}.png`);
36000
36286
  return new Promise((settle, fail) => {
36001
36287
  const child = spawn7(input.binaryPath, ["screenshot", file2], {
36002
36288
  env: browserRuntimeEnv(input.env),
@@ -36066,8 +36352,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
36066
36352
  }
36067
36353
  };
36068
36354
  try {
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");
36355
+ for (const base2 of bases) for (const suffix of [".json", ".json.enc", ".json.previous", ".json.enc.previous"]) remove(join34(directory, base2 + suffix));
36356
+ const pendingDirectory = join34(directory, ".tmp");
36071
36357
  let pendingFiles = [];
36072
36358
  try {
36073
36359
  pendingFiles = readdirSync3(pendingDirectory);
@@ -36075,8 +36361,8 @@ async function clearBrowserSessionState(binaryPath, session, options = {}) {
36075
36361
  if (error51.code !== "ENOENT") throw error51;
36076
36362
  }
36077
36363
  const candidates = bases.map((base2) => new RegExp(`^${base2}-candidate-[0-9]+\\.json(?:\\.enc)?$`));
36078
- for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(join33(pendingDirectory, name));
36079
- preparedBrowserSessions.delete(join33(directory, session));
36364
+ for (const name of pendingFiles) if (candidates.some((candidate) => candidate.test(name))) remove(join34(pendingDirectory, name));
36365
+ preparedBrowserSessions.delete(join34(directory, session));
36080
36366
  return true;
36081
36367
  } catch {
36082
36368
  return false;
@@ -36105,7 +36391,7 @@ var import_qrcode_terminal = __toESM(require_main(), 1);
36105
36391
  import { spawn as spawn8 } from "node:child_process";
36106
36392
  import { closeSync as closeSync3, existsSync as existsSync17, mkdirSync as mkdirSync15, openSync as openSync3, readFileSync as readFileSync20 } from "node:fs";
36107
36393
  import { homedir as homedir24 } from "node:os";
36108
- import { dirname as dirname11, join as join34, resolve as resolve12 } from "node:path";
36394
+ import { dirname as dirname11, join as join35, resolve as resolve12 } from "node:path";
36109
36395
  import { createInterface as createInterface2 } from "node:readline/promises";
36110
36396
  import { fileURLToPath as fileURLToPath3 } from "node:url";
36111
36397
 
@@ -38350,7 +38636,7 @@ function parseArgs(argv, env = process.env) {
38350
38636
  const options = {
38351
38637
  command: command === "--help" || command === "-h" ? "help" : command,
38352
38638
  port: Number(env.OMB_PORT || 8799),
38353
- dataDir: env.OMB_DATA_DIR || join34(homedir24(), ".openmausbot"),
38639
+ dataDir: env.OMB_DATA_DIR || join35(homedir24(), ".openmausbot"),
38354
38640
  tailscale: false,
38355
38641
  tunnel: false,
38356
38642
  client: false,
@@ -38505,7 +38791,7 @@ async function isWorkspaceRunning(options) {
38505
38791
  try {
38506
38792
  const { status, body } = await api(options.port, "/api/health");
38507
38793
  if (status !== 200 || body?.app !== "openmausbot") return false;
38508
- const expected = readFileSync20(join34(options.dataDir, "environment-id"), "utf8").trim();
38794
+ const expected = readFileSync20(join35(options.dataDir, "environment-id"), "utf8").trim();
38509
38795
  const descriptor = await api(options.port, "/.well-known/openmausbot/environment");
38510
38796
  return /^[0-9a-f-]{36}$/i.test(expected) && descriptor.status === 200 && descriptor.body?.environmentId === expected;
38511
38797
  } catch {
@@ -38705,7 +38991,7 @@ async function runStatus(options, io = defaultIo()) {
38705
38991
  return code;
38706
38992
  }
38707
38993
  async function runAccess(options, io = defaultIo()) {
38708
- const file2 = join34(options.dataDir, "config.json");
38994
+ const file2 = join35(options.dataDir, "config.json");
38709
38995
  let raw = {};
38710
38996
  if (existsSync17(file2)) {
38711
38997
  try {
@@ -38857,16 +39143,16 @@ async function runBrowser(options, io = defaultIo()) {
38857
39143
  return 0;
38858
39144
  }
38859
39145
  function serverEntry(here = HERE2) {
38860
- const bundled = join34(here, "index.js");
39146
+ const bundled = join35(here, "index.js");
38861
39147
  const root = resolve12(here, "..");
38862
39148
  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;
39149
+ const staticDir2 = [join35(root, "dist"), join35(here, "..", "ui")].find((d) => existsSync17(join35(d, "index.html"))) ?? null;
39150
+ const skillsDir = existsSync17(join35(root, "skills")) ? join35(root, "skills") : null;
38865
39151
  return { command: process.execPath, args: [bundled], staticDir: staticDir2, skillsDir };
38866
39152
  }
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 };
39153
+ const source = join35(here, "index.ts");
39154
+ const staticDir = existsSync17(join35(root, "dist", "index.html")) ? join35(root, "dist") : null;
39155
+ return { command: process.execPath, args: ["--experimental-strip-types", source], staticDir, skillsDir: existsSync17(join35(root, "skills")) ? join35(root, "skills") : null };
38870
39156
  }
38871
39157
  async function planTunnel(options, log) {
38872
39158
  let access2 = null;
@@ -38966,9 +39252,9 @@ async function runServe(options, log = console.log) {
38966
39252
  let child;
38967
39253
  try {
38968
39254
  if (options.guided) {
38969
- const logsDir = join34(options.dataDir, "logs");
39255
+ const logsDir = join35(options.dataDir, "logs");
38970
39256
  mkdirSync15(logsDir, { recursive: true, mode: 448 });
38971
- logPath = join34(logsDir, `server-${Date.now()}-${process.pid}.log`);
39257
+ logPath = join35(logsDir, `server-${Date.now()}-${process.pid}.log`);
38972
39258
  logFd = openSync3(logPath, "wx", 384);
38973
39259
  log("\nStarting your workspace\u2026");
38974
39260
  }
@@ -39160,7 +39446,7 @@ async function runOnboardingCommand(options, io = defaultIo(), startServer = run
39160
39446
  }
39161
39447
  if (options.command === "setup") {
39162
39448
  io.log("\nAll set. Start with: openmausbot (or npx openmausbot without a global install).");
39163
- if (options.dataDir !== join34(homedir24(), ".openmausbot") || options.port !== 8799) {
39449
+ if (options.dataDir !== join35(homedir24(), ".openmausbot") || options.port !== 8799) {
39164
39450
  io.log(`Use the same --data-dir (${options.dataDir}) and --port (${options.port}) options when starting.`);
39165
39451
  }
39166
39452
  return 0;