open-agents-ai 0.172.0 → 0.174.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +470 -251
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1374,7 +1374,7 @@ ${stdinInput ?? ""}`);
1374
1374
  }
1375
1375
  runCommand(command, timeout, stdinInput) {
1376
1376
  const start = performance.now();
1377
- return new Promise((resolve34) => {
1377
+ return new Promise((resolve35) => {
1378
1378
  const child = spawn("bash", ["-c", command], {
1379
1379
  cwd: this.workingDir,
1380
1380
  env: {
@@ -1405,7 +1405,7 @@ ${stdinInput ?? ""}`);
1405
1405
  clearTimeout(timer);
1406
1406
  if (exitFlushTimer)
1407
1407
  clearTimeout(exitFlushTimer);
1408
- resolve34(result);
1408
+ resolve35(result);
1409
1409
  };
1410
1410
  const timer = setTimeout(() => {
1411
1411
  killed = true;
@@ -3161,7 +3161,7 @@ ${JSON.stringify(extracted, null, 2)}`);
3161
3161
  return null;
3162
3162
  }
3163
3163
  runProcess(cmd, args, timeoutMs) {
3164
- return new Promise((resolve34, reject) => {
3164
+ return new Promise((resolve35, reject) => {
3165
3165
  const proc = execFile3(cmd, args, {
3166
3166
  timeout: timeoutMs,
3167
3167
  maxBuffer: 10 * 1024 * 1024,
@@ -3171,7 +3171,7 @@ ${JSON.stringify(extracted, null, 2)}`);
3171
3171
  reject(new Error(`Process timeout after ${timeoutMs}ms`));
3172
3172
  return;
3173
3173
  }
3174
- resolve34({
3174
+ resolve35({
3175
3175
  stdout: String(stdout),
3176
3176
  stderr: String(stderr),
3177
3177
  exitCode: error ? error.code ?? 1 : 0
@@ -10602,7 +10602,7 @@ var init_custom_tool = __esm({
10602
10602
  }
10603
10603
  /** Execute a single shell command and return output */
10604
10604
  runCommand(command) {
10605
- return new Promise((resolve34) => {
10605
+ return new Promise((resolve35) => {
10606
10606
  const child = spawn4("bash", ["-c", command], {
10607
10607
  cwd: this.workingDir,
10608
10608
  env: { ...process.env, CI: "true", NO_COLOR: "1" },
@@ -10627,11 +10627,11 @@ var init_custom_tool = __esm({
10627
10627
  child.kill("SIGTERM");
10628
10628
  } catch {
10629
10629
  }
10630
- resolve34({ success: false, output: stdout, error: "Command timed out after 60s" });
10630
+ resolve35({ success: false, output: stdout, error: "Command timed out after 60s" });
10631
10631
  }, 6e4);
10632
10632
  child.on("close", (code) => {
10633
10633
  clearTimeout(timer);
10634
- resolve34({
10634
+ resolve35({
10635
10635
  success: code === 0,
10636
10636
  output: stdout + (stderr && code === 0 ? `
10637
10637
  STDERR:
@@ -10641,7 +10641,7 @@ ${stderr}` : ""),
10641
10641
  });
10642
10642
  child.on("error", (err) => {
10643
10643
  clearTimeout(timer);
10644
- resolve34({ success: false, output: stdout, error: err.message });
10644
+ resolve35({ success: false, output: stdout, error: err.message });
10645
10645
  });
10646
10646
  });
10647
10647
  }
@@ -11659,8 +11659,8 @@ async function loadTranscribeCli() {
11659
11659
  const nvmBase = join19(homedir6(), ".nvm", "versions", "node");
11660
11660
  if (existsSync16(nvmBase)) {
11661
11661
  try {
11662
- const { readdirSync: readdirSync20 } = await import("node:fs");
11663
- for (const ver of readdirSync20(nvmBase)) {
11662
+ const { readdirSync: readdirSync21 } = await import("node:fs");
11663
+ for (const ver of readdirSync21(nvmBase)) {
11664
11664
  const tcPath = join19(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
11665
11665
  if (existsSync16(join19(tcPath, "dist", "index.js"))) {
11666
11666
  const { createRequire: createRequire4 } = await import("node:module");
@@ -12205,7 +12205,7 @@ import { writeFile as writeFile8, mkdtemp, rm, readdir as readdir3, stat } from
12205
12205
  import { join as join20 } from "node:path";
12206
12206
  import { tmpdir as tmpdir2 } from "node:os";
12207
12207
  function runProcess(cmd, args, options) {
12208
- return new Promise((resolve34) => {
12208
+ return new Promise((resolve35) => {
12209
12209
  const proc = spawn6(cmd, args, {
12210
12210
  cwd: options.cwd,
12211
12211
  timeout: options.timeout,
@@ -12235,7 +12235,7 @@ function runProcess(cmd, args, options) {
12235
12235
  }
12236
12236
  });
12237
12237
  proc.on("error", (err) => {
12238
- resolve34({
12238
+ resolve35({
12239
12239
  stdout,
12240
12240
  stderr: stderr || err.message,
12241
12241
  exitCode: 1,
@@ -12247,7 +12247,7 @@ function runProcess(cmd, args, options) {
12247
12247
  if (signal === "SIGTERM" || signal === "SIGKILL") {
12248
12248
  timedOut = true;
12249
12249
  }
12250
- resolve34({
12250
+ resolve35({
12251
12251
  stdout,
12252
12252
  stderr,
12253
12253
  exitCode: code ?? (timedOut ? 124 : 1),
@@ -12730,7 +12730,7 @@ Justification: ${justification || "(none provided)"}`,
12730
12730
  })();
12731
12731
  const ipfsResult = await Promise.race([
12732
12732
  ipfsPromise,
12733
- new Promise((resolve34) => setTimeout(() => resolve34(null), 2e3))
12733
+ new Promise((resolve35) => setTimeout(() => resolve35(null), 2e3))
12734
12734
  ]);
12735
12735
  if (ipfsResult && ipfsResult.success) {
12736
12736
  const cidData = JSON.parse(ipfsResult.output);
@@ -13177,7 +13177,7 @@ print("__OA_REPL_READY__")
13177
13177
  return;
13178
13178
  const sockId = randomBytes5(8).toString("hex");
13179
13179
  this.ipcPath = join22(tmpdir3(), `oa-repl-ipc-${sockId}.sock`);
13180
- return new Promise((resolve34, reject) => {
13180
+ return new Promise((resolve35, reject) => {
13181
13181
  this.ipcServer = createServer((conn) => {
13182
13182
  let buffer = new Uint8Array(0);
13183
13183
  conn.on("data", (chunk) => {
@@ -13193,7 +13193,7 @@ print("__OA_REPL_READY__")
13193
13193
  });
13194
13194
  });
13195
13195
  this.ipcServer.on("error", reject);
13196
- this.ipcServer.listen(this.ipcPath, () => resolve34());
13196
+ this.ipcServer.listen(this.ipcPath, () => resolve35());
13197
13197
  });
13198
13198
  }
13199
13199
  async processIpcBuffer(conn, input) {
@@ -13256,9 +13256,9 @@ print("__OA_REPL_READY__")
13256
13256
  }
13257
13257
  // ── Code execution ─────────────────────────────────────────────────────
13258
13258
  executeCode(code, isInit = false) {
13259
- return new Promise((resolve34) => {
13259
+ return new Promise((resolve35) => {
13260
13260
  if (!this.proc?.stdin || !this.proc?.stdout || !this.proc?.stderr) {
13261
- resolve34({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
13261
+ resolve35({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
13262
13262
  return;
13263
13263
  }
13264
13264
  const sentinel = `__OA_SENTINEL_${randomBytes5(6).toString("hex")}__`;
@@ -13268,7 +13268,7 @@ print("__OA_REPL_READY__")
13268
13268
  const timeout = setTimeout(() => {
13269
13269
  if (!resolved) {
13270
13270
  resolved = true;
13271
- resolve34({
13271
+ resolve35({
13272
13272
  success: false,
13273
13273
  output: stdout || "Execution timed out",
13274
13274
  error: `Timeout after ${this.execTimeout / 1e3}s`,
@@ -13285,13 +13285,13 @@ print("__OA_REPL_READY__")
13285
13285
  if (isInit) {
13286
13286
  const ready = cleanOutput.includes("__OA_REPL_READY__");
13287
13287
  const displayOutput = cleanOutput.replace("__OA_REPL_READY__", "").trim();
13288
- resolve34({
13288
+ resolve35({
13289
13289
  success: ready,
13290
13290
  output: displayOutput || "REPL initialized",
13291
13291
  durationMs: 0
13292
13292
  });
13293
13293
  } else {
13294
- resolve34({
13294
+ resolve35({
13295
13295
  success: true,
13296
13296
  output: cleanOutput || "(no output)",
13297
13297
  durationMs: 0
@@ -13300,7 +13300,7 @@ print("__OA_REPL_READY__")
13300
13300
  }
13301
13301
  if (stdout.length > 2e5) {
13302
13302
  cleanup();
13303
- resolve34({
13303
+ resolve35({
13304
13304
  success: true,
13305
13305
  output: stdout.slice(0, 2e5) + "\n[output truncated at 200KB]",
13306
13306
  durationMs: 0
@@ -13402,9 +13402,9 @@ print("${sentinel}")
13402
13402
  if (!this.proc || this.proc.killed) {
13403
13403
  return { success: false, path: "" };
13404
13404
  }
13405
- const { mkdirSync: mkdirSync25, writeFileSync: writeFileSync24 } = await import("node:fs");
13405
+ const { mkdirSync: mkdirSync26, writeFileSync: writeFileSync25 } = await import("node:fs");
13406
13406
  const sessionDir = join22(this.cwd, ".oa", "rlm");
13407
- mkdirSync25(sessionDir, { recursive: true });
13407
+ mkdirSync26(sessionDir, { recursive: true });
13408
13408
  const sessionPath = join22(sessionDir, "session.json");
13409
13409
  try {
13410
13410
  const inspectCode = `
@@ -13428,7 +13428,7 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
13428
13428
  trajectoryCount: this.trajectory.length,
13429
13429
  subCallCount: this.subCallCount
13430
13430
  };
13431
- writeFileSync24(sessionPath, JSON.stringify(sessionData, null, 2), "utf8");
13431
+ writeFileSync25(sessionPath, JSON.stringify(sessionData, null, 2), "utf8");
13432
13432
  return { success: true, path: sessionPath };
13433
13433
  }
13434
13434
  } catch {
@@ -13440,11 +13440,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
13440
13440
  * what was previously computed. */
13441
13441
  async loadSessionInfo() {
13442
13442
  try {
13443
- const { readFileSync: readFileSync39, existsSync: existsSync51 } = await import("node:fs");
13443
+ const { readFileSync: readFileSync40, existsSync: existsSync52 } = await import("node:fs");
13444
13444
  const sessionPath = join22(this.cwd, ".oa", "rlm", "session.json");
13445
- if (!existsSync51(sessionPath))
13445
+ if (!existsSync52(sessionPath))
13446
13446
  return null;
13447
- return JSON.parse(readFileSync39(sessionPath, "utf8"));
13447
+ return JSON.parse(readFileSync40(sessionPath, "utf8"));
13448
13448
  } catch {
13449
13449
  return null;
13450
13450
  }
@@ -13621,10 +13621,10 @@ var init_memory_metabolism = __esm({
13621
13621
  const trajDir = join23(this.cwd, ".oa", "rlm-trajectories");
13622
13622
  let lessons = [];
13623
13623
  try {
13624
- const { readdirSync: readdirSync20, readFileSync: readFileSync39 } = await import("node:fs");
13625
- const files = readdirSync20(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
13624
+ const { readdirSync: readdirSync21, readFileSync: readFileSync40 } = await import("node:fs");
13625
+ const files = readdirSync21(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
13626
13626
  for (const file of files) {
13627
- const lines = readFileSync39(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
13627
+ const lines = readFileSync40(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
13628
13628
  for (const line of lines) {
13629
13629
  try {
13630
13630
  const entry = JSON.parse(line);
@@ -14008,14 +14008,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
14008
14008
  * Optionally filter by task type for phase-aware context (FSM paper insight).
14009
14009
  */
14010
14010
  getTopMemoriesSync(k = 5, taskType) {
14011
- const { readFileSync: readFileSync39, existsSync: existsSync51 } = __require("node:fs");
14011
+ const { readFileSync: readFileSync40, existsSync: existsSync52 } = __require("node:fs");
14012
14012
  const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
14013
14013
  const storeFile = join23(metaDir, "store.json");
14014
- if (!existsSync51(storeFile))
14014
+ if (!existsSync52(storeFile))
14015
14015
  return "";
14016
14016
  let store = [];
14017
14017
  try {
14018
- store = JSON.parse(readFileSync39(storeFile, "utf8"));
14018
+ store = JSON.parse(readFileSync40(storeFile, "utf8"));
14019
14019
  } catch {
14020
14020
  return "";
14021
14021
  }
@@ -14037,14 +14037,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
14037
14037
  /** Update memory scores based on task outcome. Called after task completion.
14038
14038
  * Memories used in successful tasks get boosted. Memories present during failures get decayed. */
14039
14039
  updateFromOutcomeSync(surfacedMemoryText, succeeded) {
14040
- const { readFileSync: readFileSync39, writeFileSync: writeFileSync24, existsSync: existsSync51, mkdirSync: mkdirSync25 } = __require("node:fs");
14040
+ const { readFileSync: readFileSync40, writeFileSync: writeFileSync25, existsSync: existsSync52, mkdirSync: mkdirSync26 } = __require("node:fs");
14041
14041
  const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
14042
14042
  const storeFile = join23(metaDir, "store.json");
14043
- if (!existsSync51(storeFile))
14043
+ if (!existsSync52(storeFile))
14044
14044
  return;
14045
14045
  let store = [];
14046
14046
  try {
14047
- store = JSON.parse(readFileSync39(storeFile, "utf8"));
14047
+ store = JSON.parse(readFileSync40(storeFile, "utf8"));
14048
14048
  } catch {
14049
14049
  return;
14050
14050
  }
@@ -14068,8 +14068,8 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
14068
14068
  updated = true;
14069
14069
  }
14070
14070
  if (updated) {
14071
- mkdirSync25(metaDir, { recursive: true });
14072
- writeFileSync24(storeFile, JSON.stringify(store, null, 2));
14071
+ mkdirSync26(metaDir, { recursive: true });
14072
+ writeFileSync25(storeFile, JSON.stringify(store, null, 2));
14073
14073
  }
14074
14074
  }
14075
14075
  // ── Storage ──────────────────────────────────────────────────────────
@@ -14491,13 +14491,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
14491
14491
  // Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
14492
14492
  /** Retrieve top-K strategies for context injection. Returns "" if none. */
14493
14493
  getRelevantStrategiesSync(k = 3, taskType) {
14494
- const { readFileSync: readFileSync39, existsSync: existsSync51 } = __require("node:fs");
14494
+ const { readFileSync: readFileSync40, existsSync: existsSync52 } = __require("node:fs");
14495
14495
  const archiveFile = join25(this.cwd, ".oa", "arche", "variants.json");
14496
- if (!existsSync51(archiveFile))
14496
+ if (!existsSync52(archiveFile))
14497
14497
  return "";
14498
14498
  let variants = [];
14499
14499
  try {
14500
- variants = JSON.parse(readFileSync39(archiveFile, "utf8"));
14500
+ variants = JSON.parse(readFileSync40(archiveFile, "utf8"));
14501
14501
  } catch {
14502
14502
  return "";
14503
14503
  }
@@ -14515,13 +14515,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
14515
14515
  }
14516
14516
  /** Archive a strategy variant synchronously (for task completion path) */
14517
14517
  archiveVariantSync(strategy, outcome, tags = []) {
14518
- const { readFileSync: readFileSync39, writeFileSync: writeFileSync24, existsSync: existsSync51, mkdirSync: mkdirSync25 } = __require("node:fs");
14518
+ const { readFileSync: readFileSync40, writeFileSync: writeFileSync25, existsSync: existsSync52, mkdirSync: mkdirSync26 } = __require("node:fs");
14519
14519
  const dir = join25(this.cwd, ".oa", "arche");
14520
14520
  const archiveFile = join25(dir, "variants.json");
14521
14521
  let variants = [];
14522
14522
  try {
14523
- if (existsSync51(archiveFile))
14524
- variants = JSON.parse(readFileSync39(archiveFile, "utf8"));
14523
+ if (existsSync52(archiveFile))
14524
+ variants = JSON.parse(readFileSync40(archiveFile, "utf8"));
14525
14525
  } catch {
14526
14526
  }
14527
14527
  variants.push({
@@ -14536,8 +14536,8 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
14536
14536
  });
14537
14537
  if (variants.length > 50)
14538
14538
  variants = variants.slice(-50);
14539
- mkdirSync25(dir, { recursive: true });
14540
- writeFileSync24(archiveFile, JSON.stringify(variants, null, 2));
14539
+ mkdirSync26(dir, { recursive: true });
14540
+ writeFileSync25(archiveFile, JSON.stringify(variants, null, 2));
14541
14541
  }
14542
14542
  async saveArchive(variants) {
14543
14543
  const dir = join25(this.cwd, ".oa", "arche");
@@ -21684,7 +21684,7 @@ import { spawn as spawn14 } from "node:child_process";
21684
21684
  async function runShell(options) {
21685
21685
  const { command, args = [], cwd: cwd4, env, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
21686
21686
  const mergedEnv = env ? { ...process.env, ...env } : process.env;
21687
- return new Promise((resolve34) => {
21687
+ return new Promise((resolve35) => {
21688
21688
  const start = Date.now();
21689
21689
  let timedOut = false;
21690
21690
  const child = spawn14(command, args, {
@@ -21708,7 +21708,7 @@ async function runShell(options) {
21708
21708
  clearTimeout(timer);
21709
21709
  const durationMs = Date.now() - start;
21710
21710
  const exitCode = timedOut ? -1 : code ?? -1;
21711
- resolve34({
21711
+ resolve35({
21712
21712
  stdout,
21713
21713
  stderr,
21714
21714
  exitCode,
@@ -21720,7 +21720,7 @@ async function runShell(options) {
21720
21720
  child.on("error", (err) => {
21721
21721
  clearTimeout(timer);
21722
21722
  const durationMs = Date.now() - start;
21723
- resolve34({
21723
+ resolve35({
21724
21724
  stdout,
21725
21725
  stderr: stderr + err.message,
21726
21726
  exitCode: -1,
@@ -21835,7 +21835,7 @@ async function applyUnifiedDiff(patch) {
21835
21835
  }
21836
21836
  function runWithStdin(options) {
21837
21837
  const { command, args, cwd: cwd4, stdin } = options;
21838
- return new Promise((resolve34) => {
21838
+ return new Promise((resolve35) => {
21839
21839
  const child = spawn15(command, args, {
21840
21840
  cwd: cwd4,
21841
21841
  stdio: ["pipe", "pipe", "pipe"]
@@ -21852,10 +21852,10 @@ function runWithStdin(options) {
21852
21852
  child.stdin.end();
21853
21853
  child.on("close", (code) => {
21854
21854
  const exitCode = code ?? -1;
21855
- resolve34({ success: exitCode === 0, exitCode, stdout, stderr });
21855
+ resolve35({ success: exitCode === 0, exitCode, stdout, stderr });
21856
21856
  });
21857
21857
  child.on("error", (err) => {
21858
- resolve34({ success: false, exitCode: -1, stdout, stderr: err.message });
21858
+ resolve35({ success: false, exitCode: -1, stdout, stderr: err.message });
21859
21859
  });
21860
21860
  });
21861
21861
  }
@@ -25597,8 +25597,8 @@ ${this.options.dynamicContext}`,
25597
25597
  async waitIfPaused() {
25598
25598
  if (!this._paused)
25599
25599
  return true;
25600
- await new Promise((resolve34) => {
25601
- this._pauseResolve = resolve34;
25600
+ await new Promise((resolve35) => {
25601
+ this._pauseResolve = resolve35;
25602
25602
  });
25603
25603
  return !this.aborted;
25604
25604
  }
@@ -25688,7 +25688,32 @@ Respond with your assessment, then take action.`;
25688
25688
 
25689
25689
  TASK: ${task}` : task }
25690
25690
  ];
25691
- const toolDefs = this.buildToolDefinitions();
25691
+ let toolDefs = this.buildToolDefinitions();
25692
+ let textToolModeActive = this.options.textToolMode ?? false;
25693
+ if (textToolModeActive) {
25694
+ const toolDescriptions = Array.from(this.tools.values()).map((t) => `- ${t.name}: ${t.description}`).join("\n");
25695
+ messages[0].content += [
25696
+ "\n\n[TEXT TOOL MODE]",
25697
+ "This model uses text-based tool invocation (no native tool API).",
25698
+ "To use a tool, output a JSON block in your response:",
25699
+ "```json",
25700
+ '{"tool": "tool_name", "args": {"param": "value"}}',
25701
+ "```",
25702
+ "\nAvailable tools:",
25703
+ toolDescriptions,
25704
+ "\nRules:",
25705
+ "- Output EXACTLY ONE tool call per response in the JSON format above",
25706
+ "- After seeing the tool result, continue or call another tool",
25707
+ '- When done: {"tool": "task_complete", "args": {"summary": "what you did"}}',
25708
+ "- You CAN also write ```bash ... ``` blocks which will be auto-executed"
25709
+ ].join("\n");
25710
+ toolDefs = [];
25711
+ this.emit({
25712
+ type: "status",
25713
+ content: "Text tool mode active \u2014 tools described in prompt, parsed from JSON/code blocks",
25714
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
25715
+ });
25716
+ }
25692
25717
  let totalTokens = 0;
25693
25718
  let promptTokens = 0;
25694
25719
  let completionTokens = 0;
@@ -26674,14 +26699,14 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
26674
26699
  waitForSudoPassword(timeoutMs = 12e4) {
26675
26700
  if (this._sudoPassword)
26676
26701
  return Promise.resolve(this._sudoPassword);
26677
- return new Promise((resolve34) => {
26702
+ return new Promise((resolve35) => {
26678
26703
  const timer = setTimeout(() => {
26679
26704
  this._sudoResolve = null;
26680
- resolve34(null);
26705
+ resolve35(null);
26681
26706
  }, timeoutMs);
26682
26707
  this._sudoResolve = (pw) => {
26683
26708
  clearTimeout(timer);
26684
- resolve34(pw);
26709
+ resolve35(pw);
26685
26710
  };
26686
26711
  });
26687
26712
  }
@@ -26814,10 +26839,10 @@ ${marker}` : marker);
26814
26839
  if (!this._workingDirectory)
26815
26840
  return;
26816
26841
  try {
26817
- const { mkdirSync: mkdirSync25, writeFileSync: writeFileSync24 } = __require("node:fs");
26818
- const { join: join71 } = __require("node:path");
26819
- const sessionDir = join71(this._workingDirectory, ".oa", "session", this._sessionId);
26820
- mkdirSync25(sessionDir, { recursive: true });
26842
+ const { mkdirSync: mkdirSync26, writeFileSync: writeFileSync25 } = __require("node:fs");
26843
+ const { join: join72 } = __require("node:path");
26844
+ const sessionDir = join72(this._workingDirectory, ".oa", "session", this._sessionId);
26845
+ mkdirSync26(sessionDir, { recursive: true });
26821
26846
  const checkpoint = {
26822
26847
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
26823
26848
  sessionId: this._sessionId,
@@ -26829,7 +26854,7 @@ ${marker}` : marker);
26829
26854
  memexEntryCount: this._memexArchive.size,
26830
26855
  fileRegistrySize: this._fileRegistry.size
26831
26856
  };
26832
- writeFileSync24(join71(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
26857
+ writeFileSync25(join72(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
26833
26858
  } catch {
26834
26859
  }
26835
26860
  }
@@ -28405,12 +28430,12 @@ var init_nexusBackend = __esm({
28405
28430
  const deadline = Date.now() + (request.timeoutMs ?? 12e4);
28406
28431
  try {
28407
28432
  while (!done && Date.now() < deadline) {
28408
- await new Promise((resolve34) => {
28433
+ await new Promise((resolve35) => {
28409
28434
  let resolved = false;
28410
28435
  const finish = () => {
28411
28436
  if (!resolved) {
28412
28437
  resolved = true;
28413
- resolve34();
28438
+ resolve35();
28414
28439
  }
28415
28440
  };
28416
28441
  let watcher = null;
@@ -29492,9 +29517,9 @@ function ensureTranscribeCliBackground() {
29492
29517
  }
29493
29518
  try {
29494
29519
  const { exec: exec4 } = await import("node:child_process");
29495
- return new Promise((resolve34) => {
29520
+ return new Promise((resolve35) => {
29496
29521
  exec4("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
29497
- resolve34(!err);
29522
+ resolve35(!err);
29498
29523
  });
29499
29524
  });
29500
29525
  } catch {
@@ -29553,7 +29578,7 @@ var init_listen = __esm({
29553
29578
  return this._ready;
29554
29579
  }
29555
29580
  async start() {
29556
- return new Promise((resolve34, reject) => {
29581
+ return new Promise((resolve35, reject) => {
29557
29582
  const timeout = setTimeout(() => {
29558
29583
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
29559
29584
  }, 3e5);
@@ -29581,7 +29606,7 @@ var init_listen = __esm({
29581
29606
  this._ready = true;
29582
29607
  clearTimeout(timeout);
29583
29608
  this.emit("ready");
29584
- resolve34();
29609
+ resolve35();
29585
29610
  break;
29586
29611
  case "transcript":
29587
29612
  this.emit("transcript", {
@@ -29719,8 +29744,8 @@ var init_listen = __esm({
29719
29744
  const nvmBase = join48(homedir10(), ".nvm", "versions", "node");
29720
29745
  if (existsSync32(nvmBase)) {
29721
29746
  try {
29722
- const { readdirSync: readdirSync20 } = await import("node:fs");
29723
- for (const ver of readdirSync20(nvmBase)) {
29747
+ const { readdirSync: readdirSync21 } = await import("node:fs");
29748
+ for (const ver of readdirSync21(nvmBase)) {
29724
29749
  const tcPath = join48(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
29725
29750
  if (existsSync32(join48(tcPath, "dist", "index.js"))) {
29726
29751
  const { createRequire: createRequire4 } = await import("node:module");
@@ -29785,11 +29810,11 @@ var init_listen = __esm({
29785
29810
  this.liveTranscriber.on("error", (err) => {
29786
29811
  this.emit("error", err);
29787
29812
  });
29788
- await new Promise((resolve34, reject) => {
29813
+ await new Promise((resolve35, reject) => {
29789
29814
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
29790
29815
  this.liveTranscriber.on("ready", () => {
29791
29816
  clearTimeout(timeout);
29792
- resolve34();
29817
+ resolve35();
29793
29818
  });
29794
29819
  this.liveTranscriber.on("error", (err) => {
29795
29820
  clearTimeout(timeout);
@@ -29951,11 +29976,11 @@ transcribe-cli error: ${transcribeCliError}` : "";
29951
29976
  sampleWidth: 2,
29952
29977
  chunkDuration: 3
29953
29978
  });
29954
- await new Promise((resolve34, reject) => {
29979
+ await new Promise((resolve35, reject) => {
29955
29980
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
29956
29981
  transcriber.on("ready", () => {
29957
29982
  clearTimeout(timeout);
29958
- resolve34();
29983
+ resolve35();
29959
29984
  });
29960
29985
  transcriber.on("error", (err) => {
29961
29986
  clearTimeout(timeout);
@@ -32258,7 +32283,7 @@ var require_websocket = __commonJS({
32258
32283
  var http = __require("http");
32259
32284
  var net = __require("net");
32260
32285
  var tls = __require("tls");
32261
- var { randomBytes: randomBytes15, createHash: createHash6 } = __require("crypto");
32286
+ var { randomBytes: randomBytes16, createHash: createHash6 } = __require("crypto");
32262
32287
  var { Duplex, Readable } = __require("stream");
32263
32288
  var { URL: URL3 } = __require("url");
32264
32289
  var PerMessageDeflate = require_permessage_deflate();
@@ -32788,7 +32813,7 @@ var require_websocket = __commonJS({
32788
32813
  }
32789
32814
  }
32790
32815
  const defaultPort = isSecure ? 443 : 80;
32791
- const key = randomBytes15(16).toString("base64");
32816
+ const key = randomBytes16(16).toString("base64");
32792
32817
  const request = isSecure ? https.request : http.request;
32793
32818
  const protocolSet = /* @__PURE__ */ new Set();
32794
32819
  let perMessageDeflate;
@@ -34928,8 +34953,8 @@ var init_voice_session = __esm({
34928
34953
  this.server.keepAliveTimeout = 0;
34929
34954
  this.wss = new import_websocket_server.default({ server: this.server, path: "/ws" });
34930
34955
  this.wss.on("connection", (ws, req) => this.handleWSConnection(ws, req));
34931
- await new Promise((resolve34, reject) => {
34932
- this.server.listen(port, "127.0.0.1", () => resolve34());
34956
+ await new Promise((resolve35, reject) => {
34957
+ this.server.listen(port, "127.0.0.1", () => resolve35());
34933
34958
  this.server.on("error", reject);
34934
34959
  });
34935
34960
  try {
@@ -35147,7 +35172,7 @@ var init_voice_session = __esm({
35147
35172
  }
35148
35173
  // ── Cloudflared tunnel ────────────────────────────────────────────────
35149
35174
  startCloudflared(port) {
35150
- return new Promise((resolve34, reject) => {
35175
+ return new Promise((resolve35, reject) => {
35151
35176
  const timeout = setTimeout(() => {
35152
35177
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
35153
35178
  }, 3e4);
@@ -35165,7 +35190,7 @@ var init_voice_session = __esm({
35165
35190
  if (urlMatch && !urlFound) {
35166
35191
  urlFound = true;
35167
35192
  clearTimeout(timeout);
35168
- resolve34(urlMatch[0]);
35193
+ resolve35(urlMatch[0]);
35169
35194
  }
35170
35195
  };
35171
35196
  this.cloudflaredProcess.stdout?.on("data", handleOutput);
@@ -35205,13 +35230,13 @@ var init_voice_session = __esm({
35205
35230
  }
35206
35231
  // ── Helpers ───────────────────────────────────────────────────────────
35207
35232
  findFreePort() {
35208
- return new Promise((resolve34, reject) => {
35233
+ return new Promise((resolve35, reject) => {
35209
35234
  const srv = createServer2();
35210
35235
  srv.listen(0, "127.0.0.1", () => {
35211
35236
  const addr = srv.address();
35212
35237
  if (addr && typeof addr === "object") {
35213
35238
  const port = addr.port;
35214
- srv.close(() => resolve34(port));
35239
+ srv.close(() => resolve35(port));
35215
35240
  } else {
35216
35241
  srv.close(() => reject(new Error("Could not find free port")));
35217
35242
  }
@@ -35334,8 +35359,8 @@ async function collectSystemMetricsAsync() {
35334
35359
  vramUtilization: 0
35335
35360
  };
35336
35361
  try {
35337
- const smi = await new Promise((resolve34, reject) => {
35338
- exec("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve34(stdout));
35362
+ const smi = await new Promise((resolve35, reject) => {
35363
+ exec("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve35(stdout));
35339
35364
  });
35340
35365
  const line = smi.trim().split("\n")[0];
35341
35366
  if (line) {
@@ -35483,8 +35508,8 @@ var init_expose = __esm({
35483
35508
  throw new Error("Gateway already running");
35484
35509
  const port = await this.findFreePort();
35485
35510
  this.server = this.createProxyServer(port);
35486
- await new Promise((resolve34, reject) => {
35487
- this.server.listen(port, "127.0.0.1", () => resolve34());
35511
+ await new Promise((resolve35, reject) => {
35512
+ this.server.listen(port, "127.0.0.1", () => resolve35());
35488
35513
  this.server.on("error", reject);
35489
35514
  });
35490
35515
  let lastStartErr;
@@ -35546,8 +35571,8 @@ var init_expose = __esm({
35546
35571
  this._cloudflaredPid = state.pid;
35547
35572
  this._proxyPort = state.proxyPort;
35548
35573
  this.server = this.createProxyServer(state.proxyPort);
35549
- await new Promise((resolve34, reject) => {
35550
- this.server.listen(state.proxyPort, "127.0.0.1", () => resolve34());
35574
+ await new Promise((resolve35, reject) => {
35575
+ this.server.listen(state.proxyPort, "127.0.0.1", () => resolve35());
35551
35576
  this.server.on("error", reject);
35552
35577
  });
35553
35578
  this._stats.status = "active";
@@ -35572,8 +35597,8 @@ var init_expose = __esm({
35572
35597
  }
35573
35598
  this._cloudflaredPid = null;
35574
35599
  if (this.server) {
35575
- await new Promise((resolve34) => {
35576
- this.server.close(() => resolve34());
35600
+ await new Promise((resolve35) => {
35601
+ this.server.close(() => resolve35());
35577
35602
  });
35578
35603
  this.server = null;
35579
35604
  }
@@ -35905,7 +35930,7 @@ var init_expose = __esm({
35905
35930
  _proxyPort = 0;
35906
35931
  startCloudflared(port) {
35907
35932
  this._proxyPort = port;
35908
- return new Promise((resolve34, reject) => {
35933
+ return new Promise((resolve35, reject) => {
35909
35934
  const timeout = setTimeout(() => {
35910
35935
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
35911
35936
  }, 3e4);
@@ -35934,7 +35959,7 @@ var init_expose = __esm({
35934
35959
  this.cloudflaredProcess?.unref();
35935
35960
  this.cloudflaredProcess?.stdout?.destroy();
35936
35961
  this.cloudflaredProcess?.stderr?.destroy();
35937
- resolve34(urlMatch[0]);
35962
+ resolve35(urlMatch[0]);
35938
35963
  }
35939
35964
  };
35940
35965
  this.cloudflaredProcess.stdout?.on("data", handleOutput);
@@ -36023,13 +36048,13 @@ ${this.formatConnectionInfo()}`);
36023
36048
  }
36024
36049
  // ── Helpers ─────────────────────────────────────────────────────────────
36025
36050
  findFreePort() {
36026
- return new Promise((resolve34, reject) => {
36051
+ return new Promise((resolve35, reject) => {
36027
36052
  const srv = createServer3();
36028
36053
  srv.listen(0, "127.0.0.1", () => {
36029
36054
  const addr = srv.address();
36030
36055
  if (addr && typeof addr === "object") {
36031
36056
  const port = addr.port;
36032
- srv.close(() => resolve34(port));
36057
+ srv.close(() => resolve35(port));
36033
36058
  } else {
36034
36059
  srv.close(() => reject(new Error("Could not find free port")));
36035
36060
  }
@@ -36976,8 +37001,8 @@ var init_peer_mesh = __esm({
36976
37001
  this.wss.on("connection", (ws, req) => {
36977
37002
  this.handleInboundConnection(ws, req.url ?? "");
36978
37003
  });
36979
- await new Promise((resolve34, reject) => {
36980
- this.server.listen(port, "127.0.0.1", () => resolve34());
37004
+ await new Promise((resolve35, reject) => {
37005
+ this.server.listen(port, "127.0.0.1", () => resolve35());
36981
37006
  this.server.on("error", reject);
36982
37007
  });
36983
37008
  this.pingTimer = setInterval(() => this.pingAll(), PING_INTERVAL_MS);
@@ -37016,7 +37041,7 @@ var init_peer_mesh = __esm({
37016
37041
  this.wss = null;
37017
37042
  }
37018
37043
  if (this.server) {
37019
- await new Promise((resolve34) => this.server.close(() => resolve34()));
37044
+ await new Promise((resolve35) => this.server.close(() => resolve35()));
37020
37045
  this.server = null;
37021
37046
  }
37022
37047
  this.emit("stopped");
@@ -37034,7 +37059,7 @@ var init_peer_mesh = __esm({
37034
37059
  if (!wsUrl.includes("/p2p"))
37035
37060
  wsUrl += "/p2p";
37036
37061
  wsUrl += `?key=${encodeURIComponent(this._authKey)}`;
37037
- return new Promise((resolve34, reject) => {
37062
+ return new Promise((resolve35, reject) => {
37038
37063
  const ws = new import_websocket.default(wsUrl, { handshakeTimeout: 1e4 });
37039
37064
  let resolved = false;
37040
37065
  const timeout = setTimeout(() => {
@@ -37074,7 +37099,7 @@ var init_peer_mesh = __esm({
37074
37099
  this.connections.set(peer.peerId, ws);
37075
37100
  this.setupPeerHandlers(ws, peer.peerId);
37076
37101
  this.emit("peer_connected", peer);
37077
- resolve34(peer);
37102
+ resolve35(peer);
37078
37103
  } else {
37079
37104
  this.handleMessage(msg, ws);
37080
37105
  }
@@ -37129,12 +37154,12 @@ var init_peer_mesh = __esm({
37129
37154
  throw new Error(`Peer ${peerId} not connected`);
37130
37155
  }
37131
37156
  const msgId = randomBytes14(8).toString("hex");
37132
- return new Promise((resolve34, reject) => {
37157
+ return new Promise((resolve35, reject) => {
37133
37158
  const timeout = setTimeout(() => {
37134
37159
  this.pendingRequests.delete(msgId);
37135
37160
  reject(new Error(`Inference timeout (${timeoutMs}ms)`));
37136
37161
  }, timeoutMs);
37137
- this.pendingRequests.set(msgId, { resolve: resolve34, reject, timeout, chunks: [] });
37162
+ this.pendingRequests.set(msgId, { resolve: resolve35, reject, timeout, chunks: [] });
37138
37163
  this.sendMsg(ws, "infer_request", request, msgId);
37139
37164
  });
37140
37165
  }
@@ -37356,13 +37381,13 @@ var init_peer_mesh = __esm({
37356
37381
  ws.send(JSON.stringify(msg));
37357
37382
  }
37358
37383
  findFreePort() {
37359
- return new Promise((resolve34, reject) => {
37384
+ return new Promise((resolve35, reject) => {
37360
37385
  const srv = createServer4();
37361
37386
  srv.listen(0, "127.0.0.1", () => {
37362
37387
  const addr = srv.address();
37363
37388
  if (addr && typeof addr === "object") {
37364
37389
  const port = addr.port;
37365
- srv.close(() => resolve34(port));
37390
+ srv.close(() => resolve35(port));
37366
37391
  } else {
37367
37392
  srv.close(() => reject(new Error("Could not find free port")));
37368
37393
  }
@@ -37992,26 +38017,26 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
37992
38017
  async function fetchPeerModels(peerId, authKey) {
37993
38018
  try {
37994
38019
  const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
37995
- const { existsSync: existsSync51, readFileSync: readFileSync39 } = await import("node:fs");
37996
- const { join: join71 } = await import("node:path");
38020
+ const { existsSync: existsSync52, readFileSync: readFileSync40 } = await import("node:fs");
38021
+ const { join: join72 } = await import("node:path");
37997
38022
  const cwd4 = process.cwd();
37998
38023
  const nexusTool = new NexusTool2(cwd4);
37999
38024
  const nexusDir = nexusTool.getNexusDir();
38000
38025
  let isLocalPeer = false;
38001
38026
  try {
38002
- const statusPath = join71(nexusDir, "status.json");
38003
- if (existsSync51(statusPath)) {
38004
- const status = JSON.parse(readFileSync39(statusPath, "utf8"));
38027
+ const statusPath = join72(nexusDir, "status.json");
38028
+ if (existsSync52(statusPath)) {
38029
+ const status = JSON.parse(readFileSync40(statusPath, "utf8"));
38005
38030
  if (status.peerId === peerId)
38006
38031
  isLocalPeer = true;
38007
38032
  }
38008
38033
  } catch {
38009
38034
  }
38010
38035
  if (isLocalPeer) {
38011
- const pricingPath = join71(nexusDir, "pricing.json");
38012
- if (existsSync51(pricingPath)) {
38036
+ const pricingPath = join72(nexusDir, "pricing.json");
38037
+ if (existsSync52(pricingPath)) {
38013
38038
  try {
38014
- const pricing = JSON.parse(readFileSync39(pricingPath, "utf8"));
38039
+ const pricing = JSON.parse(readFileSync40(pricingPath, "utf8"));
38015
38040
  const localModels = (pricing.models || []).map((m) => ({
38016
38041
  name: m.model || "unknown",
38017
38042
  size: m.parameterSize || "",
@@ -38025,10 +38050,10 @@ async function fetchPeerModels(peerId, authKey) {
38025
38050
  }
38026
38051
  }
38027
38052
  }
38028
- const cachePath = join71(nexusDir, "peer-models-cache.json");
38029
- if (existsSync51(cachePath)) {
38053
+ const cachePath = join72(nexusDir, "peer-models-cache.json");
38054
+ if (existsSync52(cachePath)) {
38030
38055
  try {
38031
- const cache4 = JSON.parse(readFileSync39(cachePath, "utf8"));
38056
+ const cache4 = JSON.parse(readFileSync40(cachePath, "utf8"));
38032
38057
  if (cache4.peerId === peerId && cache4.models?.length > 0) {
38033
38058
  const age = Date.now() - new Date(cache4.cachedAt).getTime();
38034
38059
  if (age < 5 * 60 * 1e3) {
@@ -38143,10 +38168,10 @@ async function fetchPeerModels(peerId, authKey) {
38143
38168
  } catch {
38144
38169
  }
38145
38170
  if (isLocalPeer) {
38146
- const pricingPath = join71(nexusDir, "pricing.json");
38147
- if (existsSync51(pricingPath)) {
38171
+ const pricingPath = join72(nexusDir, "pricing.json");
38172
+ if (existsSync52(pricingPath)) {
38148
38173
  try {
38149
- const pricing = JSON.parse(readFileSync39(pricingPath, "utf8"));
38174
+ const pricing = JSON.parse(readFileSync40(pricingPath, "utf8"));
38150
38175
  return (pricing.models || []).map((m) => ({
38151
38176
  name: m.model || "unknown",
38152
38177
  size: m.parameterSize || "",
@@ -39132,6 +39157,34 @@ import { promisify as promisify6 } from "node:util";
39132
39157
  import { existsSync as existsSync37, writeFileSync as writeFileSync16, readFileSync as readFileSync28, appendFileSync as appendFileSync2, mkdirSync as mkdirSync15 } from "node:fs";
39133
39158
  import { join as join54 } from "node:path";
39134
39159
  import { homedir as homedir12, platform as platform2 } from "node:os";
39160
+ async function checkToolSupport(modelName, backendUrl = "http://localhost:11434") {
39161
+ if (_toolSupportCache.has(modelName))
39162
+ return _toolSupportCache.get(modelName);
39163
+ try {
39164
+ const resp = await fetch(`${backendUrl.replace(/\/+$/, "")}/api/show`, {
39165
+ method: "POST",
39166
+ headers: { "Content-Type": "application/json" },
39167
+ body: JSON.stringify({ name: modelName }),
39168
+ signal: AbortSignal.timeout(5e3)
39169
+ });
39170
+ if (!resp.ok) {
39171
+ _toolSupportCache.set(modelName, false);
39172
+ return false;
39173
+ }
39174
+ const data = await resp.json();
39175
+ const template = data.template ?? "";
39176
+ const hasTools = template.includes("{{.Tools}}") || template.includes("{{ .Tools }}");
39177
+ _toolSupportCache.set(modelName, hasTools);
39178
+ return hasTools;
39179
+ } catch {
39180
+ _toolSupportCache.set(modelName, false);
39181
+ return false;
39182
+ }
39183
+ }
39184
+ async function needsTextToolMode(modelName, backendUrl) {
39185
+ const hasTools = await checkToolSupport(modelName, backendUrl);
39186
+ return !hasTools;
39187
+ }
39135
39188
  function detectSystemSpecs() {
39136
39189
  let totalRamGB = 0;
39137
39190
  let availableRamGB = 0;
@@ -39259,21 +39312,13 @@ function calculateContextWindow(specs, modelSizeGB2, kvBytesPerToken, archMax) {
39259
39312
  const label = numCtx >= 1024 ? `${Math.floor(numCtx / 1024)}K` : String(numCtx);
39260
39313
  return { numCtx, label };
39261
39314
  }
39262
- function modelSupportsToolCalling(modelName) {
39263
- const lower = modelName.toLowerCase();
39264
- for (const known of TOOL_CALLING_MODELS) {
39265
- if (lower.startsWith(known) || lower.includes(known))
39266
- return true;
39267
- }
39268
- return false;
39269
- }
39270
39315
  function ask(rl, question) {
39271
- return new Promise((resolve34) => {
39272
- rl.question(question, (answer) => resolve34(answer.trim()));
39316
+ return new Promise((resolve35) => {
39317
+ rl.question(question, (answer) => resolve35(answer.trim()));
39273
39318
  });
39274
39319
  }
39275
39320
  function askSecret(rl, question) {
39276
- return new Promise((resolve34) => {
39321
+ return new Promise((resolve35) => {
39277
39322
  process.stdout.write(question);
39278
39323
  let secret = "";
39279
39324
  const stdin = process.stdin;
@@ -39291,7 +39336,7 @@ function askSecret(rl, question) {
39291
39336
  stdin.setRawMode(hadRawMode ?? false);
39292
39337
  }
39293
39338
  process.stdout.write("\n");
39294
- resolve34(secret.trim());
39339
+ resolve35(secret.trim());
39295
39340
  return;
39296
39341
  } else if (c3 === "") {
39297
39342
  stdin.removeListener("data", onData);
@@ -39299,7 +39344,7 @@ function askSecret(rl, question) {
39299
39344
  stdin.setRawMode(hadRawMode ?? false);
39300
39345
  }
39301
39346
  process.stdout.write("\n");
39302
- resolve34("");
39347
+ resolve35("");
39303
39348
  return;
39304
39349
  } else if (c3 === "\x7F" || c3 === "\b") {
39305
39350
  if (secret.length > 0) {
@@ -39534,7 +39579,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
39534
39579
  return false;
39535
39580
  }
39536
39581
  for (let i = 0; i < 5; i++) {
39537
- await new Promise((resolve34) => setTimeout(resolve34, 2e3));
39582
+ await new Promise((resolve35) => setTimeout(resolve35, 2e3));
39538
39583
  try {
39539
39584
  const resp = await fetch(`${backendUrl}/api/tags`, {
39540
39585
  signal: AbortSignal.timeout(3e3)
@@ -39995,7 +40040,7 @@ async function doSetup(config, rl) {
39995
40040
  try {
39996
40041
  const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
39997
40042
  child.unref();
39998
- await new Promise((resolve34) => setTimeout(resolve34, 3e3));
40043
+ await new Promise((resolve35) => setTimeout(resolve35, 3e3));
39999
40044
  try {
40000
40045
  models = await fetchOllamaModels(config.backendUrl);
40001
40046
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -40023,7 +40068,7 @@ async function doSetup(config, rl) {
40023
40068
  try {
40024
40069
  const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
40025
40070
  child.unref();
40026
- await new Promise((resolve34) => setTimeout(resolve34, 3e3));
40071
+ await new Promise((resolve35) => setTimeout(resolve35, 3e3));
40027
40072
  try {
40028
40073
  models = await fetchOllamaModels(config.backendUrl);
40029
40074
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -40065,33 +40110,42 @@ async function doSetup(config, rl) {
40065
40110
  process.stdout.write(` ${c2.yellow("\u26A0")} Default model ${c2.bold(config.model)} is not available.
40066
40111
 
40067
40112
  `);
40068
- const toolCallingModels = models.filter((m) => modelSupportsToolCalling(m.name));
40069
- if (toolCallingModels.length > 0) {
40070
- process.stdout.write(` ${c2.cyan("\u25CF")} Found ${toolCallingModels.length} model(s) with tool-calling support:
40113
+ if (models.length > 0) {
40114
+ const backendUrl = config.backendUrl || "http://localhost:11434";
40115
+ const modelChecks = await Promise.all(models.slice(0, 15).map(async (m) => ({
40116
+ ...m,
40117
+ hasTools: await checkToolSupport(m.name, backendUrl)
40118
+ })));
40119
+ process.stdout.write(` ${c2.cyan("\u25CF")} Available models:
40071
40120
 
40072
40121
  `);
40073
- for (let i = 0; i < Math.min(toolCallingModels.length, 10); i++) {
40074
- const m = toolCallingModels[i];
40075
- process.stdout.write(` ${c2.bold(String(i + 1))}. ${m.name} ${c2.dim(`(${m.size})`)}
40122
+ for (let i = 0; i < modelChecks.length; i++) {
40123
+ const m = modelChecks[i];
40124
+ const toolTag = m.hasTools ? c2.green("tools \u2713") : c2.yellow("text mode");
40125
+ process.stdout.write(` ${c2.bold(String(i + 1))}. ${m.name} ${c2.dim(`(${m.size})`)} ${toolTag}
40076
40126
  `);
40077
40127
  }
40078
40128
  process.stdout.write(`
40079
40129
  ${c2.dim("0")}. Pull a new qwen3.5 model instead
40130
+ `);
40131
+ process.stdout.write(`
40132
+ ${c2.dim("Models marked 'text mode' work via instruct-and-parse (no native tool API needed)")}
40080
40133
  `);
40081
40134
  process.stdout.write("\n");
40082
- const choice = await ask(rl, ` ${c2.bold("Select a model")} (1-${Math.min(toolCallingModels.length, 10)}, or 0 to pull new): `);
40135
+ const choice = await ask(rl, ` ${c2.bold("Select a model")} (1-${modelChecks.length}, or 0 to pull new): `);
40083
40136
  const idx = parseInt(choice, 10);
40084
- if (idx > 0 && idx <= toolCallingModels.length) {
40085
- const selected = toolCallingModels[idx - 1];
40137
+ if (idx > 0 && idx <= modelChecks.length) {
40138
+ const selected = modelChecks[idx - 1];
40086
40139
  setConfigValue("model", selected.name);
40140
+ const mode = selected.hasTools ? "native tool calling" : "text mode (instruct-and-parse)";
40087
40141
  process.stdout.write(`
40088
- ${c2.green("\u2714")} Selected ${c2.bold(selected.name)}. Saved to config.
40142
+ ${c2.green("\u2714")} Selected ${c2.bold(selected.name)} \u2014 ${mode}. Saved to config.
40089
40143
 
40090
40144
  `);
40091
40145
  return selected.name;
40092
40146
  }
40093
40147
  } else {
40094
- process.stdout.write(` ${c2.yellow("\u26A0")} No tool-calling capable models found on this system.
40148
+ process.stdout.write(` ${c2.yellow("\u26A0")} No models found on this system.
40095
40149
 
40096
40150
  `);
40097
40151
  }
@@ -40809,7 +40863,7 @@ export PATH="${binDir}:$PATH" # Added by open-agents for nvim
40809
40863
  } catch {
40810
40864
  }
40811
40865
  }
40812
- var execAsync, QWEN_VARIANTS, TOOL_CALLING_MODELS, _cloudflaredInstallPromise;
40866
+ var execAsync, QWEN_VARIANTS, _toolSupportCache, _cloudflaredInstallPromise;
40813
40867
  var init_setup = __esm({
40814
40868
  "packages/cli/dist/tui/setup.js"() {
40815
40869
  "use strict";
@@ -40829,19 +40883,7 @@ var init_setup = __esm({
40829
40883
  { tag: "qwen3.5:cloud", sizeGB: 0, label: "Cloud (Ollama Cloud)", cloud: true },
40830
40884
  { tag: "qwen3.5:397b-cloud", sizeGB: 0, label: "397B Cloud (Ollama Cloud)", cloud: true }
40831
40885
  ];
40832
- TOOL_CALLING_MODELS = /* @__PURE__ */ new Set([
40833
- "qwen3.5",
40834
- "qwen3",
40835
- "qwen2.5",
40836
- "llama3.3",
40837
- "llama3.1",
40838
- "mistral",
40839
- "mixtral",
40840
- "command-r",
40841
- "gemma3",
40842
- "devstral",
40843
- "deepseek"
40844
- ]);
40886
+ _toolSupportCache = /* @__PURE__ */ new Map();
40845
40887
  _cloudflaredInstallPromise = null;
40846
40888
  }
40847
40889
  });
@@ -41015,7 +41057,7 @@ function tuiSelect(opts) {
41015
41057
  const maxVisible = opts.maxVisible ?? Math.max(3, contentArea - selectChrome);
41016
41058
  let scrollOffset = 0;
41017
41059
  let lastRenderedLines = 0;
41018
- return new Promise((resolve34) => {
41060
+ return new Promise((resolve35) => {
41019
41061
  const stdin = process.stdin;
41020
41062
  const hadRawMode = stdin.isRaw;
41021
41063
  const savedRlListeners = [];
@@ -41190,7 +41232,7 @@ function tuiSelect(opts) {
41190
41232
  if (!isSkippable(itemIdx) && matchSet.has(itemIdx)) {
41191
41233
  cursor = itemIdx;
41192
41234
  cleanup();
41193
- resolve34({ confirmed: true, key: items[cursor].key, index: cursor });
41235
+ resolve35({ confirmed: true, key: items[cursor].key, index: cursor });
41194
41236
  return;
41195
41237
  } else if (!isSkippable(itemIdx)) {
41196
41238
  cursor = itemIdx;
@@ -41266,7 +41308,7 @@ function tuiSelect(opts) {
41266
41308
  items.splice(deletedIdx, 1);
41267
41309
  if (items.length === 0) {
41268
41310
  cleanup();
41269
- resolve34({ confirmed: false, key: null, index: -1 });
41311
+ resolve35({ confirmed: false, key: null, index: -1 });
41270
41312
  return;
41271
41313
  }
41272
41314
  updateFilter();
@@ -41355,7 +41397,7 @@ function tuiSelect(opts) {
41355
41397
  } else if (seq === "\r" || seq === "\n") {
41356
41398
  if (!isSkippable(cursor) && matchSet.has(cursor)) {
41357
41399
  cleanup();
41358
- resolve34({ confirmed: true, key: items[cursor].key, index: cursor });
41400
+ resolve35({ confirmed: true, key: items[cursor].key, index: cursor });
41359
41401
  }
41360
41402
  } else if (seq === "\x1B" || seq === "\x1B\x1B") {
41361
41403
  if (filter) {
@@ -41368,14 +41410,14 @@ function tuiSelect(opts) {
41368
41410
  render();
41369
41411
  } else if (hasBreadcrumbs) {
41370
41412
  cleanup();
41371
- resolve34({ confirmed: false, key: "__back__", index: cursor });
41413
+ resolve35({ confirmed: false, key: "__back__", index: cursor });
41372
41414
  } else {
41373
41415
  cleanup();
41374
- resolve34({ confirmed: false, key: null, index: cursor });
41416
+ resolve35({ confirmed: false, key: null, index: cursor });
41375
41417
  }
41376
41418
  } else if (seq === "") {
41377
41419
  cleanup();
41378
- resolve34({ confirmed: false, key: null, index: cursor });
41420
+ resolve35({ confirmed: false, key: null, index: cursor });
41379
41421
  } else if (seq === "\x7F" || seq === "\b") {
41380
41422
  if (filter.length > 0) {
41381
41423
  filter = filter.slice(0, -1);
@@ -41389,7 +41431,7 @@ function tuiSelect(opts) {
41389
41431
  render();
41390
41432
  } else if (hasBreadcrumbs) {
41391
41433
  cleanup();
41392
- resolve34({ confirmed: false, key: "__back__", index: cursor });
41434
+ resolve35({ confirmed: false, key: "__back__", index: cursor });
41393
41435
  }
41394
41436
  } else if (seq.length === 1 && seq.charCodeAt(0) >= 32 && seq.charCodeAt(0) < 127) {
41395
41437
  if (opts.onCustomKey && !isSkippable(cursor) && matchSet.has(cursor)) {
@@ -41397,7 +41439,7 @@ function tuiSelect(opts) {
41397
41439
  done: () => render(),
41398
41440
  resolve: (result) => {
41399
41441
  cleanup();
41400
- resolve34(result);
41442
+ resolve35(result);
41401
41443
  },
41402
41444
  getInput: (prompt, prefill) => getInputFromUser(prompt, prefill),
41403
41445
  render: () => render(),
@@ -41939,12 +41981,12 @@ function stopNeovimMode() {
41939
41981
  } catch {
41940
41982
  }
41941
41983
  const s = _state;
41942
- return new Promise((resolve34) => {
41984
+ return new Promise((resolve35) => {
41943
41985
  setTimeout(() => {
41944
41986
  if (s && !s.cleanedUp) {
41945
41987
  doCleanup(s);
41946
41988
  }
41947
- resolve34();
41989
+ resolve35();
41948
41990
  }, 300);
41949
41991
  });
41950
41992
  }
@@ -43615,7 +43657,7 @@ var init_voice = __esm({
43615
43657
  this.speaking = false;
43616
43658
  }
43617
43659
  sleep(ms) {
43618
- return new Promise((resolve34) => setTimeout(resolve34, ms));
43660
+ return new Promise((resolve35) => setTimeout(resolve35, ms));
43619
43661
  }
43620
43662
  // -------------------------------------------------------------------------
43621
43663
  // Synthesis pipeline
@@ -43881,7 +43923,7 @@ var init_voice = __esm({
43881
43923
  const cmd = this.getPlayCommand(path);
43882
43924
  if (!cmd)
43883
43925
  return;
43884
- return new Promise((resolve34) => {
43926
+ return new Promise((resolve35) => {
43885
43927
  const child = nodeSpawn(cmd[0], cmd.slice(1), {
43886
43928
  stdio: "ignore",
43887
43929
  detached: false
@@ -43890,12 +43932,12 @@ var init_voice = __esm({
43890
43932
  child.on("close", () => {
43891
43933
  if (this.currentPlayback === child)
43892
43934
  this.currentPlayback = null;
43893
- resolve34();
43935
+ resolve35();
43894
43936
  });
43895
43937
  child.on("error", () => {
43896
43938
  if (this.currentPlayback === child)
43897
43939
  this.currentPlayback = null;
43898
- resolve34();
43940
+ resolve35();
43899
43941
  });
43900
43942
  setTimeout(() => {
43901
43943
  if (this.currentPlayback === child) {
@@ -43905,7 +43947,7 @@ var init_voice = __esm({
43905
43947
  }
43906
43948
  this.currentPlayback = null;
43907
43949
  }
43908
- resolve34();
43950
+ resolve35();
43909
43951
  }, 15e3);
43910
43952
  });
43911
43953
  }
@@ -43980,7 +44022,7 @@ var init_voice = __esm({
43980
44022
  /** Non-blocking shell execution — async alternative to execSync.
43981
44023
  * Returns stdout string on exit 0, rejects otherwise. */
43982
44024
  asyncShell(command, timeoutMs = 3e4) {
43983
- return new Promise((resolve34, reject) => {
44025
+ return new Promise((resolve35, reject) => {
43984
44026
  const proc = nodeSpawn("sh", ["-c", command], {
43985
44027
  stdio: ["ignore", "pipe", "pipe"],
43986
44028
  cwd: tmpdir9()
@@ -44001,7 +44043,7 @@ var init_voice = __esm({
44001
44043
  proc.on("close", (code) => {
44002
44044
  clearTimeout(timer);
44003
44045
  if (code === 0)
44004
- resolve34(stdout.trim());
44046
+ resolve35(stdout.trim());
44005
44047
  else
44006
44048
  reject(new Error(stderr.slice(0, 300) || `Exit code ${code}`));
44007
44049
  });
@@ -44493,7 +44535,7 @@ if __name__ == '__main__':
44493
44535
  const venvPy = luxttsVenvPy();
44494
44536
  if (!existsSync40(venvPy))
44495
44537
  return false;
44496
- return new Promise((resolve34) => {
44538
+ return new Promise((resolve35) => {
44497
44539
  const env = { ...process.env, LUXTTS_REPO_PATH: luxttsRepoDir() };
44498
44540
  const daemon = nodeSpawn(venvPy, [luxttsInferScript()], {
44499
44541
  stdio: ["pipe", "pipe", "pipe"],
@@ -44512,7 +44554,7 @@ if __name__ == '__main__':
44512
44554
  try {
44513
44555
  const msg = JSON.parse(line);
44514
44556
  if (msg.type === "ready") {
44515
- resolve34(true);
44557
+ resolve35(true);
44516
44558
  } else if (msg.type === "result" || msg.type === "error") {
44517
44559
  const pending = this._luxttsPending.get(msg.id);
44518
44560
  if (pending) {
@@ -44536,25 +44578,25 @@ if __name__ == '__main__':
44536
44578
  });
44537
44579
  daemon.on("error", () => {
44538
44580
  this._luxttsDaemon = null;
44539
- resolve34(false);
44581
+ resolve35(false);
44540
44582
  });
44541
44583
  setTimeout(() => {
44542
44584
  if (this._luxttsDaemon === daemon && !this._luxttsPending.has("__ready__")) {
44543
- resolve34(false);
44585
+ resolve35(false);
44544
44586
  }
44545
44587
  }, 6e4);
44546
44588
  });
44547
44589
  }
44548
44590
  /** Send a request to the LuxTTS daemon and await the response */
44549
44591
  luxttsRequest(req) {
44550
- return new Promise((resolve34, reject) => {
44592
+ return new Promise((resolve35, reject) => {
44551
44593
  if (!this._luxttsDaemon || this._luxttsDaemon.killed) {
44552
44594
  reject(new Error("LuxTTS daemon not running"));
44553
44595
  return;
44554
44596
  }
44555
44597
  const id = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
44556
44598
  req.id = id;
44557
- this._luxttsPending.set(id, { resolve: resolve34, reject });
44599
+ this._luxttsPending.set(id, { resolve: resolve35, reject });
44558
44600
  this._luxttsDaemon.stdin.write(JSON.stringify(req) + "\n");
44559
44601
  setTimeout(() => {
44560
44602
  if (this._luxttsPending.has(id)) {
@@ -45937,8 +45979,8 @@ async function handleSlashCommand(input, ctx) {
45937
45979
  writeFileSync18(jwtFile, JSON.stringify(jwtPayload, null, 2));
45938
45980
  renderInfo(`Launching fortemi-react from ${fDir}...`);
45939
45981
  try {
45940
- const { spawn: spawn21 } = __require("node:child_process");
45941
- const child = spawn21("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
45982
+ const { spawn: spawn22 } = __require("node:child_process");
45983
+ const child = spawn22("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
45942
45984
  cwd: join57(fDir, "apps", "standalone"),
45943
45985
  stdio: "ignore",
45944
45986
  detached: true,
@@ -47695,12 +47737,12 @@ async function handleVoiceMenu(ctx, save, hasLocal) {
47695
47737
  continue;
47696
47738
  }
47697
47739
  const { basename: basename18, join: pathJoin } = await import("node:path");
47698
- const { copyFileSync: copyFileSync2, mkdirSync: mkdirSync25, existsSync: exists } = await import("node:fs");
47740
+ const { copyFileSync: copyFileSync2, mkdirSync: mkdirSync26, existsSync: exists } = await import("node:fs");
47699
47741
  const { homedir: homedir18 } = await import("node:os");
47700
47742
  const modelName = basename18(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
47701
47743
  const destDir = pathJoin(homedir18(), ".open-agents", "voice", "models", modelName);
47702
47744
  if (!exists(destDir))
47703
- mkdirSync25(destDir, { recursive: true });
47745
+ mkdirSync26(destDir, { recursive: true });
47704
47746
  copyFileSync2(onnxDrop.path, pathJoin(destDir, "model.onnx"));
47705
47747
  copyFileSync2(jsonDrop.path, pathJoin(destDir, "config.json"));
47706
47748
  const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
@@ -48192,11 +48234,11 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
48192
48234
  const models = await fetchModels(peerUrl, authKey);
48193
48235
  if (models.length > 0) {
48194
48236
  try {
48195
- const { writeFileSync: writeFileSync24, mkdirSync: mkdirSync25 } = await import("node:fs");
48196
- const { join: join71, dirname: dirname22 } = await import("node:path");
48197
- const cachePath = join71(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
48198
- mkdirSync25(dirname22(cachePath), { recursive: true });
48199
- writeFileSync24(cachePath, JSON.stringify({
48237
+ const { writeFileSync: writeFileSync25, mkdirSync: mkdirSync26 } = await import("node:fs");
48238
+ const { join: join72, dirname: dirname22 } = await import("node:path");
48239
+ const cachePath = join72(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
48240
+ mkdirSync26(dirname22(cachePath), { recursive: true });
48241
+ writeFileSync25(cachePath, JSON.stringify({
48200
48242
  peerId,
48201
48243
  cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
48202
48244
  models: models.map((m) => ({ name: m.name, size: m.size, parameterSize: m.parameterSize }))
@@ -48347,8 +48389,8 @@ Environment="OLLAMA_NUM_PARALLEL=${n}"
48347
48389
  }
48348
48390
  await new Promise((r) => setTimeout(r, 1e3));
48349
48391
  process.env.OLLAMA_NUM_PARALLEL = String(n);
48350
- const { spawn: spawn21 } = await import("node:child_process");
48351
- const child = spawn21("ollama", ["serve"], {
48392
+ const { spawn: spawn22 } = await import("node:child_process");
48393
+ const child = spawn22("ollama", ["serve"], {
48352
48394
  stdio: "ignore",
48353
48395
  detached: true,
48354
48396
  env: { ...process.env, OLLAMA_NUM_PARALLEL: String(n) }
@@ -48395,17 +48437,17 @@ async function handleUpdate(subcommand, ctx) {
48395
48437
  try {
48396
48438
  const { createRequire: createRequire4 } = await import("node:module");
48397
48439
  const { fileURLToPath: fileURLToPath14 } = await import("node:url");
48398
- const { dirname: dirname22, join: join71 } = await import("node:path");
48399
- const { existsSync: existsSync51 } = await import("node:fs");
48440
+ const { dirname: dirname22, join: join72 } = await import("node:path");
48441
+ const { existsSync: existsSync52 } = await import("node:fs");
48400
48442
  const req = createRequire4(import.meta.url);
48401
48443
  const thisDir = dirname22(fileURLToPath14(import.meta.url));
48402
48444
  const candidates = [
48403
- join71(thisDir, "..", "package.json"),
48404
- join71(thisDir, "..", "..", "package.json"),
48405
- join71(thisDir, "..", "..", "..", "package.json")
48445
+ join72(thisDir, "..", "package.json"),
48446
+ join72(thisDir, "..", "..", "package.json"),
48447
+ join72(thisDir, "..", "..", "..", "package.json")
48406
48448
  ];
48407
48449
  for (const pkgPath of candidates) {
48408
- if (existsSync51(pkgPath)) {
48450
+ if (existsSync52(pkgPath)) {
48409
48451
  const pkg = req(pkgPath);
48410
48452
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
48411
48453
  currentVersion = pkg.version ?? "0.0.0";
@@ -48599,11 +48641,11 @@ async function handleUpdate(subcommand, ctx) {
48599
48641
  const targetVersion = info?.latestVersion ?? currentVersion;
48600
48642
  const installOverlay = startInstallOverlay(targetVersion);
48601
48643
  let installError = "";
48602
- const runInstall2 = (cmd) => new Promise((resolve34) => {
48644
+ const runInstall2 = (cmd) => new Promise((resolve35) => {
48603
48645
  const child = exec4(cmd, { timeout: 18e4 }, (err, _stdout, stderr) => {
48604
48646
  if (err)
48605
48647
  installError = (stderr || err.message || "").trim();
48606
- resolve34(!err);
48648
+ resolve35(!err);
48607
48649
  });
48608
48650
  child.stdout?.on("data", (chunk) => {
48609
48651
  const text = String(chunk);
@@ -48697,8 +48739,8 @@ async function handleUpdate(subcommand, ctx) {
48697
48739
  }
48698
48740
  if (doRebuild) {
48699
48741
  installOverlay.setStatus("Rebuilding native modules...");
48700
- await new Promise((resolve34) => {
48701
- const child = exec4(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve34(true));
48742
+ await new Promise((resolve35) => {
48743
+ const child = exec4(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve35(true));
48702
48744
  child.stdout?.resume();
48703
48745
  child.stderr?.resume();
48704
48746
  });
@@ -48730,8 +48772,8 @@ async function handleUpdate(subcommand, ctx) {
48730
48772
  const venvPip2 = isWin2 ? pathJoin(venvDir, "Scripts", "pip.exe") : pathJoin(venvDir, "bin", "pip");
48731
48773
  if (fsExists(venvPip2)) {
48732
48774
  installOverlay.setStatus("Upgrading Python packages...");
48733
- await new Promise((resolve34) => {
48734
- const child = exec4(`"${venvPip2}" install --upgrade moondream-station pytesseract Pillow opencv-python-headless numpy 2>/dev/null || true`, { timeout: 3e5 }, (err) => resolve34(!err));
48775
+ await new Promise((resolve35) => {
48776
+ const child = exec4(`"${venvPip2}" install --upgrade moondream-station pytesseract Pillow opencv-python-headless numpy 2>/dev/null || true`, { timeout: 3e5 }, (err) => resolve35(!err));
48735
48777
  child.stdout?.resume();
48736
48778
  child.stderr?.resume();
48737
48779
  });
@@ -49127,16 +49169,16 @@ async function showExposeDashboard(gateway, rl, ctx) {
49127
49169
  renderDashboard();
49128
49170
  }, 1e3);
49129
49171
  let stopGateway = false;
49130
- await new Promise((resolve34) => {
49172
+ await new Promise((resolve35) => {
49131
49173
  const onData = (data) => {
49132
49174
  const key = data.toString();
49133
49175
  if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
49134
- resolve34();
49176
+ resolve35();
49135
49177
  return;
49136
49178
  }
49137
49179
  if (key === "s" || key === "S") {
49138
49180
  stopGateway = true;
49139
- resolve34();
49181
+ resolve35();
49140
49182
  return;
49141
49183
  }
49142
49184
  if (key === "c" || key === "C") {
@@ -49187,8 +49229,8 @@ async function showExposeDashboard(gateway, rl, ctx) {
49187
49229
  process.stdout.write("\x1B[?1002h\x1B[?1006h");
49188
49230
  }
49189
49231
  };
49190
- const origResolve = resolve34;
49191
- resolve34 = (() => {
49232
+ const origResolve = resolve35;
49233
+ resolve35 = (() => {
49192
49234
  cleanup();
49193
49235
  origResolve();
49194
49236
  });
@@ -56589,8 +56631,8 @@ async function collectNetworkMetrics() {
56589
56631
  }
56590
56632
  if (plat === "darwin") {
56591
56633
  try {
56592
- const output = await new Promise((resolve34, reject) => {
56593
- exec3("netstat -ib 2>/dev/null | head -30", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve34(stdout));
56634
+ const output = await new Promise((resolve35, reject) => {
56635
+ exec3("netstat -ib 2>/dev/null | head -30", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve35(stdout));
56594
56636
  });
56595
56637
  let rxBytes = 0, txBytes = 0;
56596
56638
  for (const line of output.split("\n")) {
@@ -56624,8 +56666,8 @@ async function collectGpuMetrics() {
56624
56666
  if (_nvidiaSmiAvailable === false)
56625
56667
  return noGpu;
56626
56668
  try {
56627
- const smi = await new Promise((resolve34, reject) => {
56628
- exec3("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve34(stdout));
56669
+ const smi = await new Promise((resolve35, reject) => {
56670
+ exec3("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve35(stdout));
56629
56671
  });
56630
56672
  _nvidiaSmiAvailable = true;
56631
56673
  const line = smi.trim().split("\n")[0];
@@ -60073,9 +60115,17 @@ ${lines.join("\n")}
60073
60115
  personalityName: personality ?? void 0,
60074
60116
  identityInjection,
60075
60117
  environmentProvider
60118
+ // Text tool mode is set dynamically after runner creation (async check)
60119
+ // The runner also auto-detects this when Ollama returns HTTP 400 for tools
60076
60120
  });
60077
60121
  runner.setWorkingDirectory(repoRoot);
60078
60122
  _activeRunnerRef = runner;
60123
+ needsTextToolMode(config.model, config.backendUrl).then((needsText) => {
60124
+ if (needsText) {
60125
+ runner.options.textToolMode = true;
60126
+ }
60127
+ }).catch(() => {
60128
+ });
60079
60129
  const tools = buildTools(repoRoot, config, contextWindowSize);
60080
60130
  if (contextWindowSize && contextWindowSize > 0) {
60081
60131
  for (const tool of tools) {
@@ -60994,14 +61044,14 @@ Review its full output in the [${id}] tab or via full_sub_agent(action='output',
60994
61044
  renderInfo(msg);
60995
61045
  statusBar.endContentWrite();
60996
61046
  }
60997
- }, () => new Promise((resolve34) => {
61047
+ }, () => new Promise((resolve35) => {
60998
61048
  depSudoPromptPending = true;
60999
61049
  depSudoResolver = (pw) => {
61000
61050
  depSudoPromptPending = false;
61001
61051
  depSudoResolver = null;
61002
61052
  if (pw)
61003
61053
  sessionSudoPassword = pw;
61004
- resolve34(pw);
61054
+ resolve35(pw);
61005
61055
  };
61006
61056
  const pwPrompt1 = ` ${c2.bold(c2.yellow("\u{1F511} Password needed for dependency install:"))}
61007
61057
  `;
@@ -64032,8 +64082,21 @@ var init_interactive = __esm({
64032
64082
  // packages/cli/dist/commands/run.js
64033
64083
  var run_exports = {};
64034
64084
  __export(run_exports, {
64035
- runCommand: () => runCommand
64085
+ jobsCommand: () => jobsCommand,
64086
+ runCommand: () => runCommand,
64087
+ statusCommand: () => statusCommand
64036
64088
  });
64089
+ import { resolve as resolve32 } from "node:path";
64090
+ import { spawn as spawn20 } from "node:child_process";
64091
+ import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync23, readFileSync as readFileSync39, readdirSync as readdirSync20, existsSync as existsSync50 } from "node:fs";
64092
+ import { randomBytes as randomBytes15 } from "node:crypto";
64093
+ import { join as join67 } from "node:path";
64094
+ function jobsDir(repoPath) {
64095
+ const root = resolve32(repoPath ?? process.cwd());
64096
+ const dir = join67(root, ".oa", "jobs");
64097
+ mkdirSync24(dir, { recursive: true });
64098
+ return dir;
64099
+ }
64037
64100
  async function runCommand(opts, config) {
64038
64101
  const mergedConfig = {
64039
64102
  ...config,
@@ -64043,11 +64106,148 @@ async function runCommand(opts, config) {
64043
64106
  ...opts.maxRetries !== void 0 ? { maxRetries: opts.maxRetries } : {}
64044
64107
  };
64045
64108
  if (opts.task) {
64046
- await runWithTUI(opts.task, mergedConfig, opts.repoPath);
64109
+ if (opts.background) {
64110
+ await runBackground(opts.task, mergedConfig, opts);
64111
+ } else if (opts.json) {
64112
+ await runJson(opts.task, mergedConfig, opts.repoPath);
64113
+ } else {
64114
+ await runWithTUI(opts.task, mergedConfig, opts.repoPath);
64115
+ }
64047
64116
  } else {
64048
64117
  await startInteractive(mergedConfig, opts.repoPath);
64049
64118
  }
64050
64119
  }
64120
+ async function runJson(task, config, repoPath) {
64121
+ const startTime = Date.now();
64122
+ const origWrite = process.stdout.write.bind(process.stdout);
64123
+ const captured = [];
64124
+ process.stdout.write = ((chunk, ...args) => {
64125
+ if (typeof chunk === "string")
64126
+ captured.push(chunk);
64127
+ return true;
64128
+ });
64129
+ let result;
64130
+ try {
64131
+ await runWithTUI(task, config, repoPath);
64132
+ result = {
64133
+ status: "completed",
64134
+ summary: extractSummary(captured),
64135
+ durationMs: Date.now() - startTime,
64136
+ exitCode: 0
64137
+ };
64138
+ } catch (err) {
64139
+ result = {
64140
+ status: "failed",
64141
+ error: err instanceof Error ? err.message : String(err),
64142
+ durationMs: Date.now() - startTime,
64143
+ exitCode: 1
64144
+ };
64145
+ }
64146
+ process.stdout.write = origWrite;
64147
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
64148
+ if (result.exitCode !== 0)
64149
+ process.exit(1);
64150
+ }
64151
+ function extractSummary(captured) {
64152
+ const all = captured.join("");
64153
+ const match = all.match(/task_complete.*?summary[:\s]*["']?([^"'\n]+)/i);
64154
+ if (match)
64155
+ return match[1].trim();
64156
+ const lines = all.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").split("\n").filter((l) => l.trim());
64157
+ return lines.slice(-3).join(" ").slice(0, 200);
64158
+ }
64159
+ async function runBackground(task, config, opts) {
64160
+ const id = `job-${randomBytes15(3).toString("hex")}`;
64161
+ const dir = jobsDir(opts.repoPath);
64162
+ const repoRoot = resolve32(opts.repoPath ?? process.cwd());
64163
+ const job = {
64164
+ id,
64165
+ pid: 0,
64166
+ task,
64167
+ status: "running",
64168
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
64169
+ };
64170
+ const oaBin = process.argv[1] || "oa";
64171
+ const args = [task, "--json"];
64172
+ if (config.model)
64173
+ args.push("--model", config.model);
64174
+ const child = spawn20("node", [oaBin, ...args], {
64175
+ cwd: repoRoot,
64176
+ env: { ...process.env, OA_JOB_ID: id },
64177
+ stdio: ["ignore", "pipe", "pipe"],
64178
+ detached: true
64179
+ });
64180
+ child.unref();
64181
+ job.pid = child.pid ?? 0;
64182
+ writeFileSync23(join67(dir, `${id}.json`), JSON.stringify(job, null, 2));
64183
+ let output = "";
64184
+ child.stdout?.on("data", (chunk) => {
64185
+ output += chunk.toString();
64186
+ });
64187
+ child.stderr?.on("data", (chunk) => {
64188
+ output += chunk.toString();
64189
+ });
64190
+ child.on("exit", (code) => {
64191
+ try {
64192
+ const result = output.trim() ? JSON.parse(output) : { status: code === 0 ? "completed" : "failed" };
64193
+ job.status = result.status || (code === 0 ? "completed" : "failed");
64194
+ job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
64195
+ job.summary = result.summary;
64196
+ job.durationMs = result.durationMs;
64197
+ job.error = result.error;
64198
+ writeFileSync23(join67(dir, `${id}.json`), JSON.stringify(job, null, 2));
64199
+ } catch {
64200
+ }
64201
+ });
64202
+ console.log(`Job started: ${id} (PID ${job.pid})`);
64203
+ console.log("");
64204
+ console.log("Monitor this job:");
64205
+ console.log(` oa status ${id} # Check progress`);
64206
+ console.log(` oa output ${id} # See full output`);
64207
+ console.log(` oa jobs # List all jobs`);
64208
+ console.log(` kill ${job.pid} # Stop the job`);
64209
+ console.log("");
64210
+ console.log(`Job file: .oa/jobs/${id}.json`);
64211
+ }
64212
+ function statusCommand(jobId, repoPath) {
64213
+ const dir = jobsDir(repoPath);
64214
+ const file = join67(dir, `${jobId}.json`);
64215
+ if (!existsSync50(file)) {
64216
+ console.error(`Job not found: ${jobId}`);
64217
+ console.log(`Available jobs: oa jobs`);
64218
+ process.exit(1);
64219
+ }
64220
+ const job = JSON.parse(readFileSync39(file, "utf-8"));
64221
+ 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`;
64222
+ const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
64223
+ console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
64224
+ console.log(` Task: ${job.task.slice(0, 80)}`);
64225
+ console.log(` PID: ${job.pid}`);
64226
+ if (job.summary)
64227
+ console.log(` Summary: ${job.summary}`);
64228
+ if (job.error)
64229
+ console.log(` Error: ${job.error}`);
64230
+ if (job.durationMs)
64231
+ console.log(` Duration: ${(job.durationMs / 1e3).toFixed(1)}s`);
64232
+ }
64233
+ function jobsCommand(repoPath) {
64234
+ const dir = jobsDir(repoPath);
64235
+ const files = readdirSync20(dir).filter((f) => f.endsWith(".json")).sort();
64236
+ if (files.length === 0) {
64237
+ console.log("No jobs found.");
64238
+ return;
64239
+ }
64240
+ console.log("Jobs:");
64241
+ for (const file of files) {
64242
+ try {
64243
+ const job = JSON.parse(readFileSync39(join67(dir, file), "utf-8"));
64244
+ const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
64245
+ 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`;
64246
+ console.log(` ${icon} ${job.id} [${job.status}] ${runtime} \u2014 ${job.task.slice(0, 60)}`);
64247
+ } catch {
64248
+ }
64249
+ }
64250
+ }
64051
64251
  var init_run = __esm({
64052
64252
  "packages/cli/dist/commands/run.js"() {
64053
64253
  "use strict";
@@ -64060,7 +64260,7 @@ import { glob } from "glob";
64060
64260
  import ignore from "ignore";
64061
64261
  import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
64062
64262
  import { createHash as createHash5 } from "node:crypto";
64063
- import { join as join67, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
64263
+ import { join as join68, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
64064
64264
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
64065
64265
  var init_codebase_indexer = __esm({
64066
64266
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -64104,7 +64304,7 @@ var init_codebase_indexer = __esm({
64104
64304
  const ig = ignore.default();
64105
64305
  if (this.config.respectGitignore) {
64106
64306
  try {
64107
- const gitignoreContent = await readFile23(join67(this.config.rootDir, ".gitignore"), "utf-8");
64307
+ const gitignoreContent = await readFile23(join68(this.config.rootDir, ".gitignore"), "utf-8");
64108
64308
  ig.add(gitignoreContent);
64109
64309
  } catch {
64110
64310
  }
@@ -64119,7 +64319,7 @@ var init_codebase_indexer = __esm({
64119
64319
  for (const relativePath of files) {
64120
64320
  if (ig.ignores(relativePath))
64121
64321
  continue;
64122
- const fullPath = join67(this.config.rootDir, relativePath);
64322
+ const fullPath = join68(this.config.rootDir, relativePath);
64123
64323
  try {
64124
64324
  const fileStat = await stat4(fullPath);
64125
64325
  if (fileStat.size > this.config.maxFileSize)
@@ -64165,7 +64365,7 @@ var init_codebase_indexer = __esm({
64165
64365
  if (!child) {
64166
64366
  child = {
64167
64367
  name: part,
64168
- path: join67(current.path, part),
64368
+ path: join68(current.path, part),
64169
64369
  type: "directory",
64170
64370
  children: []
64171
64371
  };
@@ -64247,14 +64447,14 @@ var index_repo_exports = {};
64247
64447
  __export(index_repo_exports, {
64248
64448
  indexRepoCommand: () => indexRepoCommand
64249
64449
  });
64250
- import { resolve as resolve32 } from "node:path";
64251
- import { existsSync as existsSync50, statSync as statSync16 } from "node:fs";
64450
+ import { resolve as resolve33 } from "node:path";
64451
+ import { existsSync as existsSync51, statSync as statSync16 } from "node:fs";
64252
64452
  import { cwd as cwd2 } from "node:process";
64253
64453
  async function indexRepoCommand(opts, _config) {
64254
- const repoRoot = resolve32(opts.repoPath ?? cwd2());
64454
+ const repoRoot = resolve33(opts.repoPath ?? cwd2());
64255
64455
  printHeader("Index Repository");
64256
64456
  printInfo(`Indexing: ${repoRoot}`);
64257
- if (!existsSync50(repoRoot)) {
64457
+ if (!existsSync51(repoRoot)) {
64258
64458
  printError(`Path does not exist: ${repoRoot}`);
64259
64459
  process.exit(1);
64260
64460
  }
@@ -64346,9 +64546,9 @@ var init_index_repo = __esm({
64346
64546
  // packages/cli/dist/commands/status.js
64347
64547
  var status_exports = {};
64348
64548
  __export(status_exports, {
64349
- statusCommand: () => statusCommand
64549
+ statusCommand: () => statusCommand2
64350
64550
  });
64351
- async function statusCommand(opts, config) {
64551
+ async function statusCommand2(opts, config) {
64352
64552
  printHeader("open-agents status");
64353
64553
  const backendType = config.backendType;
64354
64554
  if (backendType === "ollama") {
@@ -64506,7 +64706,7 @@ var config_exports = {};
64506
64706
  __export(config_exports, {
64507
64707
  configCommand: () => configCommand
64508
64708
  });
64509
- import { join as join68, resolve as resolve33 } from "node:path";
64709
+ import { join as join69, resolve as resolve34 } from "node:path";
64510
64710
  import { homedir as homedir17 } from "node:os";
64511
64711
  import { cwd as cwd3 } from "node:process";
64512
64712
  function redactIfSensitive(key, value) {
@@ -64539,7 +64739,7 @@ async function configCommand(opts, config) {
64539
64739
  return handleShow(opts, config);
64540
64740
  }
64541
64741
  function handleShow(opts, config) {
64542
- const repoRoot = resolve33(opts.repoPath ?? cwd3());
64742
+ const repoRoot = resolve34(opts.repoPath ?? cwd3());
64543
64743
  printHeader("Configuration");
64544
64744
  const resolved = resolveSettings(repoRoot);
64545
64745
  printSection("Core Inference");
@@ -64589,7 +64789,7 @@ function handleShow(opts, config) {
64589
64789
  }
64590
64790
  }
64591
64791
  printSection("Config File");
64592
- printInfo(`~/.open-agents/config.json (${join68(homedir17(), ".open-agents", "config.json")})`);
64792
+ printInfo(`~/.open-agents/config.json (${join69(homedir17(), ".open-agents", "config.json")})`);
64593
64793
  printSection("Priority Chain");
64594
64794
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
64595
64795
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -64622,13 +64822,13 @@ function handleSet(opts, _config) {
64622
64822
  process.exit(1);
64623
64823
  }
64624
64824
  if (opts.local) {
64625
- const repoRoot = resolve33(opts.repoPath ?? cwd3());
64825
+ const repoRoot = resolve34(opts.repoPath ?? cwd3());
64626
64826
  try {
64627
64827
  initOaDirectory(repoRoot);
64628
64828
  const coerced = coerceForSettings(key, value);
64629
64829
  saveProjectSettings(repoRoot, { [key]: coerced });
64630
64830
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
64631
- printInfo(`Saved to ${join68(repoRoot, ".oa", "settings.json")}`);
64831
+ printInfo(`Saved to ${join69(repoRoot, ".oa", "settings.json")}`);
64632
64832
  printInfo("This override applies only when running in this workspace.");
64633
64833
  } catch (err) {
64634
64834
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -64728,7 +64928,7 @@ var serve_exports = {};
64728
64928
  __export(serve_exports, {
64729
64929
  serveCommand: () => serveCommand
64730
64930
  });
64731
- import { spawn as spawn20 } from "node:child_process";
64931
+ import { spawn as spawn21 } from "node:child_process";
64732
64932
  async function serveCommand(opts, config) {
64733
64933
  const backendType = config.backendType;
64734
64934
  if (backendType === "ollama") {
@@ -64820,8 +65020,8 @@ async function serveVllm(opts, config) {
64820
65020
  await runVllmServer(args, opts.verbose ?? false);
64821
65021
  }
64822
65022
  async function runVllmServer(args, verbose) {
64823
- return new Promise((resolve34, reject) => {
64824
- const child = spawn20("python", args, {
65023
+ return new Promise((resolve35, reject) => {
65024
+ const child = spawn21("python", args, {
64825
65025
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
64826
65026
  env: { ...process.env }
64827
65027
  });
@@ -64855,10 +65055,10 @@ async function runVllmServer(args, verbose) {
64855
65055
  child.once("exit", (code, signal) => {
64856
65056
  if (signal) {
64857
65057
  printInfo(`vLLM server stopped by signal ${signal}`);
64858
- resolve34();
65058
+ resolve35();
64859
65059
  } else if (code === 0) {
64860
65060
  printSuccess("vLLM server exited cleanly");
64861
- resolve34();
65061
+ resolve35();
64862
65062
  } else {
64863
65063
  printError(`vLLM server exited with code ${code}`);
64864
65064
  reject(new Error(`vLLM exited with code ${code}`));
@@ -64886,8 +65086,8 @@ __export(eval_exports, {
64886
65086
  evalCommand: () => evalCommand
64887
65087
  });
64888
65088
  import { tmpdir as tmpdir10 } from "node:os";
64889
- import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync23 } from "node:fs";
64890
- import { join as join69 } from "node:path";
65089
+ import { mkdirSync as mkdirSync25, writeFileSync as writeFileSync24 } from "node:fs";
65090
+ import { join as join70 } from "node:path";
64891
65091
  async function evalCommand(opts, config) {
64892
65092
  const suiteName = opts.suite ?? "basic";
64893
65093
  const suite = SUITES[suiteName];
@@ -65012,9 +65212,9 @@ async function evalCommand(opts, config) {
65012
65212
  process.exit(failed > 0 ? 1 : 0);
65013
65213
  }
65014
65214
  function createTempEvalRepo() {
65015
- const dir = join69(tmpdir10(), `open-agents-eval-${Date.now()}`);
65016
- mkdirSync24(dir, { recursive: true });
65017
- writeFileSync23(join69(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
65215
+ const dir = join70(tmpdir10(), `open-agents-eval-${Date.now()}`);
65216
+ mkdirSync25(dir, { recursive: true });
65217
+ writeFileSync24(join70(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
65018
65218
  return dir;
65019
65219
  }
65020
65220
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -65074,7 +65274,7 @@ init_updater();
65074
65274
  import { parseArgs as nodeParseArgs2 } from "node:util";
65075
65275
  import { createRequire as createRequire3 } from "node:module";
65076
65276
  import { fileURLToPath as fileURLToPath13 } from "node:url";
65077
- import { dirname as dirname21, join as join70 } from "node:path";
65277
+ import { dirname as dirname21, join as join71 } from "node:path";
65078
65278
 
65079
65279
  // packages/cli/dist/cli.js
65080
65280
  import { createInterface } from "node:readline";
@@ -65181,7 +65381,7 @@ init_output();
65181
65381
  function getVersion4() {
65182
65382
  try {
65183
65383
  const require2 = createRequire3(import.meta.url);
65184
- const pkgPath = join70(dirname21(fileURLToPath13(import.meta.url)), "..", "package.json");
65384
+ const pkgPath = join71(dirname21(fileURLToPath13(import.meta.url)), "..", "package.json");
65185
65385
  const pkg = require2(pkgPath);
65186
65386
  return pkg.version;
65187
65387
  } catch {
@@ -65189,7 +65389,7 @@ function getVersion4() {
65189
65389
  }
65190
65390
  }
65191
65391
  function routeCommand(command) {
65192
- const valid = /* @__PURE__ */ new Set(["run", "index", "status", "config", "serve", "eval"]);
65392
+ const valid = /* @__PURE__ */ new Set(["run", "index", "status", "config", "serve", "eval", "jobs"]);
65193
65393
  return valid.has(command) ? command : "unknown";
65194
65394
  }
65195
65395
  function parseCliArgs(argv) {
@@ -65209,6 +65409,8 @@ function parseCliArgs(argv) {
65209
65409
  local: { type: "boolean", short: "l" },
65210
65410
  port: { type: "string" },
65211
65411
  suite: { type: "string" },
65412
+ json: { type: "boolean", short: "j" },
65413
+ background: { type: "boolean" },
65212
65414
  help: { type: "boolean", short: "h" },
65213
65415
  version: { type: "boolean", short: "V" }
65214
65416
  },
@@ -65229,6 +65431,8 @@ function parseCliArgs(argv) {
65229
65431
  timeoutMs: typeof values["timeout-ms"] === "string" ? parseInt(values["timeout-ms"], 10) : void 0,
65230
65432
  offline: values.offline === true,
65231
65433
  local: values.local === true,
65434
+ json: values.json === true,
65435
+ background: values.background === true,
65232
65436
  help: values.help === true,
65233
65437
  version: values.version === true
65234
65438
  };
@@ -65259,6 +65463,9 @@ function parseCliArgs(argv) {
65259
65463
  result.servePort = parseInt(values.port, 10);
65260
65464
  }
65261
65465
  break;
65466
+ case "status":
65467
+ result.task = rest[0];
65468
+ break;
65262
65469
  case "eval":
65263
65470
  result.evalSuite = typeof values.suite === "string" ? values.suite : void 0;
65264
65471
  break;
@@ -65365,7 +65572,9 @@ async function main() {
65365
65572
  verbose: parsed.verbose,
65366
65573
  maxRetries: parsed.maxRetries,
65367
65574
  timeoutMs: parsed.timeoutMs,
65368
- offline: parsed.offline
65575
+ offline: parsed.offline,
65576
+ json: parsed.json,
65577
+ background: parsed.background
65369
65578
  }, config);
65370
65579
  break;
65371
65580
  }
@@ -65378,8 +65587,18 @@ async function main() {
65378
65587
  break;
65379
65588
  }
65380
65589
  case "status": {
65381
- const { statusCommand: statusCommand2 } = await Promise.resolve().then(() => (init_status(), status_exports));
65382
- await statusCommand2({ verbose: parsed.verbose }, config);
65590
+ if (parsed.task && parsed.task.startsWith("job-")) {
65591
+ const { statusCommand: jobStatusCmd } = await Promise.resolve().then(() => (init_run(), run_exports));
65592
+ jobStatusCmd(parsed.task, parsed.repoPath);
65593
+ } else {
65594
+ const { statusCommand: statusCommand3 } = await Promise.resolve().then(() => (init_status(), status_exports));
65595
+ await statusCommand3({ verbose: parsed.verbose }, config);
65596
+ }
65597
+ break;
65598
+ }
65599
+ case "jobs": {
65600
+ const { jobsCommand: jobsCommand2 } = await Promise.resolve().then(() => (init_run(), run_exports));
65601
+ jobsCommand2(parsed.repoPath);
65383
65602
  break;
65384
65603
  }
65385
65604
  case "config": {