open-agents-ai 0.187.491 → 0.187.493

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.
package/dist/index.js CHANGED
@@ -23668,7 +23668,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
23668
23668
  bits2int_modN: "function"
23669
23669
  });
23670
23670
  ecdsaOpts = Object.assign({}, ecdsaOpts);
23671
- const randomBytes24 = ecdsaOpts.randomBytes || randomBytes7;
23671
+ const randomBytes25 = ecdsaOpts.randomBytes || randomBytes7;
23672
23672
  const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
23673
23673
  const { Fp, Fn } = Point;
23674
23674
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
@@ -23810,7 +23810,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
23810
23810
  throw new Error("invalid private key");
23811
23811
  const seedArgs = [int2octets(d2), int2octets(h1int)];
23812
23812
  if (extraEntropy != null && extraEntropy !== false) {
23813
- const e2 = extraEntropy === true ? randomBytes24(lengths.secretKey) : extraEntropy;
23813
+ const e2 = extraEntropy === true ? randomBytes25(lengths.secretKey) : extraEntropy;
23814
23814
  seedArgs.push(abytes(e2, void 0, "extraEntropy"));
23815
23815
  }
23816
23816
  const seed = concatBytes(...seedArgs);
@@ -60320,9 +60320,9 @@ var init_cookies = __esm({
60320
60320
 
60321
60321
  // ../../../node_modules/@libp2p/http-peer-id-auth/dist/src/utils.js
60322
60322
  function generateChallenge() {
60323
- const randomBytes24 = new Uint8Array(32);
60324
- crypto.getRandomValues(randomBytes24);
60325
- return toString2(randomBytes24, "base64urlpad");
60323
+ const randomBytes25 = new Uint8Array(32);
60324
+ crypto.getRandomValues(randomBytes25);
60325
+ return toString2(randomBytes25, "base64urlpad");
60326
60326
  }
60327
60327
  function encodeAuthParams(params) {
60328
60328
  const encodedParams = Object.entries(params).map(([key, value2]) => `${key}="${value2}"`).join(", ");
@@ -232436,7 +232436,7 @@ var require_websocket2 = __commonJS({
232436
232436
  var http6 = __require("http");
232437
232437
  var net5 = __require("net");
232438
232438
  var tls2 = __require("tls");
232439
- var { randomBytes: randomBytes24, createHash: createHash16 } = __require("crypto");
232439
+ var { randomBytes: randomBytes25, createHash: createHash16 } = __require("crypto");
232440
232440
  var { Duplex: Duplex3, Readable } = __require("stream");
232441
232441
  var { URL: URL3 } = __require("url");
232442
232442
  var PerMessageDeflate2 = require_permessage_deflate2();
@@ -232966,7 +232966,7 @@ var require_websocket2 = __commonJS({
232966
232966
  }
232967
232967
  }
232968
232968
  const defaultPort = isSecure ? 443 : 80;
232969
- const key = randomBytes24(16).toString("base64");
232969
+ const key = randomBytes25(16).toString("base64");
232970
232970
  const request = isSecure ? https4.request : http6.request;
232971
232971
  const protocolSet = /* @__PURE__ */ new Set();
232972
232972
  let perMessageDeflate;
@@ -247331,9 +247331,9 @@ print("${sentinel}")
247331
247331
  if (!this.proc || this.proc.killed) {
247332
247332
  return { success: false, path: "" };
247333
247333
  }
247334
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = await import("node:fs");
247334
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
247335
247335
  const sessionDir = join28(this.cwd, ".oa", "rlm");
247336
- mkdirSync66(sessionDir, { recursive: true });
247336
+ mkdirSync67(sessionDir, { recursive: true });
247337
247337
  const sessionPath2 = join28(sessionDir, "session.json");
247338
247338
  try {
247339
247339
  const inspectCode = `
@@ -247357,7 +247357,7 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
247357
247357
  trajectoryCount: this.trajectory.length,
247358
247358
  subCallCount: this.subCallCount
247359
247359
  };
247360
- writeFileSync58(sessionPath2, JSON.stringify(sessionData, null, 2), "utf8");
247360
+ writeFileSync59(sessionPath2, JSON.stringify(sessionData, null, 2), "utf8");
247361
247361
  return { success: true, path: sessionPath2 };
247362
247362
  }
247363
247363
  } catch {
@@ -247369,11 +247369,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
247369
247369
  * what was previously computed. */
247370
247370
  async loadSessionInfo() {
247371
247371
  try {
247372
- const { readFileSync: readFileSync82, existsSync: existsSync102 } = await import("node:fs");
247372
+ const { readFileSync: readFileSync83, existsSync: existsSync103 } = await import("node:fs");
247373
247373
  const sessionPath2 = join28(this.cwd, ".oa", "rlm", "session.json");
247374
- if (!existsSync102(sessionPath2))
247374
+ if (!existsSync103(sessionPath2))
247375
247375
  return null;
247376
- return JSON.parse(readFileSync82(sessionPath2, "utf8"));
247376
+ return JSON.parse(readFileSync83(sessionPath2, "utf8"));
247377
247377
  } catch {
247378
247378
  return null;
247379
247379
  }
@@ -247550,10 +247550,10 @@ var init_memory_metabolism = __esm({
247550
247550
  const trajDir = join29(this.cwd, ".oa", "rlm-trajectories");
247551
247551
  let lessons = [];
247552
247552
  try {
247553
- const { readdirSync: readdirSync37, readFileSync: readFileSync82 } = await import("node:fs");
247553
+ const { readdirSync: readdirSync37, readFileSync: readFileSync83 } = await import("node:fs");
247554
247554
  const files = readdirSync37(trajDir).filter((f2) => f2.endsWith(".jsonl")).sort().reverse().slice(0, 3);
247555
247555
  for (const file of files) {
247556
- const lines = readFileSync82(join29(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
247556
+ const lines = readFileSync83(join29(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
247557
247557
  for (const line of lines) {
247558
247558
  try {
247559
247559
  const entry = JSON.parse(line);
@@ -247937,14 +247937,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
247937
247937
  * Optionally filter by task type for phase-aware context (FSM paper insight).
247938
247938
  */
247939
247939
  getTopMemoriesSync(k = 5, taskType) {
247940
- const { readFileSync: readFileSync82, existsSync: existsSync102 } = __require("node:fs");
247940
+ const { readFileSync: readFileSync83, existsSync: existsSync103 } = __require("node:fs");
247941
247941
  const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
247942
247942
  const storeFile = join29(metaDir, "store.json");
247943
- if (!existsSync102(storeFile))
247943
+ if (!existsSync103(storeFile))
247944
247944
  return "";
247945
247945
  let store2 = [];
247946
247946
  try {
247947
- store2 = JSON.parse(readFileSync82(storeFile, "utf8"));
247947
+ store2 = JSON.parse(readFileSync83(storeFile, "utf8"));
247948
247948
  } catch {
247949
247949
  return "";
247950
247950
  }
@@ -247966,14 +247966,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
247966
247966
  /** Update memory scores based on task outcome. Called after task completion.
247967
247967
  * Memories used in successful tasks get boosted. Memories present during failures get decayed. */
247968
247968
  updateFromOutcomeSync(surfacedMemoryText, succeeded) {
247969
- const { readFileSync: readFileSync82, writeFileSync: writeFileSync58, existsSync: existsSync102, mkdirSync: mkdirSync66 } = __require("node:fs");
247969
+ const { readFileSync: readFileSync83, writeFileSync: writeFileSync59, existsSync: existsSync103, mkdirSync: mkdirSync67 } = __require("node:fs");
247970
247970
  const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
247971
247971
  const storeFile = join29(metaDir, "store.json");
247972
- if (!existsSync102(storeFile))
247972
+ if (!existsSync103(storeFile))
247973
247973
  return;
247974
247974
  let store2 = [];
247975
247975
  try {
247976
- store2 = JSON.parse(readFileSync82(storeFile, "utf8"));
247976
+ store2 = JSON.parse(readFileSync83(storeFile, "utf8"));
247977
247977
  } catch {
247978
247978
  return;
247979
247979
  }
@@ -247997,8 +247997,8 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
247997
247997
  updated = true;
247998
247998
  }
247999
247999
  if (updated) {
248000
- mkdirSync66(metaDir, { recursive: true });
248001
- writeFileSync58(storeFile, JSON.stringify(store2, null, 2));
248000
+ mkdirSync67(metaDir, { recursive: true });
248001
+ writeFileSync59(storeFile, JSON.stringify(store2, null, 2));
248002
248002
  }
248003
248003
  }
248004
248004
  // ── Storage ──────────────────────────────────────────────────────────
@@ -248420,13 +248420,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
248420
248420
  // Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
248421
248421
  /** Retrieve top-K strategies for context injection. Returns "" if none. */
248422
248422
  getRelevantStrategiesSync(k = 3, taskType) {
248423
- const { readFileSync: readFileSync82, existsSync: existsSync102 } = __require("node:fs");
248423
+ const { readFileSync: readFileSync83, existsSync: existsSync103 } = __require("node:fs");
248424
248424
  const archiveFile = join31(this.cwd, ".oa", "arche", "variants.json");
248425
- if (!existsSync102(archiveFile))
248425
+ if (!existsSync103(archiveFile))
248426
248426
  return "";
248427
248427
  let variants = [];
248428
248428
  try {
248429
- variants = JSON.parse(readFileSync82(archiveFile, "utf8"));
248429
+ variants = JSON.parse(readFileSync83(archiveFile, "utf8"));
248430
248430
  } catch {
248431
248431
  return "";
248432
248432
  }
@@ -248444,13 +248444,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
248444
248444
  }
248445
248445
  /** Archive a strategy variant synchronously (for task completion path) */
248446
248446
  archiveVariantSync(strategy, outcome, tags = []) {
248447
- const { readFileSync: readFileSync82, writeFileSync: writeFileSync58, existsSync: existsSync102, mkdirSync: mkdirSync66 } = __require("node:fs");
248447
+ const { readFileSync: readFileSync83, writeFileSync: writeFileSync59, existsSync: existsSync103, mkdirSync: mkdirSync67 } = __require("node:fs");
248448
248448
  const dir = join31(this.cwd, ".oa", "arche");
248449
248449
  const archiveFile = join31(dir, "variants.json");
248450
248450
  let variants = [];
248451
248451
  try {
248452
- if (existsSync102(archiveFile))
248453
- variants = JSON.parse(readFileSync82(archiveFile, "utf8"));
248452
+ if (existsSync103(archiveFile))
248453
+ variants = JSON.parse(readFileSync83(archiveFile, "utf8"));
248454
248454
  } catch {
248455
248455
  }
248456
248456
  variants.push({
@@ -248465,8 +248465,8 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
248465
248465
  });
248466
248466
  if (variants.length > 50)
248467
248467
  variants = variants.slice(-50);
248468
- mkdirSync66(dir, { recursive: true });
248469
- writeFileSync58(archiveFile, JSON.stringify(variants, null, 2));
248468
+ mkdirSync67(dir, { recursive: true });
248469
+ writeFileSync59(archiveFile, JSON.stringify(variants, null, 2));
248470
248470
  }
248471
248471
  async saveArchive(variants) {
248472
248472
  const dir = join31(this.cwd, ".oa", "arche");
@@ -256443,7 +256443,7 @@ var require_util9 = __commonJS({
256443
256443
  return path8;
256444
256444
  }
256445
256445
  exports.normalize = normalize2;
256446
- function join120(aRoot, aPath) {
256446
+ function join121(aRoot, aPath) {
256447
256447
  if (aRoot === "") {
256448
256448
  aRoot = ".";
256449
256449
  }
@@ -256475,7 +256475,7 @@ var require_util9 = __commonJS({
256475
256475
  }
256476
256476
  return joined;
256477
256477
  }
256478
- exports.join = join120;
256478
+ exports.join = join121;
256479
256479
  exports.isAbsolute = function(aPath) {
256480
256480
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
256481
256481
  };
@@ -256648,7 +256648,7 @@ var require_util9 = __commonJS({
256648
256648
  parsed.path = parsed.path.substring(0, index + 1);
256649
256649
  }
256650
256650
  }
256651
- sourceURL = join120(urlGenerate(parsed), sourceURL);
256651
+ sourceURL = join121(urlGenerate(parsed), sourceURL);
256652
256652
  }
256653
256653
  return normalize2(sourceURL);
256654
256654
  }
@@ -472068,7 +472068,7 @@ var require_path_browserify = __commonJS({
472068
472068
  assertPath(path8);
472069
472069
  return path8.length > 0 && path8.charCodeAt(0) === 47;
472070
472070
  },
472071
- join: function join120() {
472071
+ join: function join121() {
472072
472072
  if (arguments.length === 0)
472073
472073
  return ".";
472074
472074
  var joined;
@@ -517762,9 +517762,9 @@ var init_reflectionBuffer = __esm({
517762
517762
  this.persistPath = persistPath ?? null;
517763
517763
  if (this.persistPath) {
517764
517764
  try {
517765
- const { readFileSync: readFileSync82, existsSync: existsSync102 } = __require("node:fs");
517766
- if (existsSync102(this.persistPath)) {
517767
- this.state = JSON.parse(readFileSync82(this.persistPath, "utf-8"));
517765
+ const { readFileSync: readFileSync83, existsSync: existsSync103 } = __require("node:fs");
517766
+ if (existsSync103(this.persistPath)) {
517767
+ this.state = JSON.parse(readFileSync83(this.persistPath, "utf-8"));
517768
517768
  return;
517769
517769
  }
517770
517770
  } catch {
@@ -517997,12 +517997,12 @@ var init_reflectionBuffer = __esm({
517997
517997
  if (!this.persistPath)
517998
517998
  return;
517999
517999
  try {
518000
- const { writeFileSync: writeFileSync58, mkdirSync: mkdirSync66, existsSync: existsSync102 } = __require("node:fs");
518001
- const { join: join120 } = __require("node:path");
518002
- const dir = join120(this.persistPath, "..");
518003
- if (!existsSync102(dir))
518004
- mkdirSync66(dir, { recursive: true });
518005
- writeFileSync58(this.persistPath, JSON.stringify(this.state, null, 2));
518000
+ const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: existsSync103 } = __require("node:fs");
518001
+ const { join: join121 } = __require("node:path");
518002
+ const dir = join121(this.persistPath, "..");
518003
+ if (!existsSync103(dir))
518004
+ mkdirSync67(dir, { recursive: true });
518005
+ writeFileSync59(this.persistPath, JSON.stringify(this.state, null, 2));
518006
518006
  } catch {
518007
518007
  }
518008
518008
  }
@@ -522107,40 +522107,124 @@ TASK: ${task}` : task;
522107
522107
  if (turn > this._wideExplorationCooldownUntilTurn && turn >= 12) {
522108
522108
  const _windowCalls = toolCallLog.slice(-15);
522109
522109
  if (_windowCalls.length >= 12) {
522110
- const _ldShCount = _windowCalls.filter((c9) => c9.name === "list_directory" || c9.name === "shell").length;
522111
- const _fwCount = _windowCalls.filter((c9) => ["file_write", "file_edit", "batch_edit", "file_patch"].includes(c9.name)).length;
522112
- const _hasRecentShellFailure = _windowCalls.some((c9) => c9.name === "shell" && c9.success === false);
522113
- if (_ldShCount >= 11 && _fwCount <= 2 && _hasRecentShellFailure) {
522110
+ const _readClass = /* @__PURE__ */ new Set([
522111
+ // local fs reads
522112
+ "file_read",
522113
+ "file_explore",
522114
+ "list_directory",
522115
+ // search / grep / map
522116
+ "grep_search",
522117
+ "glob_find",
522118
+ "find_files",
522119
+ "code_neighbors",
522120
+ "repo_map",
522121
+ "codebase_map",
522122
+ "semantic_map",
522123
+ "symbol_search",
522124
+ "impact_analysis",
522125
+ "import_graph",
522126
+ // discovery
522127
+ "explore_tools",
522128
+ "diagnostic",
522129
+ "git_info",
522130
+ // stateful but no-mutation
522131
+ "todo_read",
522132
+ "memory_read",
522133
+ "memory_search",
522134
+ "working_notes"
522135
+ ]);
522136
+ const _mutationClass = /* @__PURE__ */ new Set([
522137
+ "file_write",
522138
+ "file_edit",
522139
+ "batch_edit",
522140
+ "file_patch",
522141
+ "notebook_edit",
522142
+ "structured_file",
522143
+ "image_resize",
522144
+ "memory_write",
522145
+ "todo_write"
522146
+ ]);
522147
+ let _readCount = 0;
522148
+ let _mutationCount = 0;
522149
+ let _staleCount = 0;
522150
+ for (const c9 of _windowCalls) {
522151
+ const _resultText = (c9.outputPreview || "") + "";
522152
+ const _isStale = c9.success === false || /\[FORCED PROGRESS BLOCK/.test(_resultText) || /\[RE-SERVED FROM CACHE/.test(_resultText) || /\[BLOCKED\b/.test(_resultText) || /\[NO-OP\]/.test(_resultText) || /\[DUPLICATE CALL/.test(_resultText);
522153
+ if (_isStale)
522154
+ _staleCount++;
522155
+ if (_readClass.has(c9.name)) {
522156
+ _readCount++;
522157
+ } else if (_mutationClass.has(c9.name)) {
522158
+ if (!_isStale)
522159
+ _mutationCount++;
522160
+ } else if (c9.name === "shell") {
522161
+ if (c9.success === true && !_isStale) {
522162
+ _readCount++;
522163
+ } else {
522164
+ _readCount++;
522165
+ }
522166
+ }
522167
+ }
522168
+ const _trigT1 = _readCount >= 9 && _mutationCount <= 2;
522169
+ const _trigT2 = _staleCount >= Math.ceil(_windowCalls.length / 2);
522170
+ const _trigT3 = _mutationCount === 0 && _windowCalls.length >= 12;
522171
+ const _fired = _trigT1 || _trigT2 || _trigT3;
522172
+ if (_fired) {
522114
522173
  this._wideExplorationCooldownUntilTurn = turn + 8;
522174
+ const _trigLabels = [];
522175
+ if (_trigT1)
522176
+ _trigLabels.push("read-heavy");
522177
+ if (_trigT2)
522178
+ _trigLabels.push("stale-results");
522179
+ if (_trigT3)
522180
+ _trigLabels.push("zero-mutations");
522115
522181
  const _recentFailures = this._recentFailures.slice(-3);
522116
- const _failureBlocks = _recentFailures.map((f2) => {
522182
+ const _failureBlocks = _recentFailures.length > 0 ? _recentFailures.map((f2) => {
522117
522183
  const _firstLine = (f2.error || f2.output || "").split(/\r?\n/).find((l2) => l2.trim().length > 0) || "";
522118
522184
  return ` - ${f2.tool}: "${_firstLine.slice(0, 200)}"`;
522119
- }).join("\n");
522185
+ }).join("\n") : ` (no recent failures recorded — agent may be hitting cache/no-op blocks)`;
522186
+ const _staleSamples = [];
522187
+ for (const c9 of _windowCalls.slice(-6)) {
522188
+ const _t = (c9.outputPreview || "") + "";
522189
+ const _m = _t.match(/\[(?:FORCED PROGRESS BLOCK|RE-SERVED FROM CACHE|BLOCKED|NO-OP|DUPLICATE CALL)[^\]]*\]/);
522190
+ if (_m)
522191
+ _staleSamples.push(` - ${c9.name}: ${_m[0]}`);
522192
+ }
522120
522193
  messages2.push({
522121
522194
  role: "system",
522122
522195
  content: [
522123
- `[WIDE-EXPLORATION HALT — REG-44]`,
522196
+ `[STUCK DETECTOR HALT — REG-44]`,
522124
522197
  ``,
522125
- `In the last ${_windowCalls.length} turns you have made ${_ldShCount} list_directory/shell calls and only ${_fwCount} file modification(s). At least one shell command in this window failed. This pattern — explore, retry, explore, retry — is the textbook "stuck after a failure" loop where the agent re-orients instead of fixing the named problem.`,
522198
+ `Window: last ${_windowCalls.length} tool calls.`,
522199
+ ` • Reads/exploration calls: ${_readCount}`,
522200
+ ` • Productive mutations: ${_mutationCount}`,
522201
+ ` • Stale (cached/blocked/no-op) results: ${_staleCount}`,
522202
+ ` • Triggers fired: ${_trigLabels.join(", ")}`,
522126
522203
  ``,
522127
- `Stop exploring. Pick ONE of these three actions for your next response:`,
522204
+ `You are consuming turns without producing new state. Every shape of "agent stuck" read-heavy without writes, repeated cache hits, blocked-shell loops, no-op todo updates — looks like this signal. The exact tool names don't matter; the ratio does.`,
522128
522205
  ``,
522129
- ` (a) Run a web search of the EXACT error string from the failure below — most framework/version-specific errors need external knowledge your training data may not cover. Tool: \`web_search\`.`,
522206
+ `Pick ONE of these for your next response:`,
522130
522207
  ``,
522131
- ` (b) Make ONE specific, targeted fix attempt addressing the SPECIFIC failed command. Read the error message literally it often names what to do next.`,
522208
+ ` (a) PRODUCE: emit a file_write / file_edit / file_patch / shell-mutation that creates or changes content. Even a partial draft of the next planned file is progress.`,
522132
522209
  ``,
522133
- ` (c) If you have tried 3+ different approaches and the same error persists, invoke the \`debate\` tool with the failed command and error as the task get a second opinion.`,
522210
+ ` (b) WEB SEARCH: if a SPECIFIC error string or unknown API is blocking you, run \`web_search\` with the exact error / API name. External knowledge is faster than guessing.`,
522134
522211
  ``,
522135
- `Recent failures in this window:`,
522136
- _failureBlocks || ` (no recent shell failures captured — investigate toolCallLog directly)`,
522212
+ ` (c) DEBATE: if you've tried 3+ approaches and they all hit the same wall, invoke \`debate\` with the failed task as the prompt — get a second opinion.`,
522137
522213
  ``,
522138
- `Do NOT in your next response: emit another list_directory or read another file. Take direct action toward fixing the failure.`
522139
- ].join("\n")
522214
+ ` (d) DECLARE BLOCKED: if you genuinely cannot make progress (missing dependency, ambiguous spec, external service down), call \`task_complete\` with a summary that NAMES THE BLOCKER explicitly. Don't keep looping.`,
522215
+ ``,
522216
+ `Recent failures (real or synthetic):`,
522217
+ _failureBlocks,
522218
+ ``,
522219
+ _staleSamples.length > 0 ? `Stale-result samples in this window:
522220
+ ${_staleSamples.join("\n")}` : ``,
522221
+ ``,
522222
+ `Do NOT in your next response: re-read a file you've already read this turn, re-run a shell command that just got blocked, or update todos without changing them. Those are the moves that landed you here.`
522223
+ ].filter(Boolean).join("\n")
522140
522224
  });
522141
522225
  this.emit({
522142
522226
  type: "status",
522143
- content: `REG-44 wide-exploration halt fired at turn ${turn} (ld+sh=${_ldShCount}, fw=${_fwCount} in window of ${_windowCalls.length})`,
522227
+ content: `REG-44 STUCK detector fired at turn ${turn} — triggers=[${_trigLabels.join(",")}], reads=${_readCount}, mutations=${_mutationCount}, stale=${_staleCount}, window=${_windowCalls.length}`,
522144
522228
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
522145
522229
  });
522146
522230
  }
@@ -524947,10 +525031,10 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
524947
525031
  if (nodes > 0) {
524948
525032
  this.emit({ type: "status", content: `Knowledge graph: ${nodes} nodes, ${edges} active edges`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
524949
525033
  try {
524950
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = __require("node:fs");
524951
- const { join: join120 } = __require("node:path");
524952
- const contextDir = join120(this._workingDirectory || process.cwd(), ".oa", "context");
524953
- mkdirSync66(contextDir, { recursive: true });
525034
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
525035
+ const { join: join121 } = __require("node:path");
525036
+ const contextDir = join121(this._workingDirectory || process.cwd(), ".oa", "context");
525037
+ mkdirSync67(contextDir, { recursive: true });
524954
525038
  const topEntities = this._temporalGraph.nodesByType("entity", 3);
524955
525039
  const topFiles = this._temporalGraph.nodesByType("file", 3);
524956
525040
  const topConcepts = this._temporalGraph.nodesByType("concept", 3);
@@ -524990,9 +525074,9 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
524990
525074
  section("Top Files", topFiles);
524991
525075
  section("Top Concepts", topConcepts);
524992
525076
  lines.push("(Use file_read on this file for quick recall. See provenance JSON for full edge detail.)");
524993
- const outPath = join120(contextDir, `kg-summary-${this._sessionId}.md`);
524994
- writeFileSync58(outPath, lines.join("\n"), "utf-8");
524995
- writeFileSync58(join120(contextDir, `kg-summary-latest.md`), lines.join("\n"), "utf-8");
525077
+ const outPath = join121(contextDir, `kg-summary-${this._sessionId}.md`);
525078
+ writeFileSync59(outPath, lines.join("\n"), "utf-8");
525079
+ writeFileSync59(join121(contextDir, `kg-summary-latest.md`), lines.join("\n"), "utf-8");
524996
525080
  } catch {
524997
525081
  }
524998
525082
  }
@@ -525160,11 +525244,11 @@ ${errOutput}`;
525160
525244
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
525161
525245
  });
525162
525246
  try {
525163
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = __require("node:fs");
525164
- const { join: join120 } = __require("node:path");
525165
- const resultsDir = join120(process.cwd(), ".oa", "tool-results");
525166
- mkdirSync66(resultsDir, { recursive: true });
525167
- writeFileSync58(join120(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
525247
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
525248
+ const { join: join121 } = __require("node:path");
525249
+ const resultsDir = join121(process.cwd(), ".oa", "tool-results");
525250
+ mkdirSync67(resultsDir, { recursive: true });
525251
+ writeFileSync59(join121(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
525168
525252
  # Turn: ${turn}
525169
525253
  # Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
525170
525254
  # Size: ${result.output.length} chars, ${lineCount} lines
@@ -525380,10 +525464,10 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
525380
525464
  if (!this._workingDirectory)
525381
525465
  return;
525382
525466
  try {
525383
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = __require("node:fs");
525384
- const { join: join120 } = __require("node:path");
525385
- const sessionDir = join120(this._workingDirectory, ".oa", "session", this._sessionId);
525386
- mkdirSync66(sessionDir, { recursive: true });
525467
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
525468
+ const { join: join121 } = __require("node:path");
525469
+ const sessionDir = join121(this._workingDirectory, ".oa", "session", this._sessionId);
525470
+ mkdirSync67(sessionDir, { recursive: true });
525387
525471
  const checkpoint = {
525388
525472
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
525389
525473
  sessionId: this._sessionId,
@@ -525395,7 +525479,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
525395
525479
  memexEntryCount: this._memexArchive.size,
525396
525480
  fileRegistrySize: this._fileRegistry.size
525397
525481
  };
525398
- writeFileSync58(join120(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
525482
+ writeFileSync59(join121(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
525399
525483
  } catch {
525400
525484
  }
525401
525485
  }
@@ -525678,8 +525762,8 @@ System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
525678
525762
  let recoveredTokens = 0;
525679
525763
  for (const [filePath, entry] of entries) {
525680
525764
  try {
525681
- const { readFileSync: readFileSync82 } = await import("node:fs");
525682
- const content = readFileSync82(filePath, "utf8");
525765
+ const { readFileSync: readFileSync83 } = await import("node:fs");
525766
+ const content = readFileSync83(filePath, "utf8");
525683
525767
  const tokenEst = Math.ceil(content.length / 4);
525684
525768
  if (recoveredTokens + tokenEst > fileRecoveryBudget)
525685
525769
  break;
@@ -527177,17 +527261,17 @@ ${result}`
527177
527261
  let resizedBase64 = null;
527178
527262
  try {
527179
527263
  const { execSync: execSync57 } = await import("node:child_process");
527180
- const { writeFileSync: writeFileSync58, readFileSync: readFileSync82, unlinkSync: unlinkSync25 } = await import("node:fs");
527181
- const { join: join120 } = await import("node:path");
527264
+ const { writeFileSync: writeFileSync59, readFileSync: readFileSync83, unlinkSync: unlinkSync25 } = await import("node:fs");
527265
+ const { join: join121 } = await import("node:path");
527182
527266
  const { tmpdir: tmpdir22 } = await import("node:os");
527183
- const tmpIn = join120(tmpdir22(), `oa_img_in_${Date.now()}.png`);
527184
- const tmpOut = join120(tmpdir22(), `oa_img_out_${Date.now()}.jpg`);
527185
- writeFileSync58(tmpIn, buffer2);
527267
+ const tmpIn = join121(tmpdir22(), `oa_img_in_${Date.now()}.png`);
527268
+ const tmpOut = join121(tmpdir22(), `oa_img_out_${Date.now()}.jpg`);
527269
+ writeFileSync59(tmpIn, buffer2);
527186
527270
  const pyBin = process.platform === "win32" ? "python" : "python3";
527187
527271
  const escapedIn = tmpIn.replace(/\\/g, "\\\\");
527188
527272
  const escapedOut = tmpOut.replace(/\\/g, "\\\\");
527189
527273
  execSync57(`${pyBin} -c "from PIL import Image; img = Image.open('${escapedIn}'); img.thumbnail((512, 512), Image.LANCZOS); img = img.convert('RGB'); img.save('${escapedOut}', 'JPEG', quality=75)"`, { timeout: 1e4, stdio: "pipe" });
527190
- const resizedBuf = readFileSync82(tmpOut);
527274
+ const resizedBuf = readFileSync83(tmpOut);
527191
527275
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
527192
527276
  try {
527193
527277
  unlinkSync25(tmpIn);
@@ -533935,7 +534019,7 @@ var require_websocket3 = __commonJS({
533935
534019
  var http6 = __require("http");
533936
534020
  var net5 = __require("net");
533937
534021
  var tls2 = __require("tls");
533938
- var { randomBytes: randomBytes24, createHash: createHash16 } = __require("crypto");
534022
+ var { randomBytes: randomBytes25, createHash: createHash16 } = __require("crypto");
533939
534023
  var { Duplex: Duplex3, Readable } = __require("stream");
533940
534024
  var { URL: URL3 } = __require("url");
533941
534025
  var PerMessageDeflate2 = require_permessage_deflate3();
@@ -534465,7 +534549,7 @@ var require_websocket3 = __commonJS({
534465
534549
  }
534466
534550
  }
534467
534551
  const defaultPort = isSecure ? 443 : 80;
534468
- const key = randomBytes24(16).toString("base64");
534552
+ const key = randomBytes25(16).toString("base64");
534469
534553
  const request = isSecure ? https4.request : http6.request;
534470
534554
  const protocolSet = /* @__PURE__ */ new Set();
534471
534555
  let perMessageDeflate;
@@ -535727,25 +535811,25 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
535727
535811
  async function fetchPeerModels(peerId, authKey) {
535728
535812
  try {
535729
535813
  const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
535730
- const { existsSync: existsSync102, readFileSync: readFileSync82 } = await import("node:fs");
535731
- const { join: join120 } = await import("node:path");
535814
+ const { existsSync: existsSync103, readFileSync: readFileSync83 } = await import("node:fs");
535815
+ const { join: join121 } = await import("node:path");
535732
535816
  const cwd4 = process.cwd();
535733
535817
  const nexusTool = new NexusTool2(cwd4);
535734
535818
  const nexusDir = nexusTool.getNexusDir();
535735
535819
  let isLocalPeer = false;
535736
535820
  try {
535737
- const statusPath = join120(nexusDir, "status.json");
535738
- if (existsSync102(statusPath)) {
535739
- const status = JSON.parse(readFileSync82(statusPath, "utf8"));
535821
+ const statusPath = join121(nexusDir, "status.json");
535822
+ if (existsSync103(statusPath)) {
535823
+ const status = JSON.parse(readFileSync83(statusPath, "utf8"));
535740
535824
  if (status.peerId === peerId) isLocalPeer = true;
535741
535825
  }
535742
535826
  } catch {
535743
535827
  }
535744
535828
  if (isLocalPeer) {
535745
- const pricingPath = join120(nexusDir, "pricing.json");
535746
- if (existsSync102(pricingPath)) {
535829
+ const pricingPath = join121(nexusDir, "pricing.json");
535830
+ if (existsSync103(pricingPath)) {
535747
535831
  try {
535748
- const pricing = JSON.parse(readFileSync82(pricingPath, "utf8"));
535832
+ const pricing = JSON.parse(readFileSync83(pricingPath, "utf8"));
535749
535833
  const localModels = (pricing.models || []).map((m2) => ({
535750
535834
  name: m2.model || "unknown",
535751
535835
  size: m2.parameterSize || "",
@@ -535758,10 +535842,10 @@ async function fetchPeerModels(peerId, authKey) {
535758
535842
  }
535759
535843
  }
535760
535844
  }
535761
- const cachePath = join120(nexusDir, "peer-models-cache.json");
535762
- if (existsSync102(cachePath)) {
535845
+ const cachePath = join121(nexusDir, "peer-models-cache.json");
535846
+ if (existsSync103(cachePath)) {
535763
535847
  try {
535764
- const cache8 = JSON.parse(readFileSync82(cachePath, "utf8"));
535848
+ const cache8 = JSON.parse(readFileSync83(cachePath, "utf8"));
535765
535849
  if (cache8.peerId === peerId && cache8.models?.length > 0) {
535766
535850
  const age = Date.now() - new Date(cache8.cachedAt).getTime();
535767
535851
  if (age < 5 * 60 * 1e3) {
@@ -535873,10 +535957,10 @@ async function fetchPeerModels(peerId, authKey) {
535873
535957
  } catch {
535874
535958
  }
535875
535959
  if (isLocalPeer) {
535876
- const pricingPath = join120(nexusDir, "pricing.json");
535877
- if (existsSync102(pricingPath)) {
535960
+ const pricingPath = join121(nexusDir, "pricing.json");
535961
+ if (existsSync103(pricingPath)) {
535878
535962
  try {
535879
- const pricing = JSON.parse(readFileSync82(pricingPath, "utf8"));
535963
+ const pricing = JSON.parse(readFileSync83(pricingPath, "utf8"));
535880
535964
  return (pricing.models || []).map((m2) => ({
535881
535965
  name: m2.model || "unknown",
535882
535966
  size: m2.parameterSize || "",
@@ -553695,9 +553779,9 @@ async function ensureVoiceDeps(ctx3) {
553695
553779
  }
553696
553780
  if (typeof mod2.getVenvPython === "function") {
553697
553781
  const { dirname: dirname38 } = await import("node:path");
553698
- const { existsSync: existsSync102 } = await import("node:fs");
553782
+ const { existsSync: existsSync103 } = await import("node:fs");
553699
553783
  const venvPy = mod2.getVenvPython();
553700
- if (existsSync102(venvPy)) {
553784
+ if (existsSync103(venvPy)) {
553701
553785
  process.env.TRANSCRIBE_PYTHON = venvPy;
553702
553786
  const venvBin = dirname38(venvPy);
553703
553787
  const sep2 = process.platform === "win32" ? ";" : ":";
@@ -554015,11 +554099,11 @@ async function handleSlashCommand(input, ctx3) {
554015
554099
  let key = process.env["OA_API_KEY"] || "";
554016
554100
  if (!key) {
554017
554101
  try {
554018
- const { homedir: homedir43 } = await import("node:os");
554019
- const { readFileSync: readFileSync82, existsSync: existsSync102 } = await import("node:fs");
554020
- const { join: join120 } = await import("node:path");
554021
- const p2 = join120(homedir43(), ".open-agents", "api.key");
554022
- if (existsSync102(p2)) key = readFileSync82(p2, "utf8").trim();
554102
+ const { homedir: homedir44 } = await import("node:os");
554103
+ const { readFileSync: readFileSync83, existsSync: existsSync103 } = await import("node:fs");
554104
+ const { join: join121 } = await import("node:path");
554105
+ const p2 = join121(homedir44(), ".open-agents", "api.key");
554106
+ if (existsSync103(p2)) key = readFileSync83(p2, "utf8").trim();
554023
554107
  } catch {
554024
554108
  }
554025
554109
  }
@@ -554056,15 +554140,15 @@ async function handleSlashCommand(input, ctx3) {
554056
554140
  }
554057
554141
  if (action === "new") {
554058
554142
  try {
554059
- const { randomBytes: randomBytes24 } = await import("node:crypto");
554060
- const { homedir: homedir43 } = await import("node:os");
554061
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = await import("node:fs");
554062
- const { join: join120 } = await import("node:path");
554063
- const newKey = randomBytes24(16).toString("hex");
554143
+ const { randomBytes: randomBytes25 } = await import("node:crypto");
554144
+ const { homedir: homedir44 } = await import("node:os");
554145
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
554146
+ const { join: join121 } = await import("node:path");
554147
+ const newKey = randomBytes25(16).toString("hex");
554064
554148
  process.env["OA_API_KEY"] = newKey;
554065
- const dir = join120(homedir43(), ".open-agents");
554066
- mkdirSync66(dir, { recursive: true });
554067
- writeFileSync58(join120(dir, "api.key"), newKey + "\n", "utf8");
554149
+ const dir = join121(homedir44(), ".open-agents");
554150
+ mkdirSync67(dir, { recursive: true });
554151
+ writeFileSync59(join121(dir, "api.key"), newKey + "\n", "utf8");
554068
554152
  renderInfo2(`New API key: ${c3.bold(c3.yellow(newKey))}`);
554069
554153
  renderInfo2("Restart the daemon to apply if needed. Use /access any to restart quickly.");
554070
554154
  } catch (e2) {
@@ -554245,18 +554329,18 @@ async function handleSlashCommand(input, ctx3) {
554245
554329
  }
554246
554330
  process.env["OA_ACCESS"] = val2;
554247
554331
  if (val2 === "any" && !process.env["OA_API_KEY"]) {
554248
- const { randomBytes: randomBytes24 } = await import("node:crypto");
554249
- const apiKey = randomBytes24(16).toString("hex");
554332
+ const { randomBytes: randomBytes25 } = await import("node:crypto");
554333
+ const apiKey = randomBytes25(16).toString("hex");
554250
554334
  process.env["OA_API_KEY"] = apiKey;
554251
554335
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
554252
554336
  renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
554253
554337
  try {
554254
- const { homedir: homedir44 } = await import("node:os");
554255
- const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
554256
- const { join: join121 } = await import("node:path");
554257
- const dir = join121(homedir44(), ".open-agents");
554258
- mkdirSync67(dir, { recursive: true });
554259
- writeFileSync59(join121(dir, "api.key"), apiKey + "\n", "utf8");
554338
+ const { homedir: homedir45 } = await import("node:os");
554339
+ const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
554340
+ const { join: join122 } = await import("node:path");
554341
+ const dir = join122(homedir45(), ".open-agents");
554342
+ mkdirSync68(dir, { recursive: true });
554343
+ writeFileSync60(join122(dir, "api.key"), apiKey + "\n", "utf8");
554260
554344
  } catch {
554261
554345
  }
554262
554346
  }
@@ -554267,12 +554351,12 @@ async function handleSlashCommand(input, ctx3) {
554267
554351
  }
554268
554352
  const port2 = parseInt(process.env["OA_PORT"] || "11435", 10);
554269
554353
  try {
554270
- const { homedir: homedir44 } = await import("node:os");
554271
- const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
554272
- const { join: join121 } = await import("node:path");
554273
- const dir = join121(homedir44(), ".open-agents");
554274
- mkdirSync67(dir, { recursive: true });
554275
- writeFileSync59(join121(dir, "access"), `${val2}
554354
+ const { homedir: homedir45 } = await import("node:os");
554355
+ const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
554356
+ const { join: join122 } = await import("node:path");
554357
+ const dir = join122(homedir45(), ".open-agents");
554358
+ mkdirSync68(dir, { recursive: true });
554359
+ writeFileSync60(join122(dir, "access"), `${val2}
554276
554360
  `, "utf8");
554277
554361
  } catch {
554278
554362
  }
@@ -554347,18 +554431,18 @@ async function handleSlashCommand(input, ctx3) {
554347
554431
  }
554348
554432
  process.env["OA_ACCESS"] = val;
554349
554433
  if (val === "any" && !process.env["OA_API_KEY"]) {
554350
- const { randomBytes: randomBytes24 } = await import("node:crypto");
554351
- const apiKey = randomBytes24(16).toString("hex");
554434
+ const { randomBytes: randomBytes25 } = await import("node:crypto");
554435
+ const apiKey = randomBytes25(16).toString("hex");
554352
554436
  process.env["OA_API_KEY"] = apiKey;
554353
554437
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
554354
554438
  renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
554355
554439
  try {
554356
- const { homedir: homedir44 } = await import("node:os");
554357
- const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
554358
- const { join: join121 } = await import("node:path");
554359
- const dir = join121(homedir44(), ".open-agents");
554360
- mkdirSync67(dir, { recursive: true });
554361
- writeFileSync59(join121(dir, "api.key"), apiKey + "\n", "utf8");
554440
+ const { homedir: homedir45 } = await import("node:os");
554441
+ const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
554442
+ const { join: join122 } = await import("node:path");
554443
+ const dir = join122(homedir45(), ".open-agents");
554444
+ mkdirSync68(dir, { recursive: true });
554445
+ writeFileSync60(join122(dir, "api.key"), apiKey + "\n", "utf8");
554362
554446
  } catch {
554363
554447
  }
554364
554448
  }
@@ -554368,13 +554452,13 @@ async function handleSlashCommand(input, ctx3) {
554368
554452
  ctx3.saveSettings({ oaAccess: val });
554369
554453
  }
554370
554454
  const port = parseInt(process.env["OA_PORT"] || "11435", 10);
554371
- const { homedir: homedir43 } = await import("node:os");
554372
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = await import("node:fs");
554373
- const { join: join120 } = await import("node:path");
554455
+ const { homedir: homedir44 } = await import("node:os");
554456
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
554457
+ const { join: join121 } = await import("node:path");
554374
554458
  try {
554375
- const dir = join120(homedir43(), ".open-agents");
554376
- mkdirSync66(dir, { recursive: true });
554377
- writeFileSync58(join120(dir, "access"), `${val}
554459
+ const dir = join121(homedir44(), ".open-agents");
554460
+ mkdirSync67(dir, { recursive: true });
554461
+ writeFileSync59(join121(dir, "access"), `${val}
554378
554462
  `, "utf8");
554379
554463
  } catch (e2) {
554380
554464
  renderWarning2(`Could not persist ~/.open-agents/access: ${e2 instanceof Error ? e2.message : String(e2)}`);
@@ -554727,9 +554811,9 @@ async function handleSlashCommand(input, ctx3) {
554727
554811
  renderInfo2("No wallet configured. Ask the agent to create one via the nexus tool.");
554728
554812
  }
554729
554813
  } else if (sub === "name") {
554730
- const { homedir: homedir43 } = __require("node:os");
554814
+ const { homedir: homedir44 } = __require("node:os");
554731
554815
  const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
554732
- const namePath = __require("node:path").join(homedir43(), ".open-agents", "agent-name");
554816
+ const namePath = __require("node:path").join(homedir44(), ".open-agents", "agent-name");
554733
554817
  if (rest2) {
554734
554818
  const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
554735
554819
  if (!customName) {
@@ -556926,8 +557010,8 @@ sleep 1
556926
557010
  let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
556927
557011
  if (!sponsorName || sponsorName.length < 2) {
556928
557012
  try {
556929
- const { homedir: homedir43 } = __require("os");
556930
- const namePath = __require("path").join(homedir43(), ".open-agents", "agent-name");
557013
+ const { homedir: homedir44 } = __require("os");
557014
+ const namePath = __require("path").join(homedir44(), ".open-agents", "agent-name");
556931
557015
  if (existsSync77(namePath)) sponsorName = readFileSync61(namePath, "utf8").trim();
556932
557016
  } catch {
556933
557017
  }
@@ -558591,11 +558675,11 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
558591
558675
  continue;
558592
558676
  }
558593
558677
  const { basename: basename20, join: pathJoin } = await import("node:path");
558594
- const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync66, existsSync: exists2 } = await import("node:fs");
558595
- const { homedir: homedir43 } = await import("node:os");
558678
+ const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync67, existsSync: exists2 } = await import("node:fs");
558679
+ const { homedir: homedir44 } = await import("node:os");
558596
558680
  const modelName = basename20(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
558597
- const destDir = pathJoin(homedir43(), ".open-agents", "voice", "models", modelName);
558598
- if (!exists2(destDir)) mkdirSync66(destDir, { recursive: true });
558681
+ const destDir = pathJoin(homedir44(), ".open-agents", "voice", "models", modelName);
558682
+ if (!exists2(destDir)) mkdirSync67(destDir, { recursive: true });
558599
558683
  copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
558600
558684
  copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
558601
558685
  const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
@@ -559345,10 +559429,10 @@ async function handleSponsoredEndpoint(ctx3, local) {
559345
559429
  sponsors.push(...verified);
559346
559430
  if (verified.length > 0) {
559347
559431
  try {
559348
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = __require("node:fs");
559349
- mkdirSync66(sponsorDir2, { recursive: true });
559432
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
559433
+ mkdirSync67(sponsorDir2, { recursive: true });
559350
559434
  const cached = verified.map((s2) => ({ ...s2, lastVerified: Date.now() }));
559351
- writeFileSync58(knownFile, JSON.stringify(cached, null, 2));
559435
+ writeFileSync59(knownFile, JSON.stringify(cached, null, 2));
559352
559436
  } catch {
559353
559437
  }
559354
559438
  }
@@ -559521,11 +559605,11 @@ async function handlePeerEndpoint(peerId, authKey, ctx3, local) {
559521
559605
  const models = await fetchModels(peerUrl, authKey);
559522
559606
  if (models.length > 0) {
559523
559607
  try {
559524
- const { writeFileSync: writeFileSync58, mkdirSync: mkdirSync66 } = await import("node:fs");
559525
- const { join: join120, dirname: dirname38 } = await import("node:path");
559526
- const cachePath = join120(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
559527
- mkdirSync66(dirname38(cachePath), { recursive: true });
559528
- writeFileSync58(cachePath, JSON.stringify({
559608
+ const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67 } = await import("node:fs");
559609
+ const { join: join121, dirname: dirname38 } = await import("node:path");
559610
+ const cachePath = join121(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
559611
+ mkdirSync67(dirname38(cachePath), { recursive: true });
559612
+ writeFileSync59(cachePath, JSON.stringify({
559529
559613
  peerId,
559530
559614
  cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
559531
559615
  models: models.map((m2) => ({ name: m2.name, size: m2.size, parameterSize: m2.parameterSize }))
@@ -560094,17 +560178,17 @@ async function handleUpdate(subcommand, ctx3) {
560094
560178
  try {
560095
560179
  const { createRequire: createRequire7 } = await import("node:module");
560096
560180
  const { fileURLToPath: fileURLToPath20 } = await import("node:url");
560097
- const { dirname: dirname38, join: join120 } = await import("node:path");
560098
- const { existsSync: existsSync102 } = await import("node:fs");
560181
+ const { dirname: dirname38, join: join121 } = await import("node:path");
560182
+ const { existsSync: existsSync103 } = await import("node:fs");
560099
560183
  const req2 = createRequire7(import.meta.url);
560100
560184
  const thisDir = dirname38(fileURLToPath20(import.meta.url));
560101
560185
  const candidates = [
560102
- join120(thisDir, "..", "package.json"),
560103
- join120(thisDir, "..", "..", "package.json"),
560104
- join120(thisDir, "..", "..", "..", "package.json")
560186
+ join121(thisDir, "..", "package.json"),
560187
+ join121(thisDir, "..", "..", "package.json"),
560188
+ join121(thisDir, "..", "..", "..", "package.json")
560105
560189
  ];
560106
560190
  for (const pkgPath of candidates) {
560107
- if (existsSync102(pkgPath)) {
560191
+ if (existsSync103(pkgPath)) {
560108
560192
  const pkg = req2(pkgPath);
560109
560193
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
560110
560194
  currentVersion = pkg.version ?? "0.0.0";
@@ -561250,15 +561334,15 @@ var init_commands = __esm({
561250
561334
  process.env["OA_ACCESS"] = val;
561251
561335
  if (val === "any" && !process.env["OA_API_KEY"]) {
561252
561336
  try {
561253
- const { randomBytes: randomBytes24 } = await import("node:crypto");
561254
- const { homedir: homedir43 } = await import("node:os");
561255
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = await import("node:fs");
561256
- const { join: join120 } = await import("node:path");
561257
- const apiKey = randomBytes24(16).toString("hex");
561337
+ const { randomBytes: randomBytes25 } = await import("node:crypto");
561338
+ const { homedir: homedir44 } = await import("node:os");
561339
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
561340
+ const { join: join121 } = await import("node:path");
561341
+ const apiKey = randomBytes25(16).toString("hex");
561258
561342
  process.env["OA_API_KEY"] = apiKey;
561259
- const dir = join120(homedir43(), ".open-agents");
561260
- mkdirSync66(dir, { recursive: true });
561261
- writeFileSync58(join120(dir, "api.key"), apiKey + "\n", "utf8");
561343
+ const dir = join121(homedir44(), ".open-agents");
561344
+ mkdirSync67(dir, { recursive: true });
561345
+ writeFileSync59(join121(dir, "api.key"), apiKey + "\n", "utf8");
561262
561346
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
561263
561347
  renderInfo2("Use Authorization: Bearer <key> or click 'key' in the Web UI header to paste it.");
561264
561348
  } catch (e2) {
@@ -561272,12 +561356,12 @@ var init_commands = __esm({
561272
561356
  }
561273
561357
  const port = parseInt(process.env["OA_PORT"] || "11435", 10);
561274
561358
  try {
561275
- const { homedir: homedir43 } = await import("node:os");
561276
- const { mkdirSync: mkdirSync66, writeFileSync: writeFileSync58 } = await import("node:fs");
561277
- const { join: join120 } = await import("node:path");
561278
- const dir = join120(homedir43(), ".open-agents");
561279
- mkdirSync66(dir, { recursive: true });
561280
- writeFileSync58(join120(dir, "access"), `${val}
561359
+ const { homedir: homedir44 } = await import("node:os");
561360
+ const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
561361
+ const { join: join121 } = await import("node:path");
561362
+ const dir = join121(homedir44(), ".open-agents");
561363
+ mkdirSync67(dir, { recursive: true });
561364
+ writeFileSync59(join121(dir, "access"), `${val}
561281
561365
  `, "utf8");
561282
561366
  } catch {
561283
561367
  }
@@ -576712,10 +576796,108 @@ var init_aiwg = __esm({
576712
576796
  }
576713
576797
  });
576714
576798
 
576715
- // packages/cli/src/api/routes-v1.ts
576716
- import { existsSync as existsSync94, readFileSync as readFileSync76, readdirSync as readdirSync32, statSync as statSync28 } from "node:fs";
576717
- import { join as join110, resolve as pathResolve } from "node:path";
576799
+ // packages/cli/src/api/runtime-keys.ts
576800
+ var runtime_keys_exports = {};
576801
+ __export(runtime_keys_exports, {
576802
+ listKeysSafe: () => listKeysSafe,
576803
+ lookupKey: () => lookupKey,
576804
+ mintKey: () => mintKey,
576805
+ revokeByPrefix: () => revokeByPrefix
576806
+ });
576807
+ import { existsSync as existsSync94, readFileSync as readFileSync76, writeFileSync as writeFileSync51, mkdirSync as mkdirSync59, chmodSync } from "node:fs";
576808
+ import { join as join110 } from "node:path";
576718
576809
  import { homedir as homedir37 } from "node:os";
576810
+ import { randomBytes as randomBytes21 } from "node:crypto";
576811
+ function ensureDir2() {
576812
+ const dir = join110(homedir37(), ".open-agents");
576813
+ if (!existsSync94(dir)) mkdirSync59(dir, { recursive: true });
576814
+ }
576815
+ function loadAll() {
576816
+ if (!existsSync94(KEYS_FILE)) return [];
576817
+ try {
576818
+ const raw = readFileSync76(KEYS_FILE, "utf-8");
576819
+ const parsed = JSON.parse(raw);
576820
+ if (!Array.isArray(parsed)) return [];
576821
+ return parsed;
576822
+ } catch {
576823
+ return [];
576824
+ }
576825
+ }
576826
+ function persistAll(records) {
576827
+ ensureDir2();
576828
+ writeFileSync51(KEYS_FILE, JSON.stringify(records, null, 2), "utf-8");
576829
+ try {
576830
+ chmodSync(KEYS_FILE, 384);
576831
+ } catch {
576832
+ }
576833
+ }
576834
+ function mintKey(args) {
576835
+ const records = loadAll();
576836
+ const key = `oa_${randomBytes21(32).toString("hex")}`;
576837
+ const record = {
576838
+ key,
576839
+ scope: args.scope,
576840
+ owner: args.owner,
576841
+ profile: args.profile ?? null,
576842
+ created: (/* @__PURE__ */ new Date()).toISOString(),
576843
+ revoked: null,
576844
+ rpm: args.rpm,
576845
+ tpd: args.tpd,
576846
+ max_jobs: args.max_jobs
576847
+ };
576848
+ records.push(record);
576849
+ persistAll(records);
576850
+ return record;
576851
+ }
576852
+ function listKeysSafe() {
576853
+ return loadAll().map((r2) => ({
576854
+ ...r2,
576855
+ key: void 0,
576856
+ key_prefix: r2.key.slice(0, 8),
576857
+ key_suffix: r2.key.slice(-4)
576858
+ })).map((r2) => {
576859
+ const { key: _drop, ...rest } = r2;
576860
+ void _drop;
576861
+ return rest;
576862
+ });
576863
+ }
576864
+ function revokeByPrefix(prefix) {
576865
+ if (!prefix || prefix.length < 8) return 0;
576866
+ const records = loadAll();
576867
+ const now = (/* @__PURE__ */ new Date()).toISOString();
576868
+ let n2 = 0;
576869
+ for (const r2 of records) {
576870
+ if (r2.key.startsWith(prefix) && !r2.revoked) {
576871
+ r2.revoked = now;
576872
+ n2++;
576873
+ }
576874
+ }
576875
+ if (n2 > 0) persistAll(records);
576876
+ return n2;
576877
+ }
576878
+ function lookupKey(secret) {
576879
+ if (!secret) return null;
576880
+ const records = loadAll();
576881
+ for (const r2 of records) {
576882
+ if (r2.key === secret) {
576883
+ if (r2.revoked) return null;
576884
+ return r2;
576885
+ }
576886
+ }
576887
+ return null;
576888
+ }
576889
+ var KEYS_FILE;
576890
+ var init_runtime_keys = __esm({
576891
+ "packages/cli/src/api/runtime-keys.ts"() {
576892
+ "use strict";
576893
+ KEYS_FILE = join110(homedir37(), ".open-agents", "keys.json");
576894
+ }
576895
+ });
576896
+
576897
+ // packages/cli/src/api/routes-v1.ts
576898
+ import { existsSync as existsSync95, readFileSync as readFileSync77, readdirSync as readdirSync32, statSync as statSync28 } from "node:fs";
576899
+ import { join as join111, resolve as pathResolve } from "node:path";
576900
+ import { homedir as homedir38 } from "node:os";
576719
576901
  async function tryRouteV1(ctx3) {
576720
576902
  const { pathname, method } = ctx3;
576721
576903
  if (pathname === "/v1/skills" && method === "GET") {
@@ -576791,6 +576973,12 @@ async function tryRouteV1(ctx3) {
576791
576973
  if (pathname === "/v1/index" && method === "POST") {
576792
576974
  return handleIndex(ctx3);
576793
576975
  }
576976
+ if (pathname === "/v1/keys" && method === "GET") return handleListKeys(ctx3);
576977
+ if (pathname === "/v1/keys" && method === "POST") return handleMintKey(ctx3);
576978
+ {
576979
+ const m2 = /^\/v1\/keys\/([^/]+)$/.exec(pathname);
576980
+ if (m2 && method === "DELETE") return handleRevokeKey(ctx3, decodeURIComponent(m2[1]));
576981
+ }
576794
576982
  if (pathname === "/v1/tools" && method === "GET") {
576795
576983
  return handleListTools(ctx3);
576796
576984
  }
@@ -576937,11 +577125,11 @@ async function handleGetSkill(ctx3, name10) {
576937
577125
  async function fallbackDiscoverSkills() {
576938
577126
  return (_root) => {
576939
577127
  const roots = [
576940
- join110(homedir37(), ".local", "share", "ai-writing-guide")
577128
+ join111(homedir38(), ".local", "share", "ai-writing-guide")
576941
577129
  ];
576942
577130
  const out = [];
576943
577131
  for (const root of roots) {
576944
- if (!existsSync94(root)) continue;
577132
+ if (!existsSync95(root)) continue;
576945
577133
  walkForSkills(root, out, 0);
576946
577134
  }
576947
577135
  return out;
@@ -576952,12 +577140,12 @@ function walkForSkills(dir, out, depth) {
576952
577140
  try {
576953
577141
  for (const e2 of readdirSync32(dir, { withFileTypes: true })) {
576954
577142
  if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
576955
- const p2 = join110(dir, e2.name);
577143
+ const p2 = join111(dir, e2.name);
576956
577144
  if (e2.isDirectory()) {
576957
577145
  walkForSkills(p2, out, depth + 1);
576958
577146
  } else if (e2.isFile() && e2.name === "SKILL.md") {
576959
577147
  try {
576960
- const content = readFileSync76(p2, "utf-8").slice(0, 2e3);
577148
+ const content = readFileSync77(p2, "utf-8").slice(0, 2e3);
576961
577149
  const nameMatch = content.match(/^name:\s*(.+)$/m);
576962
577150
  const descMatch = content.match(/^description:\s*(.+)$/m);
576963
577151
  out.push({
@@ -577141,7 +577329,7 @@ async function getMemoryStores() {
577141
577329
  if (memoryInitTried) return null;
577142
577330
  memoryInitTried = true;
577143
577331
  try {
577144
- const dbPath = join110(homedir37(), ".open-agents", "memory.db");
577332
+ const dbPath = join111(homedir38(), ".open-agents", "memory.db");
577145
577333
  const sharedDb = initDb(dbPath);
577146
577334
  memoryStoresCache = {
577147
577335
  episode: new EpisodeStore(dbPath),
@@ -577399,7 +577587,7 @@ async function handleFilesRead(ctx3) {
577399
577587
  }));
577400
577588
  return true;
577401
577589
  }
577402
- if (!existsSync94(resolved)) {
577590
+ if (!existsSync95(resolved)) {
577403
577591
  sendProblem(res, problemDetails({
577404
577592
  type: P.notFound,
577405
577593
  status: 404,
@@ -577431,7 +577619,7 @@ async function handleFilesRead(ctx3) {
577431
577619
  }));
577432
577620
  return true;
577433
577621
  }
577434
- const content = readFileSync76(resolved, "utf-8");
577622
+ const content = readFileSync77(resolved, "utf-8");
577435
577623
  const offset = typeof body.offset === "number" && body.offset >= 0 ? body.offset : 0;
577436
577624
  const limit = typeof body.limit === "number" && body.limit > 0 ? body.limit : content.length;
577437
577625
  const slice2 = content.slice(offset, offset + limit);
@@ -577664,14 +577852,14 @@ async function handleNexusStatus(ctx3) {
577664
577852
  const { res, requestId } = ctx3;
577665
577853
  try {
577666
577854
  const statePaths = [
577667
- join110(process.cwd(), ".oa", "nexus-peer-state.json"),
577668
- join110(homedir37(), ".open-agents", "nexus-peer-cache.json")
577855
+ join111(process.cwd(), ".oa", "nexus-peer-state.json"),
577856
+ join111(homedir38(), ".open-agents", "nexus-peer-cache.json")
577669
577857
  ];
577670
577858
  const states = [];
577671
577859
  for (const p2 of statePaths) {
577672
- if (!existsSync94(p2)) continue;
577860
+ if (!existsSync95(p2)) continue;
577673
577861
  try {
577674
- const raw = readFileSync76(p2, "utf-8");
577862
+ const raw = readFileSync77(p2, "utf-8");
577675
577863
  states.push({ source: p2, data: JSON.parse(raw) });
577676
577864
  } catch (e2) {
577677
577865
  states.push({ source: p2, error: String(e2) });
@@ -577698,8 +577886,8 @@ async function handleNexusStatus(ctx3) {
577698
577886
  }
577699
577887
  function loadAgentName() {
577700
577888
  try {
577701
- const p2 = join110(homedir37(), ".open-agents", "agent-name");
577702
- if (existsSync94(p2)) return readFileSync76(p2, "utf-8").trim();
577889
+ const p2 = join111(homedir38(), ".open-agents", "agent-name");
577890
+ if (existsSync95(p2)) return readFileSync77(p2, "utf-8").trim();
577703
577891
  } catch {
577704
577892
  }
577705
577893
  return null;
@@ -577708,14 +577896,14 @@ async function handleSponsors(ctx3) {
577708
577896
  const { req: req2, res, url, requestId } = ctx3;
577709
577897
  try {
577710
577898
  const candidates = [
577711
- join110(homedir37(), ".open-agents", "sponsor-cache.json"),
577712
- join110(homedir37(), ".open-agents", "sponsors.json")
577899
+ join111(homedir38(), ".open-agents", "sponsor-cache.json"),
577900
+ join111(homedir38(), ".open-agents", "sponsors.json")
577713
577901
  ];
577714
577902
  let sponsors = [];
577715
577903
  for (const p2 of candidates) {
577716
- if (!existsSync94(p2)) continue;
577904
+ if (!existsSync95(p2)) continue;
577717
577905
  try {
577718
- const raw = JSON.parse(readFileSync76(p2, "utf-8"));
577906
+ const raw = JSON.parse(readFileSync77(p2, "utf-8"));
577719
577907
  if (Array.isArray(raw)) {
577720
577908
  sponsors = raw;
577721
577909
  break;
@@ -577784,8 +577972,8 @@ async function handleEvaluate(ctx3) {
577784
577972
  }));
577785
577973
  return true;
577786
577974
  }
577787
- const jobPath = join110(process.cwd(), ".oa", "jobs", `${runId}.json`);
577788
- if (!existsSync94(jobPath)) {
577975
+ const jobPath = join111(process.cwd(), ".oa", "jobs", `${runId}.json`);
577976
+ if (!existsSync95(jobPath)) {
577789
577977
  sendProblem(res, problemDetails({
577790
577978
  type: P.notFound,
577791
577979
  status: 404,
@@ -577795,7 +577983,7 @@ async function handleEvaluate(ctx3) {
577795
577983
  }));
577796
577984
  return true;
577797
577985
  }
577798
- const job = JSON.parse(readFileSync76(jobPath, "utf-8"));
577986
+ const job = JSON.parse(readFileSync77(jobPath, "utf-8"));
577799
577987
  sendJson(res, 200, {
577800
577988
  run_id: runId,
577801
577989
  task: job.task,
@@ -577846,6 +578034,130 @@ async function handleIndex(ctx3) {
577846
578034
  return true;
577847
578035
  }
577848
578036
  }
578037
+ async function handleListKeys(ctx3) {
578038
+ const { req: req2, res, requestId } = ctx3;
578039
+ const reqAuth = req2;
578040
+ if (reqAuth._authScope !== "admin") {
578041
+ sendProblem(res, problemDetails({
578042
+ type: P.forbidden,
578043
+ status: 403,
578044
+ title: "Admin scope required",
578045
+ detail: "Listing keys requires 'admin' scope.",
578046
+ instance: requestId
578047
+ }));
578048
+ return true;
578049
+ }
578050
+ try {
578051
+ const { listKeysSafe: listKeysSafe2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
578052
+ sendJson(res, 200, { keys: listKeysSafe2() });
578053
+ } catch (err) {
578054
+ sendProblem(res, problemDetails({
578055
+ type: P.internalError,
578056
+ status: 500,
578057
+ title: "List keys failed",
578058
+ detail: err instanceof Error ? err.message : String(err),
578059
+ instance: requestId
578060
+ }));
578061
+ }
578062
+ return true;
578063
+ }
578064
+ async function handleMintKey(ctx3) {
578065
+ const { req: req2, res, requestId } = ctx3;
578066
+ const reqAuth = req2;
578067
+ if (reqAuth._authScope !== "admin") {
578068
+ sendProblem(res, problemDetails({
578069
+ type: P.forbidden,
578070
+ status: 403,
578071
+ title: "Admin scope required",
578072
+ detail: "Minting keys requires 'admin' scope.",
578073
+ instance: requestId
578074
+ }));
578075
+ return true;
578076
+ }
578077
+ try {
578078
+ const body = await parseJsonBodyStrict(req2).catch(() => null);
578079
+ if (!body || typeof body !== "object") {
578080
+ sendProblem(res, problemDetails({
578081
+ type: P.invalidRequest,
578082
+ status: 400,
578083
+ title: "Body must be JSON object",
578084
+ detail: "POST {scope: 'read'|'run'|'admin', owner: string, profile?: string}",
578085
+ instance: requestId
578086
+ }));
578087
+ return true;
578088
+ }
578089
+ const scope = body.scope;
578090
+ if (scope !== "read" && scope !== "run" && scope !== "admin") {
578091
+ sendProblem(res, problemDetails({
578092
+ type: P.invalidRequest,
578093
+ status: 400,
578094
+ title: "Invalid scope",
578095
+ detail: "scope must be one of 'read', 'run', 'admin'.",
578096
+ instance: requestId
578097
+ }));
578098
+ return true;
578099
+ }
578100
+ const owner = typeof body.owner === "string" ? body.owner.slice(0, 200) : "anonymous";
578101
+ const profile = typeof body.profile === "string" ? body.profile.slice(0, 100) : null;
578102
+ const { mintKey: mintKey2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
578103
+ const rec = mintKey2({
578104
+ scope,
578105
+ owner,
578106
+ profile,
578107
+ rpm: typeof body.rpm === "number" ? body.rpm : void 0,
578108
+ tpd: typeof body.tpd === "number" ? body.tpd : void 0,
578109
+ max_jobs: typeof body.max_jobs === "number" ? body.max_jobs : void 0
578110
+ });
578111
+ sendJson(res, 201, { ...rec, _note: "This is the ONLY response that contains the full key. Persist it now." });
578112
+ } catch (err) {
578113
+ sendProblem(res, problemDetails({
578114
+ type: P.internalError,
578115
+ status: 500,
578116
+ title: "Key mint failed",
578117
+ detail: err instanceof Error ? err.message : String(err),
578118
+ instance: requestId
578119
+ }));
578120
+ }
578121
+ return true;
578122
+ }
578123
+ async function handleRevokeKey(ctx3, prefix) {
578124
+ const { req: req2, res, requestId } = ctx3;
578125
+ const reqAuth = req2;
578126
+ if (reqAuth._authScope !== "admin") {
578127
+ sendProblem(res, problemDetails({
578128
+ type: P.forbidden,
578129
+ status: 403,
578130
+ title: "Admin scope required",
578131
+ detail: "Revoking keys requires 'admin' scope.",
578132
+ instance: requestId
578133
+ }));
578134
+ return true;
578135
+ }
578136
+ if (!prefix || prefix.length < 8) {
578137
+ sendProblem(res, problemDetails({
578138
+ type: P.invalidRequest,
578139
+ status: 400,
578140
+ title: "Prefix too short",
578141
+ detail: "Provide at least the first 8 characters of the key to revoke.",
578142
+ instance: requestId
578143
+ }));
578144
+ return true;
578145
+ }
578146
+ try {
578147
+ const { revokeByPrefix: revokeByPrefix2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
578148
+ const n2 = revokeByPrefix2(prefix);
578149
+ sendJson(res, 200, { revoked: n2 });
578150
+ } catch (err) {
578151
+ sendProblem(res, problemDetails({
578152
+ type: P.internalError,
578153
+ status: 500,
578154
+ title: "Key revoke failed",
578155
+ detail: err instanceof Error ? err.message : String(err),
578156
+ instance: requestId
578157
+ }));
578158
+ }
578159
+ return true;
578160
+ }
577849
578161
  async function handleListTools(ctx3) {
577850
578162
  const { req: req2, res, url, requestId } = ctx3;
577851
578163
  try {
@@ -577889,10 +578201,15 @@ async function handleListTools(ctx3) {
577889
578201
  const filterCat = url.searchParams.get("category");
577890
578202
  const filterScope = url.searchParams.get("scope");
577891
578203
  const filterRisk = url.searchParams.get("risk");
578204
+ const filterOffDeviceRaw = url.searchParams.get("off_device");
577892
578205
  let filtered = tools;
577893
578206
  if (filterCat) filtered = filtered.filter((t2) => t2.security?.categories?.includes(filterCat));
577894
578207
  if (filterScope) filtered = filtered.filter((t2) => t2.security?.requires_scope === filterScope);
577895
578208
  if (filterRisk) filtered = filtered.filter((t2) => t2.security?.risk === filterRisk);
578209
+ if (filterOffDeviceRaw !== null) {
578210
+ const want = filterOffDeviceRaw === "true";
578211
+ filtered = filtered.filter((t2) => t2.security?.off_device_allowed === want);
578212
+ }
577896
578213
  const page2 = parsePagination(url.searchParams);
577897
578214
  const envelope = paginated(filtered, page2);
577898
578215
  const etag = computeEtag(envelope);
@@ -577965,6 +578282,13 @@ async function handleGetTool(ctx3, name10) {
577965
578282
  endpoints: {
577966
578283
  call: `/v1/tools/${encodeURIComponent(name10)}/call`,
577967
578284
  schema: `/v1/tools/${encodeURIComponent(name10)}`
578285
+ },
578286
+ // Q4: document the canonical body shape for /v1/tools/{name}/call.
578287
+ // The `parameters` field IS the JSON-schema describing what goes
578288
+ // INSIDE the args wrapper — it's not the wrapper itself.
578289
+ call_body_shape: {
578290
+ args: "<object matching the `parameters` JSON schema>",
578291
+ working_dir: "<optional absolute path; defaults to daemon cwd>"
577968
578292
  }
577969
578293
  };
577970
578294
  const etag = computeEtag(body);
@@ -578147,17 +578471,17 @@ async function handleListAgentTypes(ctx3) {
578147
578471
  }
578148
578472
  async function handleListEngines(ctx3) {
578149
578473
  const { res } = ctx3;
578150
- const home = homedir37();
578474
+ const home = homedir38();
578151
578475
  sendJson(res, 200, {
578152
578476
  engines: [
578153
- { name: "dream", state_file: join110(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
578154
- { name: "bless", state_file: join110(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
578155
- { name: "call", state_file: join110(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
578156
- { name: "listen", state_file: join110(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
578157
- { name: "telegram", state_file: join110(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
578158
- { name: "expose", state_file: join110(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
578159
- { name: "nexus", state_file: join110(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
578160
- { name: "ipfs", state_file: join110(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
578477
+ { name: "dream", state_file: join111(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
578478
+ { name: "bless", state_file: join111(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
578479
+ { name: "call", state_file: join111(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
578480
+ { name: "listen", state_file: join111(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
578481
+ { name: "telegram", state_file: join111(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
578482
+ { name: "expose", state_file: join111(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
578483
+ { name: "nexus", state_file: join111(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
578484
+ { name: "ipfs", state_file: join111(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
578161
578485
  ],
578162
578486
  note: "Engine instrumentation lives in the running TUI process. Full status + control requires the daemon↔TUI bridge (PT-07). See parity audit WO-PARITY-04."
578163
578487
  });
@@ -578240,21 +578564,21 @@ async function tryAimsRoute(ctx3) {
578240
578564
  return false;
578241
578565
  }
578242
578566
  function aimsDir() {
578243
- return join110(homedir37(), ".open-agents", "aims");
578567
+ return join111(homedir38(), ".open-agents", "aims");
578244
578568
  }
578245
578569
  function readAimsFile(name10, fallback) {
578246
578570
  try {
578247
- const p2 = join110(aimsDir(), name10);
578248
- if (existsSync94(p2)) return JSON.parse(readFileSync76(p2, "utf-8"));
578571
+ const p2 = join111(aimsDir(), name10);
578572
+ if (existsSync95(p2)) return JSON.parse(readFileSync77(p2, "utf-8"));
578249
578573
  } catch {
578250
578574
  }
578251
578575
  return fallback;
578252
578576
  }
578253
578577
  function writeAimsFile(name10, data) {
578254
578578
  const dir = aimsDir();
578255
- const { mkdirSync: mkdirSync66, writeFileSync: wf, renameSync: rn } = __require("node:fs");
578256
- mkdirSync66(dir, { recursive: true });
578257
- const finalPath = join110(dir, name10);
578579
+ const { mkdirSync: mkdirSync67, writeFileSync: wf, renameSync: rn } = __require("node:fs");
578580
+ mkdirSync67(dir, { recursive: true });
578581
+ const finalPath = join111(dir, name10);
578258
578582
  const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
578259
578583
  try {
578260
578584
  wf(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
@@ -578584,12 +578908,12 @@ async function handleAimsSuppliers(ctx3) {
578584
578908
  }
578585
578909
  ];
578586
578910
  const sponsorPaths = [
578587
- join110(homedir37(), ".open-agents", "sponsor-cache.json")
578911
+ join111(homedir38(), ".open-agents", "sponsor-cache.json")
578588
578912
  ];
578589
578913
  for (const p2 of sponsorPaths) {
578590
- if (!existsSync94(p2)) continue;
578914
+ if (!existsSync95(p2)) continue;
578591
578915
  try {
578592
- const raw = JSON.parse(readFileSync76(p2, "utf-8"));
578916
+ const raw = JSON.parse(readFileSync77(p2, "utf-8"));
578593
578917
  const list = Array.isArray(raw) ? raw : raw?.sponsors ?? [];
578594
578918
  for (const s2 of list) {
578595
578919
  suppliers.push({
@@ -578651,11 +578975,11 @@ async function handleAimsIncidentPost(ctx3) {
578651
578975
  }));
578652
578976
  return true;
578653
578977
  }
578654
- const { randomBytes: randomBytes24 } = await import("node:crypto");
578978
+ const { randomBytes: randomBytes25 } = await import("node:crypto");
578655
578979
  const record = await withAimsLock("incidents.json", () => {
578656
578980
  const existing = readAimsFile("incidents.json", []);
578657
578981
  const rec = {
578658
- id: `INC-${Date.now()}-${randomBytes24(4).toString("hex")}`,
578982
+ id: `INC-${Date.now()}-${randomBytes25(4).toString("hex")}`,
578659
578983
  ts: (/* @__PURE__ */ new Date()).toISOString(),
578660
578984
  raised_by: user ?? "anonymous",
578661
578985
  status: "open",
@@ -585783,10 +586107,24 @@ function getOpenApiSpec() {
585783
586107
  "/v1/models": { get: { summary: "List aggregated models", tags: ["Inference"], responses: { 200: { description: "OpenAI-format model list" }, ...ErrorResponses } } },
585784
586108
  "/v1/chat/completions": {
585785
586109
  post: {
585786
- summary: "OpenAI-compatible chat completion",
586110
+ summary: "OpenAI-compatible chat completion (with optional server-side agent loop)",
585787
586111
  tags: ["Inference"],
585788
- requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["model", "messages"], properties: { model: { type: "string" }, messages: { type: "array" }, stream: { type: "boolean" }, temperature: { type: "number" } } } } } },
585789
- responses: { 200: { description: "Chat response (SSE if stream=true)" }, ...ErrorResponses }
586112
+ description: "Standard OpenAI chat-completion proxy by default. Set agent_loop=true to enter a synchronous server-side loop that auto-executes daemon tools (web_search, web_fetch, file_read, ocr, etc.) and re-prompts the model collapsing N round-trips into 1. include_daemon_tools=['read','run'] auto-merges daemon tools matching those scopes into the offered tools[]. timeout_s overrides OA_BACKEND_TIMEOUT_S (default 120s, max 1h). prompt_template='factual-first' prepends a web_search-first policy. SSE streaming honors tool_calls in delta as standard OpenAI shape: delta.tool_calls=[{id,type:'function',index,function:{name,arguments:<JSON-string>}}]. parallel_tool_calls is forwarded to the backend.",
586113
+ requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["model", "messages"], properties: {
586114
+ model: { type: "string" },
586115
+ messages: { type: "array" },
586116
+ stream: { type: "boolean" },
586117
+ temperature: { type: "number" },
586118
+ tools: { type: "array", description: "OpenAI-shape tools array. Forwarded to the backend." },
586119
+ tool_choice: { description: "OpenAI-shape tool_choice. Forwarded to the backend." },
586120
+ parallel_tool_calls: { type: "boolean", description: "Q7 — forwarded to backend; some models (qwen3, llama3) emit multiple tool_calls in one response." },
586121
+ timeout_s: { type: "number", description: "Q1 — per-request timeout in seconds (1-3600). Overrides OA_BACKEND_TIMEOUT_S." },
586122
+ agent_loop: { type: "boolean", description: "Q2 — when true, daemon runs an N-turn agent loop server-side. Daemon tools execute inline; client tool_calls cause the loop to yield." },
586123
+ include_daemon_tools: { type: "array", items: { type: "string", enum: ["read", "run", "admin"] }, description: "Q3 — scopes to merge from daemon tool catalog into tools[]." },
586124
+ max_turns: { type: "integer", description: "Q2 — agent_loop max iterations (default 8, max 64)." },
586125
+ prompt_template: { type: "string", enum: ["factual-first"], description: "Q8 — prepended system policy template. 'factual-first' instructs model to call web_search FIRST for any factual question." }
586126
+ } } } } },
586127
+ responses: { 200: { description: "OpenAI chat.completion shape, SSE if stream=true. agent_loop responses include _agent_loop:{turns,log,done,reason}." }, ...ErrorResponses }
585790
586128
  }
585791
586129
  },
585792
586130
  "/v1/embeddings": { post: { summary: "Generate embeddings", tags: ["Inference"], responses: { 200: { description: "Embedding vectors" }, ...ErrorResponses } } },
@@ -585998,7 +586336,7 @@ function getOpenApiSpec() {
585998
586336
  post: {
585999
586337
  summary: "Execute a single tool directly (MCP-style, no agent loop)",
586000
586338
  tags: ["Tools"],
586001
- description: "Body: {args: object, working_dir?: string}. Returns the tool's ToolResult {success, output, llmContent?, error?, durationMs} plus security metadata. Auth gating: request scope (read/run/admin) must satisfy tool.requires_scope; non-loopback callers need admin scope unless tool.off_device_allowed=true. Anonymous loopback callers default to admin scope; anonymous remote callers default to read scope.",
586339
+ description: "Body: {args: object, working_dir?: string}. The `args` key is canonical (Q4) — the JSON-schema in /v1/tools/{name} `parameters` describes what goes INSIDE the args wrapper. Returns ToolResult {success, output, llmContent?, error?, durationMs} plus security metadata. Auth gating: request scope (read/run/admin) must satisfy tool.requires_scope; non-loopback callers need admin scope unless tool.off_device_allowed=true. Anonymous loopback callers default to admin scope; anonymous remote callers default to read scope.",
586002
586340
  parameters: [{ name: "name", in: "path", required: true, schema: { type: "string" } }],
586003
586341
  responses: {
586004
586342
  200: { description: "Tool result envelope" },
@@ -586008,6 +586346,28 @@ function getOpenApiSpec() {
586008
586346
  }
586009
586347
  }
586010
586348
  },
586349
+ "/v1/keys": {
586350
+ get: {
586351
+ summary: "List runtime API keys (admin scope)",
586352
+ tags: ["Tools"],
586353
+ description: "Returns runtime keys with secrets masked (only first 8 + last 4 chars). Q6 — runtime-mintable alternative to OA_API_KEY/OA_API_KEYS env vars.",
586354
+ responses: { 200: { description: "Masked key list" }, 403: { description: "Admin scope required" } }
586355
+ },
586356
+ post: {
586357
+ summary: "Mint a new runtime API key (admin scope)",
586358
+ tags: ["Tools"],
586359
+ description: "Body: {scope: 'read'|'run'|'admin', owner: string, profile?: string, rpm?, tpd?, max_jobs?}. Returns the FULL key — only response that contains the secret. Persisted at ~/.open-agents/keys.json mode 0600.",
586360
+ responses: { 201: { description: "Key minted" }, 400: { description: "Invalid body" }, 403: { description: "Admin scope required" } }
586361
+ }
586362
+ },
586363
+ "/v1/keys/{prefix}": {
586364
+ delete: {
586365
+ summary: "Revoke a runtime key by prefix (admin scope)",
586366
+ tags: ["Tools"],
586367
+ parameters: [{ name: "prefix", in: "path", required: true, schema: { type: "string", minLength: 8 }, description: "First 8+ characters of the key" }],
586368
+ responses: { 200: { description: "Number of keys revoked" }, 400: { description: "Prefix too short" }, 403: { description: "Admin scope required" } }
586369
+ }
586370
+ },
586011
586371
  "/v1/hooks": { get: { summary: "List hook types and counts", tags: ["Tools"], responses: { 200: { description: "Hook registry" } } } },
586012
586372
  "/v1/agents": { get: { summary: "List agent types", tags: ["Tools"], responses: { 200: { description: "Agent type registry" } } } },
586013
586373
  "/v1/engines": { get: { summary: "List long-running engines", tags: ["Engines"], responses: { 200: { description: "Engine status + state files" } } } },
@@ -586440,15 +586800,15 @@ var init_auth_oidc = __esm({
586440
586800
  });
586441
586801
 
586442
586802
  // packages/cli/src/api/usage-tracker.ts
586443
- import { mkdirSync as mkdirSync59, readFileSync as readFileSync77, writeFileSync as writeFileSync51, existsSync as existsSync95 } from "node:fs";
586444
- import { join as join111 } from "node:path";
586803
+ import { mkdirSync as mkdirSync60, readFileSync as readFileSync78, writeFileSync as writeFileSync52, existsSync as existsSync96 } from "node:fs";
586804
+ import { join as join112 } from "node:path";
586445
586805
  function initUsageTracker(oaDir) {
586446
- const dir = join111(oaDir, "usage");
586447
- mkdirSync59(dir, { recursive: true });
586448
- usageFile = join111(dir, "token-usage.json");
586806
+ const dir = join112(oaDir, "usage");
586807
+ mkdirSync60(dir, { recursive: true });
586808
+ usageFile = join112(dir, "token-usage.json");
586449
586809
  try {
586450
- if (existsSync95(usageFile)) {
586451
- store = JSON.parse(readFileSync77(usageFile, "utf-8"));
586810
+ if (existsSync96(usageFile)) {
586811
+ store = JSON.parse(readFileSync78(usageFile, "utf-8"));
586452
586812
  }
586453
586813
  } catch {
586454
586814
  store = { providers: {}, lastSaved: "" };
@@ -586484,7 +586844,7 @@ function flush2() {
586484
586844
  if (!initialized2 || !dirty) return;
586485
586845
  try {
586486
586846
  store.lastSaved = (/* @__PURE__ */ new Date()).toISOString();
586487
- writeFileSync51(usageFile, JSON.stringify(store, null, 2), "utf-8");
586847
+ writeFileSync52(usageFile, JSON.stringify(store, null, 2), "utf-8");
586488
586848
  dirty = false;
586489
586849
  } catch {
586490
586850
  }
@@ -586512,24 +586872,24 @@ var init_usage_tracker = __esm({
586512
586872
  });
586513
586873
 
586514
586874
  // packages/cli/src/api/profiles.ts
586515
- import { existsSync as existsSync96, readFileSync as readFileSync78, writeFileSync as writeFileSync52, mkdirSync as mkdirSync60, readdirSync as readdirSync33, unlinkSync as unlinkSync23 } from "node:fs";
586516
- import { join as join112 } from "node:path";
586517
- import { homedir as homedir38 } from "node:os";
586518
- import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes21, scryptSync as scryptSync3 } from "node:crypto";
586875
+ import { existsSync as existsSync97, readFileSync as readFileSync79, writeFileSync as writeFileSync53, mkdirSync as mkdirSync61, readdirSync as readdirSync33, unlinkSync as unlinkSync23 } from "node:fs";
586876
+ import { join as join113 } from "node:path";
586877
+ import { homedir as homedir39 } from "node:os";
586878
+ import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes22, scryptSync as scryptSync3 } from "node:crypto";
586519
586879
  function globalProfileDir() {
586520
- return join112(homedir38(), ".open-agents", "profiles");
586880
+ return join113(homedir39(), ".open-agents", "profiles");
586521
586881
  }
586522
586882
  function projectProfileDir(projectDir2) {
586523
- return join112(projectDir2 || process.cwd(), ".oa", "profiles");
586883
+ return join113(projectDir2 || process.cwd(), ".oa", "profiles");
586524
586884
  }
586525
586885
  function listProfiles(projectDir2) {
586526
586886
  const result = [];
586527
586887
  const seen = /* @__PURE__ */ new Set();
586528
586888
  const projDir = projectProfileDir(projectDir2);
586529
- if (existsSync96(projDir)) {
586889
+ if (existsSync97(projDir)) {
586530
586890
  for (const f2 of readdirSync33(projDir).filter((f3) => f3.endsWith(".json"))) {
586531
586891
  try {
586532
- const raw = JSON.parse(readFileSync78(join112(projDir, f2), "utf8"));
586892
+ const raw = JSON.parse(readFileSync79(join113(projDir, f2), "utf8"));
586533
586893
  const name10 = f2.replace(".json", "");
586534
586894
  seen.add(name10);
586535
586895
  result.push({
@@ -586543,12 +586903,12 @@ function listProfiles(projectDir2) {
586543
586903
  }
586544
586904
  }
586545
586905
  const globDir = globalProfileDir();
586546
- if (existsSync96(globDir)) {
586906
+ if (existsSync97(globDir)) {
586547
586907
  for (const f2 of readdirSync33(globDir).filter((f3) => f3.endsWith(".json"))) {
586548
586908
  const name10 = f2.replace(".json", "");
586549
586909
  if (seen.has(name10)) continue;
586550
586910
  try {
586551
- const raw = JSON.parse(readFileSync78(join112(globDir, f2), "utf8"));
586911
+ const raw = JSON.parse(readFileSync79(join113(globDir, f2), "utf8"));
586552
586912
  result.push({
586553
586913
  name: name10,
586554
586914
  description: raw.description || "",
@@ -586563,11 +586923,11 @@ function listProfiles(projectDir2) {
586563
586923
  }
586564
586924
  function loadProfile(name10, password, projectDir2) {
586565
586925
  const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
586566
- const projPath = join112(projectProfileDir(projectDir2), `${sanitized}.json`);
586567
- const globPath = join112(globalProfileDir(), `${sanitized}.json`);
586568
- const filePath = existsSync96(projPath) ? projPath : existsSync96(globPath) ? globPath : null;
586926
+ const projPath = join113(projectProfileDir(projectDir2), `${sanitized}.json`);
586927
+ const globPath = join113(globalProfileDir(), `${sanitized}.json`);
586928
+ const filePath = existsSync97(projPath) ? projPath : existsSync97(globPath) ? globPath : null;
586569
586929
  if (!filePath) return null;
586570
- const raw = JSON.parse(readFileSync78(filePath, "utf8"));
586930
+ const raw = JSON.parse(readFileSync79(filePath, "utf8"));
586571
586931
  if (raw.encrypted === true) {
586572
586932
  if (!password) return null;
586573
586933
  return decryptProfile(raw, password);
@@ -586576,32 +586936,32 @@ function loadProfile(name10, password, projectDir2) {
586576
586936
  }
586577
586937
  function saveProfile(profile, password, scope = "global", projectDir2) {
586578
586938
  const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
586579
- mkdirSync60(dir, { recursive: true });
586939
+ mkdirSync61(dir, { recursive: true });
586580
586940
  const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
586581
- const filePath = join112(dir, `${sanitized}.json`);
586941
+ const filePath = join113(dir, `${sanitized}.json`);
586582
586942
  profile.modified = (/* @__PURE__ */ new Date()).toISOString();
586583
586943
  if (password) {
586584
586944
  const encrypted = encryptProfile(profile, password);
586585
- writeFileSync52(filePath, JSON.stringify(encrypted, null, 2), { mode: 384 });
586945
+ writeFileSync53(filePath, JSON.stringify(encrypted, null, 2), { mode: 384 });
586586
586946
  } else {
586587
586947
  profile.encrypted = false;
586588
- writeFileSync52(filePath, JSON.stringify(profile, null, 2), { mode: 420 });
586948
+ writeFileSync53(filePath, JSON.stringify(profile, null, 2), { mode: 420 });
586589
586949
  }
586590
586950
  }
586591
586951
  function deleteProfile(name10, scope = "global", projectDir2) {
586592
586952
  const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
586593
586953
  const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
586594
- const filePath = join112(dir, `${sanitized}.json`);
586595
- if (existsSync96(filePath)) {
586954
+ const filePath = join113(dir, `${sanitized}.json`);
586955
+ if (existsSync97(filePath)) {
586596
586956
  unlinkSync23(filePath);
586597
586957
  return true;
586598
586958
  }
586599
586959
  return false;
586600
586960
  }
586601
586961
  function encryptProfile(profile, password) {
586602
- const salt = randomBytes21(32);
586962
+ const salt = randomBytes22(32);
586603
586963
  const key = scryptSync3(password, salt, 32);
586604
- const iv = randomBytes21(16);
586964
+ const iv = randomBytes22(16);
586605
586965
  const cipher = createCipheriv4("aes-256-gcm", key, iv);
586606
586966
  const plaintext = JSON.stringify(profile);
586607
586967
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
@@ -586707,23 +587067,23 @@ var init_profiles = __esm({
586707
587067
 
586708
587068
  // packages/cli/src/docker.ts
586709
587069
  import { execSync as execSync54, spawn as spawn24 } from "node:child_process";
586710
- import { existsSync as existsSync97, mkdirSync as mkdirSync61, writeFileSync as writeFileSync53 } from "node:fs";
586711
- import { join as join113, resolve as resolve37, dirname as dirname34 } from "node:path";
586712
- import { homedir as homedir39 } from "node:os";
587070
+ import { existsSync as existsSync98, mkdirSync as mkdirSync62, writeFileSync as writeFileSync54 } from "node:fs";
587071
+ import { join as join114, resolve as resolve37, dirname as dirname34 } from "node:path";
587072
+ import { homedir as homedir40 } from "node:os";
586713
587073
  import { fileURLToPath as fileURLToPath16 } from "node:url";
586714
587074
  function getDockerDir() {
586715
587075
  try {
586716
587076
  if (typeof __dirname !== "undefined") {
586717
- return join113(__dirname, "..", "..", "..", "docker");
587077
+ return join114(__dirname, "..", "..", "..", "docker");
586718
587078
  }
586719
587079
  } catch {
586720
587080
  }
586721
587081
  try {
586722
587082
  const thisDir = dirname34(fileURLToPath16(import.meta.url));
586723
- return join113(thisDir, "..", "..", "..", "docker");
587083
+ return join114(thisDir, "..", "..", "..", "docker");
586724
587084
  } catch {
586725
587085
  }
586726
- return join113(process.cwd(), "docker");
587086
+ return join114(process.cwd(), "docker");
586727
587087
  }
586728
587088
  function isDockerAvailable() {
586729
587089
  try {
@@ -586854,11 +587214,11 @@ async function ensureOaImage(force = false) {
586854
587214
  }
586855
587215
  let buildContext;
586856
587216
  const dockerDir = getDockerDir();
586857
- if (existsSync97(join113(dockerDir, "Dockerfile"))) {
587217
+ if (existsSync98(join114(dockerDir, "Dockerfile"))) {
586858
587218
  buildContext = dockerDir;
586859
587219
  } else {
586860
- buildContext = join113(homedir39(), ".oa", "docker-build");
586861
- mkdirSync61(buildContext, { recursive: true });
587220
+ buildContext = join114(homedir40(), ".oa", "docker-build");
587221
+ mkdirSync62(buildContext, { recursive: true });
586862
587222
  writeDockerfiles(buildContext);
586863
587223
  }
586864
587224
  try {
@@ -586932,8 +587292,8 @@ chown -R node:node /workspace /home/node/.oa /home/node/.open-agents 2>/dev/null
586932
587292
  if [ "$1" = "oa" ]; then shift; exec su - node -c "cd /workspace && oa $*"; fi
586933
587293
  exec "$@"
586934
587294
  `;
586935
- writeFileSync53(join113(dir, "Dockerfile"), dockerfile);
586936
- writeFileSync53(join113(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
587295
+ writeFileSync54(join114(dir, "Dockerfile"), dockerfile);
587296
+ writeFileSync54(join114(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
586937
587297
  }
586938
587298
  function hasNvidiaGpu() {
586939
587299
  try {
@@ -587186,23 +587546,23 @@ import * as http5 from "node:http";
587186
587546
  import * as https3 from "node:https";
587187
587547
  import { createRequire as createRequire4 } from "node:module";
587188
587548
  import { fileURLToPath as fileURLToPath17 } from "node:url";
587189
- import { dirname as dirname35, join as join114, resolve as resolve38 } from "node:path";
587190
- import { homedir as homedir40 } from "node:os";
587549
+ import { dirname as dirname35, join as join115, resolve as resolve38 } from "node:path";
587550
+ import { homedir as homedir41 } from "node:os";
587191
587551
  import { spawn as spawn25, execSync as execSync55 } from "node:child_process";
587192
- import { mkdirSync as mkdirSync62, writeFileSync as writeFileSync54, readFileSync as readFileSync79, readdirSync as readdirSync34, existsSync as existsSync98, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
587193
- import { randomBytes as randomBytes22, randomUUID as randomUUID14 } from "node:crypto";
587552
+ import { mkdirSync as mkdirSync63, writeFileSync as writeFileSync55, readFileSync as readFileSync80, readdirSync as readdirSync34, existsSync as existsSync99, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
587553
+ import { randomBytes as randomBytes23, randomUUID as randomUUID14 } from "node:crypto";
587194
587554
  import { createHash as createHash15 } from "node:crypto";
587195
587555
  function getVersion3() {
587196
587556
  try {
587197
587557
  const thisDir = dirname35(fileURLToPath17(import.meta.url));
587198
587558
  const candidates = [
587199
- join114(thisDir, "..", "package.json"),
587200
- join114(thisDir, "..", "..", "package.json"),
587201
- join114(thisDir, "..", "..", "..", "package.json")
587559
+ join115(thisDir, "..", "package.json"),
587560
+ join115(thisDir, "..", "..", "package.json"),
587561
+ join115(thisDir, "..", "..", "..", "package.json")
587202
587562
  ];
587203
587563
  for (const pkgPath of candidates) {
587204
587564
  try {
587205
- if (!existsSync98(pkgPath)) continue;
587565
+ if (!existsSync99(pkgPath)) continue;
587206
587566
  const pkg = require3(pkgPath);
587207
587567
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
587208
587568
  return pkg.version ?? "0.0.0";
@@ -587349,6 +587709,19 @@ function resolveModelEndpoint(modelId) {
587349
587709
  }
587350
587710
  return null;
587351
587711
  }
587712
+ function getBackendTimeoutMs(perRequestSeconds) {
587713
+ if (typeof perRequestSeconds === "number" && perRequestSeconds > 0) {
587714
+ return Math.min(Math.floor(perRequestSeconds * 1e3), BACKEND_TIMEOUT_MAX_MS);
587715
+ }
587716
+ const envS = process.env["OA_BACKEND_TIMEOUT_S"];
587717
+ if (envS) {
587718
+ const n2 = parseFloat(envS);
587719
+ if (Number.isFinite(n2) && n2 > 0) {
587720
+ return Math.min(Math.floor(n2 * 1e3), BACKEND_TIMEOUT_MAX_MS);
587721
+ }
587722
+ }
587723
+ return BACKEND_TIMEOUT_DEFAULT_MS;
587724
+ }
587352
587725
  function recordMetric(method, path8, status) {
587353
587726
  const key = `${method}|${path8}|${status}`;
587354
587727
  const existing = metrics.requests.get(key);
@@ -587391,9 +587764,9 @@ function isOriginAllowed(origin) {
587391
587764
  if (!origin) return true;
587392
587765
  let accessMode = (process.env["OA_ACCESS"] || "").toLowerCase().trim();
587393
587766
  try {
587394
- const accessFile = join114(homedir40(), ".open-agents", "access");
587395
- if (existsSync98(accessFile)) {
587396
- const persisted = readFileSync79(accessFile, "utf8").trim().toLowerCase();
587767
+ const accessFile = join115(homedir41(), ".open-agents", "access");
587768
+ if (existsSync99(accessFile)) {
587769
+ const persisted = readFileSync80(accessFile, "utf8").trim().toLowerCase();
587397
587770
  if (persisted === "any" || persisted === "lan" || persisted === "loopback") {
587398
587771
  accessMode = persisted;
587399
587772
  }
@@ -587453,7 +587826,7 @@ async function retrieveMemoryContext(userMessage, sessionId, maxEpisodes = 5) {
587453
587826
  if (!memMod || !memMod.EpisodeStore) {
587454
587827
  return { contextBlock: "", retrieved: [] };
587455
587828
  }
587456
- const dbPath = join114(homedir40(), ".open-agents", "memory.db");
587829
+ const dbPath = join115(homedir41(), ".open-agents", "memory.db");
587457
587830
  const store2 = new memMod.EpisodeStore(dbPath);
587458
587831
  const recent = store2.search({ limit: 30, sessionId: void 0 }) ?? [];
587459
587832
  const qLower = userMessage.toLowerCase();
@@ -587496,7 +587869,7 @@ async function writeMemoryEpisodes(sessionId, userMessage, assistantContent, too
587496
587869
  try {
587497
587870
  const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2)).catch(() => null);
587498
587871
  if (!memMod || !memMod.EpisodeStore) return 0;
587499
- const dbPath = join114(homedir40(), ".open-agents", "memory.db");
587872
+ const dbPath = join115(homedir41(), ".open-agents", "memory.db");
587500
587873
  const store2 = new memMod.EpisodeStore(dbPath);
587501
587874
  let written = 0;
587502
587875
  try {
@@ -587598,7 +587971,8 @@ async function directChatBackend(opts) {
587598
587971
  proxyRes.on("error", reject);
587599
587972
  });
587600
587973
  proxyReq.on("error", reject);
587601
- proxyReq.setTimeout(12e4, () => proxyReq.destroy(new Error("Backend timeout (120s)")));
587974
+ const _dctTo = getBackendTimeoutMs(extraFields?.["timeout_s"]);
587975
+ proxyReq.setTimeout(_dctTo, () => proxyReq.destroy(new Error(`Backend timeout (${Math.round(_dctTo / 1e3)}s)`)));
587602
587976
  proxyReq.write(reqBody);
587603
587977
  proxyReq.end();
587604
587978
  });
@@ -587751,7 +588125,7 @@ function backendAuthHeaders(endpoint) {
587751
588125
  if (key) return { Authorization: `Bearer ${key}` };
587752
588126
  return {};
587753
588127
  }
587754
- function ollamaRequest(ollamaUrl, path8, method, body) {
588128
+ function ollamaRequest(ollamaUrl, path8, method, body, timeoutMs) {
587755
588129
  return new Promise((resolve43, reject) => {
587756
588130
  const url = new URL(path8, ollamaUrl);
587757
588131
  const isHttps = url.protocol === "https:";
@@ -587778,15 +588152,16 @@ function ollamaRequest(ollamaUrl, path8, method, body) {
587778
588152
  });
587779
588153
  });
587780
588154
  });
587781
- proxyReq.setTimeout(12e4, () => {
587782
- proxyReq.destroy(new Error("Backend request timeout (120s)"));
588155
+ const _to = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
588156
+ proxyReq.setTimeout(_to, () => {
588157
+ proxyReq.destroy(new Error(`Backend request timeout (${Math.round(_to / 1e3)}s)`));
587783
588158
  });
587784
588159
  proxyReq.on("error", reject);
587785
588160
  if (body) proxyReq.write(body);
587786
588161
  proxyReq.end();
587787
588162
  });
587788
588163
  }
587789
- function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError) {
588164
+ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError, timeoutMs) {
587790
588165
  const url = new URL(path8, ollamaUrl);
587791
588166
  const isHttps = url.protocol === "https:";
587792
588167
  const options2 = {
@@ -587806,8 +588181,9 @@ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError) {
587806
588181
  proxyRes.on("data", onData);
587807
588182
  proxyRes.on("end", onEnd);
587808
588183
  });
587809
- proxyReq.setTimeout(12e4, () => {
587810
- proxyReq.destroy(new Error("Backend stream timeout (120s)"));
588184
+ const _streamTo = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
588185
+ proxyReq.setTimeout(_streamTo, () => {
588186
+ proxyReq.destroy(new Error(`Backend stream timeout (${Math.round(_streamTo / 1e3)}s)`));
587811
588187
  });
587812
588188
  proxyReq.on("error", onError);
587813
588189
  if (body) proxyReq.write(body);
@@ -587815,32 +588191,76 @@ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError) {
587815
588191
  }
587816
588192
  function jobsDir() {
587817
588193
  const root = resolve38(process.cwd());
587818
- const dir = join114(root, ".oa", "jobs");
587819
- mkdirSync62(dir, { recursive: true });
588194
+ const dir = join115(root, ".oa", "jobs");
588195
+ mkdirSync63(dir, { recursive: true });
587820
588196
  return dir;
587821
588197
  }
587822
588198
  function loadJob(id) {
587823
- const file = join114(jobsDir(), `${id}.json`);
587824
- if (!existsSync98(file)) return null;
588199
+ const file = join115(jobsDir(), `${id}.json`);
588200
+ if (!existsSync99(file)) return null;
587825
588201
  try {
587826
- return JSON.parse(readFileSync79(file, "utf-8"));
588202
+ return JSON.parse(readFileSync80(file, "utf-8"));
587827
588203
  } catch {
587828
588204
  return null;
587829
588205
  }
587830
588206
  }
587831
588207
  function listJobs() {
587832
588208
  const dir = jobsDir();
587833
- if (!existsSync98(dir)) return [];
588209
+ if (!existsSync99(dir)) return [];
587834
588210
  const files = readdirSync34(dir).filter((f2) => f2.endsWith(".json")).sort();
587835
588211
  const jobs = [];
587836
588212
  for (const file of files) {
587837
588213
  try {
587838
- jobs.push(JSON.parse(readFileSync79(join114(dir, file), "utf-8")));
588214
+ jobs.push(JSON.parse(readFileSync80(join115(dir, file), "utf-8")));
587839
588215
  } catch {
587840
588216
  }
587841
588217
  }
587842
588218
  return jobs;
587843
588219
  }
588220
+ function pruneOldJobs() {
588221
+ const retentionH = parseFloat(process.env["OA_RUN_RETENTION_H"] || "24");
588222
+ const cutoffMs = Date.now() - (Number.isFinite(retentionH) && retentionH > 0 ? retentionH : 24) * 36e5;
588223
+ const dir = jobsDir();
588224
+ if (!existsSync99(dir)) return { pruned: 0, kept: 0 };
588225
+ let pruned = 0;
588226
+ let kept = 0;
588227
+ for (const file of readdirSync34(dir)) {
588228
+ if (!file.endsWith(".json")) continue;
588229
+ const path8 = join115(dir, file);
588230
+ try {
588231
+ const job = JSON.parse(readFileSync80(path8, "utf-8"));
588232
+ if (job.status === "running") {
588233
+ kept++;
588234
+ continue;
588235
+ }
588236
+ const ageRef = job.completedAt || job.startedAt;
588237
+ const ts = ageRef ? Date.parse(ageRef) : NaN;
588238
+ if (Number.isFinite(ts) && ts < cutoffMs) {
588239
+ try {
588240
+ unlinkSync24(path8);
588241
+ } catch {
588242
+ }
588243
+ const outFile = path8.replace(/\.json$/, ".output");
588244
+ if (existsSync99(outFile)) {
588245
+ try {
588246
+ unlinkSync24(outFile);
588247
+ } catch {
588248
+ }
588249
+ }
588250
+ pruned++;
588251
+ } else {
588252
+ kept++;
588253
+ }
588254
+ } catch {
588255
+ try {
588256
+ unlinkSync24(path8);
588257
+ pruned++;
588258
+ } catch {
588259
+ }
588260
+ }
588261
+ }
588262
+ return { pruned, kept };
588263
+ }
587844
588264
  function getKeyUsage(user) {
587845
588265
  if (!perKeyUsage.has(user)) {
587846
588266
  perKeyUsage.set(user, { requestTimestamps: [], tokensToday: 0, tokenDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), activeJobs: 0 });
@@ -587909,14 +588329,14 @@ function autoSeedTodosFromPrompt(prompt) {
587909
588329
  return [];
587910
588330
  }
587911
588331
  function atomicJobWrite(dir, id, job) {
587912
- const finalPath = join114(dir, `${id}.json`);
588332
+ const finalPath = join115(dir, `${id}.json`);
587913
588333
  const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
587914
588334
  try {
587915
- writeFileSync54(tmpPath, JSON.stringify(job, null, 2), "utf-8");
588335
+ writeFileSync55(tmpPath, JSON.stringify(job, null, 2), "utf-8");
587916
588336
  renameSync8(tmpPath, finalPath);
587917
588337
  } catch {
587918
588338
  try {
587919
- writeFileSync54(finalPath, JSON.stringify(job, null, 2), "utf-8");
588339
+ writeFileSync55(finalPath, JSON.stringify(job, null, 2), "utf-8");
587920
588340
  } catch {
587921
588341
  }
587922
588342
  try {
@@ -587948,8 +588368,27 @@ function resolveAuth(req2) {
587948
588368
  return { authenticated: false, scope: "read" };
587949
588369
  }
587950
588370
  const singleKey = process.env["OA_API_KEY"];
588371
+ if (singleKey) {
588372
+ if (token === singleKey) return { authenticated: true, scope: "admin" };
588373
+ }
588374
+ if (token) {
588375
+ try {
588376
+ const { lookupKey: _lk } = require3("./runtime-keys.js");
588377
+ const rec = _lk(token);
588378
+ if (rec) {
588379
+ return {
588380
+ authenticated: true,
588381
+ scope: rec.scope,
588382
+ user: rec.owner,
588383
+ rpm: rec.rpm,
588384
+ tpd: rec.tpd,
588385
+ maxJobs: rec.max_jobs
588386
+ };
588387
+ }
588388
+ } catch {
588389
+ }
588390
+ }
587951
588391
  if (!singleKey) return { authenticated: true, scope: "admin" };
587952
- if (token === singleKey) return { authenticated: true, scope: "admin" };
587953
588392
  return { authenticated: false, scope: "read" };
587954
588393
  }
587955
588394
  function checkAuth(req2, res, requiredScope = "read") {
@@ -588070,7 +588509,41 @@ function handleHelp(req2, res) {
588070
588509
  },
588071
588510
  off_device_policy: "Tools with off_device_allowed=false are loopback-only; remote callers need admin scope to bypass.",
588072
588511
  anonymous_default: "Loopback callers default to admin scope. Remote callers default to read scope until authenticated.",
588073
- override: "Operators can override per-tool classification via OA_TOOL_OVERRIDES env var (JSON map of name → partial security info)."
588512
+ override: "Operators can override per-tool classification via OA_TOOL_OVERRIDES env var (JSON map of name → partial security info).",
588513
+ filters: "GET /v1/tools supports ?category=, ?scope=, ?risk=, ?off_device=true|false (Q9). E.g. /v1/tools?scope=read&off_device=true returns the safe-to-expose set."
588514
+ },
588515
+ runtime_keys: {
588516
+ "GET /v1/keys": "List runtime keys (admin scope). Secrets masked.",
588517
+ "POST /v1/keys": "Mint a runtime key (admin scope). Body: {scope, owner, profile?, rpm?, tpd?, max_jobs?}. Returns full secret ONCE.",
588518
+ "DELETE /v1/keys/{prefix}": "Revoke a key by its first 8+ chars (admin scope). Soft-delete; record retained for audit.",
588519
+ env_alternative: 'OA_API_KEY (single, admin) or OA_API_KEYS="key:scope:owner:rpm:tpd:max_jobs,...". Runtime keys are checked AFTER env keys.',
588520
+ per_key_profile: "Bind a key to a tool profile (allow/deny lists from /v1/profiles) for capability scoping beyond coarse read/run/admin.",
588521
+ storage: "~/.open-agents/keys.json (mode 600). Soft-deleted keys are kept for audit."
588522
+ },
588523
+ agent_loop_inference: {
588524
+ enable: "POST /v1/chat/completions with body {agent_loop: true} runs an N-turn server-side loop. Daemon executes any tool_calls matching daemon-resident tools and re-prompts; client-side tool_calls cause the loop to yield back so caller can execute them.",
588525
+ merge_daemon_tools: "Body field include_daemon_tools: ['read'] (or ['read','run']) merges the daemon's matching tools into the offered tools[] array automatically — no need to hand-list web_search/web_fetch/file_read/etc.",
588526
+ max_turns: "Body field max_turns (default 8, max 64).",
588527
+ timeout: "Body field timeout_s caps the whole loop (default 30 min, max 1 hour). Per-backend-call timeout is separate (see OA_BACKEND_TIMEOUT_S).",
588528
+ prompt_template: "Body field prompt_template: 'factual-first' prepends a system message instructing the model to call web_search FIRST for any factual question.",
588529
+ response_envelope: "Standard OpenAI chat.completion shape PLUS a _agent_loop: {turns, log:[], done, reason} field. Reason is one of: model_returned_content, client_tools_pending, max_turns_exhausted."
588530
+ },
588531
+ backend_timeout: {
588532
+ env: "OA_BACKEND_TIMEOUT_S — default 120 seconds, max 3600 (1 hour).",
588533
+ per_request: "Body field timeout_s on /v1/chat/completions, /v1/run, agent_loop. Caps to 1h.",
588534
+ rationale: "Q1 (Cody/SA) — was hardcoded 120s, broke cold-start tool-calling thinks on large models."
588535
+ },
588536
+ run_lifecycle: {
588537
+ gc: "Q10 — completed/failed runs older than OA_RUN_RETENTION_H hours (default 24) are pruned at startup and on a 1h interval. Set OA_RUN_RETENTION_H=0 to disable. Running runs are never pruned.",
588538
+ manual_delete: "DELETE /v1/runs/{id} — explicit cleanup."
588539
+ },
588540
+ sse_chunk_shape: {
588541
+ chat_completions: "Standard OpenAI delta shape. tool_calls in delta: [{id:'call_<hex>', type:'function', index:N, function:{name:'...', arguments:'<JSON-string>'}}]. Final chunk: {choices:[{finish_reason:'stop', delta:{}}]} then 'data: [DONE]'.",
588542
+ events_bus: "GET /v1/events streams the daemon-event bus (different shape): event:'tool.called', data:{run_id, tool, args, ts}. NOT the same as chat completions SSE."
588543
+ },
588544
+ parallel_tool_calls: {
588545
+ passthrough: "Request body field parallel_tool_calls: true is forwarded to the backend (Ollama/vLLM). Models supporting it (qwen3, llama3) emit multiple tool_calls in one response — daemon forwards them in delta.tool_calls[].",
588546
+ agent_loop: "When agent_loop=true with multiple daemon-tool tool_calls, all execute sequentially (still server-side; saves N round-trips vs the client doing each one)."
588074
588547
  },
588075
588548
  mcp: {
588076
588549
  "GET /v1/mcps": "List connected MCP (Model Context Protocol) servers",
@@ -588309,6 +588782,277 @@ async function handleApiTags(res) {
588309
588782
  });
588310
588783
  }
588311
588784
  }
588785
+ async function runAgentLoopChatCompletions(opts) {
588786
+ const { req: req2, res, ollamaUrl, requestBody, perReqTimeoutS } = opts;
588787
+ const startMs = Date.now();
588788
+ const reqTimeoutMs = getBackendTimeoutMs(perReqTimeoutS);
588789
+ const totalDeadline = startMs + (perReqTimeoutS && perReqTimeoutS > 0 ? Math.min(perReqTimeoutS * 1e3, BACKEND_TIMEOUT_MAX_MS) : 30 * 60 * 1e3);
588790
+ const model = requestBody["model"] || "unknown";
588791
+ const route = resolveModelEndpoint(model);
588792
+ const targetUrl = route?.endpoint.url ?? ollamaUrl;
588793
+ const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
588794
+ const originalModel = route?.originalId ?? model;
588795
+ const maxTurns = typeof requestBody["max_turns"] === "number" ? Math.max(1, Math.min(64, requestBody["max_turns"])) : 8;
588796
+ const remoteIp = (req2.socket?.remoteAddress || "").replace(/^::ffff:/, "");
588797
+ const origin = /^(127\.\d+\.\d+\.\d+|::1|localhost)$/.test(remoteIp) ? "loopback" : "remote";
588798
+ const reqAuth = req2;
588799
+ const scope = reqAuth._authScope ?? (origin === "loopback" ? "admin" : "read");
588800
+ const execMod = await Promise.resolve().then(() => (init_dist5(), dist_exports)).catch(() => null);
588801
+ if (!execMod) {
588802
+ jsonResponse(res, 500, { error: "Execution module unavailable" });
588803
+ return;
588804
+ }
588805
+ const classify = execMod.classifyTool;
588806
+ const canInvoke = execMod.canInvokeTool;
588807
+ const daemonTools = /* @__PURE__ */ new Map();
588808
+ for (const [classKey, value2] of Object.entries(execMod)) {
588809
+ if (typeof value2 !== "function") continue;
588810
+ const proto = value2.prototype;
588811
+ if (!proto || typeof proto.execute !== "function") continue;
588812
+ let probe = null;
588813
+ try {
588814
+ probe = new value2();
588815
+ } catch {
588816
+ try {
588817
+ probe = new value2(process.cwd());
588818
+ } catch {
588819
+ probe = null;
588820
+ }
588821
+ }
588822
+ if (probe?.name && typeof probe.name === "string") {
588823
+ daemonTools.set(probe.name, { ToolClass: value2, classKey });
588824
+ }
588825
+ }
588826
+ const includeDaemonTools = Array.isArray(requestBody["include_daemon_tools"]) ? requestBody["include_daemon_tools"].filter((s2) => typeof s2 === "string") : [];
588827
+ const advertisedDaemonNames = /* @__PURE__ */ new Set();
588828
+ if (includeDaemonTools.length > 0) {
588829
+ for (const [toolName, { ToolClass: _T }] of daemonTools.entries()) {
588830
+ void _T;
588831
+ const sec = classify(toolName);
588832
+ if (!sec) continue;
588833
+ if (!includeDaemonTools.includes(sec.requires_scope)) continue;
588834
+ if (canInvoke({ toolName, origin, scope }) !== null) continue;
588835
+ advertisedDaemonNames.add(toolName);
588836
+ }
588837
+ }
588838
+ const callerTools = Array.isArray(requestBody["tools"]) ? requestBody["tools"].filter((t2) => t2?.type === "function" && typeof t2?.function?.name === "string") : [];
588839
+ const callerToolNames = new Set(callerTools.map((t2) => t2.function.name));
588840
+ const daemonToolEntries = [];
588841
+ for (const name10 of advertisedDaemonNames) {
588842
+ if (callerToolNames.has(name10)) continue;
588843
+ const meta = daemonTools.get(name10);
588844
+ if (!meta) continue;
588845
+ let inst = null;
588846
+ try {
588847
+ inst = new meta.ToolClass();
588848
+ } catch {
588849
+ try {
588850
+ inst = new meta.ToolClass(process.cwd());
588851
+ } catch {
588852
+ inst = null;
588853
+ }
588854
+ }
588855
+ if (!inst) continue;
588856
+ daemonToolEntries.push({
588857
+ type: "function",
588858
+ function: {
588859
+ name: name10,
588860
+ description: typeof inst.description === "string" ? inst.description : "",
588861
+ parameters: inst.parameters ?? { type: "object", properties: {} }
588862
+ }
588863
+ });
588864
+ }
588865
+ const mergedTools = [...callerTools, ...daemonToolEntries];
588866
+ const messages2 = Array.isArray(requestBody["messages"]) ? requestBody["messages"].slice() : [];
588867
+ const promptTemplate = typeof requestBody["prompt_template"] === "string" ? requestBody["prompt_template"] : null;
588868
+ if (promptTemplate === "factual-first" && advertisedDaemonNames.has("web_search")) {
588869
+ const SYSTEM_FACTUAL_FIRST = [
588870
+ "[POLICY: factual-first]",
588871
+ "For any user question that asks for a fact, statistic, current event,",
588872
+ "person/place/product detail, or anything you might be tempted to answer",
588873
+ "from training data alone — your FIRST tool_call MUST be `web_search`",
588874
+ "with a query derived from the user's question. Do NOT answer from",
588875
+ "training data. After web_search returns, optionally call `web_fetch`",
588876
+ "on the most relevant URL, then synthesize a grounded answer citing",
588877
+ "the source. Decline to answer factual questions if web_search is",
588878
+ "unavailable."
588879
+ ].join(" ");
588880
+ const firstSystemIdx = messages2.findIndex((m2) => m2.role === "system");
588881
+ if (firstSystemIdx >= 0 && typeof messages2[firstSystemIdx].content === "string") {
588882
+ messages2[firstSystemIdx] = {
588883
+ ...messages2[firstSystemIdx],
588884
+ content: `${SYSTEM_FACTUAL_FIRST}
588885
+
588886
+ ${messages2[firstSystemIdx].content}`
588887
+ };
588888
+ } else {
588889
+ messages2.unshift({ role: "system", content: SYSTEM_FACTUAL_FIRST });
588890
+ }
588891
+ }
588892
+ const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
588893
+ const turnsLog = [];
588894
+ for (let turn = 1; turn <= maxTurns; turn++) {
588895
+ if (Date.now() > totalDeadline) {
588896
+ jsonResponse(res, 504, {
588897
+ error: "agent_loop timed out",
588898
+ turn,
588899
+ elapsed_ms: Date.now() - startMs,
588900
+ timeout_s: perReqTimeoutS ?? null
588901
+ });
588902
+ return;
588903
+ }
588904
+ const turnBody = {
588905
+ ...requestBody,
588906
+ model: originalModel,
588907
+ messages: messages2,
588908
+ tools: mergedTools.length > 0 ? mergedTools : void 0,
588909
+ stream: false,
588910
+ // Strip our own loop-control fields so they don't confuse the backend
588911
+ agent_loop: void 0,
588912
+ include_daemon_tools: void 0,
588913
+ max_turns: void 0,
588914
+ timeout_s: void 0
588915
+ };
588916
+ for (const k of Object.keys(turnBody)) if (turnBody[k] === void 0) delete turnBody[k];
588917
+ let parsed;
588918
+ try {
588919
+ const path8 = targetType === "vllm" || targetType === "openai" ? "/v1/chat/completions" : "/v1/chat/completions";
588920
+ const result = await ollamaRequest(targetUrl, path8, "POST", JSON.stringify(turnBody), reqTimeoutMs);
588921
+ if (result.status !== 200) {
588922
+ jsonResponse(res, result.status, {
588923
+ error: "Backend request failed during agent_loop",
588924
+ turn,
588925
+ details: result.body.slice(0, 500)
588926
+ });
588927
+ return;
588928
+ }
588929
+ parsed = JSON.parse(result.body);
588930
+ } catch (err) {
588931
+ jsonResponse(res, 502, {
588932
+ error: "Backend proxy error during agent_loop",
588933
+ message: err instanceof Error ? err.message : String(err),
588934
+ turn
588935
+ });
588936
+ return;
588937
+ }
588938
+ const choice = parsed?.choices?.[0];
588939
+ const message2 = choice?.message || { role: "assistant", content: "" };
588940
+ const toolCalls = Array.isArray(message2.tool_calls) ? message2.tool_calls : [];
588941
+ if (toolCalls.length === 0) {
588942
+ jsonResponse(res, 200, {
588943
+ ...parsed,
588944
+ id: chatId,
588945
+ _agent_loop: { turns: turn, log: turnsLog, done: true, reason: "model_returned_content" }
588946
+ });
588947
+ return;
588948
+ }
588949
+ const daemonCalls = [];
588950
+ const clientCalls = [];
588951
+ for (const tc of toolCalls) {
588952
+ const name10 = tc?.function?.name ?? tc?.name ?? "";
588953
+ if (advertisedDaemonNames.has(name10)) daemonCalls.push(tc);
588954
+ else clientCalls.push(tc);
588955
+ }
588956
+ if (clientCalls.length > 0) {
588957
+ turnsLog.push({ turn, tool_calls: toolCalls.length, daemon_executed: 0, client_yielded: clientCalls.length });
588958
+ jsonResponse(res, 200, {
588959
+ ...parsed,
588960
+ id: chatId,
588961
+ _agent_loop: {
588962
+ turns: turn,
588963
+ log: turnsLog,
588964
+ done: false,
588965
+ reason: "client_tools_pending",
588966
+ pending_tool_calls: clientCalls.length
588967
+ }
588968
+ });
588969
+ return;
588970
+ }
588971
+ messages2.push(message2);
588972
+ let executed = 0;
588973
+ for (const tc of daemonCalls) {
588974
+ const name10 = tc?.function?.name ?? tc?.name ?? "";
588975
+ const argsRaw = tc?.function?.arguments ?? tc?.arguments ?? "{}";
588976
+ let args = {};
588977
+ try {
588978
+ args = typeof argsRaw === "string" ? JSON.parse(argsRaw) : argsRaw || {};
588979
+ } catch {
588980
+ args = {};
588981
+ }
588982
+ const denial = canInvoke({ toolName: name10, origin, scope });
588983
+ if (denial) {
588984
+ messages2.push({
588985
+ role: "tool",
588986
+ tool_call_id: tc.id,
588987
+ name: name10,
588988
+ content: JSON.stringify({ error: denial.reason, status: denial.status })
588989
+ });
588990
+ continue;
588991
+ }
588992
+ const meta = daemonTools.get(name10);
588993
+ if (!meta) {
588994
+ messages2.push({
588995
+ role: "tool",
588996
+ tool_call_id: tc.id,
588997
+ name: name10,
588998
+ content: JSON.stringify({ error: `Daemon tool '${name10}' not found` })
588999
+ });
589000
+ continue;
589001
+ }
589002
+ let tool = null;
589003
+ try {
589004
+ tool = new meta.ToolClass(process.cwd());
589005
+ } catch {
589006
+ try {
589007
+ tool = new meta.ToolClass();
589008
+ } catch {
589009
+ tool = null;
589010
+ }
589011
+ }
589012
+ if (!tool) {
589013
+ messages2.push({
589014
+ role: "tool",
589015
+ tool_call_id: tc.id,
589016
+ name: name10,
589017
+ content: JSON.stringify({ error: `Could not instantiate ${meta.classKey}` })
589018
+ });
589019
+ continue;
589020
+ }
589021
+ let toolResult;
589022
+ try {
589023
+ toolResult = await tool.execute(args);
589024
+ } catch (e2) {
589025
+ toolResult = { success: false, output: "", error: e2 instanceof Error ? e2.message : String(e2), durationMs: 0 };
589026
+ }
589027
+ messages2.push({
589028
+ role: "tool",
589029
+ tool_call_id: tc.id,
589030
+ name: name10,
589031
+ content: JSON.stringify(toolResult)
589032
+ });
589033
+ executed++;
589034
+ }
589035
+ turnsLog.push({ turn, tool_calls: toolCalls.length, daemon_executed: executed, client_yielded: 0 });
589036
+ }
589037
+ jsonResponse(res, 200, {
589038
+ id: chatId,
589039
+ object: "chat.completion",
589040
+ created: Math.floor(Date.now() / 1e3),
589041
+ model,
589042
+ choices: [{
589043
+ index: 0,
589044
+ message: { role: "assistant", content: "[agent_loop reached max_turns without producing a final answer]" },
589045
+ finish_reason: "length"
589046
+ }],
589047
+ _agent_loop: {
589048
+ turns: maxTurns,
589049
+ log: turnsLog,
589050
+ done: false,
589051
+ reason: "max_turns_exhausted",
589052
+ max_turns: maxTurns
589053
+ }
589054
+ });
589055
+ }
588312
589056
  async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588313
589057
  const body = await parseJsonBody(req2);
588314
589058
  if (!body || typeof body !== "object") {
@@ -588318,6 +589062,18 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588318
589062
  const requestBody = body;
588319
589063
  const stream = requestBody["stream"] === true;
588320
589064
  const model = requestBody["model"] || "unknown";
589065
+ const perReqTimeoutS = typeof requestBody["timeout_s"] === "number" ? requestBody["timeout_s"] : void 0;
589066
+ if (requestBody["agent_loop"] === true) {
589067
+ await runAgentLoopChatCompletions({
589068
+ req: req2,
589069
+ res,
589070
+ ollamaUrl,
589071
+ requestBody,
589072
+ perReqTimeoutS
589073
+ });
589074
+ return;
589075
+ }
589076
+ const reqTimeoutMs = getBackendTimeoutMs(perReqTimeoutS);
588321
589077
  const route = resolveModelEndpoint(model);
588322
589078
  const targetUrl = route?.endpoint.url ?? ollamaUrl;
588323
589079
  const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
@@ -588357,11 +589113,12 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588357
589113
  } catch {
588358
589114
  }
588359
589115
  res.end();
588360
- }
589116
+ },
589117
+ reqTimeoutMs
588361
589118
  );
588362
589119
  } else {
588363
589120
  try {
588364
- const result = await ollamaRequest(targetUrl, "/v1/chat/completions", "POST", payload);
589121
+ const result = await ollamaRequest(targetUrl, "/v1/chat/completions", "POST", payload, reqTimeoutMs);
588365
589122
  if (result.status !== 200) {
588366
589123
  jsonResponse(res, result.status, { error: "Backend request failed", details: result.body });
588367
589124
  return;
@@ -588397,7 +589154,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588397
589154
  "Cache-Control": "no-cache",
588398
589155
  "Connection": "keep-alive"
588399
589156
  });
588400
- const chatId = `chatcmpl-${randomBytes22(12).toString("hex")}`;
589157
+ const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
588401
589158
  let buffer2 = "";
588402
589159
  ollamaStream(
588403
589160
  targetUrl,
@@ -588439,7 +589196,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588439
589196
  if (ollamaChunk.message.content) delta.content = ollamaChunk.message.content;
588440
589197
  if (ollamaChunk.message.tool_calls) {
588441
589198
  delta.tool_calls = ollamaChunk.message.tool_calls.map((tc, idx) => ({
588442
- id: tc.id || `call_${randomBytes22(8).toString("hex")}`,
589199
+ id: tc.id || `call_${randomBytes23(8).toString("hex")}`,
588443
589200
  type: "function",
588444
589201
  function: {
588445
589202
  name: tc?.function?.name ?? tc?.name ?? "",
@@ -588501,11 +589258,12 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588501
589258
  } catch {
588502
589259
  }
588503
589260
  res.end();
588504
- }
589261
+ },
589262
+ reqTimeoutMs
588505
589263
  );
588506
589264
  } else {
588507
589265
  try {
588508
- const result = await ollamaRequest(targetUrl, "/api/chat", "POST", ollamaPayload);
589266
+ const result = await ollamaRequest(targetUrl, "/api/chat", "POST", ollamaPayload, reqTimeoutMs);
588509
589267
  if (result.status !== 200) {
588510
589268
  jsonResponse(res, result.status, {
588511
589269
  error: "Ollama request failed",
@@ -588517,14 +589275,14 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
588517
589275
  if (ollamaResp.eval_count) metrics.totalTokensOut += ollamaResp.eval_count;
588518
589276
  if (ollamaResp.prompt_eval_count) metrics.totalTokensIn += ollamaResp.prompt_eval_count;
588519
589277
  trackTokens("local", ollamaResp.prompt_eval_count ?? 0, ollamaResp.eval_count ?? 0);
588520
- const chatId = `chatcmpl-${randomBytes22(12).toString("hex")}`;
589278
+ const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
588521
589279
  const responseMessage = {
588522
589280
  role: ollamaResp.message?.role ?? "assistant",
588523
589281
  content: ollamaResp.message?.content ?? ""
588524
589282
  };
588525
589283
  if (ollamaResp.message?.tool_calls && ollamaResp.message.tool_calls.length > 0) {
588526
589284
  responseMessage.tool_calls = ollamaResp.message.tool_calls.map((tc, idx) => ({
588527
- id: tc.id || `call_${randomBytes22(8).toString("hex")}`,
589285
+ id: tc.id || `call_${randomBytes23(8).toString("hex")}`,
588528
589286
  type: "function",
588529
589287
  function: {
588530
589288
  name: tc?.function?.name ?? tc?.name ?? "",
@@ -588997,27 +589755,27 @@ ${task}` : task;
588997
589755
  });
588998
589756
  }
588999
589757
  function updateStateFile() {
589000
- return join114(homedir40(), ".open-agents", "update-state.json");
589758
+ return join115(homedir41(), ".open-agents", "update-state.json");
589001
589759
  }
589002
589760
  function updateLogPath() {
589003
- return join114(homedir40(), ".open-agents", "update.log");
589761
+ return join115(homedir41(), ".open-agents", "update.log");
589004
589762
  }
589005
589763
  function readUpdateState() {
589006
589764
  try {
589007
589765
  const p2 = updateStateFile();
589008
- if (!existsSync98(p2)) return null;
589009
- return JSON.parse(readFileSync79(p2, "utf-8"));
589766
+ if (!existsSync99(p2)) return null;
589767
+ return JSON.parse(readFileSync80(p2, "utf-8"));
589010
589768
  } catch {
589011
589769
  return null;
589012
589770
  }
589013
589771
  }
589014
589772
  function writeUpdateState(state) {
589015
589773
  try {
589016
- const dir = join114(homedir40(), ".open-agents");
589017
- mkdirSync62(dir, { recursive: true });
589774
+ const dir = join115(homedir41(), ".open-agents");
589775
+ mkdirSync63(dir, { recursive: true });
589018
589776
  const finalPath = updateStateFile();
589019
589777
  const tmpPath = `${finalPath}.tmp.${process.pid}`;
589020
- writeFileSync54(tmpPath, JSON.stringify(state, null, 2), "utf-8");
589778
+ writeFileSync55(tmpPath, JSON.stringify(state, null, 2), "utf-8");
589021
589779
  renameSync8(tmpPath, finalPath);
589022
589780
  } catch {
589023
589781
  }
@@ -589061,15 +589819,15 @@ async function handleV1Update(req2, res, requestId) {
589061
589819
  const { execSync: es } = require3("node:child_process");
589062
589820
  const isWin2 = process.platform === "win32";
589063
589821
  let npmBin = "";
589064
- for (const candidate of isWin2 ? [join114(nodeDir, "npm.cmd"), join114(nodeDir, "npm")] : [join114(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
589065
- if (existsSync98(candidate)) {
589822
+ for (const candidate of isWin2 ? [join115(nodeDir, "npm.cmd"), join115(nodeDir, "npm")] : [join115(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
589823
+ if (existsSync99(candidate)) {
589066
589824
  npmBin = candidate;
589067
589825
  break;
589068
589826
  }
589069
589827
  }
589070
589828
  if (!npmBin) npmBin = isWin2 ? "npm.cmd" : "npm";
589071
589829
  const pkgSpec = `open-agents-ai@${targetVersion}`;
589072
- const dir = join114(homedir40(), ".open-agents");
589830
+ const dir = join115(homedir41(), ".open-agents");
589073
589831
  fs7.mkdirSync(dir, { recursive: true });
589074
589832
  const logFd = fs7.openSync(logPath3, "w");
589075
589833
  const npmPrefix = dirname35(nodeDir);
@@ -589079,13 +589837,13 @@ async function handleV1Update(req2, res, requestId) {
589079
589837
  globalBinDir = es(`${npmBin} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
589080
589838
  } else {
589081
589839
  const npmCliCandidates = [
589082
- join114(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
589083
- join114(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
589840
+ join115(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
589841
+ join115(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
589084
589842
  ];
589085
589843
  let npmCli = "";
589086
589844
  for (const c9 of npmCliCandidates) {
589087
589845
  try {
589088
- if (existsSync98(c9)) {
589846
+ if (existsSync99(c9)) {
589089
589847
  npmCli = c9;
589090
589848
  break;
589091
589849
  }
@@ -589117,13 +589875,13 @@ async function handleV1Update(req2, res, requestId) {
589117
589875
  });
589118
589876
  } else {
589119
589877
  const npmCliCandidates = [
589120
- join114(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
589121
- join114(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
589878
+ join115(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
589879
+ join115(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
589122
589880
  ];
589123
589881
  let npmCli = "";
589124
589882
  for (const c9 of npmCliCandidates) {
589125
589883
  try {
589126
- if (existsSync98(c9)) {
589884
+ if (existsSync99(c9)) {
589127
589885
  npmCli = c9;
589128
589886
  break;
589129
589887
  }
@@ -589220,8 +589978,8 @@ function handleV1UpdateStatus(res) {
589220
589978
  let logTail = "";
589221
589979
  let exitCode = null;
589222
589980
  try {
589223
- if (existsSync98(logPath3)) {
589224
- const raw = readFileSync79(logPath3, "utf-8");
589981
+ if (existsSync99(logPath3)) {
589982
+ const raw = readFileSync80(logPath3, "utf-8");
589225
589983
  const m2 = raw.match(/__EXIT_CODE=(\d+)/);
589226
589984
  if (m2) exitCode = parseInt(m2[1], 10);
589227
589985
  logTail = raw.slice(-2e3);
@@ -589309,7 +590067,7 @@ async function handleV1Run(req2, res) {
589309
590067
  return;
589310
590068
  }
589311
590069
  }
589312
- const id = `job-${randomBytes22(8).toString("hex")}`;
590070
+ const id = `job-${randomBytes23(8).toString("hex")}`;
589313
590071
  const dir = jobsDir();
589314
590072
  const workingDir = requestBody["working_directory"] || req2.headers["x-working-directory"];
589315
590073
  const isolate = requestBody["isolate"] === true;
@@ -589317,8 +590075,8 @@ async function handleV1Run(req2, res) {
589317
590075
  if (workingDir) {
589318
590076
  cwd4 = resolve38(workingDir);
589319
590077
  } else if (isolate) {
589320
- const wsDir = join114(dir, "..", "workspaces", id);
589321
- mkdirSync62(wsDir, { recursive: true });
590078
+ const wsDir = join115(dir, "..", "workspaces", id);
590079
+ mkdirSync63(wsDir, { recursive: true });
589322
590080
  cwd4 = wsDir;
589323
590081
  } else {
589324
590082
  cwd4 = resolve38(process.cwd());
@@ -589460,7 +590218,7 @@ async function handleV1Run(req2, res) {
589460
590218
  let output = "";
589461
590219
  let tailBytes = 0;
589462
590220
  const TAIL_BUDGET = 1048576;
589463
- const outputWriter = new DiskTaskOutput(join114(dir, `${id}.output`));
590221
+ const outputWriter = new DiskTaskOutput(join115(dir, `${id}.output`));
589464
590222
  job.outputFile = outputWriter.path;
589465
590223
  atomicJobWrite(dir, id, job);
589466
590224
  child.stdout?.on("data", (chunk) => {
@@ -590353,10 +591111,10 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
590353
591111
  return;
590354
591112
  }
590355
591113
  const { tmpdir: tmpdir22 } = await import("node:os");
590356
- const { writeFileSync: writeFileSync58, unlinkSync: unlinkSync25 } = await import("node:fs");
591114
+ const { writeFileSync: writeFileSync59, unlinkSync: unlinkSync25 } = await import("node:fs");
590357
591115
  const { join: pjoin } = await import("node:path");
590358
591116
  const tmpPath = pjoin(tmpdir22(), `oa-clone-upload-${Date.now()}-${safeName}`);
590359
- writeFileSync58(tmpPath, buf);
591117
+ writeFileSync59(tmpPath, buf);
590360
591118
  try {
590361
591119
  const ve = getVoiceEngine();
590362
591120
  const msg = await ve.setCloneVoice(tmpPath);
@@ -590906,7 +591664,7 @@ data: ${JSON.stringify(data)}
590906
591664
  }
590907
591665
  for (const f2 of seenFiles) {
590908
591666
  try {
590909
- writeFileSync54(f2, JSON.stringify({ tasks: [] }, null, 2));
591667
+ writeFileSync55(f2, JSON.stringify({ tasks: [] }, null, 2));
590910
591668
  deleted++;
590911
591669
  } catch {
590912
591670
  }
@@ -591968,7 +592726,7 @@ ${steering}`;
591968
592726
  function getScheduleRoots() {
591969
592727
  const rootsEnv = process.env["OA_SCHEDULE_ROOTS"] || "";
591970
592728
  const roots = rootsEnv.split(rootsEnv.includes(";") ? ";" : ":").filter(Boolean);
591971
- const defaults3 = [process.cwd(), join114(homedir40(), "Documents")];
592729
+ const defaults3 = [process.cwd(), join115(homedir41(), "Documents")];
591972
592730
  const set = /* @__PURE__ */ new Set([...defaults3, ...roots]);
591973
592731
  return [...set];
591974
592732
  }
@@ -591980,10 +592738,10 @@ function listScheduledTasks() {
591980
592738
  for (const root of roots) {
591981
592739
  try {
591982
592740
  walk(root, 0, (dir) => {
591983
- if (dir.endsWith(`${join114(".oa", "scheduled")}`) || dir.includes(`${join114(".oa", "scheduled")}`)) {
591984
- const file = join114(dir, "tasks.json");
592741
+ if (dir.endsWith(`${join115(".oa", "scheduled")}`) || dir.includes(`${join115(".oa", "scheduled")}`)) {
592742
+ const file = join115(dir, "tasks.json");
591985
592743
  try {
591986
- const raw = readFileSync79(file, "utf-8");
592744
+ const raw = readFileSync80(file, "utf-8");
591987
592745
  const json = JSON.parse(raw);
591988
592746
  const tasks = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
591989
592747
  tasks.forEach((t2, i2) => {
@@ -592048,7 +592806,7 @@ function walk(dir, depth, onDir, maxDepth) {
592048
592806
  if (e2.name === "node_modules" || e2.name.startsWith(".")) {
592049
592807
  if (e2.name !== ".oa") continue;
592050
592808
  }
592051
- const child = join114(dir, e2.name);
592809
+ const child = join115(dir, e2.name);
592052
592810
  walk(child, depth + 1, onDir, maxDepth);
592053
592811
  }
592054
592812
  }
@@ -592057,18 +592815,18 @@ function setScheduledEnabled(id, enabled2) {
592057
592815
  const target = tasks.find((t2) => t2.id === id);
592058
592816
  if (!target) return false;
592059
592817
  try {
592060
- const raw = readFileSync79(target.file, "utf-8");
592818
+ const raw = readFileSync80(target.file, "utf-8");
592061
592819
  const json = JSON.parse(raw);
592062
592820
  const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
592063
592821
  if (!arr[target.index]) return false;
592064
592822
  arr[target.index].enabled = enabled2;
592065
592823
  if (Array.isArray(json?.tasks)) {
592066
592824
  json.tasks = arr;
592067
- writeFileSync54(target.file, JSON.stringify(json, null, 2));
592825
+ writeFileSync55(target.file, JSON.stringify(json, null, 2));
592068
592826
  } else if (Array.isArray(json)) {
592069
- writeFileSync54(target.file, JSON.stringify(arr, null, 2));
592827
+ writeFileSync55(target.file, JSON.stringify(arr, null, 2));
592070
592828
  } else {
592071
- writeFileSync54(target.file, JSON.stringify({ tasks: arr }, null, 2));
592829
+ writeFileSync55(target.file, JSON.stringify({ tasks: arr }, null, 2));
592072
592830
  }
592073
592831
  if (!enabled2) {
592074
592832
  try {
@@ -592090,7 +592848,7 @@ function deleteScheduledById(id) {
592090
592848
  const target = tasks.find((t2) => t2.id === id);
592091
592849
  if (!target) return false;
592092
592850
  try {
592093
- const raw = readFileSync79(target.file, "utf-8");
592851
+ const raw = readFileSync80(target.file, "utf-8");
592094
592852
  const json = JSON.parse(raw);
592095
592853
  const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
592096
592854
  if (!arr[target.index]) return false;
@@ -592098,11 +592856,11 @@ function deleteScheduledById(id) {
592098
592856
  arr.splice(target.index, 1);
592099
592857
  if (Array.isArray(json?.tasks)) {
592100
592858
  json.tasks = arr;
592101
- writeFileSync54(target.file, JSON.stringify(json, null, 2));
592859
+ writeFileSync55(target.file, JSON.stringify(json, null, 2));
592102
592860
  } else if (Array.isArray(json)) {
592103
- writeFileSync54(target.file, JSON.stringify(arr, null, 2));
592861
+ writeFileSync55(target.file, JSON.stringify(arr, null, 2));
592104
592862
  } else {
592105
- writeFileSync54(target.file, JSON.stringify({ tasks: arr }, null, 2));
592863
+ writeFileSync55(target.file, JSON.stringify({ tasks: arr }, null, 2));
592106
592864
  }
592107
592865
  const candidates = [];
592108
592866
  if (id) candidates.push(id);
@@ -592355,11 +593113,11 @@ function reconcileScheduledTasks(apply) {
592355
593113
  const errors = [];
592356
593114
  for (const f2 of found) {
592357
593115
  const wdir = f2.workingDir || process.cwd();
592358
- const file = join114(wdir, ".oa", "scheduled", "tasks.json");
593116
+ const file = join115(wdir, ".oa", "scheduled", "tasks.json");
592359
593117
  try {
592360
593118
  let json = { tasks: [] };
592361
593119
  try {
592362
- const raw = readFileSync79(file, "utf-8");
593120
+ const raw = readFileSync80(file, "utf-8");
592363
593121
  json = JSON.parse(raw);
592364
593122
  } catch {
592365
593123
  }
@@ -592370,9 +593128,9 @@ function reconcileScheduledTasks(apply) {
592370
593128
  const entry = { task: f2.task || `legacy ${f2.id}`, schedule: f2.cron, enabled: true };
592371
593129
  arr.push(entry);
592372
593130
  const toWrite = Array.isArray(json?.tasks) ? { ...json, tasks: arr } : Array.isArray(json) ? arr : { tasks: arr };
592373
- mkdirSync62(join114(wdir, ".oa", "scheduled"), { recursive: true });
592374
- mkdirSync62(join114(wdir, ".oa", "scheduled", "logs"), { recursive: true });
592375
- writeFileSync54(file, JSON.stringify(toWrite, null, 2));
593131
+ mkdirSync63(join115(wdir, ".oa", "scheduled"), { recursive: true });
593132
+ mkdirSync63(join115(wdir, ".oa", "scheduled", "logs"), { recursive: true });
593133
+ writeFileSync55(file, JSON.stringify(toWrite, null, 2));
592376
593134
  adopted.push({ file, index: arr.length - 1 });
592377
593135
  }
592378
593136
  } else {
@@ -592416,32 +593174,32 @@ function writeCrontabLines(lines) {
592416
593174
  }
592417
593175
  function canonicalCronLine(rec) {
592418
593176
  const oaBin = findOaBinary4();
592419
- const logDir = join114(rec.workingDir, ".oa", "scheduled", "logs");
592420
- const logFile = join114(logDir, `${rec.id}.log`);
592421
- const storeFile = join114(rec.workingDir, ".oa", "scheduled", "tasks.json");
593177
+ const logDir = join115(rec.workingDir, ".oa", "scheduled", "logs");
593178
+ const logFile = join115(logDir, `${rec.id}.log`);
593179
+ const storeFile = join115(rec.workingDir, ".oa", "scheduled", "tasks.json");
592422
593180
  const taskEsc = rec.task.replace(/'/g, "'\\''");
592423
- const lockDir = join114(rec.workingDir, ".oa", "run");
592424
- const lockPath = join114(lockDir, `${rec.id}.lock`);
593181
+ const lockDir = join115(rec.workingDir, ".oa", "run");
593182
+ const lockPath = join115(lockDir, `${rec.id}.lock`);
592425
593183
  const wrapper = [
592426
593184
  `cd ${JSON.stringify(rec.workingDir)}`,
592427
593185
  `mkdir -p ${JSON.stringify(logDir)}`,
592428
593186
  `mkdir -p ${JSON.stringify(lockDir)}`,
592429
593187
  `if mkdir ${JSON.stringify(lockPath)} 2>/dev/null; then`,
592430
- ` echo $$ > ${JSON.stringify(join114(lockPath, "pid"))}`,
593188
+ ` echo $$ > ${JSON.stringify(join115(lockPath, "pid"))}`,
592431
593189
  ` trap 'rm -rf ${lockPath}' EXIT`,
592432
593190
  `else`,
592433
- ` if [ -f ${JSON.stringify(join114(lockPath, "pid"))} ]; then`,
592434
- ` oldpid=$(cat ${JSON.stringify(join114(lockPath, "pid"))} 2>/dev/null || echo)`,
593191
+ ` if [ -f ${JSON.stringify(join115(lockPath, "pid"))} ]; then`,
593192
+ ` oldpid=$(cat ${JSON.stringify(join115(lockPath, "pid"))} 2>/dev/null || echo)`,
592435
593193
  ` if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then`,
592436
593194
  ` echo "[oa-scheduler] ${rec.id} already running as PID $oldpid; skipping" >> ${JSON.stringify(logFile)}`,
592437
593195
  ` exit 0`,
592438
593196
  ` else`,
592439
593197
  ` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
592440
- ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join114(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
593198
+ ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join115(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
592441
593199
  ` fi`,
592442
593200
  ` else`,
592443
593201
  ` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
592444
- ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join114(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
593202
+ ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join115(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
592445
593203
  ` fi`,
592446
593204
  `fi`,
592447
593205
  `${oaBin} '${taskEsc}' >> ${JSON.stringify(logFile)} 2>&1; _oa_exit=$?`,
@@ -592473,9 +593231,9 @@ function fixupOrMigrateScheduled(mode, dryRun) {
592473
593231
  try {
592474
593232
  if (!f2.workingDir || !f2.task) continue;
592475
593233
  const unitBase = `oa-${f2.id}`;
592476
- const unitDir = join114(homedir40(), ".config", "systemd", "user");
592477
- const svc = join114(unitDir, `${unitBase}.service`);
592478
- const tim = join114(unitDir, `${unitBase}.timer`);
593234
+ const unitDir = join115(homedir41(), ".config", "systemd", "user");
593235
+ const svc = join115(unitDir, `${unitBase}.service`);
593236
+ const tim = join115(unitDir, `${unitBase}.timer`);
592479
593237
  const oaBin = findOaBinary4();
592480
593238
  const rec = { id: f2.id, cron: f2.cron, workingDir: f2.workingDir, task: f2.task };
592481
593239
  const cmd = canonicalCronLine(rec).split(" ").slice(5).join(" ");
@@ -592505,9 +593263,9 @@ Persistent=true
592505
593263
  WantedBy=timers.target
592506
593264
  `;
592507
593265
  if (!dryRun) {
592508
- mkdirSync62(unitDir, { recursive: true });
592509
- writeFileSync54(svc, svcText);
592510
- writeFileSync54(tim, timText);
593266
+ mkdirSync63(unitDir, { recursive: true });
593267
+ writeFileSync55(svc, svcText);
593268
+ writeFileSync55(tim, timText);
592511
593269
  try {
592512
593270
  const { execSync: es } = require3("node:child_process");
592513
593271
  es("systemctl --user daemon-reload", { stdio: "pipe" });
@@ -592601,8 +593359,8 @@ function startApiServer(options2 = {}) {
592601
593359
  const config = loadConfig();
592602
593360
  const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
592603
593361
  const cwd4 = process.cwd();
592604
- initAuditLog(join114(cwd4, ".oa"));
592605
- initUsageTracker(join114(cwd4, ".oa"));
593362
+ initAuditLog(join115(cwd4, ".oa"));
593363
+ initUsageTracker(join115(cwd4, ".oa"));
592606
593364
  try {
592607
593365
  const taskMgr = getSharedTaskManager();
592608
593366
  taskMgr.setEventPublisher((type, data, opts) => {
@@ -592644,7 +593402,7 @@ function startApiServer(options2 = {}) {
592644
593402
  try {
592645
593403
  const dir = todoDir();
592646
593404
  try {
592647
- mkdirSync62(dir, { recursive: true });
593405
+ mkdirSync63(dir, { recursive: true });
592648
593406
  } catch {
592649
593407
  }
592650
593408
  const cache8 = /* @__PURE__ */ new Map();
@@ -592653,7 +593411,7 @@ function startApiServer(options2 = {}) {
592653
593411
  if (!f2.endsWith(".json") || f2.includes(".tmp.")) continue;
592654
593412
  const sid = f2.replace(/\.json$/, "");
592655
593413
  try {
592656
- const items = JSON.parse(readFileSync79(join114(dir, f2), "utf-8"));
593414
+ const items = JSON.parse(readFileSync80(join115(dir, f2), "utf-8"));
592657
593415
  if (Array.isArray(items)) {
592658
593416
  cache8.set(sid, new Map(items.map((t2) => [t2.id, t2])));
592659
593417
  }
@@ -592665,10 +593423,10 @@ function startApiServer(options2 = {}) {
592665
593423
  const watcher = fsWatch3(dir, (_evt, fname) => {
592666
593424
  if (!fname || !fname.endsWith(".json") || fname.includes(".tmp.")) return;
592667
593425
  const sid = fname.replace(/\.json$/, "");
592668
- const fp = join114(dir, fname);
593426
+ const fp = join115(dir, fname);
592669
593427
  let next = [];
592670
593428
  try {
592671
- if (!existsSync98(fp)) {
593429
+ if (!existsSync99(fp)) {
592672
593430
  const old = cache8.get(sid);
592673
593431
  if (old) {
592674
593432
  for (const t2 of old.values()) {
@@ -592681,7 +593439,7 @@ function startApiServer(options2 = {}) {
592681
593439
  }
592682
593440
  return;
592683
593441
  }
592684
- next = JSON.parse(readFileSync79(fp, "utf-8"));
593442
+ next = JSON.parse(readFileSync80(fp, "utf-8"));
592685
593443
  if (!Array.isArray(next)) return;
592686
593444
  } catch {
592687
593445
  return;
@@ -592720,14 +593478,14 @@ function startApiServer(options2 = {}) {
592720
593478
  const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
592721
593479
  if (retentionDays > 0) {
592722
593480
  try {
592723
- const jobsDir3 = join114(cwd4, ".oa", "jobs");
592724
- if (existsSync98(jobsDir3)) {
593481
+ const jobsDir3 = join115(cwd4, ".oa", "jobs");
593482
+ if (existsSync99(jobsDir3)) {
592725
593483
  const cutoff = Date.now() - retentionDays * 864e5;
592726
593484
  for (const f2 of readdirSync34(jobsDir3)) {
592727
593485
  if (!f2.endsWith(".json")) continue;
592728
593486
  try {
592729
- const jobPath = join114(jobsDir3, f2);
592730
- const job = JSON.parse(readFileSync79(jobPath, "utf-8"));
593487
+ const jobPath = join115(jobsDir3, f2);
593488
+ const job = JSON.parse(readFileSync80(jobPath, "utf-8"));
592731
593489
  const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
592732
593490
  if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
592733
593491
  const { unlinkSync: unlinkSync25 } = require3("node:fs");
@@ -592747,8 +593505,8 @@ function startApiServer(options2 = {}) {
592747
593505
  if (useTls) {
592748
593506
  try {
592749
593507
  tlsOpts = {
592750
- cert: readFileSync79(resolve38(tlsCert)),
592751
- key: readFileSync79(resolve38(tlsKey))
593508
+ cert: readFileSync80(resolve38(tlsCert)),
593509
+ key: readFileSync80(resolve38(tlsKey))
592752
593510
  };
592753
593511
  } catch (e2) {
592754
593512
  log22(`
@@ -592759,9 +593517,9 @@ function startApiServer(options2 = {}) {
592759
593517
  }
592760
593518
  let runtimeAccessMode = resolveAccessMode(process.env["OA_ACCESS"], host);
592761
593519
  try {
592762
- const accessFile = join114(homedir40(), ".open-agents", "access");
592763
- if (existsSync98(accessFile)) {
592764
- const persisted = readFileSync79(accessFile, "utf8").trim();
593520
+ const accessFile = join115(homedir41(), ".open-agents", "access");
593521
+ if (existsSync99(accessFile)) {
593522
+ const persisted = readFileSync80(accessFile, "utf8").trim();
592765
593523
  const resolved = resolveAccessMode(persisted, host);
592766
593524
  if (resolved) runtimeAccessMode = resolved;
592767
593525
  }
@@ -592814,9 +593572,9 @@ function startApiServer(options2 = {}) {
592814
593572
  const previous = runtimeAccessMode;
592815
593573
  runtimeAccessMode = requested;
592816
593574
  try {
592817
- const dir = join114(homedir40(), ".open-agents");
592818
- mkdirSync62(dir, { recursive: true });
592819
- writeFileSync54(join114(dir, "access"), `${runtimeAccessMode}
593575
+ const dir = join115(homedir41(), ".open-agents");
593576
+ mkdirSync63(dir, { recursive: true });
593577
+ writeFileSync55(join115(dir, "access"), `${runtimeAccessMode}
592820
593578
  `, "utf8");
592821
593579
  } catch {
592822
593580
  }
@@ -593029,9 +593787,9 @@ function startApiServer(options2 = {}) {
593029
593787
  try {
593030
593788
  const { startEmbeddingWorkers: startEmbeddingWorkers2 } = await Promise.resolve().then(() => (init_embedding_workers(), embedding_workers_exports));
593031
593789
  const { ensureEmbedDeps: ensureEmbedDeps2, runEmbedImage: runEmbedImage2, runEmbedAudio: runEmbedAudio2 } = await Promise.resolve().then(() => (init_py_embed(), py_embed_exports));
593032
- const dbBase = join114(cwd4, ".oa");
593033
- const epStore = new mem.EpisodeStore(join114(dbBase, "memory.db"));
593034
- const kg = new mem.TemporalGraph(join114(dbBase, "kg.db"));
593790
+ const dbBase = join115(cwd4, ".oa");
593791
+ const epStore = new mem.EpisodeStore(join115(dbBase, "memory.db"));
593792
+ const kg = new mem.TemporalGraph(join115(dbBase, "kg.db"));
593035
593793
  try {
593036
593794
  ensureEmbedDeps2();
593037
593795
  } catch {
@@ -593108,6 +593866,24 @@ function startApiServer(options2 = {}) {
593108
593866
  `);
593109
593867
  log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
593110
593868
  `);
593869
+ const _retCheck = process.env["OA_RUN_RETENTION_H"];
593870
+ const _retOff = _retCheck === "0";
593871
+ if (!_retOff) {
593872
+ try {
593873
+ const initial = pruneOldJobs();
593874
+ if (initial.pruned > 0) {
593875
+ log22(` Run GC: pruned ${initial.pruned} old job records (kept ${initial.kept}).
593876
+ `);
593877
+ }
593878
+ } catch {
593879
+ }
593880
+ setInterval(() => {
593881
+ try {
593882
+ pruneOldJobs();
593883
+ } catch {
593884
+ }
593885
+ }, 36e5).unref();
593886
+ }
593111
593887
  if (process.env["OA_API_KEYS"]) {
593112
593888
  const keyCount = process.env["OA_API_KEYS"].split(",").length;
593113
593889
  log22(` Auth: ${keyCount} scoped key(s) (read/run/admin)
@@ -593228,10 +594004,10 @@ async function handleMemoryIngest(req2, res, ollamaUrl) {
593228
594004
  const labels = Array.isArray(b.labels) ? b.labels : [];
593229
594005
  const mediaPath = typeof b.media_path === "string" ? b.media_path : void 0;
593230
594006
  const cwd4 = process.cwd();
593231
- const dbBase = join114(cwd4, ".oa");
594007
+ const dbBase = join115(cwd4, ".oa");
593232
594008
  const { EpisodeStore: EpisodeStore3, TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
593233
- const epStore = new EpisodeStore3(join114(dbBase, "memory.db"));
593234
- const kg = new TemporalGraph3(join114(dbBase, "kg.db"));
594009
+ const epStore = new EpisodeStore3(join115(dbBase, "memory.db"));
594010
+ const kg = new TemporalGraph3(join115(dbBase, "kg.db"));
593235
594011
  const meta = {};
593236
594012
  if (mediaPath) meta.media_path = mediaPath;
593237
594013
  const epId = epStore.insert({ modality, content: content || (mediaPath || ""), metadata: meta, toolName: "memory_ingest" });
@@ -593298,7 +594074,7 @@ async function handleEntitiesList(req2, res) {
593298
594074
  const type = url.searchParams.get("type") || "person";
593299
594075
  const limit = Math.max(1, Math.min(1e3, parseInt(url.searchParams.get("limit") || "100", 10)));
593300
594076
  const { TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
593301
- const kg = new TemporalGraph3(join114(process.cwd(), ".oa", "kg.db"));
594077
+ const kg = new TemporalGraph3(join115(process.cwd(), ".oa", "kg.db"));
593302
594078
  const nodes = kg.nodesByType(type, limit).map((n2) => ({ id: n2.id, text: n2.text, mentionCount: n2.mentionCount, firstSeen: n2.firstSeen, lastSeen: n2.lastSeen }));
593303
594079
  jsonResponse(res, 200, { object: "list", data: nodes });
593304
594080
  } catch (err) {
@@ -593320,7 +594096,7 @@ async function handleMemorySearch2(req2, res) {
593320
594096
  const wLex = typeof b.lexical_weight === "number" ? b.lexical_weight : 1;
593321
594097
  const wEmb = typeof b.embedding_weight === "number" ? b.embedding_weight : 1;
593322
594098
  const { EpisodeStore: EpisodeStore3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
593323
- const epStore = new EpisodeStore3(join114(process.cwd(), ".oa", "memory.db"));
594099
+ const epStore = new EpisodeStore3(join115(process.cwd(), ".oa", "memory.db"));
593324
594100
  const results = epStore.search({ query, modality, limit }, { queryEmbedding: qEmb, lexicalWeight: wLex, embeddingWeight: wEmb });
593325
594101
  jsonResponse(res, 200, { object: "list", data: results.map((e2) => ({ id: e2.id, modality: e2.modality, content: e2.content, timestamp: e2.timestamp })) });
593326
594102
  } catch (err) {
@@ -593387,7 +594163,7 @@ function setTimerEnabled(name10, enabled2) {
593387
594163
  return false;
593388
594164
  }
593389
594165
  }
593390
- var require3, endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
594166
+ var require3, endpointRegistry, modelRouteMap, endpointUsage, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
593391
594167
  var init_serve = __esm({
593392
594168
  "packages/cli/src/api/serve.ts"() {
593393
594169
  "use strict";
@@ -593419,6 +594195,8 @@ var init_serve = __esm({
593419
594195
  endpointRegistry = [];
593420
594196
  modelRouteMap = /* @__PURE__ */ new Map();
593421
594197
  endpointUsage = /* @__PURE__ */ new Map();
594198
+ BACKEND_TIMEOUT_DEFAULT_MS = 12e4;
594199
+ BACKEND_TIMEOUT_MAX_MS = 36e5;
593422
594200
  metrics = {
593423
594201
  requests: /* @__PURE__ */ new Map(),
593424
594202
  totalTokensIn: 0,
@@ -593434,13 +594212,13 @@ var init_serve = __esm({
593434
594212
 
593435
594213
  // packages/cli/src/tui/interactive.ts
593436
594214
  import { cwd } from "node:process";
593437
- import { resolve as resolve39, join as join115, dirname as dirname36, extname as extname12 } from "node:path";
594215
+ import { resolve as resolve39, join as join116, dirname as dirname36, extname as extname12 } from "node:path";
593438
594216
  import { createRequire as createRequire5 } from "node:module";
593439
594217
  import { fileURLToPath as fileURLToPath18 } from "node:url";
593440
- import { readFileSync as readFileSync80, writeFileSync as writeFileSync55, appendFileSync as appendFileSync8, rmSync as rmSync5, readdirSync as readdirSync35, mkdirSync as mkdirSync63 } from "node:fs";
593441
- import { existsSync as existsSync99 } from "node:fs";
594218
+ import { readFileSync as readFileSync81, writeFileSync as writeFileSync56, appendFileSync as appendFileSync8, rmSync as rmSync5, readdirSync as readdirSync35, mkdirSync as mkdirSync64 } from "node:fs";
594219
+ import { existsSync as existsSync100 } from "node:fs";
593442
594220
  import { execSync as execSync56 } from "node:child_process";
593443
- import { homedir as homedir41 } from "node:os";
594221
+ import { homedir as homedir42 } from "node:os";
593444
594222
  function formatTimeAgo2(date) {
593445
594223
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
593446
594224
  if (seconds < 60) return "just now";
@@ -593456,12 +594234,12 @@ function getVersion4() {
593456
594234
  const require4 = createRequire5(import.meta.url);
593457
594235
  const thisDir = dirname36(fileURLToPath18(import.meta.url));
593458
594236
  const candidates = [
593459
- join115(thisDir, "..", "package.json"),
593460
- join115(thisDir, "..", "..", "package.json"),
593461
- join115(thisDir, "..", "..", "..", "package.json")
594237
+ join116(thisDir, "..", "package.json"),
594238
+ join116(thisDir, "..", "..", "package.json"),
594239
+ join116(thisDir, "..", "..", "..", "package.json")
593462
594240
  ];
593463
594241
  for (const pkgPath of candidates) {
593464
- if (existsSync99(pkgPath)) {
594242
+ if (existsSync100(pkgPath)) {
593465
594243
  const pkg = require4(pkgPath);
593466
594244
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
593467
594245
  return pkg.version ?? "0.0.0";
@@ -594224,14 +595002,14 @@ Meta-critique: quality ${meta.quality}/5, thorough: ${meta.thorough}`;
594224
595002
  function gatherMemorySnippets(root) {
594225
595003
  const snippets = [];
594226
595004
  const dirs = [
594227
- join115(root, ".oa", "memory"),
594228
- join115(root, ".open-agents", "memory")
595005
+ join116(root, ".oa", "memory"),
595006
+ join116(root, ".open-agents", "memory")
594229
595007
  ];
594230
595008
  for (const dir of dirs) {
594231
- if (!existsSync99(dir)) continue;
595009
+ if (!existsSync100(dir)) continue;
594232
595010
  try {
594233
595011
  for (const f2 of readdirSync35(dir).filter((f3) => f3.endsWith(".json"))) {
594234
- const data = JSON.parse(readFileSync80(join115(dir, f2), "utf-8"));
595012
+ const data = JSON.parse(readFileSync81(join116(dir, f2), "utf-8"));
594235
595013
  for (const val of Object.values(data)) {
594236
595014
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
594237
595015
  if (v.length > 10) snippets.push(v);
@@ -594385,9 +595163,9 @@ ${metabolismMemories}
594385
595163
  } catch {
594386
595164
  }
594387
595165
  try {
594388
- const archeFile = join115(repoRoot, ".oa", "arche", "variants.json");
594389
- if (existsSync99(archeFile)) {
594390
- const variants = JSON.parse(readFileSync80(archeFile, "utf8"));
595166
+ const archeFile = join116(repoRoot, ".oa", "arche", "variants.json");
595167
+ if (existsSync100(archeFile)) {
595168
+ const variants = JSON.parse(readFileSync81(archeFile, "utf8"));
594391
595169
  if (variants.length > 0) {
594392
595170
  let filtered = variants;
594393
595171
  if (taskType) {
@@ -594559,9 +595337,9 @@ RULES:
594559
595337
  const compactionThreshold = Number.isFinite(envOverride) && envOverride > 0 ? envOverride : modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
594560
595338
  let identityInjection = "";
594561
595339
  try {
594562
- const ikStateFile = join115(repoRoot, ".oa", "identity", "self-state.json");
594563
- if (existsSync99(ikStateFile)) {
594564
- const selfState = JSON.parse(readFileSync80(ikStateFile, "utf8"));
595340
+ const ikStateFile = join116(repoRoot, ".oa", "identity", "self-state.json");
595341
+ if (existsSync100(ikStateFile)) {
595342
+ const selfState = JSON.parse(readFileSync81(ikStateFile, "utf8"));
594565
595343
  const lines = [
594566
595344
  `[Identity State v${selfState.version}]`,
594567
595345
  `Self: ${selfState.narrative_summary}`,
@@ -595422,13 +596200,13 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
595422
596200
  });
595423
596201
  }
595424
596202
  try {
595425
- const ikDir = join115(repoRoot, ".oa", "identity");
595426
- const ikFile = join115(ikDir, "self-state.json");
596203
+ const ikDir = join116(repoRoot, ".oa", "identity");
596204
+ const ikFile = join116(ikDir, "self-state.json");
595427
596205
  let ikState;
595428
- if (existsSync99(ikFile)) {
595429
- ikState = JSON.parse(readFileSync80(ikFile, "utf8"));
596206
+ if (existsSync100(ikFile)) {
596207
+ ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
595430
596208
  } else {
595431
- mkdirSync63(ikDir, { recursive: true });
596209
+ mkdirSync64(ikDir, { recursive: true });
595432
596210
  const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
595433
596211
  ikState = {
595434
596212
  self_id: `oa-${machineId}`,
@@ -595484,7 +596262,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
595484
596262
  }
595485
596263
  ikState.session_count = (ikState.session_count || 0) + 1;
595486
596264
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
595487
- writeFileSync55(ikFile, JSON.stringify(ikState, null, 2));
596265
+ writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
595488
596266
  } catch (ikErr) {
595489
596267
  try {
595490
596268
  console.error("[IK-OBSERVE]", ikErr);
@@ -595503,9 +596281,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
595503
596281
  } else {
595504
596282
  renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
595505
596283
  try {
595506
- const ikFile = join115(repoRoot, ".oa", "identity", "self-state.json");
595507
- if (existsSync99(ikFile)) {
595508
- const ikState = JSON.parse(readFileSync80(ikFile, "utf8"));
596284
+ const ikFile = join116(repoRoot, ".oa", "identity", "self-state.json");
596285
+ if (existsSync100(ikFile)) {
596286
+ const ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
595509
596287
  if (!ikState.stats) ikState.stats = { queries_served: 0 };
595510
596288
  ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
595511
596289
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.03);
@@ -595516,7 +596294,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
595516
596294
  if (ikState.version_history.length > 200) ikState.version_history = ikState.version_history.slice(-200);
595517
596295
  ikState.session_count = (ikState.session_count || 0) + 1;
595518
596296
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
595519
- writeFileSync55(ikFile, JSON.stringify(ikState, null, 2));
596297
+ writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
595520
596298
  }
595521
596299
  } catch {
595522
596300
  }
@@ -595761,10 +596539,10 @@ async function startInteractive(config, repoPath) {
595761
596539
  process.stdin.pause();
595762
596540
  }
595763
596541
  try {
595764
- const oaDir = join115(repoRoot, ".oa");
595765
- const nexusPidFile = join115(oaDir, "nexus", "daemon.pid");
595766
- if (existsSync99(nexusPidFile)) {
595767
- const pid = parseInt(readFileSync80(nexusPidFile, "utf8").trim(), 10);
596542
+ const oaDir = join116(repoRoot, ".oa");
596543
+ const nexusPidFile = join116(oaDir, "nexus", "daemon.pid");
596544
+ if (existsSync100(nexusPidFile)) {
596545
+ const pid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
595768
596546
  if (pid > 0) {
595769
596547
  try {
595770
596548
  process.kill(pid, 0);
@@ -596424,7 +597202,7 @@ ${result.summary}`
596424
597202
  let p2pGateway = null;
596425
597203
  let peerMesh = null;
596426
597204
  let inferenceRouter = null;
596427
- const secretVault = new SecretVault(join115(repoRoot, ".oa", "vault.enc"));
597205
+ const secretVault = new SecretVault(join116(repoRoot, ".oa", "vault.enc"));
596428
597206
  let adminSessionKey = null;
596429
597207
  const callSubAgents = /* @__PURE__ */ new Map();
596430
597208
  const streamRenderer = new StreamRenderer();
@@ -596655,13 +597433,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
596655
597433
  const hits = allCompletions.filter((c9) => c9.toLowerCase().startsWith(lower));
596656
597434
  return [hits, line];
596657
597435
  }
596658
- const HISTORY_DIR = join115(homedir41(), ".open-agents");
596659
- const HISTORY_FILE = join115(HISTORY_DIR, "repl-history");
597436
+ const HISTORY_DIR = join116(homedir42(), ".open-agents");
597437
+ const HISTORY_FILE = join116(HISTORY_DIR, "repl-history");
596660
597438
  const MAX_HISTORY_LINES = 500;
596661
597439
  let savedHistory = [];
596662
597440
  try {
596663
- if (existsSync99(HISTORY_FILE)) {
596664
- const raw = readFileSync80(HISTORY_FILE, "utf8").trim();
597441
+ if (existsSync100(HISTORY_FILE)) {
597442
+ const raw = readFileSync81(HISTORY_FILE, "utf8").trim();
596665
597443
  if (raw) savedHistory = raw.split("\n").reverse();
596666
597444
  }
596667
597445
  } catch {
@@ -596808,12 +597586,12 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
596808
597586
  function persistHistoryLine(line) {
596809
597587
  if (!line.trim()) return;
596810
597588
  try {
596811
- mkdirSync63(HISTORY_DIR, { recursive: true });
597589
+ mkdirSync64(HISTORY_DIR, { recursive: true });
596812
597590
  appendFileSync8(HISTORY_FILE, line + "\n", "utf8");
596813
597591
  if (Math.random() < 0.02) {
596814
- const all2 = readFileSync80(HISTORY_FILE, "utf8").trim().split("\n");
597592
+ const all2 = readFileSync81(HISTORY_FILE, "utf8").trim().split("\n");
596815
597593
  if (all2.length > MAX_HISTORY_LINES) {
596816
- writeFileSync55(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
597594
+ writeFileSync56(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
596817
597595
  }
596818
597596
  }
596819
597597
  } catch {
@@ -596998,10 +597776,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
596998
597776
  const { unlinkSync: _rmStale } = await import("node:fs");
596999
597777
  const { homedir: _hdir } = await import("node:os");
597000
597778
  for (const dp of [
597001
- join115(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
597002
- join115(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
597779
+ join116(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
597780
+ join116(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
597003
597781
  ]) {
597004
- if (existsSync99(dp)) try {
597782
+ if (existsSync100(dp)) try {
597005
597783
  _rmStale(dp);
597006
597784
  } catch {
597007
597785
  }
@@ -597012,9 +597790,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
597012
597790
  const autoNexus = new NexusTool(repoRoot);
597013
597791
  const _registerNexusDaemon = () => {
597014
597792
  try {
597015
- const nexusPidFile = join115(repoRoot, ".oa", "nexus", "daemon.pid");
597016
- if (existsSync99(nexusPidFile)) {
597017
- const nPid = parseInt(readFileSync80(nexusPidFile, "utf8").trim(), 10);
597793
+ const nexusPidFile = join116(repoRoot, ".oa", "nexus", "daemon.pid");
597794
+ if (existsSync100(nexusPidFile)) {
597795
+ const nPid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
597018
597796
  if (nPid > 0 && !registry2.daemons.has("Nexus")) {
597019
597797
  registry2.register({ name: "Nexus", pid: nPid, startedAt: Date.now(), status: "running" });
597020
597798
  statusBar.ensureMonitorTimer();
@@ -597071,7 +597849,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
597071
597849
  } catch {
597072
597850
  }
597073
597851
  try {
597074
- const oaDir = join115(repoRoot, ".oa");
597852
+ const oaDir = join116(repoRoot, ".oa");
597075
597853
  const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
597076
597854
  onInfo: (msg) => writeContent(() => renderInfo2(msg)),
597077
597855
  onError: (msg) => writeContent(() => renderWarning2(msg))
@@ -597103,7 +597881,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
597103
597881
  } catch {
597104
597882
  }
597105
597883
  try {
597106
- const oaDir = join115(repoRoot, ".oa");
597884
+ const oaDir = join116(repoRoot, ".oa");
597107
597885
  const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
597108
597886
  onInfo: (msg) => writeContent(() => renderInfo2(msg)),
597109
597887
  onError: (msg) => writeContent(() => renderWarning2(msg))
@@ -597144,10 +597922,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
597144
597922
  }
597145
597923
  try {
597146
597924
  const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
597147
- const globalNamePath = join115(_hd(), ".open-agents", "agent-name");
597925
+ const globalNamePath = join116(_hd(), ".open-agents", "agent-name");
597148
597926
  let agName = "";
597149
597927
  try {
597150
- if (existsSync99(globalNamePath)) agName = readFileSync80(globalNamePath, "utf8").trim();
597928
+ if (existsSync100(globalNamePath)) agName = readFileSync81(globalNamePath, "utf8").trim();
597151
597929
  } catch {
597152
597930
  }
597153
597931
  if (!agName) {
@@ -597176,11 +597954,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
597176
597954
  }
597177
597955
  if (!ollamaAlive) {
597178
597956
  try {
597179
- const savedSponsorsPath = join115(repoRoot, ".oa", "sponsor", "known-sponsors.json");
597957
+ const savedSponsorsPath = join116(repoRoot, ".oa", "sponsor", "known-sponsors.json");
597180
597958
  let savedSponsors = [];
597181
597959
  try {
597182
- if (existsSync99(savedSponsorsPath)) {
597183
- savedSponsors = JSON.parse(readFileSync80(savedSponsorsPath, "utf8"));
597960
+ if (existsSync100(savedSponsorsPath)) {
597961
+ savedSponsors = JSON.parse(readFileSync81(savedSponsorsPath, "utf8"));
597184
597962
  const oneHourAgo = Date.now() - 36e5;
597185
597963
  savedSponsors = savedSponsors.filter((s2) => (s2.lastVerified || 0) > oneHourAgo);
597186
597964
  }
@@ -598272,10 +599050,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598272
599050
  if (name10 === "voice_list_files") {
598273
599051
  const baseDir = String(args?.dir ?? ".");
598274
599052
  const { readdirSync: readdirSync37, statSync: statSync30 } = __require("node:fs");
598275
- const { join: join120, resolve: resolve43 } = __require("node:path");
598276
- const base3 = baseDir.startsWith("/") ? baseDir : resolve43(join120(repoRoot, baseDir));
599053
+ const { join: join121, resolve: resolve43 } = __require("node:path");
599054
+ const base3 = baseDir.startsWith("/") ? baseDir : resolve43(join121(repoRoot, baseDir));
598277
599055
  const items = readdirSync37(base3).slice(0, 200).map((f2) => {
598278
- const s2 = statSync30(join120(base3, f2));
599056
+ const s2 = statSync30(join121(base3, f2));
598279
599057
  return { name: f2, dir: s2.isDirectory(), size: s2.size };
598280
599058
  });
598281
599059
  return JSON.stringify({ dir: base3, items }, null, 2);
@@ -598363,7 +599141,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598363
599141
  kind,
598364
599142
  targetUrl,
598365
599143
  authKey,
598366
- stateDir: join115(repoRoot, ".oa"),
599144
+ stateDir: join116(repoRoot, ".oa"),
598367
599145
  passthrough: passthrough ?? false,
598368
599146
  loadbalance: loadbalance ?? false,
598369
599147
  endpointAuth: passthrough ? currentConfig.apiKey : void 0,
@@ -598409,7 +599187,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598409
599187
  await tunnelGateway.stop();
598410
599188
  tunnelGateway = null;
598411
599189
  }
598412
- const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join115(repoRoot, ".oa") });
599190
+ const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join116(repoRoot, ".oa") });
598413
599191
  newTunnel.on("stats", (stats) => {
598414
599192
  statusBar.setExposeStatus({
598415
599193
  status: stats.status,
@@ -598496,9 +599274,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598496
599274
  });
598497
599275
  if (!result.success) throw new Error(result.error || "Connect failed");
598498
599276
  try {
598499
- const nexusPidFile = join115(repoRoot, ".oa", "nexus", "daemon.pid");
598500
- if (existsSync99(nexusPidFile)) {
598501
- const pid = parseInt(readFileSync80(nexusPidFile, "utf8").trim(), 10);
599277
+ const nexusPidFile = join116(repoRoot, ".oa", "nexus", "daemon.pid");
599278
+ if (existsSync100(nexusPidFile)) {
599279
+ const pid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
598502
599280
  if (pid > 0) {
598503
599281
  registry2.register({
598504
599282
  name: "Nexus",
@@ -598686,10 +599464,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598686
599464
  writeContent(() => renderInfo2(`Killed ${bgKilled} background task(s).`));
598687
599465
  }
598688
599466
  try {
598689
- const nexusDir = join115(repoRoot, OA_DIR, "nexus");
598690
- const pidFile = join115(nexusDir, "daemon.pid");
598691
- if (existsSync99(pidFile)) {
598692
- const pid = parseInt(readFileSync80(pidFile, "utf8").trim(), 10);
599467
+ const nexusDir = join116(repoRoot, OA_DIR, "nexus");
599468
+ const pidFile = join116(nexusDir, "daemon.pid");
599469
+ if (existsSync100(pidFile)) {
599470
+ const pid = parseInt(readFileSync81(pidFile, "utf8").trim(), 10);
598693
599471
  if (pid > 0) {
598694
599472
  try {
598695
599473
  if (process.platform === "win32") {
@@ -598711,13 +599489,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598711
599489
  } catch {
598712
599490
  }
598713
599491
  try {
598714
- const voiceDir2 = join115(homedir41(), ".open-agents", "voice");
599492
+ const voiceDir2 = join116(homedir42(), ".open-agents", "voice");
598715
599493
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
598716
599494
  for (const pf of voicePidFiles) {
598717
- const pidPath = join115(voiceDir2, pf);
598718
- if (existsSync99(pidPath)) {
599495
+ const pidPath = join116(voiceDir2, pf);
599496
+ if (existsSync100(pidPath)) {
598719
599497
  try {
598720
- const pid = parseInt(readFileSync80(pidPath, "utf8").trim(), 10);
599498
+ const pid = parseInt(readFileSync81(pidPath, "utf8").trim(), 10);
598721
599499
  if (pid > 0) {
598722
599500
  if (process.platform === "win32") {
598723
599501
  try {
@@ -598741,8 +599519,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598741
599519
  execSync56(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
598742
599520
  } catch {
598743
599521
  }
598744
- const oaPath = join115(repoRoot, OA_DIR);
598745
- if (existsSync99(oaPath)) {
599522
+ const oaPath = join116(repoRoot, OA_DIR);
599523
+ if (existsSync100(oaPath)) {
598746
599524
  let deleted = false;
598747
599525
  for (let attempt = 0; attempt < 3; attempt++) {
598748
599526
  try {
@@ -598826,19 +599604,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
598826
599604
  try {
598827
599605
  const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
598828
599606
  if (isPersonaPlexRunning2()) {
598829
- const ppPidFile = join115(homedir41(), ".open-agents", "voice", "personaplex", "daemon.pid");
598830
- const ppPortFile = join115(homedir41(), ".open-agents", "voice", "personaplex", "daemon.port");
598831
- if (existsSync99(ppPidFile)) {
598832
- const ppPid = parseInt(readFileSync80(ppPidFile, "utf8").trim(), 10);
598833
- const ppPort = existsSync99(ppPortFile) ? parseInt(readFileSync80(ppPortFile, "utf8").trim(), 10) : void 0;
599607
+ const ppPidFile = join116(homedir42(), ".open-agents", "voice", "personaplex", "daemon.pid");
599608
+ const ppPortFile = join116(homedir42(), ".open-agents", "voice", "personaplex", "daemon.port");
599609
+ if (existsSync100(ppPidFile)) {
599610
+ const ppPid = parseInt(readFileSync81(ppPidFile, "utf8").trim(), 10);
599611
+ const ppPort = existsSync100(ppPortFile) ? parseInt(readFileSync81(ppPortFile, "utf8").trim(), 10) : void 0;
598834
599612
  if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
598835
599613
  registry2.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
598836
599614
  }
598837
599615
  }
598838
599616
  }
598839
- const nexusPidFile = join115(repoRoot, ".oa", "nexus", "daemon.pid");
598840
- if (existsSync99(nexusPidFile)) {
598841
- const nPid = parseInt(readFileSync80(nexusPidFile, "utf8").trim(), 10);
599617
+ const nexusPidFile = join116(repoRoot, ".oa", "nexus", "daemon.pid");
599618
+ if (existsSync100(nexusPidFile)) {
599619
+ const nPid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
598842
599620
  if (nPid > 0 && !registry2.daemons.has("Nexus")) {
598843
599621
  try {
598844
599622
  process.kill(nPid, 0);
@@ -599205,9 +599983,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
599205
599983
  }
599206
599984
  }
599207
599985
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
599208
- const isImage = isImagePath(cleanPath) && existsSync99(resolve39(repoRoot, cleanPath));
599209
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync99(resolve39(repoRoot, cleanPath));
599210
- const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync99(resolve39(repoRoot, cleanPath));
599986
+ const isImage = isImagePath(cleanPath) && existsSync100(resolve39(repoRoot, cleanPath));
599987
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync100(resolve39(repoRoot, cleanPath));
599988
+ const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync100(resolve39(repoRoot, cleanPath));
599211
599989
  if (activeTask) {
599212
599990
  if (activeTask.runner.isPaused) {
599213
599991
  activeTask.runner.resume();
@@ -599216,7 +599994,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
599216
599994
  if (isImage) {
599217
599995
  try {
599218
599996
  const imgPath = resolve39(repoRoot, cleanPath);
599219
- const imgBuffer = readFileSync80(imgPath);
599997
+ const imgBuffer = readFileSync81(imgPath);
599220
599998
  const base642 = imgBuffer.toString("base64");
599221
599999
  const ext = extname12(cleanPath).toLowerCase();
599222
600000
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -599372,7 +600150,7 @@ ${result.text}`;
599372
600150
  if (isMarkdown && fullInput === input) {
599373
600151
  try {
599374
600152
  const mdPath = resolve39(repoRoot, cleanPath);
599375
- const mdContent = readFileSync80(mdPath, "utf8");
600153
+ const mdContent = readFileSync81(mdPath, "utf8");
599376
600154
  const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
599377
600155
  const result = parseMcpMarkdown2(mdContent);
599378
600156
  if (result.servers.length > 0) {
@@ -599794,13 +600572,13 @@ async function runWithTUI(task, config, repoPath, callbacks) {
599794
600572
  const handle2 = startTask(task, config, repoRoot);
599795
600573
  await handle2.promise;
599796
600574
  try {
599797
- const ikDir = join115(repoRoot, ".oa", "identity");
599798
- const ikFile = join115(ikDir, "self-state.json");
600575
+ const ikDir = join116(repoRoot, ".oa", "identity");
600576
+ const ikFile = join116(ikDir, "self-state.json");
599799
600577
  let ikState;
599800
- if (existsSync99(ikFile)) {
599801
- ikState = JSON.parse(readFileSync80(ikFile, "utf8"));
600578
+ if (existsSync100(ikFile)) {
600579
+ ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
599802
600580
  } else {
599803
- mkdirSync63(ikDir, { recursive: true });
600581
+ mkdirSync64(ikDir, { recursive: true });
599804
600582
  ikState = {
599805
600583
  self_id: `oa-${Date.now().toString(36)}`,
599806
600584
  version: 1,
@@ -599822,7 +600600,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
599822
600600
  ikState.homeostasis.coherence = Math.min(1, ikState.homeostasis.coherence + 0.05);
599823
600601
  ikState.session_count = (ikState.session_count || 0) + 1;
599824
600602
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
599825
- writeFileSync55(ikFile, JSON.stringify(ikState, null, 2));
600603
+ writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
599826
600604
  } catch (ikErr) {
599827
600605
  }
599828
600606
  try {
@@ -599835,11 +600613,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
599835
600613
  );
599836
600614
  } catch {
599837
600615
  try {
599838
- const archeDir = join115(repoRoot, ".oa", "arche");
599839
- const archeFile = join115(archeDir, "variants.json");
600616
+ const archeDir = join116(repoRoot, ".oa", "arche");
600617
+ const archeFile = join116(archeDir, "variants.json");
599840
600618
  let variants = [];
599841
600619
  try {
599842
- if (existsSync99(archeFile)) variants = JSON.parse(readFileSync80(archeFile, "utf8"));
600620
+ if (existsSync100(archeFile)) variants = JSON.parse(readFileSync81(archeFile, "utf8"));
599843
600621
  } catch {
599844
600622
  }
599845
600623
  variants.push({
@@ -599853,15 +600631,15 @@ async function runWithTUI(task, config, repoPath, callbacks) {
599853
600631
  tags: ["general"]
599854
600632
  });
599855
600633
  if (variants.length > 50) variants = variants.slice(-50);
599856
- mkdirSync63(archeDir, { recursive: true });
599857
- writeFileSync55(archeFile, JSON.stringify(variants, null, 2));
600634
+ mkdirSync64(archeDir, { recursive: true });
600635
+ writeFileSync56(archeFile, JSON.stringify(variants, null, 2));
599858
600636
  } catch {
599859
600637
  }
599860
600638
  }
599861
600639
  try {
599862
- const metaFile = join115(repoRoot, ".oa", "memory", "metabolism", "store.json");
599863
- if (existsSync99(metaFile)) {
599864
- const store2 = JSON.parse(readFileSync80(metaFile, "utf8"));
600640
+ const metaFile = join116(repoRoot, ".oa", "memory", "metabolism", "store.json");
600641
+ if (existsSync100(metaFile)) {
600642
+ const store2 = JSON.parse(readFileSync81(metaFile, "utf8"));
599865
600643
  const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
599866
600644
  let updated = false;
599867
600645
  for (const item of surfaced) {
@@ -599872,7 +600650,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
599872
600650
  updated = true;
599873
600651
  }
599874
600652
  if (updated) {
599875
- writeFileSync55(metaFile, JSON.stringify(store2, null, 2));
600653
+ writeFileSync56(metaFile, JSON.stringify(store2, null, 2));
599876
600654
  }
599877
600655
  }
599878
600656
  } catch {
@@ -599925,9 +600703,9 @@ Rules:
599925
600703
  try {
599926
600704
  const { initDb: initDb2 } = __require("@open-agents/memory");
599927
600705
  const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
599928
- const dbDir = join115(repoRoot, ".oa", "memory");
599929
- mkdirSync63(dbDir, { recursive: true });
599930
- const db = initDb2(join115(dbDir, "structured.db"));
600706
+ const dbDir = join116(repoRoot, ".oa", "memory");
600707
+ mkdirSync64(dbDir, { recursive: true });
600708
+ const db = initDb2(join116(dbDir, "structured.db"));
599931
600709
  const memStore = new ProceduralMemoryStore2(db);
599932
600710
  memStore.createWithEmbedding({
599933
600711
  content: content.slice(0, 600),
@@ -599942,11 +600720,11 @@ Rules:
599942
600720
  db.close();
599943
600721
  } catch {
599944
600722
  }
599945
- const metaDir = join115(repoRoot, ".oa", "memory", "metabolism");
599946
- const storeFile = join115(metaDir, "store.json");
600723
+ const metaDir = join116(repoRoot, ".oa", "memory", "metabolism");
600724
+ const storeFile = join116(metaDir, "store.json");
599947
600725
  let store2 = [];
599948
600726
  try {
599949
- if (existsSync99(storeFile)) store2 = JSON.parse(readFileSync80(storeFile, "utf8"));
600727
+ if (existsSync100(storeFile)) store2 = JSON.parse(readFileSync81(storeFile, "utf8"));
599950
600728
  } catch {
599951
600729
  }
599952
600730
  store2.push({
@@ -599961,26 +600739,26 @@ Rules:
599961
600739
  accessCount: 0
599962
600740
  });
599963
600741
  if (store2.length > 100) store2 = store2.slice(-100);
599964
- mkdirSync63(metaDir, { recursive: true });
599965
- writeFileSync55(storeFile, JSON.stringify(store2, null, 2));
600742
+ mkdirSync64(metaDir, { recursive: true });
600743
+ writeFileSync56(storeFile, JSON.stringify(store2, null, 2));
599966
600744
  }
599967
600745
  }
599968
600746
  } catch {
599969
600747
  }
599970
600748
  try {
599971
- const cohereSettingsFile = join115(repoRoot, ".oa", "settings.json");
600749
+ const cohereSettingsFile = join116(repoRoot, ".oa", "settings.json");
599972
600750
  let cohereActive = false;
599973
600751
  try {
599974
- if (existsSync99(cohereSettingsFile)) {
599975
- const settings = JSON.parse(readFileSync80(cohereSettingsFile, "utf8"));
600752
+ if (existsSync100(cohereSettingsFile)) {
600753
+ const settings = JSON.parse(readFileSync81(cohereSettingsFile, "utf8"));
599976
600754
  cohereActive = settings.cohere === true;
599977
600755
  }
599978
600756
  } catch {
599979
600757
  }
599980
600758
  if (cohereActive) {
599981
- const metaFile = join115(repoRoot, ".oa", "memory", "metabolism", "store.json");
599982
- if (existsSync99(metaFile)) {
599983
- const store2 = JSON.parse(readFileSync80(metaFile, "utf8"));
600759
+ const metaFile = join116(repoRoot, ".oa", "memory", "metabolism", "store.json");
600760
+ if (existsSync100(metaFile)) {
600761
+ const store2 = JSON.parse(readFileSync81(metaFile, "utf8"));
599984
600762
  const latest = store2.filter((m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
599985
600763
  if (latest && latest.scores?.confidence >= 0.6) {
599986
600764
  try {
@@ -600005,18 +600783,18 @@ Rules:
600005
600783
  }
600006
600784
  } catch (err) {
600007
600785
  try {
600008
- const ikFile = join115(repoRoot, ".oa", "identity", "self-state.json");
600009
- if (existsSync99(ikFile)) {
600010
- const ikState = JSON.parse(readFileSync80(ikFile, "utf8"));
600786
+ const ikFile = join116(repoRoot, ".oa", "identity", "self-state.json");
600787
+ if (existsSync100(ikFile)) {
600788
+ const ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
600011
600789
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
600012
600790
  ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
600013
600791
  ikState.session_count = (ikState.session_count || 0) + 1;
600014
600792
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
600015
- writeFileSync55(ikFile, JSON.stringify(ikState, null, 2));
600793
+ writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
600016
600794
  }
600017
- const metaFile = join115(repoRoot, ".oa", "memory", "metabolism", "store.json");
600018
- if (existsSync99(metaFile)) {
600019
- const store2 = JSON.parse(readFileSync80(metaFile, "utf8"));
600795
+ const metaFile = join116(repoRoot, ".oa", "memory", "metabolism", "store.json");
600796
+ if (existsSync100(metaFile)) {
600797
+ const store2 = JSON.parse(readFileSync81(metaFile, "utf8"));
600020
600798
  const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
600021
600799
  for (const item of surfaced) {
600022
600800
  item.accessCount = (item.accessCount || 0) + 1;
@@ -600024,14 +600802,14 @@ Rules:
600024
600802
  item.scores.utility = Math.max(0, (item.scores.utility || 0.5) - 0.05);
600025
600803
  item.scores.confidence = Math.max(0, (item.scores.confidence || 0.5) - 0.02);
600026
600804
  }
600027
- writeFileSync55(metaFile, JSON.stringify(store2, null, 2));
600805
+ writeFileSync56(metaFile, JSON.stringify(store2, null, 2));
600028
600806
  }
600029
600807
  try {
600030
- const archeDir = join115(repoRoot, ".oa", "arche");
600031
- const archeFile = join115(archeDir, "variants.json");
600808
+ const archeDir = join116(repoRoot, ".oa", "arche");
600809
+ const archeFile = join116(archeDir, "variants.json");
600032
600810
  let variants = [];
600033
600811
  try {
600034
- if (existsSync99(archeFile)) variants = JSON.parse(readFileSync80(archeFile, "utf8"));
600812
+ if (existsSync100(archeFile)) variants = JSON.parse(readFileSync81(archeFile, "utf8"));
600035
600813
  } catch {
600036
600814
  }
600037
600815
  variants.push({
@@ -600045,8 +600823,8 @@ Rules:
600045
600823
  tags: ["general"]
600046
600824
  });
600047
600825
  if (variants.length > 50) variants = variants.slice(-50);
600048
- mkdirSync63(archeDir, { recursive: true });
600049
- writeFileSync55(archeFile, JSON.stringify(variants, null, 2));
600826
+ mkdirSync64(archeDir, { recursive: true });
600827
+ writeFileSync56(archeFile, JSON.stringify(variants, null, 2));
600050
600828
  } catch {
600051
600829
  }
600052
600830
  } catch {
@@ -600135,13 +600913,13 @@ __export(run_exports, {
600135
600913
  });
600136
600914
  import { resolve as resolve40 } from "node:path";
600137
600915
  import { spawn as spawn26 } from "node:child_process";
600138
- import { mkdirSync as mkdirSync64, writeFileSync as writeFileSync56, readFileSync as readFileSync81, readdirSync as readdirSync36, existsSync as existsSync100 } from "node:fs";
600139
- import { randomBytes as randomBytes23 } from "node:crypto";
600140
- import { join as join116 } from "node:path";
600916
+ import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57, readFileSync as readFileSync82, readdirSync as readdirSync36, existsSync as existsSync101 } from "node:fs";
600917
+ import { randomBytes as randomBytes24 } from "node:crypto";
600918
+ import { join as join117 } from "node:path";
600141
600919
  function jobsDir2(repoPath) {
600142
600920
  const root = resolve40(repoPath ?? process.cwd());
600143
- const dir = join116(root, ".oa", "jobs");
600144
- mkdirSync64(dir, { recursive: true });
600921
+ const dir = join117(root, ".oa", "jobs");
600922
+ mkdirSync65(dir, { recursive: true });
600145
600923
  return dir;
600146
600924
  }
600147
600925
  async function runCommand(opts, config) {
@@ -600231,7 +601009,7 @@ function extractSummary(captured) {
600231
601009
  return lines.slice(-3).join(" ").slice(0, 200);
600232
601010
  }
600233
601011
  async function runBackground(task, config, opts) {
600234
- const id = `job-${randomBytes23(3).toString("hex")}`;
601012
+ const id = `job-${randomBytes24(3).toString("hex")}`;
600235
601013
  const dir = jobsDir2(opts.repoPath);
600236
601014
  const repoRoot = resolve40(opts.repoPath ?? process.cwd());
600237
601015
  const job = {
@@ -600260,7 +601038,7 @@ async function runBackground(task, config, opts) {
600260
601038
  }
600261
601039
  });
600262
601040
  job.pid = child.pid ?? 0;
600263
- writeFileSync56(join116(dir, `${id}.json`), JSON.stringify(job, null, 2));
601041
+ writeFileSync57(join117(dir, `${id}.json`), JSON.stringify(job, null, 2));
600264
601042
  let output = "";
600265
601043
  child.stdout?.on("data", (chunk) => {
600266
601044
  output += chunk.toString();
@@ -600276,7 +601054,7 @@ async function runBackground(task, config, opts) {
600276
601054
  job.summary = result.summary;
600277
601055
  job.durationMs = result.durationMs;
600278
601056
  job.error = result.error;
600279
- writeFileSync56(join116(dir, `${id}.json`), JSON.stringify(job, null, 2));
601057
+ writeFileSync57(join117(dir, `${id}.json`), JSON.stringify(job, null, 2));
600280
601058
  } catch {
600281
601059
  }
600282
601060
  });
@@ -600292,13 +601070,13 @@ async function runBackground(task, config, opts) {
600292
601070
  }
600293
601071
  function statusCommand(jobId, repoPath) {
600294
601072
  const dir = jobsDir2(repoPath);
600295
- const file = join116(dir, `${jobId}.json`);
600296
- if (!existsSync100(file)) {
601073
+ const file = join117(dir, `${jobId}.json`);
601074
+ if (!existsSync101(file)) {
600297
601075
  console.error(`Job not found: ${jobId}`);
600298
601076
  console.log(`Available jobs: oa jobs`);
600299
601077
  process.exit(1);
600300
601078
  }
600301
- const job = JSON.parse(readFileSync81(file, "utf-8"));
601079
+ const job = JSON.parse(readFileSync82(file, "utf-8"));
600302
601080
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
600303
601081
  const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
600304
601082
  console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
@@ -600319,7 +601097,7 @@ function jobsCommand(repoPath) {
600319
601097
  console.log("Jobs:");
600320
601098
  for (const file of files) {
600321
601099
  try {
600322
- const job = JSON.parse(readFileSync81(join116(dir, file), "utf-8"));
601100
+ const job = JSON.parse(readFileSync82(join117(dir, file), "utf-8"));
600323
601101
  const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
600324
601102
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
600325
601103
  const cleanListTask = cleanForStorage(job.task) || job.task;
@@ -600343,13 +601121,13 @@ __export(index_repo_exports, {
600343
601121
  indexRepoCommand: () => indexRepoCommand
600344
601122
  });
600345
601123
  import { resolve as resolve41 } from "node:path";
600346
- import { existsSync as existsSync101, statSync as statSync29 } from "node:fs";
601124
+ import { existsSync as existsSync102, statSync as statSync29 } from "node:fs";
600347
601125
  import { cwd as cwd2 } from "node:process";
600348
601126
  async function indexRepoCommand(opts, _config3) {
600349
601127
  const repoRoot = resolve41(opts.repoPath ?? cwd2());
600350
601128
  printHeader("Index Repository");
600351
601129
  printInfo(`Indexing: ${repoRoot}`);
600352
- if (!existsSync101(repoRoot)) {
601130
+ if (!existsSync102(repoRoot)) {
600353
601131
  printError(`Path does not exist: ${repoRoot}`);
600354
601132
  process.exit(1);
600355
601133
  }
@@ -600601,8 +601379,8 @@ var config_exports2 = {};
600601
601379
  __export(config_exports2, {
600602
601380
  configCommand: () => configCommand
600603
601381
  });
600604
- import { join as join117, resolve as resolve42 } from "node:path";
600605
- import { homedir as homedir42 } from "node:os";
601382
+ import { join as join118, resolve as resolve42 } from "node:path";
601383
+ import { homedir as homedir43 } from "node:os";
600606
601384
  import { cwd as cwd3 } from "node:process";
600607
601385
  function redactIfSensitive(key, value2) {
600608
601386
  if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
@@ -600683,7 +601461,7 @@ function handleShow(opts, config) {
600683
601461
  }
600684
601462
  }
600685
601463
  printSection("Config File");
600686
- printInfo(`~/.open-agents/config.json (${join117(homedir42(), ".open-agents", "config.json")})`);
601464
+ printInfo(`~/.open-agents/config.json (${join118(homedir43(), ".open-agents", "config.json")})`);
600687
601465
  printSection("Priority Chain");
600688
601466
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
600689
601467
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -600722,7 +601500,7 @@ function handleSet(opts, _config3) {
600722
601500
  const coerced = coerceForSettings(key, value2);
600723
601501
  saveProjectSettings(repoRoot, { [key]: coerced });
600724
601502
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value2)}`);
600725
- printInfo(`Saved to ${join117(repoRoot, ".oa", "settings.json")}`);
601503
+ printInfo(`Saved to ${join118(repoRoot, ".oa", "settings.json")}`);
600726
601504
  printInfo("This override applies only when running in this workspace.");
600727
601505
  } catch (err) {
600728
601506
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -600906,8 +601684,8 @@ __export(eval_exports, {
600906
601684
  evalCommand: () => evalCommand
600907
601685
  });
600908
601686
  import { tmpdir as tmpdir21 } from "node:os";
600909
- import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57 } from "node:fs";
600910
- import { join as join118 } from "node:path";
601687
+ import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync58 } from "node:fs";
601688
+ import { join as join119 } from "node:path";
600911
601689
  async function evalCommand(opts, config) {
600912
601690
  const suiteName = opts.suite ?? "basic";
600913
601691
  const suite = SUITES[suiteName];
@@ -601036,10 +601814,10 @@ async function evalCommand(opts, config) {
601036
601814
  process.exit(failed > 0 ? 1 : 0);
601037
601815
  }
601038
601816
  function createTempEvalRepo() {
601039
- const dir = join118(tmpdir21(), `open-agents-eval-${Date.now()}`);
601040
- mkdirSync65(dir, { recursive: true });
601041
- writeFileSync57(
601042
- join118(dir, "package.json"),
601817
+ const dir = join119(tmpdir21(), `open-agents-eval-${Date.now()}`);
601818
+ mkdirSync66(dir, { recursive: true });
601819
+ writeFileSync58(
601820
+ join119(dir, "package.json"),
601043
601821
  JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n",
601044
601822
  "utf8"
601045
601823
  );
@@ -601103,7 +601881,7 @@ init_typed_node_events();
601103
601881
  import { parseArgs as nodeParseArgs2 } from "node:util";
601104
601882
  import { createRequire as createRequire6 } from "node:module";
601105
601883
  import { fileURLToPath as fileURLToPath19 } from "node:url";
601106
- import { dirname as dirname37, join as join119 } from "node:path";
601884
+ import { dirname as dirname37, join as join120 } from "node:path";
601107
601885
 
601108
601886
  // packages/cli/src/cli.ts
601109
601887
  init_typed_node_events();
@@ -601243,7 +602021,7 @@ init_output();
601243
602021
  function getVersion5() {
601244
602022
  try {
601245
602023
  const require4 = createRequire6(import.meta.url);
601246
- const pkgPath = join119(dirname37(fileURLToPath19(import.meta.url)), "..", "package.json");
602024
+ const pkgPath = join120(dirname37(fileURLToPath19(import.meta.url)), "..", "package.json");
601247
602025
  const pkg = require4(pkgPath);
601248
602026
  return pkg.version;
601249
602027
  } catch {
@@ -601557,12 +602335,12 @@ function crashLog(label, err) {
601557
602335
  const logLine = `[${timestamp}] ${label}: ${msg}
601558
602336
  `;
601559
602337
  try {
601560
- const { appendFileSync: appendFileSync9, mkdirSync: mkdirSync66 } = __require("node:fs");
601561
- const { join: join120 } = __require("node:path");
601562
- const { homedir: homedir43 } = __require("node:os");
601563
- const logDir = join120(homedir43(), ".open-agents");
601564
- mkdirSync66(logDir, { recursive: true });
601565
- appendFileSync9(join120(logDir, "crash.log"), logLine);
602338
+ const { appendFileSync: appendFileSync9, mkdirSync: mkdirSync67 } = __require("node:fs");
602339
+ const { join: join121 } = __require("node:path");
602340
+ const { homedir: homedir44 } = __require("node:os");
602341
+ const logDir = join121(homedir44(), ".open-agents");
602342
+ mkdirSync67(logDir, { recursive: true });
602343
+ appendFileSync9(join121(logDir, "crash.log"), logLine);
601566
602344
  } catch {
601567
602345
  }
601568
602346
  try {