open-agents-ai 0.35.2 → 0.37.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.
package/dist/index.js CHANGED
@@ -1285,7 +1285,7 @@ ${stdinInput ?? ""}`);
1285
1285
  }
1286
1286
  runCommand(command, timeout, stdinInput) {
1287
1287
  const start = performance.now();
1288
- return new Promise((resolve23) => {
1288
+ return new Promise((resolve26) => {
1289
1289
  const child = spawn("bash", ["-c", command], {
1290
1290
  cwd: this.workingDir,
1291
1291
  env: {
@@ -1313,7 +1313,7 @@ ${stdinInput ?? ""}`);
1313
1313
  clearTimeout(timer);
1314
1314
  if (exitFlushTimer)
1315
1315
  clearTimeout(exitFlushTimer);
1316
- resolve23(result);
1316
+ resolve26(result);
1317
1317
  };
1318
1318
  const timer = setTimeout(() => {
1319
1319
  killed = true;
@@ -2317,7 +2317,7 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
2317
2317
  return null;
2318
2318
  }
2319
2319
  runProcess(cmd, args, timeoutMs) {
2320
- return new Promise((resolve23, reject) => {
2320
+ return new Promise((resolve26, reject) => {
2321
2321
  const proc = execFile3(cmd, args, {
2322
2322
  timeout: timeoutMs,
2323
2323
  maxBuffer: 10 * 1024 * 1024,
@@ -2327,7 +2327,7 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
2327
2327
  reject(new Error(`Process timeout after ${timeoutMs}ms`));
2328
2328
  return;
2329
2329
  }
2330
- resolve23({
2330
+ resolve26({
2331
2331
  stdout: String(stdout),
2332
2332
  stderr: String(stderr),
2333
2333
  exitCode: error ? error.code ?? 1 : 0
@@ -2906,6 +2906,10 @@ var init_explore_tools = __esm({
2906
2906
  code_sandbox: "Run code in an isolated sandbox",
2907
2907
  structured_read: "Read structured data files (CSV, JSON)",
2908
2908
  sub_agent: "Delegate a subtask to a new agent instance",
2909
+ browser_action: "Automate headless Chrome: navigate, click, type, screenshot, read DOM",
2910
+ scheduler: "Schedule tasks for automatic future execution via OS cron",
2911
+ reminder: "Set reminders that surface at future agent startups",
2912
+ agenda: "View all pending reminders, scheduled tasks, and attention items",
2909
2913
  background_run: "Run a shell command in the background",
2910
2914
  task_status: "Check status of background tasks",
2911
2915
  task_output: "Read output from a background task",
@@ -5357,7 +5361,7 @@ var init_custom_tool = __esm({
5357
5361
  }
5358
5362
  /** Execute a single shell command and return output */
5359
5363
  runCommand(command) {
5360
- return new Promise((resolve23) => {
5364
+ return new Promise((resolve26) => {
5361
5365
  const child = spawn3("bash", ["-c", command], {
5362
5366
  cwd: this.workingDir,
5363
5367
  env: { ...process.env, CI: "true", NO_COLOR: "1" },
@@ -5382,11 +5386,11 @@ var init_custom_tool = __esm({
5382
5386
  child.kill("SIGTERM");
5383
5387
  } catch {
5384
5388
  }
5385
- resolve23({ success: false, output: stdout, error: "Command timed out after 60s" });
5389
+ resolve26({ success: false, output: stdout, error: "Command timed out after 60s" });
5386
5390
  }, 6e4);
5387
5391
  child.on("close", (code) => {
5388
5392
  clearTimeout(timer);
5389
- resolve23({
5393
+ resolve26({
5390
5394
  success: code === 0,
5391
5395
  output: stdout + (stderr && code === 0 ? `
5392
5396
  STDERR:
@@ -5396,7 +5400,7 @@ ${stderr}` : ""),
5396
5400
  });
5397
5401
  child.on("error", (err) => {
5398
5402
  clearTimeout(timer);
5399
- resolve23({ success: false, output: stdout, error: err.message });
5403
+ resolve26({ success: false, output: stdout, error: err.message });
5400
5404
  });
5401
5405
  });
5402
5406
  }
@@ -6578,7 +6582,7 @@ import { writeFile as writeFile7, mkdtemp, rm, readdir as readdir2, stat } from
6578
6582
  import { join as join16 } from "node:path";
6579
6583
  import { tmpdir as tmpdir2 } from "node:os";
6580
6584
  function runProcess(cmd, args, options) {
6581
- return new Promise((resolve23) => {
6585
+ return new Promise((resolve26) => {
6582
6586
  const proc = spawn5(cmd, args, {
6583
6587
  cwd: options.cwd,
6584
6588
  timeout: options.timeout,
@@ -6608,7 +6612,7 @@ function runProcess(cmd, args, options) {
6608
6612
  }
6609
6613
  });
6610
6614
  proc.on("error", (err) => {
6611
- resolve23({
6615
+ resolve26({
6612
6616
  stdout,
6613
6617
  stderr: stderr || err.message,
6614
6618
  exitCode: 1,
@@ -6620,7 +6624,7 @@ function runProcess(cmd, args, options) {
6620
6624
  if (signal === "SIGTERM" || signal === "SIGKILL") {
6621
6625
  timedOut = true;
6622
6626
  }
6623
- resolve23({
6627
+ resolve26({
6624
6628
  stdout,
6625
6629
  stderr,
6626
6630
  exitCode: code ?? (timedOut ? 124 : 1),
@@ -8650,6 +8654,1248 @@ Note: Advanced Python pipeline not available \u2014 install pytesseract, opencv-
8650
8654
  }
8651
8655
  });
8652
8656
 
8657
+ // packages/execution/dist/tools/browser-action.js
8658
+ import { execSync as execSync15, spawn as spawn7 } from "node:child_process";
8659
+ import { existsSync as existsSync18, readFileSync as readFileSync13 } from "node:fs";
8660
+ import { join as join21, dirname as dirname8 } from "node:path";
8661
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
8662
+ async function probeService() {
8663
+ try {
8664
+ const controller = new AbortController();
8665
+ const timeout = setTimeout(() => controller.abort(), 3e3);
8666
+ const res = await fetch(`${BASE_URL}/health`, { signal: controller.signal });
8667
+ clearTimeout(timeout);
8668
+ return res.ok;
8669
+ } catch {
8670
+ return false;
8671
+ }
8672
+ }
8673
+ function findPython2() {
8674
+ for (const cmd of ["python3", "python"]) {
8675
+ try {
8676
+ const ver = execSync15(`${cmd} --version 2>&1`, { stdio: "pipe", timeout: 5e3 }).toString().trim();
8677
+ if (ver.includes("Python 3"))
8678
+ return cmd;
8679
+ } catch {
8680
+ }
8681
+ }
8682
+ return null;
8683
+ }
8684
+ async function launchService() {
8685
+ if (await probeService())
8686
+ return null;
8687
+ const python = findPython2();
8688
+ if (!python)
8689
+ return "Python 3 not found. Install Python 3.9+ to use browser automation.";
8690
+ if (!existsSync18(SCRAPE_SCRIPT)) {
8691
+ return `Scrape service script not found at ${SCRAPE_SCRIPT}`;
8692
+ }
8693
+ serviceProcess = spawn7(python, [SCRAPE_SCRIPT], {
8694
+ stdio: "ignore",
8695
+ detached: true,
8696
+ env: {
8697
+ ...process.env,
8698
+ SCRAPE_PORT: String(DEFAULT_PORT),
8699
+ SCRAPE_HEADLESS_DEFAULT: "1",
8700
+ SCRAPE_REQUIRE_AUTH: "0"
8701
+ }
8702
+ });
8703
+ serviceProcess.unref();
8704
+ for (let i = 0; i < 120; i++) {
8705
+ await new Promise((r) => setTimeout(r, 500));
8706
+ if (await probeService())
8707
+ return null;
8708
+ }
8709
+ return "Scrape service failed to start within 60s. Check Chrome/Chromium installation.";
8710
+ }
8711
+ async function ensureSession() {
8712
+ if (activeSessionId) {
8713
+ try {
8714
+ const res2 = await fetch(`${BASE_URL}/health`);
8715
+ if (res2.ok)
8716
+ return { sessionId: activeSessionId };
8717
+ } catch {
8718
+ }
8719
+ activeSessionId = null;
8720
+ }
8721
+ const res = await fetch(`${BASE_URL}/session/start`, {
8722
+ method: "POST",
8723
+ headers: { "Content-Type": "application/json" },
8724
+ body: JSON.stringify({ headless: true })
8725
+ });
8726
+ const data = await res.json();
8727
+ if (!data.ok)
8728
+ return { error: String(data.message ?? "Failed to start browser session"), sessionId: "" };
8729
+ activeSessionId = data.session_id;
8730
+ return { sessionId: activeSessionId };
8731
+ }
8732
+ async function apiCall(endpoint, method = "POST", body) {
8733
+ const options = {
8734
+ method,
8735
+ headers: { "Content-Type": "application/json" }
8736
+ };
8737
+ if (body && method === "POST") {
8738
+ options.body = JSON.stringify({ sid: activeSessionId, ...body });
8739
+ }
8740
+ let url = `${BASE_URL}${endpoint}`;
8741
+ if (method === "GET" && activeSessionId) {
8742
+ url += `?sid=${encodeURIComponent(activeSessionId)}`;
8743
+ }
8744
+ const res = await fetch(url, options);
8745
+ return await res.json();
8746
+ }
8747
+ var __dirname2, SCRAPE_SCRIPT, DEFAULT_PORT, BASE_URL, serviceProcess, activeSessionId, BrowserActionTool;
8748
+ var init_browser_action = __esm({
8749
+ "packages/execution/dist/tools/browser-action.js"() {
8750
+ "use strict";
8751
+ __dirname2 = dirname8(fileURLToPath5(import.meta.url));
8752
+ SCRAPE_SCRIPT = join21(__dirname2, "..", "..", "scripts", "web_scrape.py");
8753
+ DEFAULT_PORT = 8130;
8754
+ BASE_URL = `http://localhost:${DEFAULT_PORT}`;
8755
+ serviceProcess = null;
8756
+ activeSessionId = null;
8757
+ BrowserActionTool = class {
8758
+ name = "browser_action";
8759
+ description = "Automate a headless Chrome browser: navigate to URLs, click elements, type text, take screenshots, read DOM content, scroll, and navigate history. Uses a local Selenium-based service that auto-starts on first use. Better than xdotool for web automation \u2014 works headlessly without a display server. Actions: navigate, click, click_xy, type, screenshot, dom, scroll, back, forward, close.";
8760
+ parameters = {
8761
+ type: "object",
8762
+ properties: {
8763
+ action: {
8764
+ type: "string",
8765
+ enum: ["navigate", "click", "click_xy", "type", "screenshot", "dom", "scroll", "scroll_up", "scroll_down", "back", "forward", "close"],
8766
+ description: "Browser action to perform"
8767
+ },
8768
+ url: {
8769
+ type: "string",
8770
+ description: "URL to navigate to (for 'navigate' action)"
8771
+ },
8772
+ selector: {
8773
+ type: "string",
8774
+ description: "CSS selector of element to interact with (for 'click' and 'type' actions)"
8775
+ },
8776
+ text: {
8777
+ type: "string",
8778
+ description: "Text to type into the selected element (for 'type' action)"
8779
+ },
8780
+ x: {
8781
+ type: "number",
8782
+ description: "X coordinate for click_xy action (viewport pixels)"
8783
+ },
8784
+ y: {
8785
+ type: "number",
8786
+ description: "Y coordinate for click_xy action (viewport pixels)"
8787
+ },
8788
+ amount: {
8789
+ type: "number",
8790
+ description: "Scroll amount in pixels (for 'scroll' action, default 600)"
8791
+ }
8792
+ },
8793
+ required: ["action"]
8794
+ };
8795
+ async execute(args) {
8796
+ const start = Date.now();
8797
+ const action = args.action;
8798
+ const launchErr = await launchService();
8799
+ if (launchErr) {
8800
+ return { success: false, output: "", error: launchErr, durationMs: Date.now() - start };
8801
+ }
8802
+ if (action === "close") {
8803
+ if (activeSessionId) {
8804
+ try {
8805
+ await apiCall("/session/close");
8806
+ } catch {
8807
+ }
8808
+ activeSessionId = null;
8809
+ }
8810
+ return { success: true, output: "Browser session closed.", durationMs: Date.now() - start };
8811
+ }
8812
+ const session = await ensureSession();
8813
+ if (session.error) {
8814
+ return { success: false, output: "", error: session.error, durationMs: Date.now() - start };
8815
+ }
8816
+ try {
8817
+ let result;
8818
+ switch (action) {
8819
+ case "navigate":
8820
+ if (!args.url)
8821
+ return { success: false, output: "", error: "url is required for navigate action", durationMs: Date.now() - start };
8822
+ result = await apiCall("/navigate", "POST", { url: args.url });
8823
+ return {
8824
+ success: !!result.ok,
8825
+ output: result.ok ? `Navigated to ${args.url}` : String(result.message ?? "Navigation failed"),
8826
+ durationMs: Date.now() - start
8827
+ };
8828
+ case "click":
8829
+ if (!args.selector)
8830
+ return { success: false, output: "", error: "selector is required for click action", durationMs: Date.now() - start };
8831
+ result = await apiCall("/click", "POST", { selector: args.selector });
8832
+ return {
8833
+ success: !!result.ok,
8834
+ output: result.ok ? `Clicked element: ${args.selector}` : String(result.message ?? "Click failed"),
8835
+ durationMs: Date.now() - start
8836
+ };
8837
+ case "click_xy":
8838
+ if (args.x == null || args.y == null)
8839
+ return { success: false, output: "", error: "x and y are required for click_xy action", durationMs: Date.now() - start };
8840
+ result = await apiCall("/click_xy", "POST", { x: args.x, y: args.y });
8841
+ return {
8842
+ success: !!result.ok,
8843
+ output: result.ok ? `Clicked at (${args.x}, ${args.y})` : String(result.message ?? "Click failed"),
8844
+ durationMs: Date.now() - start
8845
+ };
8846
+ case "type":
8847
+ if (!args.selector || !args.text)
8848
+ return { success: false, output: "", error: "selector and text are required for type action", durationMs: Date.now() - start };
8849
+ result = await apiCall("/type", "POST", { selector: args.selector, text: args.text });
8850
+ return {
8851
+ success: !!result.ok,
8852
+ output: result.ok ? `Typed "${args.text.slice(0, 50)}" into ${args.selector}` : String(result.message ?? "Type failed"),
8853
+ durationMs: Date.now() - start
8854
+ };
8855
+ case "screenshot": {
8856
+ result = await apiCall("/screenshot", "GET");
8857
+ const b64 = result.b64;
8858
+ const width = result.width;
8859
+ const height = result.height;
8860
+ if (b64) {
8861
+ return {
8862
+ success: true,
8863
+ output: `Screenshot captured (${width}x${height}). Base64 length: ${b64.length} chars.
8864
+ [IMAGE_BASE64:image/png:${b64.slice(0, 200)}...]`,
8865
+ durationMs: Date.now() - start
8866
+ };
8867
+ }
8868
+ return { success: false, output: "", error: "Screenshot failed", durationMs: Date.now() - start };
8869
+ }
8870
+ case "dom": {
8871
+ result = await apiCall("/dom", "GET");
8872
+ const dom = result.dom;
8873
+ if (dom) {
8874
+ const truncated = dom.length > 5e4 ? dom.slice(0, 5e4) + "\n... (truncated)" : dom;
8875
+ return { success: true, output: truncated, durationMs: Date.now() - start };
8876
+ }
8877
+ return { success: false, output: "", error: "DOM capture failed", durationMs: Date.now() - start };
8878
+ }
8879
+ case "scroll":
8880
+ result = await apiCall("/scroll", "POST", { amount: args.amount ?? 600 });
8881
+ return { success: !!result.ok, output: `Scrolled ${args.amount ?? 600}px`, durationMs: Date.now() - start };
8882
+ case "scroll_up":
8883
+ result = await apiCall("/scroll/up", "POST");
8884
+ return { success: !!result.ok, output: "Scrolled up", durationMs: Date.now() - start };
8885
+ case "scroll_down":
8886
+ result = await apiCall("/scroll/down", "POST");
8887
+ return { success: !!result.ok, output: "Scrolled down", durationMs: Date.now() - start };
8888
+ case "back":
8889
+ result = await apiCall("/history/back", "POST");
8890
+ return { success: !!result.ok, output: "Navigated back", durationMs: Date.now() - start };
8891
+ case "forward":
8892
+ result = await apiCall("/history/forward", "POST");
8893
+ return { success: !!result.ok, output: "Navigated forward", durationMs: Date.now() - start };
8894
+ default:
8895
+ return { success: false, output: "", error: `Unknown action: ${action}. Available: navigate, click, click_xy, type, screenshot, dom, scroll, scroll_up, scroll_down, back, forward, close`, durationMs: Date.now() - start };
8896
+ }
8897
+ } catch (err) {
8898
+ return {
8899
+ success: false,
8900
+ output: "",
8901
+ error: `Browser action failed: ${err instanceof Error ? err.message : String(err)}`,
8902
+ durationMs: Date.now() - start
8903
+ };
8904
+ }
8905
+ }
8906
+ };
8907
+ }
8908
+ });
8909
+
8910
+ // packages/execution/dist/tools/scheduler.js
8911
+ import { execSync as execSync16, exec as execCb } from "node:child_process";
8912
+ import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir4 } from "node:fs/promises";
8913
+ import { resolve as resolve20, join as join22 } from "node:path";
8914
+ import { randomBytes as randomBytes2 } from "node:crypto";
8915
+ function isValidCron(expr) {
8916
+ const parts = expr.trim().split(/\s+/);
8917
+ if (parts.length !== 5)
8918
+ return false;
8919
+ return parts.every((p) => /^[\d*,\-/]+$/.test(p));
8920
+ }
8921
+ function resolveSchedule(schedule) {
8922
+ const lower = schedule.toLowerCase().trim();
8923
+ if (SCHEDULE_PRESETS[lower])
8924
+ return SCHEDULE_PRESETS[lower];
8925
+ const inMatch = lower.match(/^in\s+(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?)$/);
8926
+ if (inMatch) {
8927
+ const amount = parseInt(inMatch[1], 10);
8928
+ const unit = inMatch[2].charAt(0);
8929
+ const now = /* @__PURE__ */ new Date();
8930
+ if (unit === "m")
8931
+ now.setMinutes(now.getMinutes() + amount);
8932
+ else if (unit === "h")
8933
+ now.setHours(now.getHours() + amount);
8934
+ else if (unit === "d")
8935
+ now.setDate(now.getDate() + amount);
8936
+ return `${now.getMinutes()} ${now.getHours()} ${now.getDate()} ${now.getMonth() + 1} *`;
8937
+ }
8938
+ const atMatch = lower.match(/^at\s+(\d{1,2}):(\d{2})$/);
8939
+ if (atMatch) {
8940
+ const hour = parseInt(atMatch[1], 10);
8941
+ const minute = parseInt(atMatch[2], 10);
8942
+ if (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59) {
8943
+ return `${minute} ${hour} * * *`;
8944
+ }
8945
+ }
8946
+ if (isValidCron(schedule))
8947
+ return schedule.trim();
8948
+ return null;
8949
+ }
8950
+ function describeCron(expr) {
8951
+ const parts = expr.split(/\s+/);
8952
+ if (parts.length !== 5)
8953
+ return expr;
8954
+ const [min, hour, dom, mon, dow] = parts;
8955
+ if (expr === "* * * * *")
8956
+ return "every minute";
8957
+ if (min?.startsWith("*/") && hour === "*")
8958
+ return `every ${min.slice(2)} minutes`;
8959
+ if (min === "0" && hour?.startsWith("*/"))
8960
+ return `every ${hour.slice(2)} hours`;
8961
+ if (min === "0" && hour !== "*" && dom === "*" && mon === "*" && dow === "*")
8962
+ return `daily at ${hour}:00`;
8963
+ if (min !== "*" && hour !== "*" && dom === "*" && mon === "*" && dow === "*")
8964
+ return `daily at ${hour}:${min?.padStart(2, "0")}`;
8965
+ if (dow !== "*" && dom === "*")
8966
+ return `weekly on day ${dow} at ${hour}:${min?.padStart(2, "0")}`;
8967
+ if (dom !== "*" && mon === "*")
8968
+ return `monthly on day ${dom} at ${hour}:${min?.padStart(2, "0")}`;
8969
+ return expr;
8970
+ }
8971
+ function getCurrentCrontab() {
8972
+ try {
8973
+ return execSync16("crontab -l 2>/dev/null", { stdio: "pipe" }).toString().split("\n");
8974
+ } catch {
8975
+ return [];
8976
+ }
8977
+ }
8978
+ function writeCrontab(lines) {
8979
+ const content = lines.join("\n") + "\n";
8980
+ execSync16(`echo ${JSON.stringify(content)} | crontab -`, { stdio: "pipe" });
8981
+ }
8982
+ function findOaBinary() {
8983
+ for (const cmd of ["oa", "open-agents"]) {
8984
+ try {
8985
+ const path = execSync16(`which ${cmd} 2>/dev/null`, { stdio: "pipe" }).toString().trim();
8986
+ if (path)
8987
+ return path;
8988
+ } catch {
8989
+ }
8990
+ }
8991
+ return "npx open-agents-ai";
8992
+ }
8993
+ function installCronJob(task, workingDir) {
8994
+ const lines = getCurrentCrontab();
8995
+ const oaBin = findOaBinary();
8996
+ const logDir = resolve20(workingDir, ".oa", "scheduled", "logs");
8997
+ const logFile = join22(logDir, `${task.id}.log`);
8998
+ const cronLine = `${task.schedule} cd ${JSON.stringify(workingDir)} && ${oaBin} ${JSON.stringify(task.task)} >> ${JSON.stringify(logFile)} 2>&1 ${CRON_MARKER}${task.id}`;
8999
+ const filtered = lines.filter((l) => !l.includes(`${CRON_MARKER}${task.id}`));
9000
+ filtered.push(cronLine);
9001
+ writeCrontab(filtered);
9002
+ }
9003
+ function removeCronJob(taskId) {
9004
+ const lines = getCurrentCrontab();
9005
+ const filtered = lines.filter((l) => !l.includes(`${CRON_MARKER}${taskId}`));
9006
+ if (filtered.length !== lines.length) {
9007
+ writeCrontab(filtered);
9008
+ }
9009
+ }
9010
+ function listCronJobs() {
9011
+ return getCurrentCrontab().filter((l) => l.includes(CRON_MARKER)).map((l) => {
9012
+ const idMatch = l.match(new RegExp(`${CRON_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\S+)`));
9013
+ return { id: idMatch?.[1] ?? "unknown", line: l };
9014
+ });
9015
+ }
9016
+ async function loadStore(workingDir) {
9017
+ const storePath = resolve20(workingDir, ".oa", "scheduled", "tasks.json");
9018
+ try {
9019
+ const raw = await readFile9(storePath, "utf-8");
9020
+ return JSON.parse(raw);
9021
+ } catch {
9022
+ return { tasks: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9023
+ }
9024
+ }
9025
+ async function saveStore(workingDir, store) {
9026
+ const dir = resolve20(workingDir, ".oa", "scheduled");
9027
+ await mkdir4(dir, { recursive: true });
9028
+ await mkdir4(join22(dir, "logs"), { recursive: true });
9029
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9030
+ await writeFile8(join22(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
9031
+ }
9032
+ var SCHEDULE_PRESETS, CRON_MARKER, SchedulerTool;
9033
+ var init_scheduler = __esm({
9034
+ "packages/execution/dist/tools/scheduler.js"() {
9035
+ "use strict";
9036
+ SCHEDULE_PRESETS = {
9037
+ "every minute": "* * * * *",
9038
+ "every 5 minutes": "*/5 * * * *",
9039
+ "every 15 minutes": "*/15 * * * *",
9040
+ "every 30 minutes": "*/30 * * * *",
9041
+ "every hour": "0 * * * *",
9042
+ "every 2 hours": "0 */2 * * *",
9043
+ "every 6 hours": "0 */6 * * *",
9044
+ "every 12 hours": "0 */12 * * *",
9045
+ "daily": "0 9 * * *",
9046
+ "daily morning": "0 9 * * *",
9047
+ "daily evening": "0 18 * * *",
9048
+ "weekly": "0 9 * * 1",
9049
+ "monthly": "0 9 1 * *",
9050
+ "hourly": "0 * * * *"
9051
+ };
9052
+ CRON_MARKER = "# OPEN-AGENTS-SCHEDULED:";
9053
+ SchedulerTool = class {
9054
+ name = "scheduler";
9055
+ description = "Schedule tasks for automatic future execution using OS-level cron. Actions: 'create' a new scheduled task, 'list' all scheduled tasks, 'cancel' a task by ID, 'pause'/'resume' a task. Schedules: use presets ('daily', 'every 5 minutes', 'hourly', 'weekly'), natural language ('in 30m', 'at 14:30'), or raw cron expressions ('0 */2 * * *'). Tasks launch the agent automatically at the scheduled time.";
9056
+ parameters = {
9057
+ type: "object",
9058
+ properties: {
9059
+ action: {
9060
+ type: "string",
9061
+ enum: ["create", "list", "cancel", "pause", "resume", "logs"],
9062
+ description: "Scheduler action to perform"
9063
+ },
9064
+ task: {
9065
+ type: "string",
9066
+ description: "The task/prompt the agent should execute (for 'create')"
9067
+ },
9068
+ schedule: {
9069
+ type: "string",
9070
+ description: "When to run: preset ('daily', 'every 5 minutes'), natural ('in 30m', 'at 14:30'), or cron ('0 */2 * * *')"
9071
+ },
9072
+ id: {
9073
+ type: "string",
9074
+ description: "Task ID (for 'cancel', 'pause', 'resume', 'logs')"
9075
+ },
9076
+ max_runs: {
9077
+ type: "number",
9078
+ description: "Auto-disable after N executions (omit for unlimited)"
9079
+ },
9080
+ one_shot: {
9081
+ type: "boolean",
9082
+ description: "If true, task auto-removes after first execution"
9083
+ }
9084
+ },
9085
+ required: ["action"]
9086
+ };
9087
+ workingDir;
9088
+ constructor(workingDir) {
9089
+ this.workingDir = workingDir;
9090
+ }
9091
+ async execute(args) {
9092
+ const start = performance.now();
9093
+ const action = String(args["action"] ?? "list");
9094
+ try {
9095
+ switch (action) {
9096
+ case "create":
9097
+ return await this.createTask(args, start);
9098
+ case "list":
9099
+ return await this.listTasks(start);
9100
+ case "cancel":
9101
+ return await this.cancelTask(args, start);
9102
+ case "pause":
9103
+ return await this.toggleTask(args, false, start);
9104
+ case "resume":
9105
+ return await this.toggleTask(args, true, start);
9106
+ case "logs":
9107
+ return await this.viewLogs(args, start);
9108
+ default:
9109
+ return {
9110
+ success: false,
9111
+ output: "",
9112
+ error: `Unknown action '${action}'. Use: create, list, cancel, pause, resume, logs`,
9113
+ durationMs: performance.now() - start
9114
+ };
9115
+ }
9116
+ } catch (err) {
9117
+ return {
9118
+ success: false,
9119
+ output: "",
9120
+ error: `Scheduler error: ${err instanceof Error ? err.message : String(err)}`,
9121
+ durationMs: performance.now() - start
9122
+ };
9123
+ }
9124
+ }
9125
+ async createTask(args, start) {
9126
+ const task = String(args["task"] ?? "");
9127
+ const schedule = String(args["schedule"] ?? "");
9128
+ if (!task)
9129
+ return { success: false, output: "", error: "task is required for create action", durationMs: performance.now() - start };
9130
+ if (!schedule)
9131
+ return { success: false, output: "", error: "schedule is required for create action", durationMs: performance.now() - start };
9132
+ const cronExpr = resolveSchedule(schedule);
9133
+ if (!cronExpr) {
9134
+ return {
9135
+ success: false,
9136
+ output: "",
9137
+ error: `Cannot parse schedule '${schedule}'. Use presets (daily, hourly, every 5 minutes), natural (in 30m, at 14:30), or cron (0 */2 * * *). Available presets: ${Object.keys(SCHEDULE_PRESETS).join(", ")}`,
9138
+ durationMs: performance.now() - start
9139
+ };
9140
+ }
9141
+ const id = `sched-${randomBytes2(4).toString("hex")}`;
9142
+ const oneShot = Boolean(args["one_shot"]);
9143
+ const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : void 0;
9144
+ const newTask = {
9145
+ id,
9146
+ task,
9147
+ schedule: cronExpr,
9148
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
9149
+ nextRunDescription: describeCron(cronExpr),
9150
+ enabled: true,
9151
+ runCount: 0,
9152
+ maxRuns,
9153
+ oneShot: oneShot || void 0
9154
+ };
9155
+ const store = await loadStore(this.workingDir);
9156
+ store.tasks.push(newTask);
9157
+ await saveStore(this.workingDir, store);
9158
+ installCronJob(newTask, this.workingDir);
9159
+ return {
9160
+ success: true,
9161
+ output: [
9162
+ `Scheduled task created:`,
9163
+ ` ID: ${id}`,
9164
+ ` Task: ${task}`,
9165
+ ` Schedule: ${describeCron(cronExpr)} (${cronExpr})`,
9166
+ oneShot ? ` Mode: one-shot (auto-removes after first run)` : "",
9167
+ maxRuns ? ` Max runs: ${maxRuns}` : "",
9168
+ ` Status: enabled`,
9169
+ ``,
9170
+ `The agent will launch automatically at the scheduled time.`,
9171
+ `Use scheduler(action='logs', id='${id}') to check execution history.`
9172
+ ].filter(Boolean).join("\n"),
9173
+ durationMs: performance.now() - start
9174
+ };
9175
+ }
9176
+ async listTasks(start) {
9177
+ const store = await loadStore(this.workingDir);
9178
+ const cronJobs = listCronJobs();
9179
+ if (store.tasks.length === 0) {
9180
+ return {
9181
+ success: true,
9182
+ output: "No scheduled tasks. Use scheduler(action='create', task='...', schedule='daily') to create one.",
9183
+ durationMs: performance.now() - start
9184
+ };
9185
+ }
9186
+ const lines = [`Scheduled Tasks (${store.tasks.length}):
9187
+ `];
9188
+ for (const t of store.tasks) {
9189
+ const status = t.enabled ? "enabled" : "PAUSED";
9190
+ const cronInstalled = cronJobs.some((j) => j.id === t.id);
9191
+ const cronStatus = cronInstalled ? "" : " [cron not installed]";
9192
+ lines.push(` [${t.id}] ${status}${cronStatus}`);
9193
+ lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
9194
+ lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
9195
+ lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
9196
+ if (t.lastRun)
9197
+ lines.push(` Last run: ${t.lastRun}`);
9198
+ lines.push("");
9199
+ }
9200
+ return {
9201
+ success: true,
9202
+ output: lines.join("\n"),
9203
+ durationMs: performance.now() - start
9204
+ };
9205
+ }
9206
+ async cancelTask(args, start) {
9207
+ const id = String(args["id"] ?? "");
9208
+ if (!id)
9209
+ return { success: false, output: "", error: "id is required for cancel action", durationMs: performance.now() - start };
9210
+ const store = await loadStore(this.workingDir);
9211
+ const idx = store.tasks.findIndex((t) => t.id === id);
9212
+ if (idx === -1)
9213
+ return { success: false, output: "", error: `No task found with ID '${id}'`, durationMs: performance.now() - start };
9214
+ const removed = store.tasks.splice(idx, 1)[0];
9215
+ await saveStore(this.workingDir, store);
9216
+ removeCronJob(id);
9217
+ return {
9218
+ success: true,
9219
+ output: `Cancelled and removed scheduled task '${id}': ${removed.task.slice(0, 80)}`,
9220
+ durationMs: performance.now() - start
9221
+ };
9222
+ }
9223
+ async toggleTask(args, enable, start) {
9224
+ const id = String(args["id"] ?? "");
9225
+ if (!id)
9226
+ return { success: false, output: "", error: "id is required", durationMs: performance.now() - start };
9227
+ const store = await loadStore(this.workingDir);
9228
+ const task = store.tasks.find((t) => t.id === id);
9229
+ if (!task)
9230
+ return { success: false, output: "", error: `No task found with ID '${id}'`, durationMs: performance.now() - start };
9231
+ task.enabled = enable;
9232
+ await saveStore(this.workingDir, store);
9233
+ if (enable) {
9234
+ installCronJob(task, this.workingDir);
9235
+ } else {
9236
+ removeCronJob(id);
9237
+ }
9238
+ return {
9239
+ success: true,
9240
+ output: `Task '${id}' ${enable ? "resumed" : "paused"}: ${task.task.slice(0, 80)}`,
9241
+ durationMs: performance.now() - start
9242
+ };
9243
+ }
9244
+ async viewLogs(args, start) {
9245
+ const id = String(args["id"] ?? "");
9246
+ if (!id)
9247
+ return { success: false, output: "", error: "id is required for logs action", durationMs: performance.now() - start };
9248
+ const logFile = resolve20(this.workingDir, ".oa", "scheduled", "logs", `${id}.log`);
9249
+ try {
9250
+ const raw = await readFile9(logFile, "utf-8");
9251
+ const truncated = raw.length > 1e4 ? "...(truncated)\n" + raw.slice(-1e4) : raw;
9252
+ return { success: true, output: `Logs for ${id}:
9253
+ ${truncated}`, durationMs: performance.now() - start };
9254
+ } catch {
9255
+ return { success: true, output: `No logs yet for task '${id}'.`, durationMs: performance.now() - start };
9256
+ }
9257
+ }
9258
+ };
9259
+ }
9260
+ });
9261
+
9262
+ // packages/execution/dist/tools/reminder.js
9263
+ import { readFile as readFile10, writeFile as writeFile9, mkdir as mkdir5 } from "node:fs/promises";
9264
+ import { resolve as resolve21, join as join23 } from "node:path";
9265
+ import { randomBytes as randomBytes3 } from "node:crypto";
9266
+ function parseDueTime(due) {
9267
+ const lower = due.toLowerCase().trim();
9268
+ const now = /* @__PURE__ */ new Date();
9269
+ const inMatch = lower.match(/^in\s+(\d+)\s*(m|min|mins|minutes?|h|hr|hrs|hours?|d|days?|w|weeks?)$/);
9270
+ if (inMatch) {
9271
+ const amount = parseInt(inMatch[1], 10);
9272
+ const unit = inMatch[2].charAt(0);
9273
+ const target = new Date(now);
9274
+ if (unit === "m")
9275
+ target.setMinutes(target.getMinutes() + amount);
9276
+ else if (unit === "h")
9277
+ target.setHours(target.getHours() + amount);
9278
+ else if (unit === "d")
9279
+ target.setDate(target.getDate() + amount);
9280
+ else if (unit === "w")
9281
+ target.setDate(target.getDate() + amount * 7);
9282
+ return { isoDate: target.toISOString(), description: `in ${amount}${unit}` };
9283
+ }
9284
+ if (lower === "tomorrow") {
9285
+ const target = new Date(now);
9286
+ target.setDate(target.getDate() + 1);
9287
+ target.setHours(9, 0, 0, 0);
9288
+ return { isoDate: target.toISOString(), description: "tomorrow morning" };
9289
+ }
9290
+ if (lower === "next week") {
9291
+ const target = new Date(now);
9292
+ target.setDate(target.getDate() + 7);
9293
+ target.setHours(9, 0, 0, 0);
9294
+ return { isoDate: target.toISOString(), description: "next week" };
9295
+ }
9296
+ const todayMatch = lower.match(/^(?:today\s+)?at\s+(\d{1,2}):(\d{2})$/);
9297
+ if (todayMatch) {
9298
+ const target = new Date(now);
9299
+ target.setHours(parseInt(todayMatch[1], 10), parseInt(todayMatch[2], 10), 0, 0);
9300
+ if (target <= now)
9301
+ target.setDate(target.getDate() + 1);
9302
+ return { isoDate: target.toISOString(), description: `at ${todayMatch[1]}:${todayMatch[2]}` };
9303
+ }
9304
+ if (lower === "now" || lower === "next startup" || lower === "startup") {
9305
+ return { isoDate: now.toISOString(), description: "next startup" };
9306
+ }
9307
+ const parsed = new Date(due);
9308
+ if (!isNaN(parsed.getTime())) {
9309
+ return { isoDate: parsed.toISOString(), description: parsed.toLocaleDateString() };
9310
+ }
9311
+ return null;
9312
+ }
9313
+ async function getStorePath(workingDir) {
9314
+ const dir = resolve21(workingDir, ".oa", "scheduled");
9315
+ await mkdir5(dir, { recursive: true });
9316
+ return join23(dir, STORE_FILE);
9317
+ }
9318
+ async function loadReminderStore(workingDir) {
9319
+ const storePath = await getStorePath(workingDir);
9320
+ try {
9321
+ const raw = await readFile10(storePath, "utf-8");
9322
+ return JSON.parse(raw);
9323
+ } catch {
9324
+ return { reminders: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9325
+ }
9326
+ }
9327
+ async function saveReminderStore(workingDir, store) {
9328
+ const storePath = await getStorePath(workingDir);
9329
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9330
+ await writeFile9(storePath, JSON.stringify(store, null, 2), "utf-8");
9331
+ }
9332
+ async function getDueReminders(workingDir) {
9333
+ const store = await loadReminderStore(workingDir);
9334
+ const now = /* @__PURE__ */ new Date();
9335
+ return store.reminders.filter((r) => {
9336
+ if (r.status !== "pending")
9337
+ return false;
9338
+ if (!r.dueAt)
9339
+ return true;
9340
+ return new Date(r.dueAt) <= now;
9341
+ });
9342
+ }
9343
+ async function markRemindersSeen(workingDir, ids) {
9344
+ const store = await loadReminderStore(workingDir);
9345
+ const idSet = new Set(ids);
9346
+ for (const r of store.reminders) {
9347
+ if (idSet.has(r.id) && r.status === "pending") {
9348
+ r.status = "seen";
9349
+ r.seenAt = (/* @__PURE__ */ new Date()).toISOString();
9350
+ }
9351
+ }
9352
+ await saveReminderStore(workingDir, store);
9353
+ }
9354
+ var STORE_FILE, ReminderTool;
9355
+ var init_reminder = __esm({
9356
+ "packages/execution/dist/tools/reminder.js"() {
9357
+ "use strict";
9358
+ STORE_FILE = "reminders.json";
9359
+ ReminderTool = class {
9360
+ name = "reminder";
9361
+ description = "Set reminders that surface at future agent startups. Leave instructions for your future self across sessions. Actions: 'set' a new reminder, 'list' all reminders, 'complete' or 'dismiss' a reminder, 'snooze' to postpone. Reminders appear automatically when the agent starts and can have due dates, priority levels, and tags for filtering.";
9362
+ parameters = {
9363
+ type: "object",
9364
+ properties: {
9365
+ action: {
9366
+ type: "string",
9367
+ enum: ["set", "list", "complete", "dismiss", "snooze"],
9368
+ description: "Reminder action to perform"
9369
+ },
9370
+ message: {
9371
+ type: "string",
9372
+ description: "The reminder message (for 'set')"
9373
+ },
9374
+ due: {
9375
+ type: "string",
9376
+ description: "When the reminder should surface: 'in 30m', 'tomorrow', 'at 14:30', 'next startup', 'in 2d' (for 'set' and 'snooze')"
9377
+ },
9378
+ priority: {
9379
+ type: "string",
9380
+ enum: ["low", "normal", "high", "critical"],
9381
+ description: "Priority level (default: normal)"
9382
+ },
9383
+ tags: {
9384
+ type: "string",
9385
+ description: "Comma-separated tags for categorization (e.g. 'deploy,auth,urgent')"
9386
+ },
9387
+ context: {
9388
+ type: "string",
9389
+ description: "Additional context: file paths, task details, debugging notes"
9390
+ },
9391
+ id: {
9392
+ type: "string",
9393
+ description: "Reminder ID (for 'complete', 'dismiss', 'snooze')"
9394
+ },
9395
+ filter: {
9396
+ type: "string",
9397
+ description: "Filter by status: 'pending', 'seen', 'all' (for 'list', default: 'pending')"
9398
+ }
9399
+ },
9400
+ required: ["action"]
9401
+ };
9402
+ workingDir;
9403
+ constructor(workingDir) {
9404
+ this.workingDir = workingDir;
9405
+ }
9406
+ async execute(args) {
9407
+ const start = performance.now();
9408
+ const action = String(args["action"] ?? "list");
9409
+ try {
9410
+ switch (action) {
9411
+ case "set":
9412
+ return await this.setReminder(args, start);
9413
+ case "list":
9414
+ return await this.listReminders(args, start);
9415
+ case "complete":
9416
+ return await this.updateStatus(args, "completed", start);
9417
+ case "dismiss":
9418
+ return await this.updateStatus(args, "dismissed", start);
9419
+ case "snooze":
9420
+ return await this.snoozeReminder(args, start);
9421
+ default:
9422
+ return {
9423
+ success: false,
9424
+ output: "",
9425
+ error: `Unknown action '${action}'. Use: set, list, complete, dismiss, snooze`,
9426
+ durationMs: performance.now() - start
9427
+ };
9428
+ }
9429
+ } catch (err) {
9430
+ return {
9431
+ success: false,
9432
+ output: "",
9433
+ error: `Reminder error: ${err instanceof Error ? err.message : String(err)}`,
9434
+ durationMs: performance.now() - start
9435
+ };
9436
+ }
9437
+ }
9438
+ async setReminder(args, start) {
9439
+ const message = String(args["message"] ?? "");
9440
+ if (!message)
9441
+ return { success: false, output: "", error: "message is required for set action", durationMs: performance.now() - start };
9442
+ const priority = args["priority"] ?? "normal";
9443
+ const tagsStr = args["tags"] ?? "";
9444
+ const tags = tagsStr ? tagsStr.split(",").map((t) => t.trim()).filter(Boolean) : [];
9445
+ const context = args["context"] ?? void 0;
9446
+ const dueStr = args["due"] ?? "";
9447
+ let dueAt;
9448
+ let dueDescription;
9449
+ if (dueStr) {
9450
+ const parsed = parseDueTime(dueStr);
9451
+ if (!parsed) {
9452
+ return {
9453
+ success: false,
9454
+ output: "",
9455
+ error: `Cannot parse due time '${dueStr}'. Try: 'in 30m', 'tomorrow', 'at 14:30', 'next startup', 'in 2d'`,
9456
+ durationMs: performance.now() - start
9457
+ };
9458
+ }
9459
+ dueAt = parsed.isoDate;
9460
+ dueDescription = parsed.description;
9461
+ }
9462
+ const id = `rem-${randomBytes3(4).toString("hex")}`;
9463
+ const entry = {
9464
+ id,
9465
+ message,
9466
+ priority,
9467
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
9468
+ dueAt,
9469
+ dueDescription,
9470
+ tags,
9471
+ status: "pending",
9472
+ context,
9473
+ source: "agent"
9474
+ };
9475
+ const store = await loadReminderStore(this.workingDir);
9476
+ store.reminders.push(entry);
9477
+ await saveReminderStore(this.workingDir, store);
9478
+ return {
9479
+ success: true,
9480
+ output: [
9481
+ `Reminder set:`,
9482
+ ` ID: ${id}`,
9483
+ ` Message: ${message}`,
9484
+ ` Priority: ${priority}`,
9485
+ dueDescription ? ` Due: ${dueDescription}` : ` Due: next startup`,
9486
+ tags.length > 0 ? ` Tags: ${tags.join(", ")}` : "",
9487
+ context ? ` Context: ${context.slice(0, 100)}` : "",
9488
+ ``,
9489
+ `This reminder will surface when the agent next starts${dueDescription ? ` (after ${dueDescription})` : ""}.`
9490
+ ].filter(Boolean).join("\n"),
9491
+ durationMs: performance.now() - start
9492
+ };
9493
+ }
9494
+ async listReminders(args, start) {
9495
+ const store = await loadReminderStore(this.workingDir);
9496
+ const filter = String(args["filter"] ?? "pending");
9497
+ let filtered = store.reminders;
9498
+ if (filter === "pending")
9499
+ filtered = filtered.filter((r) => r.status === "pending" || r.status === "seen");
9500
+ else if (filter !== "all")
9501
+ filtered = filtered.filter((r) => r.status === filter);
9502
+ if (filtered.length === 0) {
9503
+ return {
9504
+ success: true,
9505
+ output: filter === "all" ? "No reminders set. Use reminder(action='set', message='...') to create one." : `No ${filter} reminders. Use reminder(action='list', filter='all') to see all.`,
9506
+ durationMs: performance.now() - start
9507
+ };
9508
+ }
9509
+ const priorityOrder = { critical: 0, high: 1, normal: 2, low: 3 };
9510
+ filtered.sort((a, b) => (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2));
9511
+ const lines = [`Reminders (${filtered.length} ${filter}):
9512
+ `];
9513
+ for (const r of filtered) {
9514
+ const priorityIcon = r.priority === "critical" ? "[!!!]" : r.priority === "high" ? "[!!]" : r.priority === "low" ? "[.]" : "[*]";
9515
+ const statusLabel = r.status === "seen" ? " (seen)" : r.status === "completed" ? " (done)" : r.status === "dismissed" ? " (dismissed)" : "";
9516
+ lines.push(` ${priorityIcon} [${r.id}]${statusLabel}`);
9517
+ lines.push(` ${r.message}`);
9518
+ if (r.dueDescription)
9519
+ lines.push(` Due: ${r.dueDescription}`);
9520
+ if (r.tags.length > 0)
9521
+ lines.push(` Tags: ${r.tags.join(", ")}`);
9522
+ if (r.context)
9523
+ lines.push(` Context: ${r.context.slice(0, 80)}${r.context.length > 80 ? "..." : ""}`);
9524
+ lines.push("");
9525
+ }
9526
+ return {
9527
+ success: true,
9528
+ output: lines.join("\n"),
9529
+ durationMs: performance.now() - start
9530
+ };
9531
+ }
9532
+ async updateStatus(args, status, start) {
9533
+ const id = String(args["id"] ?? "");
9534
+ if (!id)
9535
+ return { success: false, output: "", error: "id is required", durationMs: performance.now() - start };
9536
+ const store = await loadReminderStore(this.workingDir);
9537
+ const reminder = store.reminders.find((r) => r.id === id);
9538
+ if (!reminder)
9539
+ return { success: false, output: "", error: `No reminder found with ID '${id}'`, durationMs: performance.now() - start };
9540
+ reminder.status = status;
9541
+ await saveReminderStore(this.workingDir, store);
9542
+ return {
9543
+ success: true,
9544
+ output: `Reminder '${id}' marked as ${status}: ${reminder.message.slice(0, 80)}`,
9545
+ durationMs: performance.now() - start
9546
+ };
9547
+ }
9548
+ async snoozeReminder(args, start) {
9549
+ const id = String(args["id"] ?? "");
9550
+ const due = String(args["due"] ?? "in 1h");
9551
+ if (!id)
9552
+ return { success: false, output: "", error: "id is required for snooze", durationMs: performance.now() - start };
9553
+ const parsed = parseDueTime(due);
9554
+ if (!parsed)
9555
+ return { success: false, output: "", error: `Cannot parse due time '${due}'`, durationMs: performance.now() - start };
9556
+ const store = await loadReminderStore(this.workingDir);
9557
+ const reminder = store.reminders.find((r) => r.id === id);
9558
+ if (!reminder)
9559
+ return { success: false, output: "", error: `No reminder found with ID '${id}'`, durationMs: performance.now() - start };
9560
+ reminder.status = "pending";
9561
+ reminder.dueAt = parsed.isoDate;
9562
+ reminder.dueDescription = parsed.description;
9563
+ reminder.seenAt = void 0;
9564
+ await saveReminderStore(this.workingDir, store);
9565
+ return {
9566
+ success: true,
9567
+ output: `Reminder '${id}' snoozed until ${parsed.description}: ${reminder.message.slice(0, 80)}`,
9568
+ durationMs: performance.now() - start
9569
+ };
9570
+ }
9571
+ };
9572
+ }
9573
+ });
9574
+
9575
+ // packages/execution/dist/tools/agenda.js
9576
+ import { readFile as readFile11, writeFile as writeFile10, mkdir as mkdir6 } from "node:fs/promises";
9577
+ import { resolve as resolve22, join as join24 } from "node:path";
9578
+ import { randomBytes as randomBytes4 } from "node:crypto";
9579
+ async function loadAttentionStore(workingDir) {
9580
+ const storePath = resolve22(workingDir, ".oa", "scheduled", "attention.json");
9581
+ try {
9582
+ const raw = await readFile11(storePath, "utf-8");
9583
+ return JSON.parse(raw);
9584
+ } catch {
9585
+ return { items: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9586
+ }
9587
+ }
9588
+ async function saveAttentionStore(workingDir, store) {
9589
+ const dir = resolve22(workingDir, ".oa", "scheduled");
9590
+ await mkdir6(dir, { recursive: true });
9591
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9592
+ await writeFile10(join24(dir, "attention.json"), JSON.stringify(store, null, 2), "utf-8");
9593
+ }
9594
+ async function getActiveAttentionItems(workingDir) {
9595
+ const store = await loadAttentionStore(workingDir);
9596
+ const now = /* @__PURE__ */ new Date();
9597
+ let changed = false;
9598
+ for (const item of store.items) {
9599
+ if (item.status === "active" && item.expiresAt && new Date(item.expiresAt) <= now) {
9600
+ item.status = "expired";
9601
+ changed = true;
9602
+ }
9603
+ }
9604
+ if (changed)
9605
+ await saveAttentionStore(workingDir, store);
9606
+ return store.items.filter((i) => i.status === "active");
9607
+ }
9608
+ var AgendaTool;
9609
+ var init_agenda = __esm({
9610
+ "packages/execution/dist/tools/agenda.js"() {
9611
+ "use strict";
9612
+ init_reminder();
9613
+ AgendaTool = class {
9614
+ name = "agenda";
9615
+ description = "View and manage the agent's temporal awareness: pending reminders, scheduled tasks, and attention items. Actions: 'view' the full agenda (default), 'flag' an item for attention, 'resolve' an attention item, 'startup_brief' to see what surfaces at next startup. Categories: followup (check back on something), review (code/PR review needed), monitor (watch for changes), investigate (dig deeper), decision (needs a call).";
9616
+ parameters = {
9617
+ type: "object",
9618
+ properties: {
9619
+ action: {
9620
+ type: "string",
9621
+ enum: ["view", "flag", "resolve", "startup_brief"],
9622
+ description: "Agenda action (default: view)"
9623
+ },
9624
+ title: {
9625
+ type: "string",
9626
+ description: "Title for the attention item (for 'flag')"
9627
+ },
9628
+ description: {
9629
+ type: "string",
9630
+ description: "Detailed description (for 'flag')"
9631
+ },
9632
+ category: {
9633
+ type: "string",
9634
+ enum: ["followup", "review", "monitor", "investigate", "decision"],
9635
+ description: "Category of attention item (for 'flag')"
9636
+ },
9637
+ priority: {
9638
+ type: "string",
9639
+ enum: ["low", "normal", "high", "critical"],
9640
+ description: "Priority level (for 'flag', default: normal)"
9641
+ },
9642
+ expires_in: {
9643
+ type: "string",
9644
+ description: "Auto-dismiss after duration: 'in 1h', 'in 7d', 'in 30d' (for 'flag')"
9645
+ },
9646
+ related_files: {
9647
+ type: "string",
9648
+ description: "Comma-separated related file paths (for 'flag')"
9649
+ },
9650
+ notes: {
9651
+ type: "string",
9652
+ description: "Working notes or context (for 'flag')"
9653
+ },
9654
+ id: {
9655
+ type: "string",
9656
+ description: "Item ID (for 'resolve')"
9657
+ }
9658
+ },
9659
+ required: []
9660
+ };
9661
+ workingDir;
9662
+ constructor(workingDir) {
9663
+ this.workingDir = workingDir;
9664
+ }
9665
+ async execute(args) {
9666
+ const start = performance.now();
9667
+ const action = String(args["action"] ?? "view");
9668
+ try {
9669
+ switch (action) {
9670
+ case "view":
9671
+ return await this.viewAgenda(start);
9672
+ case "flag":
9673
+ return await this.flagAttention(args, start);
9674
+ case "resolve":
9675
+ return await this.resolveItem(args, start);
9676
+ case "startup_brief":
9677
+ return await this.startupBrief(start);
9678
+ default:
9679
+ return {
9680
+ success: false,
9681
+ output: "",
9682
+ error: `Unknown action '${action}'. Use: view, flag, resolve, startup_brief`,
9683
+ durationMs: performance.now() - start
9684
+ };
9685
+ }
9686
+ } catch (err) {
9687
+ return {
9688
+ success: false,
9689
+ output: "",
9690
+ error: `Agenda error: ${err instanceof Error ? err.message : String(err)}`,
9691
+ durationMs: performance.now() - start
9692
+ };
9693
+ }
9694
+ }
9695
+ async viewAgenda(start) {
9696
+ const [dueReminders, activeAttention, schedStore] = await Promise.all([
9697
+ getDueReminders(this.workingDir),
9698
+ getActiveAttentionItems(this.workingDir),
9699
+ this.loadScheduleStore()
9700
+ ]);
9701
+ const sections = [];
9702
+ if (dueReminders.length > 0) {
9703
+ sections.push(`REMINDERS DUE (${dueReminders.length}):`);
9704
+ for (const r of dueReminders) {
9705
+ const icon = r.priority === "critical" ? "[!!!]" : r.priority === "high" ? "[!!]" : "[*]";
9706
+ sections.push(` ${icon} [${r.id}] ${r.message}`);
9707
+ if (r.context)
9708
+ sections.push(` Context: ${r.context.slice(0, 80)}`);
9709
+ }
9710
+ sections.push("");
9711
+ }
9712
+ if (activeAttention.length > 0) {
9713
+ sections.push(`ATTENTION ITEMS (${activeAttention.length}):`);
9714
+ const priorityOrder = { critical: 0, high: 1, normal: 2, low: 3 };
9715
+ activeAttention.sort((a, b) => (priorityOrder[a.priority] ?? 2) - (priorityOrder[b.priority] ?? 2));
9716
+ for (const item of activeAttention) {
9717
+ const icon = item.priority === "critical" ? "[!!!]" : item.priority === "high" ? "[!!]" : "[*]";
9718
+ sections.push(` ${icon} [${item.id}] (${item.category}) ${item.title}`);
9719
+ if (item.description)
9720
+ sections.push(` ${item.description.slice(0, 100)}`);
9721
+ if (item.relatedFiles?.length)
9722
+ sections.push(` Files: ${item.relatedFiles.join(", ")}`);
9723
+ if (item.expiresAt)
9724
+ sections.push(` Expires: ${new Date(item.expiresAt).toLocaleString()}`);
9725
+ }
9726
+ sections.push("");
9727
+ }
9728
+ const enabledTasks = schedStore.filter((t) => t.enabled);
9729
+ if (enabledTasks.length > 0) {
9730
+ sections.push(`SCHEDULED TASKS (${enabledTasks.length} active):`);
9731
+ for (const t of enabledTasks) {
9732
+ sections.push(` [${t.id}] ${t.nextRunDescription}: ${t.task.slice(0, 80)}`);
9733
+ }
9734
+ sections.push("");
9735
+ }
9736
+ if (sections.length === 0) {
9737
+ return {
9738
+ success: true,
9739
+ output: "Agenda is clear. No pending reminders, attention items, or scheduled tasks.",
9740
+ durationMs: performance.now() - start
9741
+ };
9742
+ }
9743
+ return {
9744
+ success: true,
9745
+ output: `AGENT AGENDA
9746
+ ${"\u2500".repeat(50)}
9747
+
9748
+ ${sections.join("\n")}`,
9749
+ durationMs: performance.now() - start
9750
+ };
9751
+ }
9752
+ async flagAttention(args, start) {
9753
+ const title = String(args["title"] ?? "");
9754
+ if (!title)
9755
+ return { success: false, output: "", error: "title is required for flag action", durationMs: performance.now() - start };
9756
+ const description = String(args["description"] ?? "");
9757
+ const category = args["category"] ?? "followup";
9758
+ const priority = args["priority"] ?? "normal";
9759
+ const notes = args["notes"] ?? void 0;
9760
+ const relatedFilesStr = args["related_files"] ?? "";
9761
+ const relatedFiles = relatedFilesStr ? relatedFilesStr.split(",").map((f) => f.trim()).filter(Boolean) : void 0;
9762
+ let expiresAt;
9763
+ const expiresIn = args["expires_in"] ?? "";
9764
+ if (expiresIn) {
9765
+ const match = expiresIn.match(/^(?:in\s+)?(\d+)\s*(m|h|d|w)/);
9766
+ if (match) {
9767
+ const target = /* @__PURE__ */ new Date();
9768
+ const amount = parseInt(match[1], 10);
9769
+ const unit = match[2];
9770
+ if (unit === "m")
9771
+ target.setMinutes(target.getMinutes() + amount);
9772
+ else if (unit === "h")
9773
+ target.setHours(target.getHours() + amount);
9774
+ else if (unit === "d")
9775
+ target.setDate(target.getDate() + amount);
9776
+ else if (unit === "w")
9777
+ target.setDate(target.getDate() + amount * 7);
9778
+ expiresAt = target.toISOString();
9779
+ }
9780
+ }
9781
+ const id = `attn-${randomBytes4(4).toString("hex")}`;
9782
+ const item = {
9783
+ id,
9784
+ title,
9785
+ description,
9786
+ category,
9787
+ priority,
9788
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
9789
+ expiresAt,
9790
+ relatedFiles,
9791
+ status: "active",
9792
+ notes
9793
+ };
9794
+ const store = await loadAttentionStore(this.workingDir);
9795
+ store.items.push(item);
9796
+ await saveAttentionStore(this.workingDir, store);
9797
+ return {
9798
+ success: true,
9799
+ output: [
9800
+ `Attention item flagged:`,
9801
+ ` ID: ${id}`,
9802
+ ` Title: ${title}`,
9803
+ ` Category: ${category}`,
9804
+ ` Priority: ${priority}`,
9805
+ expiresAt ? ` Expires: ${new Date(expiresAt).toLocaleString()}` : "",
9806
+ relatedFiles ? ` Files: ${relatedFiles.join(", ")}` : "",
9807
+ ``,
9808
+ `This item will appear in the agent's agenda until resolved or expired.`
9809
+ ].filter(Boolean).join("\n"),
9810
+ durationMs: performance.now() - start
9811
+ };
9812
+ }
9813
+ async resolveItem(args, start) {
9814
+ const id = String(args["id"] ?? "");
9815
+ if (!id)
9816
+ return { success: false, output: "", error: "id is required for resolve", durationMs: performance.now() - start };
9817
+ const store = await loadAttentionStore(this.workingDir);
9818
+ const item = store.items.find((i) => i.id === id);
9819
+ if (!item)
9820
+ return { success: false, output: "", error: `No attention item found with ID '${id}'`, durationMs: performance.now() - start };
9821
+ item.status = "resolved";
9822
+ item.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
9823
+ await saveAttentionStore(this.workingDir, store);
9824
+ return {
9825
+ success: true,
9826
+ output: `Attention item '${id}' resolved: ${item.title}`,
9827
+ durationMs: performance.now() - start
9828
+ };
9829
+ }
9830
+ async startupBrief(start) {
9831
+ const [dueReminders, activeAttention] = await Promise.all([
9832
+ getDueReminders(this.workingDir),
9833
+ getActiveAttentionItems(this.workingDir)
9834
+ ]);
9835
+ const criticalReminders = dueReminders.filter((r) => r.priority === "critical" || r.priority === "high");
9836
+ const criticalAttention = activeAttention.filter((a) => a.priority === "critical" || a.priority === "high");
9837
+ const lines = [];
9838
+ if (criticalReminders.length > 0 || criticalAttention.length > 0) {
9839
+ lines.push(`URGENT ITEMS REQUIRING IMMEDIATE ATTENTION:
9840
+ `);
9841
+ for (const r of criticalReminders) {
9842
+ lines.push(` [REMINDER] ${r.message}`);
9843
+ if (r.context)
9844
+ lines.push(` Context: ${r.context}`);
9845
+ }
9846
+ for (const a of criticalAttention) {
9847
+ lines.push(` [${a.category.toUpperCase()}] ${a.title}: ${a.description}`);
9848
+ if (a.relatedFiles?.length)
9849
+ lines.push(` Files: ${a.relatedFiles.join(", ")}`);
9850
+ }
9851
+ lines.push("");
9852
+ }
9853
+ const normalReminders = dueReminders.filter((r) => r.priority !== "critical" && r.priority !== "high");
9854
+ const normalAttention = activeAttention.filter((a) => a.priority !== "critical" && a.priority !== "high");
9855
+ if (normalReminders.length > 0) {
9856
+ lines.push(`Pending reminders: ${normalReminders.length}`);
9857
+ for (const r of normalReminders.slice(0, 5)) {
9858
+ lines.push(` - ${r.message}`);
9859
+ }
9860
+ if (normalReminders.length > 5)
9861
+ lines.push(` ... and ${normalReminders.length - 5} more`);
9862
+ lines.push("");
9863
+ }
9864
+ if (normalAttention.length > 0) {
9865
+ lines.push(`Active attention items: ${normalAttention.length}`);
9866
+ for (const a of normalAttention.slice(0, 5)) {
9867
+ lines.push(` - (${a.category}) ${a.title}`);
9868
+ }
9869
+ if (normalAttention.length > 5)
9870
+ lines.push(` ... and ${normalAttention.length - 5} more`);
9871
+ }
9872
+ if (lines.length === 0) {
9873
+ return {
9874
+ success: true,
9875
+ output: "No pending items for this startup. Agenda is clear.",
9876
+ durationMs: performance.now() - start
9877
+ };
9878
+ }
9879
+ return {
9880
+ success: true,
9881
+ output: lines.join("\n"),
9882
+ durationMs: performance.now() - start
9883
+ };
9884
+ }
9885
+ async loadScheduleStore() {
9886
+ try {
9887
+ const storePath = resolve22(this.workingDir, ".oa", "scheduled", "tasks.json");
9888
+ const raw = await readFile11(storePath, "utf-8");
9889
+ const store = JSON.parse(raw);
9890
+ return store.tasks ?? [];
9891
+ } catch {
9892
+ return [];
9893
+ }
9894
+ }
9895
+ };
9896
+ }
9897
+ });
9898
+
8653
9899
  // packages/execution/dist/shellRunner.js
8654
9900
  var init_shellRunner = __esm({
8655
9901
  "packages/execution/dist/shellRunner.js"() {
@@ -8765,6 +10011,10 @@ var init_dist2 = __esm({
8765
10011
  init_ocr_pdf();
8766
10012
  init_pdf_to_text();
8767
10013
  init_ocr_image_advanced();
10014
+ init_browser_action();
10015
+ init_scheduler();
10016
+ init_reminder();
10017
+ init_agenda();
8768
10018
  init_system_deps();
8769
10019
  init_shellRunner();
8770
10020
  init_gitWorktree();
@@ -9880,8 +11130,8 @@ var init_code_retriever = __esm({
9880
11130
  });
9881
11131
  }
9882
11132
  async getFileContent(filePath, startLine, endLine) {
9883
- const { readFile: readFile12 } = await import("node:fs/promises");
9884
- const content = await readFile12(filePath, "utf-8");
11133
+ const { readFile: readFile15 } = await import("node:fs/promises");
11134
+ const content = await readFile15(filePath, "utf-8");
9885
11135
  if (startLine === void 0)
9886
11136
  return content;
9887
11137
  const lines = content.split("\n");
@@ -9896,8 +11146,8 @@ var init_code_retriever = __esm({
9896
11146
  // packages/retrieval/dist/lexicalSearch.js
9897
11147
  import { execFile as execFile5 } from "node:child_process";
9898
11148
  import { promisify as promisify4 } from "node:util";
9899
- import { readFile as readFile9, readdir as readdir3, stat as stat3 } from "node:fs/promises";
9900
- import { join as join21, extname as extname7 } from "node:path";
11149
+ import { readFile as readFile12, readdir as readdir3, stat as stat3 } from "node:fs/promises";
11150
+ import { join as join25, extname as extname7 } from "node:path";
9901
11151
  async function searchByPath(pathPattern, options) {
9902
11152
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
9903
11153
  const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
@@ -10002,7 +11252,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
10002
11252
  if (results.length >= maxMatches)
10003
11253
  break;
10004
11254
  try {
10005
- const content = await readFile9(filePath, "utf-8");
11255
+ const content = await readFile12(filePath, "utf-8");
10006
11256
  const contentLines = content.split("\n");
10007
11257
  for (let i = 0; i < contentLines.length; i++) {
10008
11258
  if (results.length >= maxMatches)
@@ -10039,7 +11289,7 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
10039
11289
  continue;
10040
11290
  if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
10041
11291
  continue;
10042
- const absPath = join21(dir, entry.name);
11292
+ const absPath = join25(dir, entry.name);
10043
11293
  if (entry.isDirectory()) {
10044
11294
  await walkForFiles(rootDir, absPath, excludeGlobs, results);
10045
11295
  } else if (entry.isFile()) {
@@ -10345,8 +11595,8 @@ var init_graphExpand = __esm({
10345
11595
  });
10346
11596
 
10347
11597
  // packages/retrieval/dist/snippetPacker.js
10348
- import { readFile as readFile10 } from "node:fs/promises";
10349
- import { join as join22 } from "node:path";
11598
+ import { readFile as readFile13 } from "node:fs/promises";
11599
+ import { join as join26 } from "node:path";
10350
11600
  async function packSnippets(requests, opts = {}) {
10351
11601
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
10352
11602
  const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
@@ -10372,10 +11622,10 @@ async function packSnippets(requests, opts = {}) {
10372
11622
  return { packed, dropped, totalTokens };
10373
11623
  }
10374
11624
  async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
10375
- const absPath = req.filePath.startsWith("/") ? req.filePath : join22(repoRoot, req.filePath);
11625
+ const absPath = req.filePath.startsWith("/") ? req.filePath : join26(repoRoot, req.filePath);
10376
11626
  let content;
10377
11627
  try {
10378
- content = await readFile10(absPath, "utf-8");
11628
+ content = await readFile13(absPath, "utf-8");
10379
11629
  } catch {
10380
11630
  return null;
10381
11631
  }
@@ -12079,8 +13329,8 @@ Rules:
12079
13329
  async waitIfPaused() {
12080
13330
  if (!this._paused)
12081
13331
  return true;
12082
- await new Promise((resolve23) => {
12083
- this._pauseResolve = resolve23;
13332
+ await new Promise((resolve26) => {
13333
+ this._pauseResolve = resolve26;
12084
13334
  });
12085
13335
  return !this.aborted;
12086
13336
  }
@@ -12298,7 +13548,8 @@ Integrate this guidance into your current approach. Continue working on the task
12298
13548
  "task_output",
12299
13549
  "image_read",
12300
13550
  "screenshot",
12301
- "ocr"
13551
+ "ocr",
13552
+ "browser_action"
12302
13553
  ]);
12303
13554
  const executeSingle = async (tc) => {
12304
13555
  if (this.aborted)
@@ -12659,14 +13910,14 @@ ${result.output}`;
12659
13910
  waitForSudoPassword(timeoutMs = 12e4) {
12660
13911
  if (this._sudoPassword)
12661
13912
  return Promise.resolve(this._sudoPassword);
12662
- return new Promise((resolve23) => {
13913
+ return new Promise((resolve26) => {
12663
13914
  const timer = setTimeout(() => {
12664
13915
  this._sudoResolve = null;
12665
- resolve23(null);
13916
+ resolve26(null);
12666
13917
  }, timeoutMs);
12667
13918
  this._sudoResolve = (pw) => {
12668
13919
  clearTimeout(timer);
12669
- resolve23(pw);
13920
+ resolve26(pw);
12670
13921
  };
12671
13922
  });
12672
13923
  }
@@ -12789,8 +14040,8 @@ ${marker}` : marker);
12789
14040
  return;
12790
14041
  try {
12791
14042
  const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync12 } = __require("node:fs");
12792
- const { join: join37 } = __require("node:path");
12793
- const sessionDir = join37(this._workingDirectory, ".oa", "session", this._sessionId);
14043
+ const { join: join41 } = __require("node:path");
14044
+ const sessionDir = join41(this._workingDirectory, ".oa", "session", this._sessionId);
12794
14045
  mkdirSync13(sessionDir, { recursive: true });
12795
14046
  const checkpoint = {
12796
14047
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12803,7 +14054,7 @@ ${marker}` : marker);
12803
14054
  memexEntryCount: this._memexArchive.size,
12804
14055
  fileRegistrySize: this._fileRegistry.size
12805
14056
  };
12806
- writeFileSync12(join37(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
14057
+ writeFileSync12(join41(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
12807
14058
  } catch {
12808
14059
  }
12809
14060
  }
@@ -13759,6 +15010,7 @@ ${transcript}`
13759
15010
  temperature: request.temperature,
13760
15011
  max_tokens: request.maxTokens,
13761
15012
  stream: true,
15013
+ stream_options: { include_usage: true },
13762
15014
  think: true
13763
15015
  };
13764
15016
  const resp = await fetch(`${this.baseUrl}/v1/chat/completions`, {
@@ -14340,11 +15592,11 @@ var init_dist5 = __esm({
14340
15592
  });
14341
15593
 
14342
15594
  // packages/cli/dist/tui/listen.js
14343
- import { spawn as spawn7, execSync as execSync15 } from "node:child_process";
14344
- import { existsSync as existsSync18, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
14345
- import { join as join23, dirname as dirname8 } from "node:path";
15595
+ import { spawn as spawn8, execSync as execSync17 } from "node:child_process";
15596
+ import { existsSync as existsSync19, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
15597
+ import { join as join27, dirname as dirname9 } from "node:path";
14346
15598
  import { homedir as homedir8 } from "node:os";
14347
- import { fileURLToPath as fileURLToPath5 } from "node:url";
15599
+ import { fileURLToPath as fileURLToPath6 } from "node:url";
14348
15600
  import { EventEmitter } from "node:events";
14349
15601
  import { createInterface as createInterface2 } from "node:readline";
14350
15602
  function isAudioPath(path) {
@@ -14362,7 +15614,7 @@ function findMicCaptureCommand() {
14362
15614
  const platform4 = process.platform;
14363
15615
  if (platform4 === "linux") {
14364
15616
  try {
14365
- execSync15("which arecord", { stdio: "pipe" });
15617
+ execSync17("which arecord", { stdio: "pipe" });
14366
15618
  return {
14367
15619
  cmd: "arecord",
14368
15620
  args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
@@ -14372,7 +15624,7 @@ function findMicCaptureCommand() {
14372
15624
  }
14373
15625
  if (platform4 === "darwin") {
14374
15626
  try {
14375
- execSync15("which sox", { stdio: "pipe" });
15627
+ execSync17("which sox", { stdio: "pipe" });
14376
15628
  return {
14377
15629
  cmd: "sox",
14378
15630
  args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
@@ -14381,7 +15633,7 @@ function findMicCaptureCommand() {
14381
15633
  }
14382
15634
  }
14383
15635
  try {
14384
- execSync15("which ffmpeg", { stdio: "pipe" });
15636
+ execSync17("which ffmpeg", { stdio: "pipe" });
14385
15637
  if (platform4 === "linux") {
14386
15638
  return {
14387
15639
  cmd: "ffmpeg",
@@ -14426,41 +15678,41 @@ function findMicCaptureCommand() {
14426
15678
  return null;
14427
15679
  }
14428
15680
  function findLiveWhisperScript() {
14429
- const thisDir = dirname8(fileURLToPath5(import.meta.url));
15681
+ const thisDir = dirname9(fileURLToPath6(import.meta.url));
14430
15682
  const candidates = [
14431
- join23(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
14432
- join23(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
14433
- join23(thisDir, "../../execution/scripts/live-whisper.py"),
15683
+ join27(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
15684
+ join27(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
15685
+ join27(thisDir, "../../execution/scripts/live-whisper.py"),
14434
15686
  // npm install layout — scripts bundled alongside dist
14435
- join23(thisDir, "../scripts/live-whisper.py"),
14436
- join23(thisDir, "../../scripts/live-whisper.py")
15687
+ join27(thisDir, "../scripts/live-whisper.py"),
15688
+ join27(thisDir, "../../scripts/live-whisper.py")
14437
15689
  ];
14438
15690
  for (const p of candidates) {
14439
- if (existsSync18(p))
15691
+ if (existsSync19(p))
14440
15692
  return p;
14441
15693
  }
14442
15694
  try {
14443
- const globalRoot = execSync15("npm root -g", {
15695
+ const globalRoot = execSync17("npm root -g", {
14444
15696
  encoding: "utf-8",
14445
15697
  timeout: 5e3,
14446
15698
  stdio: ["pipe", "pipe", "pipe"]
14447
15699
  }).trim();
14448
15700
  const candidates2 = [
14449
- join23(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
14450
- join23(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
15701
+ join27(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
15702
+ join27(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
14451
15703
  ];
14452
15704
  for (const p of candidates2) {
14453
- if (existsSync18(p))
15705
+ if (existsSync19(p))
14454
15706
  return p;
14455
15707
  }
14456
15708
  } catch {
14457
15709
  }
14458
- const nvmBase = join23(homedir8(), ".nvm", "versions", "node");
14459
- if (existsSync18(nvmBase)) {
15710
+ const nvmBase = join27(homedir8(), ".nvm", "versions", "node");
15711
+ if (existsSync19(nvmBase)) {
14460
15712
  try {
14461
15713
  for (const ver of readdirSync6(nvmBase)) {
14462
- const p = join23(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
14463
- if (existsSync18(p))
15714
+ const p = join27(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
15715
+ if (existsSync19(p))
14464
15716
  return p;
14465
15717
  }
14466
15718
  } catch {
@@ -14473,21 +15725,21 @@ function ensureTranscribeCliBackground() {
14473
15725
  return;
14474
15726
  _bgInstallPromise = (async () => {
14475
15727
  try {
14476
- const globalRoot = execSync15("npm root -g", {
15728
+ const globalRoot = execSync17("npm root -g", {
14477
15729
  encoding: "utf-8",
14478
15730
  timeout: 5e3,
14479
15731
  stdio: ["pipe", "pipe", "pipe"]
14480
15732
  }).trim();
14481
- if (existsSync18(join23(globalRoot, "transcribe-cli", "dist", "index.js"))) {
15733
+ if (existsSync19(join27(globalRoot, "transcribe-cli", "dist", "index.js"))) {
14482
15734
  return true;
14483
15735
  }
14484
15736
  } catch {
14485
15737
  }
14486
15738
  try {
14487
15739
  const { exec } = await import("node:child_process");
14488
- return new Promise((resolve23) => {
15740
+ return new Promise((resolve26) => {
14489
15741
  exec("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
14490
- resolve23(!err);
15742
+ resolve26(!err);
14491
15743
  });
14492
15744
  });
14493
15745
  } catch {
@@ -14540,11 +15792,11 @@ var init_listen = __esm({
14540
15792
  return this._ready;
14541
15793
  }
14542
15794
  async start() {
14543
- return new Promise((resolve23, reject) => {
15795
+ return new Promise((resolve26, reject) => {
14544
15796
  const timeout = setTimeout(() => {
14545
15797
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
14546
15798
  }, 3e5);
14547
- this.process = spawn7("python3", [
15799
+ this.process = spawn8("python3", [
14548
15800
  this.scriptPath,
14549
15801
  "--model",
14550
15802
  this.model,
@@ -14568,7 +15820,7 @@ var init_listen = __esm({
14568
15820
  this._ready = true;
14569
15821
  clearTimeout(timeout);
14570
15822
  this.emit("ready");
14571
- resolve23();
15823
+ resolve26();
14572
15824
  break;
14573
15825
  case "transcript":
14574
15826
  this.emit("transcript", {
@@ -14673,7 +15925,7 @@ var init_listen = __esm({
14673
15925
  }
14674
15926
  if (!this.transcribeCliAvailable) {
14675
15927
  try {
14676
- execSync15("which transcribe-cli", { stdio: "pipe" });
15928
+ execSync17("which transcribe-cli", { stdio: "pipe" });
14677
15929
  this.transcribeCliAvailable = true;
14678
15930
  } catch {
14679
15931
  this.transcribeCliAvailable = false;
@@ -14690,29 +15942,29 @@ var init_listen = __esm({
14690
15942
  } catch {
14691
15943
  }
14692
15944
  try {
14693
- const globalRoot = execSync15("npm root -g", {
15945
+ const globalRoot = execSync17("npm root -g", {
14694
15946
  encoding: "utf-8",
14695
15947
  timeout: 5e3,
14696
15948
  stdio: ["pipe", "pipe", "pipe"]
14697
15949
  }).trim();
14698
- const tcPath = join23(globalRoot, "transcribe-cli");
14699
- if (existsSync18(join23(tcPath, "dist", "index.js"))) {
15950
+ const tcPath = join27(globalRoot, "transcribe-cli");
15951
+ if (existsSync19(join27(tcPath, "dist", "index.js"))) {
14700
15952
  const { createRequire: createRequire4 } = await import("node:module");
14701
15953
  const req = createRequire4(import.meta.url);
14702
- return req(join23(tcPath, "dist", "index.js"));
15954
+ return req(join27(tcPath, "dist", "index.js"));
14703
15955
  }
14704
15956
  } catch {
14705
15957
  }
14706
- const nvmBase = join23(homedir8(), ".nvm", "versions", "node");
14707
- if (existsSync18(nvmBase)) {
15958
+ const nvmBase = join27(homedir8(), ".nvm", "versions", "node");
15959
+ if (existsSync19(nvmBase)) {
14708
15960
  try {
14709
15961
  const { readdirSync: readdirSync11 } = await import("node:fs");
14710
15962
  for (const ver of readdirSync11(nvmBase)) {
14711
- const tcPath = join23(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
14712
- if (existsSync18(join23(tcPath, "dist", "index.js"))) {
15963
+ const tcPath = join27(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
15964
+ if (existsSync19(join27(tcPath, "dist", "index.js"))) {
14713
15965
  const { createRequire: createRequire4 } = await import("node:module");
14714
15966
  const req = createRequire4(import.meta.url);
14715
- return req(join23(tcPath, "dist", "index.js"));
15967
+ return req(join27(tcPath, "dist", "index.js"));
14716
15968
  }
14717
15969
  }
14718
15970
  } catch {
@@ -14740,7 +15992,7 @@ var init_listen = __esm({
14740
15992
  }
14741
15993
  if (!tc) {
14742
15994
  try {
14743
- execSync15("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
15995
+ execSync17("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
14744
15996
  this.transcribeCliAvailable = null;
14745
15997
  tc = await this.loadTranscribeCli();
14746
15998
  } catch {
@@ -14772,11 +16024,11 @@ var init_listen = __esm({
14772
16024
  this.liveTranscriber.on("error", (err) => {
14773
16025
  this.emit("error", err);
14774
16026
  });
14775
- await new Promise((resolve23, reject) => {
16027
+ await new Promise((resolve26, reject) => {
14776
16028
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
14777
16029
  this.liveTranscriber.on("ready", () => {
14778
16030
  clearTimeout(timeout);
14779
- resolve23();
16031
+ resolve26();
14780
16032
  });
14781
16033
  this.liveTranscriber.on("error", (err) => {
14782
16034
  clearTimeout(timeout);
@@ -14826,7 +16078,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
14826
16078
  return `Failed to start live transcription: ${msg}${tcHint}`;
14827
16079
  }
14828
16080
  }
14829
- this.micProcess = spawn7(micCmd.cmd, micCmd.args, {
16081
+ this.micProcess = spawn8(micCmd.cmd, micCmd.args, {
14830
16082
  stdio: ["pipe", "pipe", "pipe"],
14831
16083
  env: { ...process.env }
14832
16084
  });
@@ -14921,7 +16173,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
14921
16173
  }
14922
16174
  if (!tc) {
14923
16175
  try {
14924
- execSync15("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
16176
+ execSync17("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
14925
16177
  this.transcribeCliAvailable = null;
14926
16178
  tc = await this.loadTranscribeCli();
14927
16179
  } catch {
@@ -14938,9 +16190,9 @@ transcribe-cli error: ${transcribeCliError}` : "";
14938
16190
  });
14939
16191
  if (outputDir) {
14940
16192
  const { basename: basename14 } = await import("node:path");
14941
- const transcriptDir = join23(outputDir, ".oa", "transcripts");
16193
+ const transcriptDir = join27(outputDir, ".oa", "transcripts");
14942
16194
  mkdirSync5(transcriptDir, { recursive: true });
14943
- const outFile = join23(transcriptDir, `${basename14(filePath)}.txt`);
16195
+ const outFile = join27(transcriptDir, `${basename14(filePath)}.txt`);
14944
16196
  writeFileSync5(outFile, result.text, "utf-8");
14945
16197
  }
14946
16198
  return {
@@ -16220,8 +17472,8 @@ Approach this task thoughtfully:
16220
17472
  });
16221
17473
 
16222
17474
  // packages/prompts/dist/index.js
16223
- import { join as join24, dirname as dirname9 } from "node:path";
16224
- import { fileURLToPath as fileURLToPath6 } from "node:url";
17475
+ import { join as join28, dirname as dirname10 } from "node:path";
17476
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
16225
17477
  var _dir, _packageRoot;
16226
17478
  var init_dist6 = __esm({
16227
17479
  "packages/prompts/dist/index.js"() {
@@ -16230,25 +17482,25 @@ var init_dist6 = __esm({
16230
17482
  init_render2();
16231
17483
  init_task_templates();
16232
17484
  init_render2();
16233
- _dir = dirname9(fileURLToPath6(import.meta.url));
16234
- _packageRoot = join24(_dir, "..");
17485
+ _dir = dirname10(fileURLToPath7(import.meta.url));
17486
+ _packageRoot = join28(_dir, "..");
16235
17487
  }
16236
17488
  });
16237
17489
 
16238
17490
  // packages/cli/dist/tui/oa-directory.js
16239
- import { existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
16240
- import { join as join25, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
17491
+ import { existsSync as existsSync20, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
17492
+ import { join as join29, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
16241
17493
  import { homedir as homedir9 } from "node:os";
16242
17494
  function initOaDirectory(repoRoot) {
16243
- const oaPath = join25(repoRoot, OA_DIR);
17495
+ const oaPath = join29(repoRoot, OA_DIR);
16244
17496
  for (const sub of SUBDIRS) {
16245
- mkdirSync6(join25(oaPath, sub), { recursive: true });
17497
+ mkdirSync6(join29(oaPath, sub), { recursive: true });
16246
17498
  }
16247
17499
  try {
16248
- const gitignorePath = join25(repoRoot, ".gitignore");
17500
+ const gitignorePath = join29(repoRoot, ".gitignore");
16249
17501
  const settingsPattern = ".oa/settings.json";
16250
- if (existsSync19(gitignorePath)) {
16251
- const content = readFileSync13(gitignorePath, "utf-8");
17502
+ if (existsSync20(gitignorePath)) {
17503
+ const content = readFileSync14(gitignorePath, "utf-8");
16252
17504
  if (!content.includes(settingsPattern)) {
16253
17505
  writeFileSync6(gitignorePath, content.trimEnd() + "\n" + settingsPattern + "\n", "utf-8");
16254
17506
  }
@@ -16258,41 +17510,41 @@ function initOaDirectory(repoRoot) {
16258
17510
  return oaPath;
16259
17511
  }
16260
17512
  function hasOaDirectory(repoRoot) {
16261
- return existsSync19(join25(repoRoot, OA_DIR, "index"));
17513
+ return existsSync20(join29(repoRoot, OA_DIR, "index"));
16262
17514
  }
16263
17515
  function loadProjectSettings(repoRoot) {
16264
- const settingsPath = join25(repoRoot, OA_DIR, "settings.json");
17516
+ const settingsPath = join29(repoRoot, OA_DIR, "settings.json");
16265
17517
  try {
16266
- if (existsSync19(settingsPath)) {
16267
- return JSON.parse(readFileSync13(settingsPath, "utf-8"));
17518
+ if (existsSync20(settingsPath)) {
17519
+ return JSON.parse(readFileSync14(settingsPath, "utf-8"));
16268
17520
  }
16269
17521
  } catch {
16270
17522
  }
16271
17523
  return {};
16272
17524
  }
16273
17525
  function saveProjectSettings(repoRoot, settings) {
16274
- const oaPath = join25(repoRoot, OA_DIR);
17526
+ const oaPath = join29(repoRoot, OA_DIR);
16275
17527
  mkdirSync6(oaPath, { recursive: true });
16276
17528
  const existing = loadProjectSettings(repoRoot);
16277
17529
  const merged = { ...existing, ...settings };
16278
- writeFileSync6(join25(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
17530
+ writeFileSync6(join29(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
16279
17531
  }
16280
17532
  function loadGlobalSettings() {
16281
- const settingsPath = join25(homedir9(), ".open-agents", "settings.json");
17533
+ const settingsPath = join29(homedir9(), ".open-agents", "settings.json");
16282
17534
  try {
16283
- if (existsSync19(settingsPath)) {
16284
- return JSON.parse(readFileSync13(settingsPath, "utf-8"));
17535
+ if (existsSync20(settingsPath)) {
17536
+ return JSON.parse(readFileSync14(settingsPath, "utf-8"));
16285
17537
  }
16286
17538
  } catch {
16287
17539
  }
16288
17540
  return {};
16289
17541
  }
16290
17542
  function saveGlobalSettings(settings) {
16291
- const dir = join25(homedir9(), ".open-agents");
17543
+ const dir = join29(homedir9(), ".open-agents");
16292
17544
  mkdirSync6(dir, { recursive: true });
16293
17545
  const existing = loadGlobalSettings();
16294
17546
  const merged = { ...existing, ...settings };
16295
- writeFileSync6(join25(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
17547
+ writeFileSync6(join29(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
16296
17548
  }
16297
17549
  function resolveSettings(repoRoot) {
16298
17550
  const global = loadGlobalSettings();
@@ -16307,12 +17559,12 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
16307
17559
  while (dir && !visited.has(dir)) {
16308
17560
  visited.add(dir);
16309
17561
  for (const name of CONTEXT_FILES) {
16310
- const filePath = join25(dir, name);
17562
+ const filePath = join29(dir, name);
16311
17563
  const normalizedName = name.toLowerCase();
16312
- if (existsSync19(filePath) && !seen.has(filePath)) {
17564
+ if (existsSync20(filePath) && !seen.has(filePath)) {
16313
17565
  seen.add(filePath);
16314
17566
  try {
16315
- let content = readFileSync13(filePath, "utf-8");
17567
+ let content = readFileSync14(filePath, "utf-8");
16316
17568
  if (content.length > maxContentLen) {
16317
17569
  content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
16318
17570
  }
@@ -16326,11 +17578,11 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
16326
17578
  }
16327
17579
  }
16328
17580
  }
16329
- const projectMap = join25(dir, OA_DIR, "context", "project-map.md");
16330
- if (existsSync19(projectMap) && !seen.has(projectMap)) {
17581
+ const projectMap = join29(dir, OA_DIR, "context", "project-map.md");
17582
+ if (existsSync20(projectMap) && !seen.has(projectMap)) {
16331
17583
  seen.add(projectMap);
16332
17584
  try {
16333
- let content = readFileSync13(projectMap, "utf-8");
17585
+ let content = readFileSync14(projectMap, "utf-8");
16334
17586
  if (content.length > maxContentLen) {
16335
17587
  content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
16336
17588
  }
@@ -16342,7 +17594,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
16342
17594
  } catch {
16343
17595
  }
16344
17596
  }
16345
- const parent = join25(dir, "..");
17597
+ const parent = join29(dir, "..");
16346
17598
  if (parent === dir)
16347
17599
  break;
16348
17600
  dir = parent;
@@ -16360,9 +17612,9 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
16360
17612
  return found;
16361
17613
  }
16362
17614
  function readIndexMeta(repoRoot) {
16363
- const metaPath = join25(repoRoot, OA_DIR, "index", "meta.json");
17615
+ const metaPath = join29(repoRoot, OA_DIR, "index", "meta.json");
16364
17616
  try {
16365
- return JSON.parse(readFileSync13(metaPath, "utf-8"));
17617
+ return JSON.parse(readFileSync14(metaPath, "utf-8"));
16366
17618
  } catch {
16367
17619
  return null;
16368
17620
  }
@@ -16413,28 +17665,28 @@ ${tree}\`\`\`
16413
17665
  sections.push("");
16414
17666
  }
16415
17667
  const content = sections.join("\n");
16416
- const contextDir = join25(repoRoot, OA_DIR, "context");
17668
+ const contextDir = join29(repoRoot, OA_DIR, "context");
16417
17669
  mkdirSync6(contextDir, { recursive: true });
16418
- writeFileSync6(join25(contextDir, "project-map.md"), content, "utf-8");
17670
+ writeFileSync6(join29(contextDir, "project-map.md"), content, "utf-8");
16419
17671
  return content;
16420
17672
  }
16421
17673
  function saveSession(repoRoot, session) {
16422
- const historyDir = join25(repoRoot, OA_DIR, "history");
17674
+ const historyDir = join29(repoRoot, OA_DIR, "history");
16423
17675
  mkdirSync6(historyDir, { recursive: true });
16424
- writeFileSync6(join25(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
17676
+ writeFileSync6(join29(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
16425
17677
  }
16426
17678
  function loadRecentSessions(repoRoot, limit = 5) {
16427
- const historyDir = join25(repoRoot, OA_DIR, "history");
16428
- if (!existsSync19(historyDir))
17679
+ const historyDir = join29(repoRoot, OA_DIR, "history");
17680
+ if (!existsSync20(historyDir))
16429
17681
  return [];
16430
17682
  try {
16431
17683
  const files = readdirSync7(historyDir).filter((f) => f.endsWith(".json") && f !== "pending-task.json").map((f) => {
16432
- const stat5 = statSync9(join25(historyDir, f));
17684
+ const stat5 = statSync9(join29(historyDir, f));
16433
17685
  return { file: f, mtime: stat5.mtimeMs };
16434
17686
  }).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
16435
17687
  return files.map((f) => {
16436
17688
  try {
16437
- return JSON.parse(readFileSync13(join25(historyDir, f.file), "utf-8"));
17689
+ return JSON.parse(readFileSync14(join29(historyDir, f.file), "utf-8"));
16438
17690
  } catch {
16439
17691
  return null;
16440
17692
  }
@@ -16444,16 +17696,16 @@ function loadRecentSessions(repoRoot, limit = 5) {
16444
17696
  }
16445
17697
  }
16446
17698
  function savePendingTask(repoRoot, task) {
16447
- const historyDir = join25(repoRoot, OA_DIR, "history");
17699
+ const historyDir = join29(repoRoot, OA_DIR, "history");
16448
17700
  mkdirSync6(historyDir, { recursive: true });
16449
- writeFileSync6(join25(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
17701
+ writeFileSync6(join29(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
16450
17702
  }
16451
17703
  function loadPendingTask(repoRoot) {
16452
- const filePath = join25(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
17704
+ const filePath = join29(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
16453
17705
  try {
16454
- if (!existsSync19(filePath))
17706
+ if (!existsSync20(filePath))
16455
17707
  return null;
16456
- const data = JSON.parse(readFileSync13(filePath, "utf-8"));
17708
+ const data = JSON.parse(readFileSync14(filePath, "utf-8"));
16457
17709
  try {
16458
17710
  unlinkSync3(filePath);
16459
17711
  } catch {
@@ -16464,13 +17716,13 @@ function loadPendingTask(repoRoot) {
16464
17716
  }
16465
17717
  }
16466
17718
  function saveSessionContext(repoRoot, entry) {
16467
- const contextDir = join25(repoRoot, OA_DIR, "context");
17719
+ const contextDir = join29(repoRoot, OA_DIR, "context");
16468
17720
  mkdirSync6(contextDir, { recursive: true });
16469
- const filePath = join25(contextDir, CONTEXT_SAVE_FILE);
17721
+ const filePath = join29(contextDir, CONTEXT_SAVE_FILE);
16470
17722
  let ctx;
16471
17723
  try {
16472
- if (existsSync19(filePath)) {
16473
- ctx = JSON.parse(readFileSync13(filePath, "utf-8"));
17724
+ if (existsSync20(filePath)) {
17725
+ ctx = JSON.parse(readFileSync14(filePath, "utf-8"));
16474
17726
  } else {
16475
17727
  ctx = { entries: [], maxEntries: MAX_CONTEXT_ENTRIES, updatedAt: "" };
16476
17728
  }
@@ -16485,11 +17737,11 @@ function saveSessionContext(repoRoot, entry) {
16485
17737
  writeFileSync6(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
16486
17738
  }
16487
17739
  function loadSessionContext(repoRoot) {
16488
- const filePath = join25(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
17740
+ const filePath = join29(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
16489
17741
  try {
16490
- if (!existsSync19(filePath))
17742
+ if (!existsSync20(filePath))
16491
17743
  return null;
16492
- return JSON.parse(readFileSync13(filePath, "utf-8"));
17744
+ return JSON.parse(readFileSync14(filePath, "utf-8"));
16493
17745
  } catch {
16494
17746
  return null;
16495
17747
  }
@@ -16536,12 +17788,12 @@ function detectManifests(repoRoot) {
16536
17788
  { file: "docker-compose.yaml", type: "Docker Compose" }
16537
17789
  ];
16538
17790
  for (const check of checks) {
16539
- const filePath = join25(repoRoot, check.file);
16540
- if (existsSync19(filePath)) {
17791
+ const filePath = join29(repoRoot, check.file);
17792
+ if (existsSync20(filePath)) {
16541
17793
  let name;
16542
17794
  if (check.nameField) {
16543
17795
  try {
16544
- const data = JSON.parse(readFileSync13(filePath, "utf-8"));
17796
+ const data = JSON.parse(readFileSync14(filePath, "utf-8"));
16545
17797
  name = data[check.nameField];
16546
17798
  } catch {
16547
17799
  }
@@ -16570,7 +17822,7 @@ function findKeyFiles(repoRoot) {
16570
17822
  { pattern: "CLAUDE.md", description: "Claude Code context" }
16571
17823
  ];
16572
17824
  for (const check of checks) {
16573
- if (existsSync19(join25(repoRoot, check.pattern))) {
17825
+ if (existsSync20(join29(repoRoot, check.pattern))) {
16574
17826
  keyFiles.push({ path: check.pattern, description: check.description });
16575
17827
  }
16576
17828
  }
@@ -16596,12 +17848,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
16596
17848
  if (entry.isDirectory()) {
16597
17849
  let fileCount = 0;
16598
17850
  try {
16599
- fileCount = readdirSync7(join25(root, entry.name)).filter((f) => !f.startsWith(".")).length;
17851
+ fileCount = readdirSync7(join29(root, entry.name)).filter((f) => !f.startsWith(".")).length;
16600
17852
  } catch {
16601
17853
  }
16602
17854
  result += `${prefix}${connector}${entry.name}/ (${fileCount})
16603
17855
  `;
16604
- result += buildDirTree(join25(root, entry.name), maxDepth, childPrefix, depth + 1);
17856
+ result += buildDirTree(join29(root, entry.name), maxDepth, childPrefix, depth + 1);
16605
17857
  } else if (depth < maxDepth) {
16606
17858
  result += `${prefix}${connector}${entry.name}
16607
17859
  `;
@@ -16654,9 +17906,9 @@ var init_oa_directory = __esm({
16654
17906
 
16655
17907
  // packages/cli/dist/tui/setup.js
16656
17908
  import * as readline from "node:readline";
16657
- import { execSync as execSync16, spawn as spawn8 } from "node:child_process";
16658
- import { existsSync as existsSync20, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
16659
- import { join as join26 } from "node:path";
17909
+ import { execSync as execSync18, spawn as spawn9 } from "node:child_process";
17910
+ import { existsSync as existsSync21, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
17911
+ import { join as join30 } from "node:path";
16660
17912
  import { homedir as homedir10, platform } from "node:os";
16661
17913
  function detectSystemSpecs() {
16662
17914
  let totalRamGB = 0;
@@ -16664,7 +17916,7 @@ function detectSystemSpecs() {
16664
17916
  let gpuVramGB = 0;
16665
17917
  let gpuName = "";
16666
17918
  try {
16667
- const memInfo = execSync16("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
17919
+ const memInfo = execSync18("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
16668
17920
  encoding: "utf8",
16669
17921
  timeout: 5e3
16670
17922
  });
@@ -16684,7 +17936,7 @@ function detectSystemSpecs() {
16684
17936
  } catch {
16685
17937
  }
16686
17938
  try {
16687
- const nvidiaSmi = execSync16("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
17939
+ const nvidiaSmi = execSync18("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
16688
17940
  const lines = nvidiaSmi.trim().split("\n");
16689
17941
  if (lines.length > 0) {
16690
17942
  for (const line of lines) {
@@ -16740,12 +17992,12 @@ function modelSupportsToolCalling(modelName) {
16740
17992
  return false;
16741
17993
  }
16742
17994
  function ask(rl, question) {
16743
- return new Promise((resolve23) => {
16744
- rl.question(question, (answer) => resolve23(answer.trim()));
17995
+ return new Promise((resolve26) => {
17996
+ rl.question(question, (answer) => resolve26(answer.trim()));
16745
17997
  });
16746
17998
  }
16747
17999
  function askSecret(rl, question) {
16748
- return new Promise((resolve23) => {
18000
+ return new Promise((resolve26) => {
16749
18001
  process.stdout.write(question);
16750
18002
  let secret = "";
16751
18003
  const stdin = process.stdin;
@@ -16763,7 +18015,7 @@ function askSecret(rl, question) {
16763
18015
  stdin.setRawMode(hadRawMode ?? false);
16764
18016
  }
16765
18017
  process.stdout.write("\n");
16766
- resolve23(secret.trim());
18018
+ resolve26(secret.trim());
16767
18019
  return;
16768
18020
  } else if (c3 === "") {
16769
18021
  stdin.removeListener("data", onData);
@@ -16771,7 +18023,7 @@ function askSecret(rl, question) {
16771
18023
  stdin.setRawMode(hadRawMode ?? false);
16772
18024
  }
16773
18025
  process.stdout.write("\n");
16774
- resolve23("");
18026
+ resolve26("");
16775
18027
  return;
16776
18028
  } else if (c3 === "\x7F" || c3 === "\b") {
16777
18029
  if (secret.length > 0) {
@@ -16809,7 +18061,7 @@ function installOllamaLinux() {
16809
18061
 
16810
18062
  `);
16811
18063
  try {
16812
- execSync16("curl -fsSL https://ollama.com/install.sh | sh", {
18064
+ execSync18("curl -fsSL https://ollama.com/install.sh | sh", {
16813
18065
  stdio: "inherit",
16814
18066
  timeout: 3e5
16815
18067
  });
@@ -16848,10 +18100,10 @@ async function installOllamaMac(rl) {
16848
18100
 
16849
18101
  `);
16850
18102
  try {
16851
- execSync16('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
18103
+ execSync18('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
16852
18104
  if (!hasCmd("brew")) {
16853
18105
  try {
16854
- const brewPrefix = existsSync20("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
18106
+ const brewPrefix = existsSync21("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
16855
18107
  process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
16856
18108
  } catch {
16857
18109
  }
@@ -16881,7 +18133,7 @@ async function installOllamaMac(rl) {
16881
18133
 
16882
18134
  `);
16883
18135
  try {
16884
- execSync16("brew install ollama", {
18136
+ execSync18("brew install ollama", {
16885
18137
  stdio: "inherit",
16886
18138
  timeout: 3e5
16887
18139
  });
@@ -16908,7 +18160,7 @@ function installOllamaWindows() {
16908
18160
 
16909
18161
  `);
16910
18162
  try {
16911
- execSync16('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
18163
+ execSync18('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
16912
18164
  stdio: "inherit",
16913
18165
  timeout: 3e5
16914
18166
  });
@@ -16931,7 +18183,7 @@ function installOllamaWindows() {
16931
18183
  }
16932
18184
  function pullModelWithAutoUpdate(tag) {
16933
18185
  try {
16934
- execSync16(`ollama pull ${tag}`, {
18186
+ execSync18(`ollama pull ${tag}`, {
16935
18187
  stdio: "inherit",
16936
18188
  timeout: 36e5
16937
18189
  // 1 hour max
@@ -16948,7 +18200,7 @@ function pullModelWithAutoUpdate(tag) {
16948
18200
 
16949
18201
  `);
16950
18202
  try {
16951
- execSync16("curl -fsSL https://ollama.com/install.sh | sh", {
18203
+ execSync18("curl -fsSL https://ollama.com/install.sh | sh", {
16952
18204
  stdio: "inherit",
16953
18205
  timeout: 3e5
16954
18206
  // 5 min max for install
@@ -16959,7 +18211,7 @@ function pullModelWithAutoUpdate(tag) {
16959
18211
  process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
16960
18212
 
16961
18213
  `);
16962
- execSync16(`ollama pull ${tag}`, {
18214
+ execSync18(`ollama pull ${tag}`, {
16963
18215
  stdio: "inherit",
16964
18216
  timeout: 36e5
16965
18217
  });
@@ -17140,9 +18392,9 @@ async function doSetup(config, rl) {
17140
18392
  ${c2.cyan("\u25CF")} Starting ollama serve in background...
17141
18393
  `);
17142
18394
  try {
17143
- const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
18395
+ const child = spawn9("ollama", ["serve"], { stdio: "ignore", detached: true });
17144
18396
  child.unref();
17145
- await new Promise((resolve23) => setTimeout(resolve23, 3e3));
18397
+ await new Promise((resolve26) => setTimeout(resolve26, 3e3));
17146
18398
  try {
17147
18399
  models = await fetchOllamaModels(config.backendUrl);
17148
18400
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -17168,9 +18420,9 @@ async function doSetup(config, rl) {
17168
18420
  ${c2.cyan("\u25CF")} Starting ollama serve...
17169
18421
  `);
17170
18422
  try {
17171
- const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
18423
+ const child = spawn9("ollama", ["serve"], { stdio: "ignore", detached: true });
17172
18424
  child.unref();
17173
- await new Promise((resolve23) => setTimeout(resolve23, 3e3));
18425
+ await new Promise((resolve26) => setTimeout(resolve26, 3e3));
17174
18426
  try {
17175
18427
  models = await fetchOllamaModels(config.backendUrl);
17176
18428
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -17325,12 +18577,12 @@ async function doSetup(config, rl) {
17325
18577
  `PARAMETER num_predict ${numPredict}`,
17326
18578
  `PARAMETER stop "<|endoftext|>"`
17327
18579
  ].join("\n");
17328
- const modelDir2 = join26(homedir10(), ".open-agents", "models");
18580
+ const modelDir2 = join30(homedir10(), ".open-agents", "models");
17329
18581
  mkdirSync7(modelDir2, { recursive: true });
17330
- const modelfilePath = join26(modelDir2, `Modelfile.${customName}`);
18582
+ const modelfilePath = join30(modelDir2, `Modelfile.${customName}`);
17331
18583
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
17332
18584
  process.stdout.write(` ${c2.dim("Creating model...")} `);
17333
- execSync16(`ollama create ${customName} -f ${modelfilePath}`, {
18585
+ execSync18(`ollama create ${customName} -f ${modelfilePath}`, {
17334
18586
  stdio: "pipe",
17335
18587
  timeout: 12e4
17336
18588
  });
@@ -17373,7 +18625,7 @@ async function isModelAvailable(config) {
17373
18625
  }
17374
18626
  function isFirstRun() {
17375
18627
  try {
17376
- return !existsSync20(join26(homedir10(), ".open-agents", "config.json"));
18628
+ return !existsSync21(join30(homedir10(), ".open-agents", "config.json"));
17377
18629
  } catch {
17378
18630
  return true;
17379
18631
  }
@@ -17381,7 +18633,7 @@ function isFirstRun() {
17381
18633
  function hasCmd(cmd) {
17382
18634
  try {
17383
18635
  const whichCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
17384
- execSync16(whichCmd, { stdio: "pipe", timeout: 3e3 });
18636
+ execSync18(whichCmd, { stdio: "pipe", timeout: 3e3 });
17385
18637
  return true;
17386
18638
  } catch {
17387
18639
  return false;
@@ -17410,11 +18662,11 @@ function detectPkgManager() {
17410
18662
  return null;
17411
18663
  }
17412
18664
  function getVenvDir() {
17413
- return join26(homedir10(), ".open-agents", "venv");
18665
+ return join30(homedir10(), ".open-agents", "venv");
17414
18666
  }
17415
18667
  function hasVenvModule() {
17416
18668
  try {
17417
- execSync16("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
18669
+ execSync18("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
17418
18670
  return true;
17419
18671
  } catch {
17420
18672
  return false;
@@ -17422,8 +18674,8 @@ function hasVenvModule() {
17422
18674
  }
17423
18675
  function ensureVenv(log) {
17424
18676
  const venvDir = getVenvDir();
17425
- const venvPip = join26(venvDir, "bin", "pip");
17426
- if (existsSync20(venvPip))
18677
+ const venvPip = join30(venvDir, "bin", "pip");
18678
+ if (existsSync21(venvPip))
17427
18679
  return venvDir;
17428
18680
  log("Creating Python venv for vision deps...");
17429
18681
  if (!hasCmd("python3")) {
@@ -17435,9 +18687,9 @@ function ensureVenv(log) {
17435
18687
  return null;
17436
18688
  }
17437
18689
  try {
17438
- mkdirSync7(join26(homedir10(), ".open-agents"), { recursive: true });
17439
- execSync16(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
17440
- execSync16(`"${join26(venvDir, "bin", "pip")}" install --upgrade pip`, {
18690
+ mkdirSync7(join30(homedir10(), ".open-agents"), { recursive: true });
18691
+ execSync18(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
18692
+ execSync18(`"${join30(venvDir, "bin", "pip")}" install --upgrade pip`, {
17441
18693
  stdio: "pipe",
17442
18694
  timeout: 6e4
17443
18695
  });
@@ -17450,7 +18702,7 @@ function ensureVenv(log) {
17450
18702
  }
17451
18703
  function trySudoPasswordless(cmd, timeoutMs = 12e4) {
17452
18704
  try {
17453
- execSync16(`sudo -n ${cmd}`, {
18705
+ execSync18(`sudo -n ${cmd}`, {
17454
18706
  stdio: "pipe",
17455
18707
  timeout: timeoutMs,
17456
18708
  env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
@@ -17462,7 +18714,7 @@ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
17462
18714
  }
17463
18715
  function runWithSudo(cmd, password, timeoutMs = 12e4) {
17464
18716
  try {
17465
- execSync16(`sudo -S ${cmd}`, {
18717
+ execSync18(`sudo -S ${cmd}`, {
17466
18718
  input: password + "\n",
17467
18719
  stdio: ["pipe", "pipe", "pipe"],
17468
18720
  timeout: timeoutMs,
@@ -17522,7 +18774,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
17522
18774
  } else {
17523
18775
  log("Installing tesseract-ocr...");
17524
18776
  try {
17525
- execSync16(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
18777
+ execSync18(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
17526
18778
  if (hasCmd("tesseract")) {
17527
18779
  log("tesseract-ocr installed successfully.");
17528
18780
  } else {
@@ -17594,7 +18846,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
17594
18846
  } else {
17595
18847
  log(`Installing ${dep.label}...`);
17596
18848
  try {
17597
- execSync16(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
18849
+ execSync18(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
17598
18850
  if (hasCmd(dep.binary)) {
17599
18851
  log(`${dep.label} installed successfully.`);
17600
18852
  } else {
@@ -17625,7 +18877,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
17625
18877
  const venvCmds = {
17626
18878
  apt: () => {
17627
18879
  try {
17628
- const pyVer = execSync16(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
18880
+ const pyVer = execSync18(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
17629
18881
  return `apt-get install -y python3-venv python${pyVer}-venv`;
17630
18882
  } catch {
17631
18883
  return "apt-get install -y python3-venv";
@@ -17646,19 +18898,19 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
17646
18898
  }
17647
18899
  }
17648
18900
  const venvDir = getVenvDir();
17649
- const venvBin = join26(venvDir, "bin");
17650
- const venvMoondream = join26(venvBin, "moondream-station");
18901
+ const venvBin = join30(venvDir, "bin");
18902
+ const venvMoondream = join30(venvBin, "moondream-station");
17651
18903
  const venv = ensureVenv(log);
17652
- if (venv && !hasCmd("moondream-station") && !existsSync20(venvMoondream)) {
17653
- const venvPip = join26(venvBin, "pip");
18904
+ if (venv && !hasCmd("moondream-station") && !existsSync21(venvMoondream)) {
18905
+ const venvPip = join30(venvBin, "pip");
17654
18906
  log("Installing moondream-station in ~/.open-agents/venv...");
17655
18907
  try {
17656
- execSync16(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
17657
- if (existsSync20(venvMoondream)) {
18908
+ execSync18(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
18909
+ if (existsSync21(venvMoondream)) {
17658
18910
  log("moondream-station installed successfully.");
17659
18911
  } else {
17660
18912
  try {
17661
- const check = execSync16(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
18913
+ const check = execSync18(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
17662
18914
  if (check.includes("moondream")) {
17663
18915
  log("moondream-station package installed.");
17664
18916
  }
@@ -17671,11 +18923,11 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
17671
18923
  }
17672
18924
  }
17673
18925
  if (venv) {
17674
- const venvPython = join26(venvBin, "python");
17675
- const venvPip2 = join26(venvBin, "pip");
18926
+ const venvPython = join30(venvBin, "python");
18927
+ const venvPip2 = join30(venvBin, "pip");
17676
18928
  let ocrStackInstalled = false;
17677
18929
  try {
17678
- execSync16(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
18930
+ execSync18(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
17679
18931
  ocrStackInstalled = true;
17680
18932
  } catch {
17681
18933
  }
@@ -17683,9 +18935,9 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
17683
18935
  const ocrPackages = "pytesseract Pillow opencv-python-headless numpy";
17684
18936
  log("Installing OCR Python stack (pytesseract, OpenCV, Pillow, numpy)...");
17685
18937
  try {
17686
- execSync16(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
18938
+ execSync18(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
17687
18939
  try {
17688
- execSync16(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
18940
+ execSync18(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
17689
18941
  log("OCR Python stack installed successfully.");
17690
18942
  } catch {
17691
18943
  log("OCR Python stack install completed but import verification failed.");
@@ -17732,11 +18984,11 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
17732
18984
  `PARAMETER num_predict ${numPredict}`,
17733
18985
  `PARAMETER stop "<|endoftext|>"`
17734
18986
  ].join("\n");
17735
- const modelDir2 = join26(homedir10(), ".open-agents", "models");
18987
+ const modelDir2 = join30(homedir10(), ".open-agents", "models");
17736
18988
  mkdirSync7(modelDir2, { recursive: true });
17737
- const modelfilePath = join26(modelDir2, `Modelfile.${customName}`);
18989
+ const modelfilePath = join30(modelDir2, `Modelfile.${customName}`);
17738
18990
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
17739
- execSync16(`ollama create ${customName} -f ${modelfilePath}`, {
18991
+ execSync18(`ollama create ${customName} -f ${modelfilePath}`, {
17740
18992
  stdio: "pipe",
17741
18993
  timeout: 12e4
17742
18994
  });
@@ -18522,18 +19774,18 @@ async function handleUpdate(subcommand, ctx) {
18522
19774
  let currentVersion = "0.0.0";
18523
19775
  try {
18524
19776
  const { createRequire: createRequire4 } = await import("node:module");
18525
- const { fileURLToPath: fileURLToPath9 } = await import("node:url");
18526
- const { dirname: dirname12, join: join37 } = await import("node:path");
18527
- const { existsSync: existsSync27 } = await import("node:fs");
19777
+ const { fileURLToPath: fileURLToPath10 } = await import("node:url");
19778
+ const { dirname: dirname13, join: join41 } = await import("node:path");
19779
+ const { existsSync: existsSync28 } = await import("node:fs");
18528
19780
  const req = createRequire4(import.meta.url);
18529
- const thisDir = dirname12(fileURLToPath9(import.meta.url));
19781
+ const thisDir = dirname13(fileURLToPath10(import.meta.url));
18530
19782
  const candidates = [
18531
- join37(thisDir, "..", "package.json"),
18532
- join37(thisDir, "..", "..", "package.json"),
18533
- join37(thisDir, "..", "..", "..", "package.json")
19783
+ join41(thisDir, "..", "package.json"),
19784
+ join41(thisDir, "..", "..", "package.json"),
19785
+ join41(thisDir, "..", "..", "..", "package.json")
18534
19786
  ];
18535
19787
  for (const pkgPath of candidates) {
18536
- if (existsSync27(pkgPath)) {
19788
+ if (existsSync28(pkgPath)) {
18537
19789
  const pkg = req(pkgPath);
18538
19790
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
18539
19791
  currentVersion = pkg.version ?? "0.0.0";
@@ -18571,8 +19823,8 @@ async function handleUpdate(subcommand, ctx) {
18571
19823
  checkSpinner.stop(`Update available: v${info.currentVersion} \u2192 v${c2.bold(c2.green(info.latestVersion))}`);
18572
19824
  const installSpinner = startInlineSpinner("Installing update");
18573
19825
  const { exec } = await import("node:child_process");
18574
- const installOk = await new Promise((resolve23) => {
18575
- const child = exec(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { timeout: 18e4 }, (err) => resolve23(!err));
19826
+ const installOk = await new Promise((resolve26) => {
19827
+ const child = exec(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { timeout: 18e4 }, (err) => resolve26(!err));
18576
19828
  child.stdout?.resume();
18577
19829
  child.stderr?.resume();
18578
19830
  });
@@ -18665,9 +19917,9 @@ var init_commands = __esm({
18665
19917
  });
18666
19918
 
18667
19919
  // packages/cli/dist/tui/project-context.js
18668
- import { existsSync as existsSync21, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "node:fs";
18669
- import { join as join27, basename as basename10 } from "node:path";
18670
- import { execSync as execSync17 } from "node:child_process";
19920
+ import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "node:fs";
19921
+ import { join as join31, basename as basename10 } from "node:path";
19922
+ import { execSync as execSync19 } from "node:child_process";
18671
19923
  import { homedir as homedir11, platform as platform2, release } from "node:os";
18672
19924
  function getModelTier(modelName) {
18673
19925
  const m = modelName.toLowerCase();
@@ -18701,10 +19953,10 @@ function loadProjectMap(repoRoot) {
18701
19953
  if (!hasOaDirectory(repoRoot)) {
18702
19954
  initOaDirectory(repoRoot);
18703
19955
  }
18704
- const mapPath = join27(repoRoot, OA_DIR, "context", "project-map.md");
18705
- if (existsSync21(mapPath)) {
19956
+ const mapPath = join31(repoRoot, OA_DIR, "context", "project-map.md");
19957
+ if (existsSync22(mapPath)) {
18706
19958
  try {
18707
- const content = readFileSync14(mapPath, "utf-8");
19959
+ const content = readFileSync15(mapPath, "utf-8");
18708
19960
  return content;
18709
19961
  } catch {
18710
19962
  }
@@ -18713,19 +19965,19 @@ function loadProjectMap(repoRoot) {
18713
19965
  }
18714
19966
  function getGitInfo(repoRoot) {
18715
19967
  try {
18716
- execSync17("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
19968
+ execSync19("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
18717
19969
  } catch {
18718
19970
  return "";
18719
19971
  }
18720
19972
  const lines = [];
18721
19973
  try {
18722
- const branch = execSync17("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
19974
+ const branch = execSync19("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
18723
19975
  if (branch)
18724
19976
  lines.push(`Branch: ${branch}`);
18725
19977
  } catch {
18726
19978
  }
18727
19979
  try {
18728
- const status = execSync17("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
19980
+ const status = execSync19("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
18729
19981
  if (status) {
18730
19982
  const changed = status.split("\n").length;
18731
19983
  lines.push(`Working tree: ${changed} changed file(s)`);
@@ -18735,7 +19987,7 @@ function getGitInfo(repoRoot) {
18735
19987
  } catch {
18736
19988
  }
18737
19989
  try {
18738
- const log = execSync17("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
19990
+ const log = execSync19("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
18739
19991
  if (log)
18740
19992
  lines.push(`Recent commits:
18741
19993
  ${log}`);
@@ -18745,31 +19997,31 @@ ${log}`);
18745
19997
  }
18746
19998
  function loadMemoryContext(repoRoot) {
18747
19999
  const sections = [];
18748
- const oaMemDir = join27(repoRoot, OA_DIR, "memory");
20000
+ const oaMemDir = join31(repoRoot, OA_DIR, "memory");
18749
20001
  const oaEntries = loadMemoryDir(oaMemDir, "project");
18750
20002
  if (oaEntries)
18751
20003
  sections.push(oaEntries);
18752
- const legacyMemDir = join27(repoRoot, ".open-agents", "memory");
18753
- if (legacyMemDir !== oaMemDir && existsSync21(legacyMemDir)) {
20004
+ const legacyMemDir = join31(repoRoot, ".open-agents", "memory");
20005
+ if (legacyMemDir !== oaMemDir && existsSync22(legacyMemDir)) {
18754
20006
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
18755
20007
  if (legacyEntries)
18756
20008
  sections.push(legacyEntries);
18757
20009
  }
18758
- const globalMemDir = join27(homedir11(), ".open-agents", "memory");
20010
+ const globalMemDir = join31(homedir11(), ".open-agents", "memory");
18759
20011
  const globalEntries = loadMemoryDir(globalMemDir, "global");
18760
20012
  if (globalEntries)
18761
20013
  sections.push(globalEntries);
18762
20014
  return sections.join("\n\n");
18763
20015
  }
18764
20016
  function loadMemoryDir(memDir, scope) {
18765
- if (!existsSync21(memDir))
20017
+ if (!existsSync22(memDir))
18766
20018
  return "";
18767
20019
  const lines = [];
18768
20020
  try {
18769
20021
  const files = readdirSync8(memDir).filter((f) => f.endsWith(".json"));
18770
20022
  for (const file of files.slice(0, 10)) {
18771
20023
  try {
18772
- const raw = readFileSync14(join27(memDir, file), "utf-8");
20024
+ const raw = readFileSync15(join31(memDir, file), "utf-8");
18773
20025
  const entries = JSON.parse(raw);
18774
20026
  const topic = basename10(file, ".json");
18775
20027
  const keys = Object.keys(entries);
@@ -19796,22 +21048,22 @@ var init_carousel = __esm({
19796
21048
  });
19797
21049
 
19798
21050
  // packages/cli/dist/tui/carousel-descriptors.js
19799
- import { existsSync as existsSync22, readFileSync as readFileSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
19800
- import { join as join28, basename as basename11 } from "node:path";
21051
+ import { existsSync as existsSync23, readFileSync as readFileSync16, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
21052
+ import { join as join32, basename as basename11 } from "node:path";
19801
21053
  function loadToolProfile(repoRoot) {
19802
- const filePath = join28(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
21054
+ const filePath = join32(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
19803
21055
  try {
19804
- if (!existsSync22(filePath))
21056
+ if (!existsSync23(filePath))
19805
21057
  return null;
19806
- return JSON.parse(readFileSync15(filePath, "utf-8"));
21058
+ return JSON.parse(readFileSync16(filePath, "utf-8"));
19807
21059
  } catch {
19808
21060
  return null;
19809
21061
  }
19810
21062
  }
19811
21063
  function saveToolProfile(repoRoot, profile) {
19812
- const contextDir = join28(repoRoot, OA_DIR, "context");
21064
+ const contextDir = join32(repoRoot, OA_DIR, "context");
19813
21065
  mkdirSync8(contextDir, { recursive: true });
19814
- writeFileSync8(join28(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
21066
+ writeFileSync8(join32(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
19815
21067
  }
19816
21068
  function categorizeToolCall(toolName) {
19817
21069
  for (const cat of TOOL_CATEGORIES) {
@@ -19869,25 +21121,25 @@ function weightedColor(profile) {
19869
21121
  return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
19870
21122
  }
19871
21123
  function loadCachedDescriptors(repoRoot) {
19872
- const filePath = join28(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
21124
+ const filePath = join32(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
19873
21125
  try {
19874
- if (!existsSync22(filePath))
21126
+ if (!existsSync23(filePath))
19875
21127
  return null;
19876
- const cached = JSON.parse(readFileSync15(filePath, "utf-8"));
21128
+ const cached = JSON.parse(readFileSync16(filePath, "utf-8"));
19877
21129
  return cached.phrases.length > 0 ? cached.phrases : null;
19878
21130
  } catch {
19879
21131
  return null;
19880
21132
  }
19881
21133
  }
19882
21134
  function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
19883
- const contextDir = join28(repoRoot, OA_DIR, "context");
21135
+ const contextDir = join32(repoRoot, OA_DIR, "context");
19884
21136
  mkdirSync8(contextDir, { recursive: true });
19885
21137
  const cached = {
19886
21138
  phrases,
19887
21139
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
19888
21140
  sourceHash
19889
21141
  };
19890
- writeFileSync8(join28(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
21142
+ writeFileSync8(join32(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
19891
21143
  }
19892
21144
  function generateDescriptors(repoRoot) {
19893
21145
  const profile = loadToolProfile(repoRoot);
@@ -19935,11 +21187,11 @@ function generateDescriptors(repoRoot) {
19935
21187
  return phrases;
19936
21188
  }
19937
21189
  function extractFromPackageJson(repoRoot, tags) {
19938
- const pkgPath = join28(repoRoot, "package.json");
21190
+ const pkgPath = join32(repoRoot, "package.json");
19939
21191
  try {
19940
- if (!existsSync22(pkgPath))
21192
+ if (!existsSync23(pkgPath))
19941
21193
  return;
19942
- const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
21194
+ const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
19943
21195
  if (pkg.name && typeof pkg.name === "string") {
19944
21196
  const parts = pkg.name.replace(/^@/, "").split("/");
19945
21197
  for (const p of parts)
@@ -19983,7 +21235,7 @@ function extractFromManifests(repoRoot, tags) {
19983
21235
  { file: ".github/workflows", tag: "ci/cd" }
19984
21236
  ];
19985
21237
  for (const check of manifestChecks) {
19986
- if (existsSync22(join28(repoRoot, check.file))) {
21238
+ if (existsSync23(join32(repoRoot, check.file))) {
19987
21239
  tags.push(check.tag);
19988
21240
  }
19989
21241
  }
@@ -20005,16 +21257,16 @@ function extractFromSessions(repoRoot, tags) {
20005
21257
  }
20006
21258
  }
20007
21259
  function extractFromMemory(repoRoot, tags) {
20008
- const memoryDir = join28(repoRoot, OA_DIR, "memory");
21260
+ const memoryDir = join32(repoRoot, OA_DIR, "memory");
20009
21261
  try {
20010
- if (!existsSync22(memoryDir))
21262
+ if (!existsSync23(memoryDir))
20011
21263
  return;
20012
21264
  const files = readdirSync9(memoryDir).filter((f) => f.endsWith(".json"));
20013
21265
  for (const file of files) {
20014
21266
  const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
20015
21267
  tags.push(topic);
20016
21268
  try {
20017
- const data = JSON.parse(readFileSync15(join28(memoryDir, file), "utf-8"));
21269
+ const data = JSON.parse(readFileSync16(join32(memoryDir, file), "utf-8"));
20018
21270
  if (data && typeof data === "object") {
20019
21271
  const keys = Object.keys(data).slice(0, 3);
20020
21272
  for (const key of keys) {
@@ -20149,25 +21401,25 @@ var init_carousel_descriptors = __esm({
20149
21401
  });
20150
21402
 
20151
21403
  // packages/cli/dist/tui/voice.js
20152
- import { existsSync as existsSync23, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync4 } from "node:fs";
20153
- import { join as join29 } from "node:path";
21404
+ import { existsSync as existsSync24, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync17, unlinkSync as unlinkSync4 } from "node:fs";
21405
+ import { join as join33 } from "node:path";
20154
21406
  import { homedir as homedir12, tmpdir as tmpdir6, platform as platform3 } from "node:os";
20155
- import { execSync as execSync18, spawn as nodeSpawn } from "node:child_process";
21407
+ import { execSync as execSync20, spawn as nodeSpawn } from "node:child_process";
20156
21408
  import { createRequire } from "node:module";
20157
21409
  function voiceDir() {
20158
- return join29(homedir12(), ".open-agents", "voice");
21410
+ return join33(homedir12(), ".open-agents", "voice");
20159
21411
  }
20160
21412
  function modelsDir() {
20161
- return join29(voiceDir(), "models");
21413
+ return join33(voiceDir(), "models");
20162
21414
  }
20163
21415
  function modelDir(id) {
20164
- return join29(modelsDir(), id);
21416
+ return join33(modelsDir(), id);
20165
21417
  }
20166
21418
  function modelOnnxPath(id) {
20167
- return join29(modelDir(id), "model.onnx");
21419
+ return join33(modelDir(id), "model.onnx");
20168
21420
  }
20169
21421
  function modelConfigPath(id) {
20170
- return join29(modelDir(id), "config.json");
21422
+ return join33(modelDir(id), "config.json");
20171
21423
  }
20172
21424
  function describeToolCall(toolName, args, personality = 2) {
20173
21425
  const path = args["path"];
@@ -20242,6 +21494,14 @@ function describeToolCallTerse(toolName, args, file) {
20242
21494
  return `Creating custom tool`;
20243
21495
  case "manage_tools":
20244
21496
  return `Managing custom tools`;
21497
+ case "browser_action":
21498
+ return `Browser ${args["action"] ?? "action"}`;
21499
+ case "scheduler":
21500
+ return `${args["action"] === "create" ? "Scheduling task" : "Checking scheduler"}`;
21501
+ case "reminder":
21502
+ return `${args["action"] === "set" ? "Setting reminder" : "Checking reminders"}`;
21503
+ case "agenda":
21504
+ return `Checking agenda`;
20245
21505
  default:
20246
21506
  return `Using ${toolName}`;
20247
21507
  }
@@ -20288,6 +21548,14 @@ function describeToolCallConversational(toolName, args, file) {
20288
21548
  return `Taking a look at that image`;
20289
21549
  case "screenshot":
20290
21550
  return `Grabbing a screenshot`;
21551
+ case "browser_action":
21552
+ return `Let me ${args["action"] === "navigate" ? "open that page" : args["action"] === "screenshot" ? "grab a screenshot of the browser" : `do a browser ${args["action"] ?? "action"}`}`;
21553
+ case "scheduler":
21554
+ return `${args["action"] === "create" ? "Setting up a scheduled task" : "Checking the schedule"}`;
21555
+ case "reminder":
21556
+ return `${args["action"] === "set" ? "Making a note for next time" : "Looking at reminders"}`;
21557
+ case "agenda":
21558
+ return `Let me check what's on the agenda`;
20291
21559
  default:
20292
21560
  return `Working with ${toolName}`;
20293
21561
  }
@@ -20334,6 +21602,14 @@ function describeToolCallChatty(toolName, args, file) {
20334
21602
  return `Let me get a good look at that image`;
20335
21603
  case "screenshot":
20336
21604
  return `Snapping a screenshot to see what's happening`;
21605
+ case "browser_action":
21606
+ return `Firing up the browser, let's ${args["action"] === "navigate" ? "see what's on that page" : args["action"] === "screenshot" ? "get a visual" : `${args["action"] ?? "do this"}`}`;
21607
+ case "scheduler":
21608
+ return `${args["action"] === "create" ? "Alright, let me set up a recurring task for you" : "Let me pull up the schedule and see what's coming up"}`;
21609
+ case "reminder":
21610
+ return `${args["action"] === "set" ? "Leaving myself a note for future me, don't let me forget" : "Let me check if past me left any reminders"}`;
21611
+ case "agenda":
21612
+ return `Let me see the full picture of what needs doing`;
20337
21613
  default:
20338
21614
  return `Pulling in ${toolName}, hang tight`;
20339
21615
  }
@@ -20589,7 +21865,7 @@ var init_voice = __esm({
20589
21865
  const audioData = result["output"].data;
20590
21866
  if (audioData.length === 0)
20591
21867
  return;
20592
- const wavPath = join29(tmpdir6(), `oa-voice-${Date.now()}.wav`);
21868
+ const wavPath = join33(tmpdir6(), `oa-voice-${Date.now()}.wav`);
20593
21869
  this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
20594
21870
  await this.playWav(wavPath);
20595
21871
  try {
@@ -20678,7 +21954,7 @@ var init_voice = __esm({
20678
21954
  const cmd = this.getPlayCommand(path);
20679
21955
  if (!cmd)
20680
21956
  return;
20681
- return new Promise((resolve23) => {
21957
+ return new Promise((resolve26) => {
20682
21958
  const child = nodeSpawn(cmd[0], cmd.slice(1), {
20683
21959
  stdio: "ignore",
20684
21960
  detached: false
@@ -20687,12 +21963,12 @@ var init_voice = __esm({
20687
21963
  child.on("close", () => {
20688
21964
  if (this.currentPlayback === child)
20689
21965
  this.currentPlayback = null;
20690
- resolve23();
21966
+ resolve26();
20691
21967
  });
20692
21968
  child.on("error", () => {
20693
21969
  if (this.currentPlayback === child)
20694
21970
  this.currentPlayback = null;
20695
- resolve23();
21971
+ resolve26();
20696
21972
  });
20697
21973
  setTimeout(() => {
20698
21974
  if (this.currentPlayback === child) {
@@ -20702,7 +21978,7 @@ var init_voice = __esm({
20702
21978
  }
20703
21979
  this.currentPlayback = null;
20704
21980
  }
20705
- resolve23();
21981
+ resolve26();
20706
21982
  }, 15e3);
20707
21983
  });
20708
21984
  }
@@ -20719,7 +21995,7 @@ var init_voice = __esm({
20719
21995
  }
20720
21996
  for (const player of ["paplay", "pw-play", "aplay"]) {
20721
21997
  try {
20722
- execSync18(`which ${player}`, { stdio: "pipe" });
21998
+ execSync20(`which ${player}`, { stdio: "pipe" });
20723
21999
  return [player, path];
20724
22000
  } catch {
20725
22001
  }
@@ -20744,14 +22020,14 @@ var init_voice = __esm({
20744
22020
  const arch = process.arch;
20745
22021
  const isArmLinux = (arch === "arm64" || arch === "arm") && process.platform === "linux";
20746
22022
  mkdirSync9(voiceDir(), { recursive: true });
20747
- const pkgPath = join29(voiceDir(), "package.json");
22023
+ const pkgPath = join33(voiceDir(), "package.json");
20748
22024
  const expectedDeps = {
20749
22025
  "onnxruntime-node": "^1.21.0",
20750
22026
  "phonemizer": "^1.2.1"
20751
22027
  };
20752
- if (existsSync23(pkgPath)) {
22028
+ if (existsSync24(pkgPath)) {
20753
22029
  try {
20754
- const existing = JSON.parse(readFileSync16(pkgPath, "utf8"));
22030
+ const existing = JSON.parse(readFileSync17(pkgPath, "utf8"));
20755
22031
  if (!existing.dependencies?.["phonemizer"]) {
20756
22032
  existing.dependencies = { ...existing.dependencies, ...expectedDeps };
20757
22033
  writeFileSync9(pkgPath, JSON.stringify(existing, null, 2));
@@ -20759,14 +22035,14 @@ var init_voice = __esm({
20759
22035
  } catch {
20760
22036
  }
20761
22037
  }
20762
- if (!existsSync23(pkgPath)) {
22038
+ if (!existsSync24(pkgPath)) {
20763
22039
  writeFileSync9(pkgPath, JSON.stringify({
20764
22040
  name: "open-agents-voice",
20765
22041
  private: true,
20766
22042
  dependencies: expectedDeps
20767
22043
  }, null, 2));
20768
22044
  }
20769
- const voiceRequire = createRequire(join29(voiceDir(), "index.js"));
22045
+ const voiceRequire = createRequire(join33(voiceDir(), "index.js"));
20770
22046
  try {
20771
22047
  this.ort = voiceRequire("onnxruntime-node");
20772
22048
  } catch {
@@ -20775,7 +22051,7 @@ var init_voice = __esm({
20775
22051
  }
20776
22052
  renderInfo("Installing ONNX runtime for voice synthesis...");
20777
22053
  try {
20778
- execSync18("npm install --no-audit --no-fund", {
22054
+ execSync20("npm install --no-audit --no-fund", {
20779
22055
  cwd: voiceDir(),
20780
22056
  stdio: "pipe",
20781
22057
  timeout: 12e4
@@ -20796,7 +22072,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
20796
22072
  }
20797
22073
  renderInfo("Installing phonemizer for voice synthesis...");
20798
22074
  try {
20799
- execSync18("npm install --no-audit --no-fund", {
22075
+ execSync20("npm install --no-audit --no-fund", {
20800
22076
  cwd: voiceDir(),
20801
22077
  stdio: "pipe",
20802
22078
  timeout: 12e4
@@ -20820,10 +22096,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
20820
22096
  const dir = modelDir(id);
20821
22097
  const onnxPath = modelOnnxPath(id);
20822
22098
  const configPath = modelConfigPath(id);
20823
- if (existsSync23(onnxPath) && existsSync23(configPath))
22099
+ if (existsSync24(onnxPath) && existsSync24(configPath))
20824
22100
  return;
20825
22101
  mkdirSync9(dir, { recursive: true });
20826
- if (!existsSync23(configPath)) {
22102
+ if (!existsSync24(configPath)) {
20827
22103
  renderInfo(`Downloading ${model.label} voice config...`);
20828
22104
  const configResp = await fetch(model.configUrl);
20829
22105
  if (!configResp.ok)
@@ -20831,7 +22107,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
20831
22107
  const configText = await configResp.text();
20832
22108
  writeFileSync9(configPath, configText);
20833
22109
  }
20834
- if (!existsSync23(onnxPath)) {
22110
+ if (!existsSync24(onnxPath)) {
20835
22111
  renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
20836
22112
  const onnxResp = await fetch(model.onnxUrl);
20837
22113
  if (!onnxResp.ok)
@@ -20867,10 +22143,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
20867
22143
  throw new Error("ONNX runtime not loaded");
20868
22144
  const onnxPath = modelOnnxPath(this.modelId);
20869
22145
  const configPath = modelConfigPath(this.modelId);
20870
- if (!existsSync23(onnxPath) || !existsSync23(configPath)) {
22146
+ if (!existsSync24(onnxPath) || !existsSync24(configPath)) {
20871
22147
  throw new Error(`Model files not found for ${this.modelId}`);
20872
22148
  }
20873
- this.config = JSON.parse(readFileSync16(configPath, "utf8"));
22149
+ this.config = JSON.parse(readFileSync17(configPath, "utf8"));
20874
22150
  renderInfo("Loading voice model...");
20875
22151
  this.session = await this.ort.InferenceSession.create(onnxPath, {
20876
22152
  executionProviders: ["cpu"],
@@ -21371,10 +22647,10 @@ var init_stream_renderer = __esm({
21371
22647
 
21372
22648
  // packages/cli/dist/tui/edit-history.js
21373
22649
  import { appendFileSync, mkdirSync as mkdirSync10 } from "node:fs";
21374
- import { join as join30 } from "node:path";
22650
+ import { join as join34 } from "node:path";
21375
22651
  function createEditHistoryLogger(repoRoot, sessionId) {
21376
- const historyDir = join30(repoRoot, ".oa", "history");
21377
- const logPath = join30(historyDir, "edits.jsonl");
22652
+ const historyDir = join34(repoRoot, ".oa", "history");
22653
+ const logPath = join34(historyDir, "edits.jsonl");
21378
22654
  try {
21379
22655
  mkdirSync10(historyDir, { recursive: true });
21380
22656
  } catch {
@@ -21485,9 +22761,9 @@ var init_edit_history = __esm({
21485
22761
  });
21486
22762
 
21487
22763
  // packages/cli/dist/tui/dream-engine.js
21488
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync17, existsSync as existsSync24, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
21489
- import { join as join31, basename as basename12 } from "node:path";
21490
- import { execSync as execSync19 } from "node:child_process";
22764
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync18, existsSync as existsSync25, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
22765
+ import { join as join35, basename as basename12 } from "node:path";
22766
+ import { execSync as execSync21 } from "node:child_process";
21491
22767
  function adaptTool(tool) {
21492
22768
  return {
21493
22769
  name: tool.name,
@@ -21661,12 +22937,12 @@ var init_dream_engine = __esm({
21661
22937
  const content = String(args["content"] ?? "");
21662
22938
  if (!rawPath)
21663
22939
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
21664
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join31(this.dreamsDir, basename12(rawPath)) : join31(this.dreamsDir, rawPath);
22940
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join35(this.dreamsDir, basename12(rawPath)) : join35(this.dreamsDir, rawPath);
21665
22941
  if (!targetPath.startsWith(this.dreamsDir)) {
21666
22942
  return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
21667
22943
  }
21668
22944
  try {
21669
- const dir = join31(targetPath, "..");
22945
+ const dir = join35(targetPath, "..");
21670
22946
  mkdirSync11(dir, { recursive: true });
21671
22947
  writeFileSync10(targetPath, content, "utf-8");
21672
22948
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -21696,15 +22972,15 @@ var init_dream_engine = __esm({
21696
22972
  const rawPath = String(args["path"] ?? "");
21697
22973
  const oldStr = String(args["old_string"] ?? "");
21698
22974
  const newStr = String(args["new_string"] ?? "");
21699
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join31(this.dreamsDir, basename12(rawPath)) : join31(this.dreamsDir, rawPath);
22975
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join35(this.dreamsDir, basename12(rawPath)) : join35(this.dreamsDir, rawPath);
21700
22976
  if (!targetPath.startsWith(this.dreamsDir)) {
21701
22977
  return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
21702
22978
  }
21703
22979
  try {
21704
- if (!existsSync24(targetPath)) {
22980
+ if (!existsSync25(targetPath)) {
21705
22981
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
21706
22982
  }
21707
- let content = readFileSync17(targetPath, "utf-8");
22983
+ let content = readFileSync18(targetPath, "utf-8");
21708
22984
  if (!content.includes(oldStr)) {
21709
22985
  return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
21710
22986
  }
@@ -21740,7 +23016,7 @@ var init_dream_engine = __esm({
21740
23016
  }
21741
23017
  }
21742
23018
  try {
21743
- const output = execSync19(cmd, {
23019
+ const output = execSync21(cmd, {
21744
23020
  cwd: this.repoRoot,
21745
23021
  timeout: 3e4,
21746
23022
  encoding: "utf-8",
@@ -21763,7 +23039,7 @@ var init_dream_engine = __esm({
21763
23039
  constructor(config, repoRoot) {
21764
23040
  this.config = config;
21765
23041
  this.repoRoot = repoRoot;
21766
- this.dreamsDir = join31(repoRoot, ".oa", "dreams");
23042
+ this.dreamsDir = join35(repoRoot, ".oa", "dreams");
21767
23043
  this.state = {
21768
23044
  mode: "default",
21769
23045
  active: false,
@@ -21835,7 +23111,7 @@ ${result.summary}`;
21835
23111
  if (mode !== "default" || cycle === totalCycles) {
21836
23112
  renderDreamContraction(cycle);
21837
23113
  const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
21838
- const summaryPath = join31(this.dreamsDir, `cycle-${cycle}-summary.md`);
23114
+ const summaryPath = join35(this.dreamsDir, `cycle-${cycle}-summary.md`);
21839
23115
  writeFileSync10(summaryPath, cycleSummary, "utf-8");
21840
23116
  }
21841
23117
  if (mode === "lucid" && !this.abortController.signal.aborted) {
@@ -21958,29 +23234,29 @@ Dreams directory: ${this.dreamsDir}`);
21958
23234
  }
21959
23235
  /** Save workspace backup for lucid mode */
21960
23236
  saveVersionCheckpoint(cycle) {
21961
- const checkpointDir = join31(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
23237
+ const checkpointDir = join35(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
21962
23238
  try {
21963
23239
  mkdirSync11(checkpointDir, { recursive: true });
21964
23240
  try {
21965
- const gitStatus = execSync19("git status --porcelain", {
23241
+ const gitStatus = execSync21("git status --porcelain", {
21966
23242
  cwd: this.repoRoot,
21967
23243
  encoding: "utf-8",
21968
23244
  timeout: 1e4
21969
23245
  });
21970
- const gitDiff = execSync19("git diff", {
23246
+ const gitDiff = execSync21("git diff", {
21971
23247
  cwd: this.repoRoot,
21972
23248
  encoding: "utf-8",
21973
23249
  timeout: 1e4
21974
23250
  });
21975
- const gitHash = execSync19("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
23251
+ const gitHash = execSync21("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
21976
23252
  cwd: this.repoRoot,
21977
23253
  encoding: "utf-8",
21978
23254
  timeout: 5e3
21979
23255
  }).trim();
21980
- writeFileSync10(join31(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
21981
- writeFileSync10(join31(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
21982
- writeFileSync10(join31(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
21983
- writeFileSync10(join31(checkpointDir, "checkpoint.json"), JSON.stringify({
23256
+ writeFileSync10(join35(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
23257
+ writeFileSync10(join35(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
23258
+ writeFileSync10(join35(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
23259
+ writeFileSync10(join35(checkpointDir, "checkpoint.json"), JSON.stringify({
21984
23260
  cycle,
21985
23261
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
21986
23262
  gitHash,
@@ -21988,7 +23264,7 @@ Dreams directory: ${this.dreamsDir}`);
21988
23264
  }, null, 2), "utf-8");
21989
23265
  renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
21990
23266
  } catch {
21991
- writeFileSync10(join31(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
23267
+ writeFileSync10(join35(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
21992
23268
  renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
21993
23269
  }
21994
23270
  } catch (err) {
@@ -22046,14 +23322,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
22046
23322
  ---
22047
23323
  *Auto-generated by open-agents dream engine*
22048
23324
  `;
22049
- writeFileSync10(join31(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
23325
+ writeFileSync10(join35(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
22050
23326
  } catch {
22051
23327
  }
22052
23328
  }
22053
23329
  /** Save dream state for resume/inspection */
22054
23330
  saveDreamState() {
22055
23331
  try {
22056
- writeFileSync10(join31(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
23332
+ writeFileSync10(join35(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
22057
23333
  } catch {
22058
23334
  }
22059
23335
  }
@@ -23109,11 +24385,11 @@ var init_status_bar = __esm({
23109
24385
  import * as readline2 from "node:readline";
23110
24386
  import { Writable } from "node:stream";
23111
24387
  import { cwd } from "node:process";
23112
- import { resolve as resolve20, join as join32, dirname as dirname10, extname as extname9 } from "node:path";
24388
+ import { resolve as resolve23, join as join36, dirname as dirname11, extname as extname9 } from "node:path";
23113
24389
  import { createRequire as createRequire2 } from "node:module";
23114
- import { fileURLToPath as fileURLToPath7 } from "node:url";
23115
- import { readFileSync as readFileSync18, rmSync as rmSync2 } from "node:fs";
23116
- import { existsSync as existsSync25 } from "node:fs";
24390
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
24391
+ import { readFileSync as readFileSync19, rmSync as rmSync2 } from "node:fs";
24392
+ import { existsSync as existsSync26 } from "node:fs";
23117
24393
  function formatTimeAgo(date) {
23118
24394
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
23119
24395
  if (seconds < 60)
@@ -23130,14 +24406,14 @@ function formatTimeAgo(date) {
23130
24406
  function getVersion() {
23131
24407
  try {
23132
24408
  const require2 = createRequire2(import.meta.url);
23133
- const thisDir = dirname10(fileURLToPath7(import.meta.url));
24409
+ const thisDir = dirname11(fileURLToPath8(import.meta.url));
23134
24410
  const candidates = [
23135
- join32(thisDir, "..", "package.json"),
23136
- join32(thisDir, "..", "..", "package.json"),
23137
- join32(thisDir, "..", "..", "..", "package.json")
24411
+ join36(thisDir, "..", "package.json"),
24412
+ join36(thisDir, "..", "..", "package.json"),
24413
+ join36(thisDir, "..", "..", "..", "package.json")
23138
24414
  ];
23139
24415
  for (const pkgPath of candidates) {
23140
- if (existsSync25(pkgPath)) {
24416
+ if (existsSync26(pkgPath)) {
23141
24417
  const pkg = require2(pkgPath);
23142
24418
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
23143
24419
  return pkg.version ?? "0.0.0";
@@ -23235,7 +24511,13 @@ function buildTools(repoRoot, config, contextWindowSize) {
23235
24511
  new OcrPdfTool(repoRoot),
23236
24512
  new PdfToTextTool(repoRoot),
23237
24513
  // Advanced image OCR (multi-variant preprocessing pipeline)
23238
- new OcrImageAdvancedTool(repoRoot)
24514
+ new OcrImageAdvancedTool(repoRoot),
24515
+ // Browser automation (headless Chrome via Hydra scrape service)
24516
+ new BrowserActionTool(),
24517
+ // Temporal agency (scheduling, reminders, attention steering)
24518
+ new SchedulerTool(repoRoot),
24519
+ new ReminderTool(repoRoot),
24520
+ new AgendaTool(repoRoot)
23239
24521
  ];
23240
24522
  return [
23241
24523
  ...executionTools.map(adaptTool2),
@@ -23648,7 +24930,7 @@ ${entry.fullContent}`
23648
24930
  } };
23649
24931
  }
23650
24932
  async function startInteractive(config, repoPath) {
23651
- const repoRoot = resolve20(repoPath ?? cwd());
24933
+ const repoRoot = resolve23(repoPath ?? cwd());
23652
24934
  const resumeFlag = process.env.__OA_RESUMED ?? "";
23653
24935
  const isResumed = resumeFlag !== "";
23654
24936
  const hasTaskToResume = resumeFlag === "1";
@@ -23801,14 +25083,14 @@ async function startInteractive(config, repoPath) {
23801
25083
  renderInfo(msg);
23802
25084
  statusBar.endContentWrite();
23803
25085
  }
23804
- }, () => new Promise((resolve23) => {
25086
+ }, () => new Promise((resolve26) => {
23805
25087
  depSudoPromptPending = true;
23806
25088
  depSudoResolver = (pw) => {
23807
25089
  depSudoPromptPending = false;
23808
25090
  depSudoResolver = null;
23809
25091
  if (pw)
23810
25092
  sessionSudoPassword = pw;
23811
- resolve23(pw);
25093
+ resolve26(pw);
23812
25094
  };
23813
25095
  if (statusBar?.isActive) {
23814
25096
  statusBar.beginContentWrite();
@@ -24230,8 +25512,8 @@ async function startInteractive(config, repoPath) {
24230
25512
  return true;
24231
25513
  },
24232
25514
  destroyProject() {
24233
- const oaPath = join32(repoRoot, OA_DIR);
24234
- if (existsSync25(oaPath)) {
25515
+ const oaPath = join36(repoRoot, OA_DIR);
25516
+ if (existsSync26(oaPath)) {
24235
25517
  try {
24236
25518
  rmSync2(oaPath, { recursive: true, force: true });
24237
25519
  writeContent(() => renderInfo(`Removed ${OA_DIR}/ directory.`));
@@ -24293,6 +25575,41 @@ async function startInteractive(config, repoPath) {
24293
25575
  }, 150);
24294
25576
  }
24295
25577
  }
25578
+ if (!isResumed) {
25579
+ (async () => {
25580
+ try {
25581
+ const [dueReminders, activeAttention] = await Promise.all([
25582
+ getDueReminders(repoRoot),
25583
+ getActiveAttentionItems(repoRoot)
25584
+ ]);
25585
+ const criticalReminders = dueReminders.filter((r) => r.priority === "critical" || r.priority === "high");
25586
+ const criticalAttention = activeAttention.filter((a) => a.priority === "critical" || a.priority === "high");
25587
+ const totalDue = dueReminders.length + activeAttention.length;
25588
+ if (totalDue > 0) {
25589
+ setTimeout(() => {
25590
+ writeContent(() => {
25591
+ if (criticalReminders.length > 0 || criticalAttention.length > 0) {
25592
+ renderWarning(`${criticalReminders.length + criticalAttention.length} urgent item(s) need attention`);
25593
+ for (const r of criticalReminders)
25594
+ renderWarning(` Reminder: ${r.message.slice(0, 80)}`);
25595
+ for (const a of criticalAttention)
25596
+ renderWarning(` ${a.category}: ${a.title}`);
25597
+ }
25598
+ if (totalDue > criticalReminders.length + criticalAttention.length) {
25599
+ const normalCount = totalDue - criticalReminders.length - criticalAttention.length;
25600
+ renderInfo(`${normalCount} pending agenda item(s). Use agenda() to view.`);
25601
+ }
25602
+ });
25603
+ showPrompt();
25604
+ }, 300);
25605
+ if (dueReminders.length > 0) {
25606
+ await markRemindersSeen(repoRoot, dueReminders.map((r) => r.id));
25607
+ }
25608
+ }
25609
+ } catch {
25610
+ }
25611
+ })();
25612
+ }
24296
25613
  if (hasTaskToResume) {
24297
25614
  const pendingTask = loadPendingTask(repoRoot);
24298
25615
  if (pendingTask) {
@@ -24463,13 +25780,13 @@ Execute this skill now. Follow the behavioral guidance above.`;
24463
25780
  }
24464
25781
  }
24465
25782
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
24466
- const isImage = isImagePath(cleanPath) && existsSync25(resolve20(repoRoot, cleanPath));
24467
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync25(resolve20(repoRoot, cleanPath));
25783
+ const isImage = isImagePath(cleanPath) && existsSync26(resolve23(repoRoot, cleanPath));
25784
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync26(resolve23(repoRoot, cleanPath));
24468
25785
  if (activeTask) {
24469
25786
  if (isImage) {
24470
25787
  try {
24471
- const imgPath = resolve20(repoRoot, cleanPath);
24472
- const imgBuffer = readFileSync18(imgPath);
25788
+ const imgPath = resolve23(repoRoot, cleanPath);
25789
+ const imgBuffer = readFileSync19(imgPath);
24473
25790
  const base64 = imgBuffer.toString("base64");
24474
25791
  const ext = extname9(cleanPath).toLowerCase();
24475
25792
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -24482,7 +25799,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
24482
25799
  } else if (isMedia) {
24483
25800
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
24484
25801
  const engine = getListenEngine();
24485
- const result = await engine.transcribeFile(resolve20(repoRoot, cleanPath), repoRoot);
25802
+ const result = await engine.transcribeFile(resolve23(repoRoot, cleanPath), repoRoot);
24486
25803
  if (result) {
24487
25804
  const transcript = `[Transcription of ${cleanPath}]
24488
25805
  ${result.text}`;
@@ -24515,7 +25832,7 @@ ${result.text}`;
24515
25832
  if (isMedia && fullInput === input) {
24516
25833
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
24517
25834
  const engine = getListenEngine();
24518
- const result = await engine.transcribeFile(resolve20(repoRoot, cleanPath), repoRoot);
25835
+ const result = await engine.transcribeFile(resolve23(repoRoot, cleanPath), repoRoot);
24519
25836
  if (result) {
24520
25837
  fullInput = `The user has provided an audio/video file: ${cleanPath}.
24521
25838
 
@@ -24646,7 +25963,7 @@ ${c2.dim("(Use /quit to exit)")}
24646
25963
  });
24647
25964
  }
24648
25965
  async function runWithTUI(task, config, repoPath) {
24649
- const repoRoot = resolve20(repoPath ?? cwd());
25966
+ const repoRoot = resolve23(repoPath ?? cwd());
24650
25967
  const needsSetup = isFirstRun() || !await isModelAvailable(config);
24651
25968
  if (needsSetup && config.backendType === "ollama") {
24652
25969
  const setupModel = await runSetupWizard(config);
@@ -24750,9 +26067,9 @@ var init_run = __esm({
24750
26067
  // packages/indexer/dist/codebase-indexer.js
24751
26068
  import { glob } from "glob";
24752
26069
  import ignore from "ignore";
24753
- import { readFile as readFile11, stat as stat4 } from "node:fs/promises";
26070
+ import { readFile as readFile14, stat as stat4 } from "node:fs/promises";
24754
26071
  import { createHash } from "node:crypto";
24755
- import { join as join33, relative as relative3, extname as extname10, basename as basename13 } from "node:path";
26072
+ import { join as join37, relative as relative3, extname as extname10, basename as basename13 } from "node:path";
24756
26073
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
24757
26074
  var init_codebase_indexer = __esm({
24758
26075
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -24796,7 +26113,7 @@ var init_codebase_indexer = __esm({
24796
26113
  const ig = ignore.default();
24797
26114
  if (this.config.respectGitignore) {
24798
26115
  try {
24799
- const gitignoreContent = await readFile11(join33(this.config.rootDir, ".gitignore"), "utf-8");
26116
+ const gitignoreContent = await readFile14(join37(this.config.rootDir, ".gitignore"), "utf-8");
24800
26117
  ig.add(gitignoreContent);
24801
26118
  } catch {
24802
26119
  }
@@ -24811,12 +26128,12 @@ var init_codebase_indexer = __esm({
24811
26128
  for (const relativePath of files) {
24812
26129
  if (ig.ignores(relativePath))
24813
26130
  continue;
24814
- const fullPath = join33(this.config.rootDir, relativePath);
26131
+ const fullPath = join37(this.config.rootDir, relativePath);
24815
26132
  try {
24816
26133
  const fileStat = await stat4(fullPath);
24817
26134
  if (fileStat.size > this.config.maxFileSize)
24818
26135
  continue;
24819
- const content = await readFile11(fullPath);
26136
+ const content = await readFile14(fullPath);
24820
26137
  const hash = createHash("sha256").update(content).digest("hex");
24821
26138
  const ext = extname10(relativePath);
24822
26139
  indexed.push({
@@ -24857,7 +26174,7 @@ var init_codebase_indexer = __esm({
24857
26174
  if (!child) {
24858
26175
  child = {
24859
26176
  name: part,
24860
- path: join33(current.path, part),
26177
+ path: join37(current.path, part),
24861
26178
  type: "directory",
24862
26179
  children: []
24863
26180
  };
@@ -24939,14 +26256,14 @@ var index_repo_exports = {};
24939
26256
  __export(index_repo_exports, {
24940
26257
  indexRepoCommand: () => indexRepoCommand
24941
26258
  });
24942
- import { resolve as resolve21 } from "node:path";
24943
- import { existsSync as existsSync26, statSync as statSync10 } from "node:fs";
26259
+ import { resolve as resolve24 } from "node:path";
26260
+ import { existsSync as existsSync27, statSync as statSync10 } from "node:fs";
24944
26261
  import { cwd as cwd2 } from "node:process";
24945
26262
  async function indexRepoCommand(opts, _config) {
24946
- const repoRoot = resolve21(opts.repoPath ?? cwd2());
26263
+ const repoRoot = resolve24(opts.repoPath ?? cwd2());
24947
26264
  printHeader("Index Repository");
24948
26265
  printInfo(`Indexing: ${repoRoot}`);
24949
- if (!existsSync26(repoRoot)) {
26266
+ if (!existsSync27(repoRoot)) {
24950
26267
  printError(`Path does not exist: ${repoRoot}`);
24951
26268
  process.exit(1);
24952
26269
  }
@@ -25198,7 +26515,7 @@ var config_exports = {};
25198
26515
  __export(config_exports, {
25199
26516
  configCommand: () => configCommand
25200
26517
  });
25201
- import { join as join34, resolve as resolve22 } from "node:path";
26518
+ import { join as join38, resolve as resolve25 } from "node:path";
25202
26519
  import { homedir as homedir13 } from "node:os";
25203
26520
  import { cwd as cwd3 } from "node:process";
25204
26521
  function redactIfSensitive(key, value) {
@@ -25225,7 +26542,7 @@ async function configCommand(opts, config) {
25225
26542
  return handleShow(opts, config);
25226
26543
  }
25227
26544
  function handleShow(opts, config) {
25228
- const repoRoot = resolve22(opts.repoPath ?? cwd3());
26545
+ const repoRoot = resolve25(opts.repoPath ?? cwd3());
25229
26546
  printHeader("Configuration");
25230
26547
  printSection("Active Settings (merged)");
25231
26548
  printKeyValue("backendUrl", config.backendUrl, 2);
@@ -25257,7 +26574,7 @@ function handleShow(opts, config) {
25257
26574
  }
25258
26575
  }
25259
26576
  printSection("Config File");
25260
- printInfo(`~/.open-agents/config.json (${join34(homedir13(), ".open-agents", "config.json")})`);
26577
+ printInfo(`~/.open-agents/config.json (${join38(homedir13(), ".open-agents", "config.json")})`);
25261
26578
  printSection("Priority Chain");
25262
26579
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
25263
26580
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -25290,13 +26607,13 @@ function handleSet(opts, _config) {
25290
26607
  process.exit(1);
25291
26608
  }
25292
26609
  if (opts.local) {
25293
- const repoRoot = resolve22(opts.repoPath ?? cwd3());
26610
+ const repoRoot = resolve25(opts.repoPath ?? cwd3());
25294
26611
  try {
25295
26612
  initOaDirectory(repoRoot);
25296
26613
  const coerced = coerceForSettings(key, value);
25297
26614
  saveProjectSettings(repoRoot, { [key]: coerced });
25298
26615
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
25299
- printInfo(`Saved to ${join34(repoRoot, ".oa", "settings.json")}`);
26616
+ printInfo(`Saved to ${join38(repoRoot, ".oa", "settings.json")}`);
25300
26617
  printInfo("This override applies only when running in this workspace.");
25301
26618
  } catch (err) {
25302
26619
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -25357,7 +26674,7 @@ var serve_exports = {};
25357
26674
  __export(serve_exports, {
25358
26675
  serveCommand: () => serveCommand
25359
26676
  });
25360
- import { spawn as spawn9 } from "node:child_process";
26677
+ import { spawn as spawn10 } from "node:child_process";
25361
26678
  async function serveCommand(opts, config) {
25362
26679
  const backendType = config.backendType;
25363
26680
  if (backendType === "ollama") {
@@ -25449,8 +26766,8 @@ async function serveVllm(opts, config) {
25449
26766
  await runVllmServer(args, opts.verbose ?? false);
25450
26767
  }
25451
26768
  async function runVllmServer(args, verbose) {
25452
- return new Promise((resolve23, reject) => {
25453
- const child = spawn9("python", args, {
26769
+ return new Promise((resolve26, reject) => {
26770
+ const child = spawn10("python", args, {
25454
26771
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
25455
26772
  env: { ...process.env }
25456
26773
  });
@@ -25484,10 +26801,10 @@ async function runVllmServer(args, verbose) {
25484
26801
  child.once("exit", (code, signal) => {
25485
26802
  if (signal) {
25486
26803
  printInfo(`vLLM server stopped by signal ${signal}`);
25487
- resolve23();
26804
+ resolve26();
25488
26805
  } else if (code === 0) {
25489
26806
  printSuccess("vLLM server exited cleanly");
25490
- resolve23();
26807
+ resolve26();
25491
26808
  } else {
25492
26809
  printError(`vLLM server exited with code ${code}`);
25493
26810
  reject(new Error(`vLLM exited with code ${code}`));
@@ -25516,7 +26833,7 @@ __export(eval_exports, {
25516
26833
  });
25517
26834
  import { tmpdir as tmpdir7 } from "node:os";
25518
26835
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
25519
- import { join as join35 } from "node:path";
26836
+ import { join as join39 } from "node:path";
25520
26837
  async function evalCommand(opts, config) {
25521
26838
  const suiteName = opts.suite ?? "basic";
25522
26839
  const suite = SUITES[suiteName];
@@ -25637,9 +26954,9 @@ async function evalCommand(opts, config) {
25637
26954
  process.exit(failed > 0 ? 1 : 0);
25638
26955
  }
25639
26956
  function createTempEvalRepo() {
25640
- const dir = join35(tmpdir7(), `open-agents-eval-${Date.now()}`);
26957
+ const dir = join39(tmpdir7(), `open-agents-eval-${Date.now()}`);
25641
26958
  mkdirSync12(dir, { recursive: true });
25642
- writeFileSync11(join35(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
26959
+ writeFileSync11(join39(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
25643
26960
  return dir;
25644
26961
  }
25645
26962
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -25698,8 +27015,8 @@ init_output();
25698
27015
  init_updater();
25699
27016
  import { parseArgs as nodeParseArgs2 } from "node:util";
25700
27017
  import { createRequire as createRequire3 } from "node:module";
25701
- import { fileURLToPath as fileURLToPath8 } from "node:url";
25702
- import { dirname as dirname11, join as join36 } from "node:path";
27018
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
27019
+ import { dirname as dirname12, join as join40 } from "node:path";
25703
27020
 
25704
27021
  // packages/cli/dist/cli.js
25705
27022
  import { createInterface } from "node:readline";
@@ -25806,7 +27123,7 @@ init_output();
25806
27123
  function getVersion2() {
25807
27124
  try {
25808
27125
  const require2 = createRequire3(import.meta.url);
25809
- const pkgPath = join36(dirname11(fileURLToPath8(import.meta.url)), "..", "package.json");
27126
+ const pkgPath = join40(dirname12(fileURLToPath9(import.meta.url)), "..", "package.json");
25810
27127
  const pkg = require2(pkgPath);
25811
27128
  return pkg.version;
25812
27129
  } catch {