open-agents-ai 0.142.2 → 0.144.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
@@ -1370,7 +1370,7 @@ ${stdinInput ?? ""}`);
1370
1370
  }
1371
1371
  runCommand(command, timeout, stdinInput) {
1372
1372
  const start = performance.now();
1373
- return new Promise((resolve32) => {
1373
+ return new Promise((resolve33) => {
1374
1374
  const child = spawn("bash", ["-c", command], {
1375
1375
  cwd: this.workingDir,
1376
1376
  env: {
@@ -1395,7 +1395,7 @@ ${stdinInput ?? ""}`);
1395
1395
  clearTimeout(timer);
1396
1396
  if (exitFlushTimer)
1397
1397
  clearTimeout(exitFlushTimer);
1398
- resolve32(result);
1398
+ resolve33(result);
1399
1399
  };
1400
1400
  const timer = setTimeout(() => {
1401
1401
  killed = true;
@@ -1492,6 +1492,61 @@ ${stderr}` : ""),
1492
1492
  // packages/execution/dist/tools/file-read.js
1493
1493
  import { readFile } from "node:fs/promises";
1494
1494
  import { resolve } from "node:path";
1495
+ function computeMaxUngatedLines(contextWindow) {
1496
+ if (contextWindow <= 0)
1497
+ return 200;
1498
+ const budget = Math.floor(contextWindow * 0.15);
1499
+ const maxLines = Math.floor(budget / 10);
1500
+ return Math.max(80, Math.min(500, maxLines));
1501
+ }
1502
+ function buildStructuralPreview(lines, filePath, maxLines) {
1503
+ const total = lines.length;
1504
+ const HEAD = Math.min(30, Math.floor(maxLines * 0.35));
1505
+ const TAIL = Math.min(15, Math.floor(maxLines * 0.15));
1506
+ const parts = [];
1507
+ parts.push(`# ${filePath} \u2014 ${total} lines (showing structural preview)
1508
+ `);
1509
+ parts.push(`## Lines 1-${HEAD}:`);
1510
+ for (let i = 0; i < HEAD; i++) {
1511
+ parts.push(`${String(i + 1).padStart(6)} | ${lines[i]}`);
1512
+ }
1513
+ const sigs = [];
1514
+ for (let i = HEAD; i < total - TAIL; i++) {
1515
+ const line = lines[i];
1516
+ if (SIG_PATTERNS.some((p) => p.test(line))) {
1517
+ sigs.push(`${String(i + 1).padStart(6)} | ${line}`);
1518
+ }
1519
+ }
1520
+ if (sigs.length > 0) {
1521
+ parts.push(`
1522
+ ## Signatures (lines ${HEAD + 1}-${total - TAIL}) \u2014 ${sigs.length} found:`);
1523
+ const maxSigs = Math.floor(maxLines * 0.4);
1524
+ if (sigs.length > maxSigs) {
1525
+ parts.push(...sigs.slice(0, maxSigs));
1526
+ parts.push(` ... ${sigs.length - maxSigs} more signatures`);
1527
+ } else {
1528
+ parts.push(...sigs);
1529
+ }
1530
+ } else {
1531
+ parts.push(`
1532
+ ## Lines ${HEAD + 1}-${total - TAIL}: ${total - HEAD - TAIL} lines (no signatures detected)`);
1533
+ }
1534
+ if (TAIL > 0) {
1535
+ const tailStart = total - TAIL;
1536
+ parts.push(`
1537
+ ## Lines ${tailStart + 1}-${total}:`);
1538
+ for (let i = tailStart; i < total; i++) {
1539
+ parts.push(`${String(i + 1).padStart(6)} | ${lines[i]}`);
1540
+ }
1541
+ }
1542
+ parts.push(``);
1543
+ parts.push(`To read a specific section: file_read(path="${filePath}", offset=LINE, limit=50)`);
1544
+ parts.push(`To search for a pattern: grep_search(pattern="...", path="${filePath}")`);
1545
+ if (sigs.length > 0) {
1546
+ parts.push(`To explore interactively: file_explore(strategy="search", path="${filePath}", query="...")`);
1547
+ }
1548
+ return parts.join("\n");
1549
+ }
1495
1550
  function extractPath(args) {
1496
1551
  if (typeof args["path"] === "string" && args["path"].trim()) {
1497
1552
  return args["path"].trim();
@@ -1516,13 +1571,25 @@ function extractPath(args) {
1516
1571
  }
1517
1572
  return null;
1518
1573
  }
1519
- var FileReadTool;
1574
+ var SIG_PATTERNS, FileReadTool;
1520
1575
  var init_file_read = __esm({
1521
1576
  "packages/execution/dist/tools/file-read.js"() {
1522
1577
  "use strict";
1578
+ SIG_PATTERNS = [
1579
+ /^\s*(export\s+)?(async\s+)?function\s+\w+/,
1580
+ /^\s*(export\s+)?(abstract\s+)?class\s+\w+/,
1581
+ /^\s*(export\s+)?interface\s+\w+/,
1582
+ /^\s*(export\s+)?type\s+\w+\s*=/,
1583
+ /^\s*(export\s+)?enum\s+\w+/,
1584
+ /^\s*(?:public|private|protected|static|async|get|set)\s+\w+\s*[(<]/,
1585
+ /^\s*(pub\s+)?(async\s+)?fn\s+\w+/,
1586
+ /^\s*(pub\s+)?struct\s+\w+/,
1587
+ /^\s*def\s+\w+/,
1588
+ /^\s*class\s+\w+/
1589
+ ];
1523
1590
  FileReadTool = class {
1524
1591
  name = "file_read";
1525
- description = "Read the contents of a file";
1592
+ description = "Read the contents of a file. For large files (200+ lines), returns a structural preview with signatures \u2014 use offset/limit to read specific sections.";
1526
1593
  parameters = {
1527
1594
  type: "object",
1528
1595
  properties: {
@@ -1537,7 +1604,7 @@ var init_file_read = __esm({
1537
1604
  constructor(workingDir) {
1538
1605
  this.workingDir = workingDir;
1539
1606
  }
1540
- /** Set actual context window size to enable auto-windowing for small contexts */
1607
+ /** Set actual context window size for proportional auto-windowing */
1541
1608
  setContextWindowSize(size) {
1542
1609
  this._contextWindowSize = size;
1543
1610
  }
@@ -1559,24 +1626,25 @@ var init_file_read = __esm({
1559
1626
  const content = await readFile(fullPath, "utf-8");
1560
1627
  let lines = content.split("\n");
1561
1628
  const totalLines = lines.length;
1562
- if (offset !== void 0) {
1563
- const startIdx = Math.max(0, offset - 1);
1629
+ if (offset !== void 0 || limit !== void 0) {
1630
+ const startIdx = Math.max(0, (offset ?? 1) - 1);
1564
1631
  lines = lines.slice(startIdx, limit ? startIdx + limit : void 0);
1565
- } else if (this._contextWindowSize > 0 && this._contextWindowSize <= 32768 && !limit) {
1566
- const maxLines = this._contextWindowSize <= 16384 ? 80 : 120;
1567
- if (totalLines > maxLines) {
1568
- lines = lines.slice(0, maxLines);
1569
- const numbered2 = lines.map((line, i) => `${String(i + 1).padStart(6)} | ${line}`).join("\n");
1570
- return {
1571
- success: true,
1572
- output: `${numbered2}
1573
-
1574
- [File has ${totalLines} lines \u2014 showing first ${maxLines}. Use offset/limit to see more.]`,
1575
- durationMs: performance.now() - start
1576
- };
1577
- }
1632
+ const numbered2 = lines.map((line, i) => `${String(startIdx + i + 1).padStart(6)} | ${line}`).join("\n");
1633
+ return {
1634
+ success: true,
1635
+ output: numbered2,
1636
+ durationMs: performance.now() - start
1637
+ };
1638
+ }
1639
+ const maxLines = computeMaxUngatedLines(this._contextWindowSize);
1640
+ if (totalLines > maxLines) {
1641
+ return {
1642
+ success: true,
1643
+ output: buildStructuralPreview(lines, filePath, maxLines),
1644
+ durationMs: performance.now() - start
1645
+ };
1578
1646
  }
1579
- const numbered = lines.map((line, i) => `${String(i + (offset ?? 1)).padStart(6)} | ${line}`).join("\n");
1647
+ const numbered = lines.map((line, i) => `${String(i + 1).padStart(6)} | ${line}`).join("\n");
1580
1648
  return {
1581
1649
  success: true,
1582
1650
  output: numbered,
@@ -2556,7 +2624,7 @@ ${JSON.stringify(extracted, null, 2)}`);
2556
2624
  return null;
2557
2625
  }
2558
2626
  runProcess(cmd, args, timeoutMs) {
2559
- return new Promise((resolve32, reject) => {
2627
+ return new Promise((resolve33, reject) => {
2560
2628
  const proc = execFile3(cmd, args, {
2561
2629
  timeout: timeoutMs,
2562
2630
  maxBuffer: 10 * 1024 * 1024,
@@ -2566,7 +2634,7 @@ ${JSON.stringify(extracted, null, 2)}`);
2566
2634
  reject(new Error(`Process timeout after ${timeoutMs}ms`));
2567
2635
  return;
2568
2636
  }
2569
- resolve32({
2637
+ resolve33({
2570
2638
  stdout: String(stdout),
2571
2639
  stderr: String(stderr),
2572
2640
  exitCode: error ? error.code ?? 1 : 0
@@ -9975,7 +10043,7 @@ var init_custom_tool = __esm({
9975
10043
  }
9976
10044
  /** Execute a single shell command and return output */
9977
10045
  runCommand(command) {
9978
- return new Promise((resolve32) => {
10046
+ return new Promise((resolve33) => {
9979
10047
  const child = spawn4("bash", ["-c", command], {
9980
10048
  cwd: this.workingDir,
9981
10049
  env: { ...process.env, CI: "true", NO_COLOR: "1" },
@@ -10000,11 +10068,11 @@ var init_custom_tool = __esm({
10000
10068
  child.kill("SIGTERM");
10001
10069
  } catch {
10002
10070
  }
10003
- resolve32({ success: false, output: stdout, error: "Command timed out after 60s" });
10071
+ resolve33({ success: false, output: stdout, error: "Command timed out after 60s" });
10004
10072
  }, 6e4);
10005
10073
  child.on("close", (code) => {
10006
10074
  clearTimeout(timer);
10007
- resolve32({
10075
+ resolve33({
10008
10076
  success: code === 0,
10009
10077
  output: stdout + (stderr && code === 0 ? `
10010
10078
  STDERR:
@@ -10014,7 +10082,7 @@ ${stderr}` : ""),
10014
10082
  });
10015
10083
  child.on("error", (err) => {
10016
10084
  clearTimeout(timer);
10017
- resolve32({ success: false, output: stdout, error: err.message });
10085
+ resolve33({ success: false, output: stdout, error: err.message });
10018
10086
  });
10019
10087
  });
10020
10088
  }
@@ -11481,7 +11549,7 @@ import { writeFile as writeFile8, mkdtemp, rm, readdir as readdir3, stat } from
11481
11549
  import { join as join18 } from "node:path";
11482
11550
  import { tmpdir as tmpdir2 } from "node:os";
11483
11551
  function runProcess(cmd, args, options) {
11484
- return new Promise((resolve32) => {
11552
+ return new Promise((resolve33) => {
11485
11553
  const proc = spawn6(cmd, args, {
11486
11554
  cwd: options.cwd,
11487
11555
  timeout: options.timeout,
@@ -11511,7 +11579,7 @@ function runProcess(cmd, args, options) {
11511
11579
  }
11512
11580
  });
11513
11581
  proc.on("error", (err) => {
11514
- resolve32({
11582
+ resolve33({
11515
11583
  stdout,
11516
11584
  stderr: stderr || err.message,
11517
11585
  exitCode: 1,
@@ -11523,7 +11591,7 @@ function runProcess(cmd, args, options) {
11523
11591
  if (signal === "SIGTERM" || signal === "SIGKILL") {
11524
11592
  timedOut = true;
11525
11593
  }
11526
- resolve32({
11594
+ resolve33({
11527
11595
  stdout,
11528
11596
  stderr,
11529
11597
  exitCode: code ?? (timedOut ? 124 : 1),
@@ -12006,7 +12074,7 @@ Justification: ${justification || "(none provided)"}`,
12006
12074
  })();
12007
12075
  const ipfsResult = await Promise.race([
12008
12076
  ipfsPromise,
12009
- new Promise((resolve32) => setTimeout(() => resolve32(null), 2e3))
12077
+ new Promise((resolve33) => setTimeout(() => resolve33(null), 2e3))
12010
12078
  ]);
12011
12079
  if (ipfsResult && ipfsResult.success) {
12012
12080
  const cidData = JSON.parse(ipfsResult.output);
@@ -12450,7 +12518,7 @@ print("__OA_REPL_READY__")
12450
12518
  return;
12451
12519
  const sockId = randomBytes3(8).toString("hex");
12452
12520
  this.ipcPath = join20(tmpdir3(), `oa-repl-ipc-${sockId}.sock`);
12453
- return new Promise((resolve32, reject) => {
12521
+ return new Promise((resolve33, reject) => {
12454
12522
  this.ipcServer = createServer((conn) => {
12455
12523
  let buffer = new Uint8Array(0);
12456
12524
  conn.on("data", (chunk) => {
@@ -12466,7 +12534,7 @@ print("__OA_REPL_READY__")
12466
12534
  });
12467
12535
  });
12468
12536
  this.ipcServer.on("error", reject);
12469
- this.ipcServer.listen(this.ipcPath, () => resolve32());
12537
+ this.ipcServer.listen(this.ipcPath, () => resolve33());
12470
12538
  });
12471
12539
  }
12472
12540
  async processIpcBuffer(conn, input) {
@@ -12529,9 +12597,9 @@ print("__OA_REPL_READY__")
12529
12597
  }
12530
12598
  // ── Code execution ─────────────────────────────────────────────────────
12531
12599
  executeCode(code, isInit = false) {
12532
- return new Promise((resolve32) => {
12600
+ return new Promise((resolve33) => {
12533
12601
  if (!this.proc?.stdin || !this.proc?.stdout || !this.proc?.stderr) {
12534
- resolve32({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
12602
+ resolve33({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
12535
12603
  return;
12536
12604
  }
12537
12605
  const sentinel = `__OA_SENTINEL_${randomBytes3(6).toString("hex")}__`;
@@ -12541,7 +12609,7 @@ print("__OA_REPL_READY__")
12541
12609
  const timeout = setTimeout(() => {
12542
12610
  if (!resolved) {
12543
12611
  resolved = true;
12544
- resolve32({
12612
+ resolve33({
12545
12613
  success: false,
12546
12614
  output: stdout || "Execution timed out",
12547
12615
  error: `Timeout after ${this.execTimeout / 1e3}s`,
@@ -12558,13 +12626,13 @@ print("__OA_REPL_READY__")
12558
12626
  if (isInit) {
12559
12627
  const ready = cleanOutput.includes("__OA_REPL_READY__");
12560
12628
  const displayOutput = cleanOutput.replace("__OA_REPL_READY__", "").trim();
12561
- resolve32({
12629
+ resolve33({
12562
12630
  success: ready,
12563
12631
  output: displayOutput || "REPL initialized",
12564
12632
  durationMs: 0
12565
12633
  });
12566
12634
  } else {
12567
- resolve32({
12635
+ resolve33({
12568
12636
  success: true,
12569
12637
  output: cleanOutput || "(no output)",
12570
12638
  durationMs: 0
@@ -12573,7 +12641,7 @@ print("__OA_REPL_READY__")
12573
12641
  }
12574
12642
  if (stdout.length > 2e5) {
12575
12643
  cleanup();
12576
- resolve32({
12644
+ resolve33({
12577
12645
  success: true,
12578
12646
  output: stdout.slice(0, 2e5) + "\n[output truncated at 200KB]",
12579
12647
  durationMs: 0
@@ -16812,6 +16880,7 @@ train.py reverted to last kept state. Ready for next experiment.`,
16812
16880
  import { execSync as execSync18, exec as execCb } from "node:child_process";
16813
16881
  import { readFile as readFile15, writeFile as writeFile15, mkdir as mkdir11 } from "node:fs/promises";
16814
16882
  import { resolve as resolve22, join as join32 } from "node:path";
16883
+ import { homedir as homedir8 } from "node:os";
16815
16884
  import { randomBytes as randomBytes4 } from "node:crypto";
16816
16885
  function isValidCron(expr) {
16817
16886
  const parts = expr.trim().split(/\s+/);
@@ -16941,6 +17010,31 @@ async function saveStore(workingDir, store) {
16941
17010
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
16942
17011
  await writeFile15(join32(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
16943
17012
  }
17013
+ function globalStoreDir() {
17014
+ return join32(homedir8(), ".open-agents", "scheduled");
17015
+ }
17016
+ async function loadGlobalStore() {
17017
+ try {
17018
+ const raw = await readFile15(join32(globalStoreDir(), "tasks.json"), "utf-8");
17019
+ return JSON.parse(raw);
17020
+ } catch {
17021
+ return { tasks: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
17022
+ }
17023
+ }
17024
+ async function saveGlobalStore(store) {
17025
+ const dir = globalStoreDir();
17026
+ await mkdir11(dir, { recursive: true });
17027
+ await mkdir11(join32(dir, "logs"), { recursive: true });
17028
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
17029
+ await writeFile15(join32(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
17030
+ }
17031
+ async function loadAllStores(workingDir) {
17032
+ const [local, global] = await Promise.all([
17033
+ loadStore(workingDir),
17034
+ loadGlobalStore()
17035
+ ]);
17036
+ return { local, global };
17037
+ }
16944
17038
  var SCHEDULE_PRESETS, CRON_MARKER, SchedulerTool;
16945
17039
  var init_scheduler = __esm({
16946
17040
  "packages/execution/dist/tools/scheduler.js"() {
@@ -16964,7 +17058,7 @@ var init_scheduler = __esm({
16964
17058
  CRON_MARKER = "# OPEN-AGENTS-SCHEDULED:";
16965
17059
  SchedulerTool = class {
16966
17060
  name = "scheduler";
16967
- 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.";
17061
+ 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 * * *'). Scope: 'local' (default, stored in .oa/) or 'global' (stored in ~/.open-agents/, visible from all projects). Tasks launch the agent automatically at the scheduled time.";
16968
17062
  parameters = {
16969
17063
  type: "object",
16970
17064
  properties: {
@@ -16992,6 +17086,11 @@ var init_scheduler = __esm({
16992
17086
  one_shot: {
16993
17087
  type: "boolean",
16994
17088
  description: "If true, task auto-removes after first execution"
17089
+ },
17090
+ scope: {
17091
+ type: "string",
17092
+ enum: ["local", "global"],
17093
+ description: "Scope: 'local' (project .oa/, default) or 'global' (~/.open-agents/, visible from all projects)"
16995
17094
  }
16996
17095
  },
16997
17096
  required: ["action"]
@@ -17053,6 +17152,7 @@ var init_scheduler = __esm({
17053
17152
  const id = `sched-${randomBytes4(4).toString("hex")}`;
17054
17153
  const oneShot = Boolean(args["one_shot"]);
17055
17154
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : void 0;
17155
+ const scope = String(args["scope"] ?? "local");
17056
17156
  const newTask = {
17057
17157
  id,
17058
17158
  task,
@@ -17062,11 +17162,19 @@ var init_scheduler = __esm({
17062
17162
  enabled: true,
17063
17163
  runCount: 0,
17064
17164
  maxRuns,
17065
- oneShot: oneShot || void 0
17165
+ oneShot: oneShot || void 0,
17166
+ scope,
17167
+ projectDir: resolve22(this.workingDir)
17066
17168
  };
17067
- const store = await loadStore(this.workingDir);
17068
- store.tasks.push(newTask);
17069
- await saveStore(this.workingDir, store);
17169
+ if (scope === "global") {
17170
+ const store = await loadGlobalStore();
17171
+ store.tasks.push(newTask);
17172
+ await saveGlobalStore(store);
17173
+ } else {
17174
+ const store = await loadStore(this.workingDir);
17175
+ store.tasks.push(newTask);
17176
+ await saveStore(this.workingDir, store);
17177
+ }
17070
17178
  installCronJob(newTask, this.workingDir);
17071
17179
  return {
17072
17180
  success: true,
@@ -17075,6 +17183,7 @@ var init_scheduler = __esm({
17075
17183
  ` ID: ${id}`,
17076
17184
  ` Task: ${task}`,
17077
17185
  ` Schedule: ${describeCron(cronExpr)} (${cronExpr})`,
17186
+ ` Scope: ${scope}${scope === "global" ? " (visible from all projects)" : " (this project only)"}`,
17078
17187
  oneShot ? ` Mode: one-shot (auto-removes after first run)` : "",
17079
17188
  maxRuns ? ` Max runs: ${maxRuns}` : "",
17080
17189
  ` Status: enabled`,
@@ -17086,28 +17195,53 @@ var init_scheduler = __esm({
17086
17195
  };
17087
17196
  }
17088
17197
  async listTasks(start) {
17089
- const store = await loadStore(this.workingDir);
17198
+ const { local, global } = await loadAllStores(this.workingDir);
17090
17199
  const cronJobs = listCronJobs();
17091
- if (store.tasks.length === 0) {
17200
+ const totalCount = local.tasks.length + global.tasks.length;
17201
+ if (totalCount === 0) {
17092
17202
  return {
17093
17203
  success: true,
17094
17204
  output: "No scheduled tasks. Use scheduler(action='create', task='...', schedule='daily') to create one.",
17095
17205
  durationMs: performance.now() - start
17096
17206
  };
17097
17207
  }
17098
- const lines = [`Scheduled Tasks (${store.tasks.length}):
17099
- `];
17100
- for (const t of store.tasks) {
17101
- const status = t.enabled ? "enabled" : "PAUSED";
17102
- const cronInstalled = cronJobs.some((j) => j.id === t.id);
17103
- const cronStatus = cronInstalled ? "" : " [cron not installed]";
17104
- lines.push(` [${t.id}] ${status}${cronStatus}`);
17105
- lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
17106
- lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
17107
- lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
17108
- if (t.lastRun)
17109
- lines.push(` Last run: ${t.lastRun}`);
17110
- lines.push("");
17208
+ const lines = [];
17209
+ if (local.tasks.length > 0) {
17210
+ lines.push(`Local Tasks \u2014 this project (${local.tasks.length}):
17211
+ `);
17212
+ for (const t of local.tasks) {
17213
+ const status = t.enabled ? "enabled" : "PAUSED";
17214
+ const cronInstalled = cronJobs.some((j) => j.id === t.id);
17215
+ const cronStatus = cronInstalled ? "" : " [cron not installed]";
17216
+ lines.push(` [${t.id}] ${status}${cronStatus} [local]`);
17217
+ lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
17218
+ lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
17219
+ lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
17220
+ if (t.lastRun)
17221
+ lines.push(` Last run: ${t.lastRun}`);
17222
+ lines.push("");
17223
+ }
17224
+ }
17225
+ if (global.tasks.length > 0) {
17226
+ lines.push(`Global Tasks \u2014 shared across projects (${global.tasks.length}):
17227
+ `);
17228
+ for (const t of global.tasks) {
17229
+ const status = t.enabled ? "enabled" : "PAUSED";
17230
+ const cronInstalled = cronJobs.some((j) => j.id === t.id);
17231
+ const cronStatus = cronInstalled ? "" : " [cron not installed]";
17232
+ const isThisProject = t.projectDir === resolve22(this.workingDir);
17233
+ const origin = isThisProject ? " [this project]" : t.projectDir ? ` [from: ${t.projectDir}]` : "";
17234
+ lines.push(` [${t.id}] ${status}${cronStatus} [global]${origin}`);
17235
+ lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
17236
+ lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
17237
+ lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
17238
+ if (t.lastRun)
17239
+ lines.push(` Last run: ${t.lastRun}`);
17240
+ if (!isThisProject && t.projectDir) {
17241
+ lines.push(` \u26A0 NOT scoped to this project \u2014 override with caution`);
17242
+ }
17243
+ lines.push("");
17244
+ }
17111
17245
  }
17112
17246
  return {
17113
17247
  success: true,
@@ -17668,7 +17802,7 @@ ${sections.join("\n")}`,
17668
17802
  const description = String(args["description"] ?? "");
17669
17803
  const category = args["category"] ?? "followup";
17670
17804
  const priority = args["priority"] ?? "normal";
17671
- const notes = args["notes"] ?? void 0;
17805
+ const notes2 = args["notes"] ?? void 0;
17672
17806
  const relatedFilesStr = args["related_files"] ?? "";
17673
17807
  const relatedFiles = relatedFilesStr ? relatedFilesStr.split(",").map((f) => f.trim()).filter(Boolean) : void 0;
17674
17808
  let expiresAt;
@@ -17701,7 +17835,7 @@ ${sections.join("\n")}`,
17701
17835
  expiresAt,
17702
17836
  relatedFiles,
17703
17837
  status: "active",
17704
- notes
17838
+ notes: notes2
17705
17839
  };
17706
17840
  const store = await loadAttentionStore(this.workingDir);
17707
17841
  store.items.push(item);
@@ -18395,6 +18529,7 @@ var init_factory = __esm({
18395
18529
  import { execSync as execSync21 } from "node:child_process";
18396
18530
  import { readFile as readFile18, writeFile as writeFile18, mkdir as mkdir14 } from "node:fs/promises";
18397
18531
  import { resolve as resolve26, join as join37 } from "node:path";
18532
+ import { homedir as homedir9 } from "node:os";
18398
18533
  import { randomBytes as randomBytes7 } from "node:crypto";
18399
18534
  function isValidCron2(expr) {
18400
18535
  const parts = expr.trim().split(/\s+/);
@@ -18523,6 +18658,31 @@ async function saveStore2(workingDir, store) {
18523
18658
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
18524
18659
  await writeFile18(join37(dir, "store.json"), JSON.stringify(store, null, 2), "utf-8");
18525
18660
  }
18661
+ function globalCronDir() {
18662
+ return join37(homedir9(), ".open-agents", "cron-agents");
18663
+ }
18664
+ async function loadGlobalCronStore() {
18665
+ try {
18666
+ const raw = await readFile18(join37(globalCronDir(), "store.json"), "utf-8");
18667
+ return JSON.parse(raw);
18668
+ } catch {
18669
+ return { jobs: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
18670
+ }
18671
+ }
18672
+ async function saveGlobalCronStore(store) {
18673
+ const dir = globalCronDir();
18674
+ await mkdir14(dir, { recursive: true });
18675
+ await mkdir14(join37(dir, "logs"), { recursive: true });
18676
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
18677
+ await writeFile18(join37(dir, "store.json"), JSON.stringify(store, null, 2), "utf-8");
18678
+ }
18679
+ async function loadAllCronStores(workingDir) {
18680
+ const [local, global] = await Promise.all([
18681
+ loadStore2(workingDir),
18682
+ loadGlobalCronStore()
18683
+ ]);
18684
+ return { local, global };
18685
+ }
18526
18686
  var LONG_HORIZON_PRESETS, CRON_AGENT_MARKER, CronAgentTool;
18527
18687
  var init_cron_agent = __esm({
18528
18688
  "packages/execution/dist/tools/cron-agent.js"() {
@@ -18591,6 +18751,11 @@ var init_cron_agent = __esm({
18591
18751
  type: "array",
18592
18752
  items: { type: "string" },
18593
18753
  description: "Tags for organizing jobs (for 'create')"
18754
+ },
18755
+ scope: {
18756
+ type: "string",
18757
+ enum: ["local", "global"],
18758
+ description: "Scope: 'local' (project .oa/, default) or 'global' (~/.open-agents/, visible from all projects)"
18594
18759
  }
18595
18760
  },
18596
18761
  required: ["action"]
@@ -18659,6 +18824,7 @@ var init_cron_agent = __esm({
18659
18824
  const verifyCommand = args["verify_command"] ? String(args["verify_command"]) : void 0;
18660
18825
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : 0;
18661
18826
  const tags = Array.isArray(args["tags"]) ? args["tags"] : [];
18827
+ const scope = String(args["scope"] ?? "local");
18662
18828
  const job = {
18663
18829
  id,
18664
18830
  task,
@@ -18672,11 +18838,19 @@ var init_cron_agent = __esm({
18672
18838
  runCount: 0,
18673
18839
  maxRuns,
18674
18840
  history: [],
18675
- tags
18841
+ tags,
18842
+ scope,
18843
+ projectDir: resolve26(this.workingDir)
18676
18844
  };
18677
- const store = await loadStore2(this.workingDir);
18678
- store.jobs.push(job);
18679
- await saveStore2(this.workingDir, store);
18845
+ if (scope === "global") {
18846
+ const store = await loadGlobalCronStore();
18847
+ store.jobs.push(job);
18848
+ await saveGlobalCronStore(store);
18849
+ } else {
18850
+ const store = await loadStore2(this.workingDir);
18851
+ store.jobs.push(job);
18852
+ await saveStore2(this.workingDir, store);
18853
+ }
18680
18854
  installCronAgentJob(job, this.workingDir);
18681
18855
  return {
18682
18856
  success: true,
@@ -18700,19 +18874,19 @@ var init_cron_agent = __esm({
18700
18874
  };
18701
18875
  }
18702
18876
  async listJobs(start) {
18703
- const store = await loadStore2(this.workingDir);
18704
- if (store.jobs.length === 0) {
18877
+ const { local, global } = await loadAllCronStores(this.workingDir);
18878
+ const totalCount = local.jobs.length + global.jobs.length;
18879
+ if (totalCount === 0) {
18705
18880
  return {
18706
18881
  success: true,
18707
18882
  output: "No cron agent jobs. Use cron_agent(action='create', ...) to schedule one.",
18708
18883
  durationMs: performance.now() - start
18709
18884
  };
18710
18885
  }
18711
- const lines = [`Cron Agent Jobs (${store.jobs.length}):
18712
- `];
18713
- for (const job of store.jobs) {
18886
+ const lines = [];
18887
+ const formatJob = (job, scopeLabel, isThisProject) => {
18714
18888
  const statusIcon = job.status === "active" ? "\u25CF" : job.status === "completed" ? "\u2714" : job.status === "paused" ? "\u23F8" : "\u2716";
18715
- lines.push(` ${statusIcon} [${job.id}] ${job.status.toUpperCase()}`);
18889
+ lines.push(` ${statusIcon} [${job.id}] ${job.status.toUpperCase()} [${scopeLabel}]`);
18716
18890
  lines.push(` Goal: ${job.goal.slice(0, 80)}${job.goal.length > 80 ? "..." : ""}`);
18717
18891
  lines.push(` Schedule: ${job.scheduleDescription}`);
18718
18892
  lines.push(` Runs: ${job.runCount}${job.maxRuns > 0 ? `/${job.maxRuns}` : ""}`);
@@ -18720,7 +18894,25 @@ var init_cron_agent = __esm({
18720
18894
  lines.push(` Last run: ${job.lastRunAt}`);
18721
18895
  if (job.tags.length > 0)
18722
18896
  lines.push(` Tags: ${job.tags.join(", ")}`);
18897
+ if (!isThisProject && job.projectDir) {
18898
+ lines.push(` Origin: ${job.projectDir}`);
18899
+ lines.push(` \u26A0 NOT scoped to this project \u2014 override with caution`);
18900
+ }
18723
18901
  lines.push("");
18902
+ };
18903
+ if (local.jobs.length > 0) {
18904
+ lines.push(`Local Cron Jobs \u2014 this project (${local.jobs.length}):
18905
+ `);
18906
+ for (const job of local.jobs)
18907
+ formatJob(job, "local", true);
18908
+ }
18909
+ if (global.jobs.length > 0) {
18910
+ lines.push(`Global Cron Jobs \u2014 shared (${global.jobs.length}):
18911
+ `);
18912
+ for (const job of global.jobs) {
18913
+ const isThisProject = job.projectDir === resolve26(this.workingDir);
18914
+ formatJob(job, isThisProject ? "global, this project" : "global", isThisProject);
18915
+ }
18724
18916
  }
18725
18917
  return {
18726
18918
  success: true,
@@ -18856,6 +19048,575 @@ ${truncated}`, durationMs: performance.now() - start };
18856
19048
  }
18857
19049
  });
18858
19050
 
19051
+ // packages/execution/dist/tools/file-explore.js
19052
+ import { readFile as readFile19 } from "node:fs/promises";
19053
+ import { resolve as resolve27 } from "node:path";
19054
+ import { execFile as execFile4 } from "node:child_process";
19055
+ import { promisify as promisify3 } from "node:util";
19056
+ function getPatterns(filePath) {
19057
+ if (/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filePath))
19058
+ return SIG_PATTERNS2.ts;
19059
+ if (/\.py$/.test(filePath))
19060
+ return SIG_PATTERNS2.py;
19061
+ if (/\.rs$/.test(filePath))
19062
+ return SIG_PATTERNS2.rs;
19063
+ if (/\.go$/.test(filePath))
19064
+ return SIG_PATTERNS2.go;
19065
+ return SIG_PATTERNS2.default;
19066
+ }
19067
+ function clearExploreNotes() {
19068
+ sessionNotes.length = 0;
19069
+ }
19070
+ function getExploreNotes() {
19071
+ return sessionNotes;
19072
+ }
19073
+ var execFileAsync3, sessionNotes, SIG_PATTERNS2, FileExploreTool;
19074
+ var init_file_explore = __esm({
19075
+ "packages/execution/dist/tools/file-explore.js"() {
19076
+ "use strict";
19077
+ execFileAsync3 = promisify3(execFile4);
19078
+ sessionNotes = [];
19079
+ SIG_PATTERNS2 = {
19080
+ ts: [
19081
+ /^\s*(export\s+)?(async\s+)?function\s+\w+/,
19082
+ /^\s*(export\s+)?(abstract\s+)?class\s+\w+/,
19083
+ /^\s*(export\s+)?(const|let|var)\s+\w+\s*[:=]/,
19084
+ /^\s*(export\s+)?interface\s+\w+/,
19085
+ /^\s*(export\s+)?type\s+\w+\s*=/,
19086
+ /^\s*(export\s+)?enum\s+\w+/,
19087
+ /^\s*(?:public|private|protected|static|async|get|set)\s+\w+\s*[(<]/
19088
+ ],
19089
+ py: [
19090
+ /^\s*def\s+\w+/,
19091
+ /^\s*class\s+\w+/,
19092
+ /^\s*async\s+def\s+\w+/,
19093
+ /^[A-Z_][A-Z_0-9]*\s*=/
19094
+ ],
19095
+ rs: [
19096
+ /^\s*(pub\s+)?(async\s+)?fn\s+\w+/,
19097
+ /^\s*(pub\s+)?struct\s+\w+/,
19098
+ /^\s*(pub\s+)?enum\s+\w+/,
19099
+ /^\s*(pub\s+)?trait\s+\w+/,
19100
+ /^\s*impl\s+/
19101
+ ],
19102
+ go: [
19103
+ /^\s*func\s+/,
19104
+ /^\s*type\s+\w+\s+struct/,
19105
+ /^\s*type\s+\w+\s+interface/
19106
+ ],
19107
+ default: [
19108
+ /^\s*(export\s+)?(function|class|const|let|var|def|fn|pub|type|interface|enum|struct|trait|impl)\s+/
19109
+ ]
19110
+ };
19111
+ FileExploreTool = class {
19112
+ name = "file_explore";
19113
+ description = "Explore large files without reading them entirely into context. Strategies: 'overview' (structural skeleton \u2014 imports, exports, signatures), 'search' (grep pattern with \xB1N context lines), 'chunk' (read specific line range, auto-saved to working notes), 'outline' (function/class/method signatures only), 'notes' (show accumulated findings from this session). Use this INSTEAD of file_read for files > 200 lines. Pattern: overview \u2192 search for target \u2192 chunk to read details \u2192 note findings.";
19114
+ parameters = {
19115
+ type: "object",
19116
+ properties: {
19117
+ path: {
19118
+ type: "string",
19119
+ description: "File path to explore"
19120
+ },
19121
+ strategy: {
19122
+ type: "string",
19123
+ enum: ["overview", "search", "chunk", "outline", "notes"],
19124
+ description: "Exploration strategy"
19125
+ },
19126
+ query: {
19127
+ type: "string",
19128
+ description: "Search pattern (for 'search' strategy) or note text (for 'chunk' with note)"
19129
+ },
19130
+ offset: {
19131
+ type: "number",
19132
+ description: "Starting line number, 1-based (for 'chunk' strategy)"
19133
+ },
19134
+ limit: {
19135
+ type: "number",
19136
+ description: "Number of lines to read (for 'chunk', default 50)"
19137
+ },
19138
+ context_lines: {
19139
+ type: "number",
19140
+ description: "Lines of context around each match (for 'search', default 5)"
19141
+ },
19142
+ note: {
19143
+ type: "string",
19144
+ description: "Working note to save about this chunk (for 'chunk' strategy)"
19145
+ }
19146
+ },
19147
+ required: ["strategy"]
19148
+ };
19149
+ workingDir;
19150
+ constructor(workingDir) {
19151
+ this.workingDir = workingDir;
19152
+ }
19153
+ async execute(args) {
19154
+ const strategy = String(args["strategy"] ?? "overview");
19155
+ const filePath = String(args["path"] ?? "");
19156
+ const start = performance.now();
19157
+ switch (strategy) {
19158
+ case "overview":
19159
+ return this.overview(filePath, start);
19160
+ case "search":
19161
+ return this.search(filePath, String(args["query"] ?? ""), args, start);
19162
+ case "chunk":
19163
+ return this.chunk(filePath, args, start);
19164
+ case "outline":
19165
+ return this.outline(filePath, start);
19166
+ case "notes":
19167
+ return this.showNotes(filePath, start);
19168
+ default:
19169
+ return {
19170
+ success: false,
19171
+ output: "",
19172
+ error: `Unknown strategy '${strategy}'. Use: overview, search, chunk, outline, notes`,
19173
+ durationMs: performance.now() - start
19174
+ };
19175
+ }
19176
+ }
19177
+ /**
19178
+ * overview: Read structural skeleton — first 30 lines (imports/config),
19179
+ * all signature lines, last 20 lines (exports/module boundary).
19180
+ */
19181
+ async overview(filePath, start) {
19182
+ if (!filePath)
19183
+ return { success: false, output: "", error: "path required for overview", durationMs: performance.now() - start };
19184
+ try {
19185
+ const fullPath = resolve27(this.workingDir, filePath);
19186
+ const content = await readFile19(fullPath, "utf-8");
19187
+ const lines = content.split("\n");
19188
+ const total = lines.length;
19189
+ const HEAD = Math.min(30, total);
19190
+ const TAIL = Math.min(20, Math.max(0, total - HEAD));
19191
+ const parts = [];
19192
+ parts.push(`# ${filePath} (${total} lines)
19193
+ `);
19194
+ parts.push("## Head (lines 1-" + HEAD + ")");
19195
+ for (let i = 0; i < HEAD; i++) {
19196
+ parts.push(`${String(i + 1).padStart(6)} | ${lines[i]}`);
19197
+ }
19198
+ if (total > HEAD + TAIL) {
19199
+ const patterns = getPatterns(filePath);
19200
+ const sigs = [];
19201
+ for (let i = HEAD; i < total - TAIL; i++) {
19202
+ const line = lines[i];
19203
+ if (patterns.some((p) => p.test(line))) {
19204
+ sigs.push(`${String(i + 1).padStart(6)} | ${line}`);
19205
+ }
19206
+ }
19207
+ if (sigs.length > 0) {
19208
+ parts.push(`
19209
+ ## Signatures (lines ${HEAD + 1}-${total - TAIL}) \u2014 ${sigs.length} found`);
19210
+ parts.push(...sigs);
19211
+ } else {
19212
+ parts.push(`
19213
+ ## Middle (lines ${HEAD + 1}-${total - TAIL}) \u2014 ${total - HEAD - TAIL} lines, no signatures detected`);
19214
+ }
19215
+ }
19216
+ if (TAIL > 0) {
19217
+ const tailStart = total - TAIL;
19218
+ parts.push(`
19219
+ ## Tail (lines ${tailStart + 1}-${total})`);
19220
+ for (let i = tailStart; i < total; i++) {
19221
+ parts.push(`${String(i + 1).padStart(6)} | ${lines[i]}`);
19222
+ }
19223
+ }
19224
+ parts.push(`
19225
+ [Use file_explore(strategy='search', query='...') to find specific sections]`);
19226
+ parts.push(`[Use file_explore(strategy='chunk', offset=N, limit=50) to read a section]`);
19227
+ return {
19228
+ success: true,
19229
+ output: parts.join("\n"),
19230
+ durationMs: performance.now() - start
19231
+ };
19232
+ } catch (error) {
19233
+ return {
19234
+ success: false,
19235
+ output: "",
19236
+ error: error instanceof Error ? error.message : String(error),
19237
+ durationMs: performance.now() - start
19238
+ };
19239
+ }
19240
+ }
19241
+ /**
19242
+ * search: Grep for pattern with context lines around each match.
19243
+ */
19244
+ async search(filePath, query, args, start) {
19245
+ if (!query)
19246
+ return { success: false, output: "", error: "query required for search strategy", durationMs: performance.now() - start };
19247
+ const contextLines = Number(args["context_lines"] ?? 5);
19248
+ const searchPath = filePath ? resolve27(this.workingDir, filePath) : this.workingDir;
19249
+ try {
19250
+ const rgArgs = [
19251
+ "--line-number",
19252
+ "--no-heading",
19253
+ "--color=never",
19254
+ "-C",
19255
+ String(contextLines)
19256
+ ];
19257
+ if (filePath) {
19258
+ rgArgs.push(query, searchPath);
19259
+ } else {
19260
+ rgArgs.push(query, this.workingDir);
19261
+ }
19262
+ const { stdout } = await execFileAsync3("rg", rgArgs, {
19263
+ cwd: this.workingDir,
19264
+ maxBuffer: 1024 * 1024
19265
+ });
19266
+ const lines = stdout.split("\n").filter((l) => l.length > 0);
19267
+ const matchCount = lines.filter((l) => /^\d+:/.test(l) || /:\d+:/.test(l)).length;
19268
+ const MAX = 80;
19269
+ const truncated = lines.length > MAX;
19270
+ const output = lines.slice(0, MAX).join("\n");
19271
+ const result = [
19272
+ `Found ${matchCount} matches for "${query}"${filePath ? ` in ${filePath}` : ""}:`,
19273
+ "",
19274
+ truncated ? output + `
19275
+
19276
+ [Truncated \u2014 ${lines.length - MAX} more lines]` : output,
19277
+ "",
19278
+ `[Use file_explore(strategy='chunk', path='...', offset=N) to read around a specific match]`
19279
+ ].join("\n");
19280
+ return {
19281
+ success: true,
19282
+ output: result,
19283
+ durationMs: performance.now() - start
19284
+ };
19285
+ } catch (error) {
19286
+ const err = error;
19287
+ if (err.code === 1) {
19288
+ return {
19289
+ success: true,
19290
+ output: `No matches for "${query}"${filePath ? ` in ${filePath}` : ""}.`,
19291
+ durationMs: performance.now() - start
19292
+ };
19293
+ }
19294
+ try {
19295
+ const grepArgs = ["-rn", "--color=never", `-C${contextLines}`];
19296
+ if (filePath) {
19297
+ grepArgs.push(query, searchPath);
19298
+ } else {
19299
+ grepArgs.push(query, this.workingDir);
19300
+ }
19301
+ const { stdout } = await execFileAsync3("grep", grepArgs, {
19302
+ cwd: this.workingDir,
19303
+ maxBuffer: 1024 * 1024
19304
+ });
19305
+ return {
19306
+ success: true,
19307
+ output: stdout.split("\n").slice(0, 80).join("\n"),
19308
+ durationMs: performance.now() - start
19309
+ };
19310
+ } catch {
19311
+ return {
19312
+ success: true,
19313
+ output: `No matches for "${query}".`,
19314
+ durationMs: performance.now() - start
19315
+ };
19316
+ }
19317
+ }
19318
+ }
19319
+ /**
19320
+ * chunk: Read a specific line range and optionally save a working note.
19321
+ */
19322
+ async chunk(filePath, args, start) {
19323
+ if (!filePath)
19324
+ return { success: false, output: "", error: "path required for chunk strategy", durationMs: performance.now() - start };
19325
+ const offset = Number(args["offset"] ?? 1);
19326
+ const limit = Number(args["limit"] ?? 50);
19327
+ const note = args["note"];
19328
+ try {
19329
+ const fullPath = resolve27(this.workingDir, filePath);
19330
+ const content = await readFile19(fullPath, "utf-8");
19331
+ const allLines = content.split("\n");
19332
+ const total = allLines.length;
19333
+ const startIdx = Math.max(0, offset - 1);
19334
+ const endIdx = Math.min(total, startIdx + limit);
19335
+ const chunk = allLines.slice(startIdx, endIdx);
19336
+ const numbered = chunk.map((line, i) => `${String(startIdx + i + 1).padStart(6)} | ${line}`).join("\n");
19337
+ if (note) {
19338
+ sessionNotes.push({
19339
+ file: filePath,
19340
+ lineRange: [startIdx + 1, endIdx],
19341
+ finding: note,
19342
+ timestamp: Date.now()
19343
+ });
19344
+ }
19345
+ const nav = [];
19346
+ if (startIdx > 0) {
19347
+ nav.push(`[Previous: file_explore(strategy='chunk', path='${filePath}', offset=${Math.max(1, startIdx + 1 - limit)}, limit=${limit})]`);
19348
+ }
19349
+ if (endIdx < total) {
19350
+ nav.push(`[Next: file_explore(strategy='chunk', path='${filePath}', offset=${endIdx + 1}, limit=${limit})]`);
19351
+ }
19352
+ nav.push(`[${total} total lines \u2014 showing ${startIdx + 1}-${endIdx}]`);
19353
+ if (sessionNotes.length > 0) {
19354
+ nav.push(`[${sessionNotes.length} working notes \u2014 file_explore(strategy='notes') to review]`);
19355
+ }
19356
+ return {
19357
+ success: true,
19358
+ output: numbered + "\n\n" + nav.join("\n"),
19359
+ durationMs: performance.now() - start
19360
+ };
19361
+ } catch (error) {
19362
+ return {
19363
+ success: false,
19364
+ output: "",
19365
+ error: error instanceof Error ? error.message : String(error),
19366
+ durationMs: performance.now() - start
19367
+ };
19368
+ }
19369
+ }
19370
+ /**
19371
+ * outline: Extract only function/class/method/export signatures.
19372
+ */
19373
+ async outline(filePath, start) {
19374
+ if (!filePath)
19375
+ return { success: false, output: "", error: "path required for outline", durationMs: performance.now() - start };
19376
+ try {
19377
+ const fullPath = resolve27(this.workingDir, filePath);
19378
+ const content = await readFile19(fullPath, "utf-8");
19379
+ const lines = content.split("\n");
19380
+ const patterns = getPatterns(filePath);
19381
+ const sigs = [];
19382
+ for (let i = 0; i < lines.length; i++) {
19383
+ const line = lines[i];
19384
+ if (patterns.some((p) => p.test(line))) {
19385
+ sigs.push(`${String(i + 1).padStart(6)} | ${line.trimEnd()}`);
19386
+ }
19387
+ }
19388
+ if (sigs.length === 0) {
19389
+ return {
19390
+ success: true,
19391
+ output: `${filePath}: ${lines.length} lines, no recognizable signatures found.
19392
+ [Use file_explore(strategy='overview') for a broader view]`,
19393
+ durationMs: performance.now() - start
19394
+ };
19395
+ }
19396
+ return {
19397
+ success: true,
19398
+ output: `# ${filePath} \u2014 ${sigs.length} signatures (${lines.length} total lines)
19399
+
19400
+ ` + sigs.join("\n") + `
19401
+
19402
+ [Use file_explore(strategy='chunk', offset=N) to read around a specific signature]`,
19403
+ durationMs: performance.now() - start
19404
+ };
19405
+ } catch (error) {
19406
+ return {
19407
+ success: false,
19408
+ output: "",
19409
+ error: error instanceof Error ? error.message : String(error),
19410
+ durationMs: performance.now() - start
19411
+ };
19412
+ }
19413
+ }
19414
+ /**
19415
+ * notes: Show accumulated working notes from this exploration session.
19416
+ */
19417
+ showNotes(filePath, start) {
19418
+ const notes2 = filePath ? sessionNotes.filter((n) => n.file === filePath) : sessionNotes;
19419
+ if (notes2.length === 0) {
19420
+ return {
19421
+ success: true,
19422
+ output: "No working notes yet. Use file_explore(strategy='chunk', note='your finding') to save notes as you explore.",
19423
+ durationMs: performance.now() - start
19424
+ };
19425
+ }
19426
+ const parts = [`# Working Notes (${notes2.length})
19427
+ `];
19428
+ for (const n of notes2) {
19429
+ parts.push(`- **${n.file}** lines ${n.lineRange[0]}-${n.lineRange[1]}: ${n.finding}`);
19430
+ }
19431
+ return {
19432
+ success: true,
19433
+ output: parts.join("\n"),
19434
+ durationMs: performance.now() - start
19435
+ };
19436
+ }
19437
+ };
19438
+ }
19439
+ });
19440
+
19441
+ // packages/execution/dist/tools/working-notes.js
19442
+ function getWorkingNotes() {
19443
+ return notes;
19444
+ }
19445
+ function getWorkingNotesSummary() {
19446
+ if (notes.length === 0)
19447
+ return "";
19448
+ const parts = [`Working notes (${notes.length}):`];
19449
+ for (const n of notes) {
19450
+ const loc = n.file ? ` [${n.file}${n.line ? `:${n.line}` : ""}]` : "";
19451
+ parts.push(`- [${n.category}] ${n.content.slice(0, 150)}${loc}`);
19452
+ }
19453
+ return parts.join("\n");
19454
+ }
19455
+ function clearWorkingNotes() {
19456
+ notes.length = 0;
19457
+ noteCounter = 0;
19458
+ }
19459
+ var noteCounter, notes, WorkingNotesTool;
19460
+ var init_working_notes = __esm({
19461
+ "packages/execution/dist/tools/working-notes.js"() {
19462
+ "use strict";
19463
+ noteCounter = 0;
19464
+ notes = [];
19465
+ WorkingNotesTool = class {
19466
+ name = "working_notes";
19467
+ description = "In-task scratchpad for tracking discoveries, decisions, and TODOs. Notes persist across tool calls and survive context compaction. Actions: 'add' a note, 'list' all notes, 'search' notes by keyword, 'clear' all notes, 'summary' get a compact summary. Use this to maintain signal when exploring large codebases \u2014 note findings as you go so you don't lose them to context limits.";
19468
+ parameters = {
19469
+ type: "object",
19470
+ properties: {
19471
+ action: {
19472
+ type: "string",
19473
+ enum: ["add", "list", "search", "clear", "summary"],
19474
+ description: "Action to perform (default: 'list')"
19475
+ },
19476
+ content: {
19477
+ type: "string",
19478
+ description: "Note content (for 'add') or search query (for 'search')"
19479
+ },
19480
+ category: {
19481
+ type: "string",
19482
+ enum: ["finding", "todo", "question", "decision", "blocker"],
19483
+ description: "Note category (for 'add', default: 'finding')"
19484
+ },
19485
+ file: {
19486
+ type: "string",
19487
+ description: "Related file path (for 'add')"
19488
+ },
19489
+ line: {
19490
+ type: "number",
19491
+ description: "Related line number (for 'add')"
19492
+ }
19493
+ },
19494
+ required: []
19495
+ };
19496
+ async execute(args) {
19497
+ const action = String(args["action"] ?? "list");
19498
+ const start = performance.now();
19499
+ switch (action) {
19500
+ case "add": {
19501
+ const content = String(args["content"] ?? "");
19502
+ if (!content)
19503
+ return { success: false, output: "", error: "content required", durationMs: performance.now() - start };
19504
+ const note = {
19505
+ id: ++noteCounter,
19506
+ category: String(args["category"] ?? "finding"),
19507
+ content,
19508
+ file: args["file"],
19509
+ line: args["line"],
19510
+ timestamp: Date.now()
19511
+ };
19512
+ notes.push(note);
19513
+ return {
19514
+ success: true,
19515
+ output: `Note #${note.id} added [${note.category}]${note.file ? ` (${note.file}${note.line ? `:${note.line}` : ""})` : ""}: ${content.slice(0, 100)}`,
19516
+ durationMs: performance.now() - start
19517
+ };
19518
+ }
19519
+ case "list": {
19520
+ if (notes.length === 0) {
19521
+ return {
19522
+ success: true,
19523
+ output: "No working notes. Use working_notes(action='add', content='...') to start tracking findings.",
19524
+ durationMs: performance.now() - start
19525
+ };
19526
+ }
19527
+ const lines = [`Working Notes (${notes.length}):
19528
+ `];
19529
+ for (const n of notes) {
19530
+ const loc = n.file ? ` @ ${n.file}${n.line ? `:${n.line}` : ""}` : "";
19531
+ lines.push(` #${n.id} [${n.category}]${loc}: ${n.content}`);
19532
+ }
19533
+ return {
19534
+ success: true,
19535
+ output: lines.join("\n"),
19536
+ durationMs: performance.now() - start
19537
+ };
19538
+ }
19539
+ case "search": {
19540
+ const query = String(args["content"] ?? "").toLowerCase();
19541
+ if (!query)
19542
+ return { success: false, output: "", error: "content (search query) required", durationMs: performance.now() - start };
19543
+ const matches = notes.filter((n) => n.content.toLowerCase().includes(query) || n.file && n.file.toLowerCase().includes(query) || n.category.toLowerCase().includes(query));
19544
+ if (matches.length === 0) {
19545
+ return {
19546
+ success: true,
19547
+ output: `No notes matching "${query}".`,
19548
+ durationMs: performance.now() - start
19549
+ };
19550
+ }
19551
+ const lines = [`Notes matching "${query}" (${matches.length}):
19552
+ `];
19553
+ for (const n of matches) {
19554
+ const loc = n.file ? ` @ ${n.file}${n.line ? `:${n.line}` : ""}` : "";
19555
+ lines.push(` #${n.id} [${n.category}]${loc}: ${n.content}`);
19556
+ }
19557
+ return {
19558
+ success: true,
19559
+ output: lines.join("\n"),
19560
+ durationMs: performance.now() - start
19561
+ };
19562
+ }
19563
+ case "clear": {
19564
+ const count = notes.length;
19565
+ notes.length = 0;
19566
+ noteCounter = 0;
19567
+ return {
19568
+ success: true,
19569
+ output: `Cleared ${count} working notes.`,
19570
+ durationMs: performance.now() - start
19571
+ };
19572
+ }
19573
+ case "summary": {
19574
+ if (notes.length === 0) {
19575
+ return {
19576
+ success: true,
19577
+ output: "No working notes to summarize.",
19578
+ durationMs: performance.now() - start
19579
+ };
19580
+ }
19581
+ const groups = /* @__PURE__ */ new Map();
19582
+ for (const n of notes) {
19583
+ const list = groups.get(n.category) ?? [];
19584
+ list.push(n);
19585
+ groups.set(n.category, list);
19586
+ }
19587
+ const parts = [`Working Notes Summary (${notes.length} total):
19588
+ `];
19589
+ for (const [cat, items] of groups) {
19590
+ parts.push(` ${cat.toUpperCase()} (${items.length}):`);
19591
+ for (const n of items) {
19592
+ const loc = n.file ? ` [${n.file}${n.line ? `:${n.line}` : ""}]` : "";
19593
+ parts.push(` - ${n.content.slice(0, 120)}${loc}`);
19594
+ }
19595
+ }
19596
+ const files = new Set(notes.filter((n) => n.file).map((n) => n.file));
19597
+ if (files.size > 0) {
19598
+ parts.push(`
19599
+ Files referenced: ${[...files].join(", ")}`);
19600
+ }
19601
+ return {
19602
+ success: true,
19603
+ output: parts.join("\n"),
19604
+ durationMs: performance.now() - start
19605
+ };
19606
+ }
19607
+ default:
19608
+ return {
19609
+ success: false,
19610
+ output: "",
19611
+ error: `Unknown action '${action}'. Use: add, list, search, clear, summary`,
19612
+ durationMs: performance.now() - start
19613
+ };
19614
+ }
19615
+ }
19616
+ };
19617
+ }
19618
+ });
19619
+
18859
19620
  // packages/execution/dist/tools/fortemi-bridge.js
18860
19621
  import { existsSync as existsSync24, readFileSync as readFileSync17 } from "node:fs";
18861
19622
  import { join as join38 } from "node:path";
@@ -19012,7 +19773,7 @@ import { spawn as spawn13 } from "node:child_process";
19012
19773
  async function runShell(options) {
19013
19774
  const { command, args = [], cwd: cwd4, env, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
19014
19775
  const mergedEnv = env ? { ...process.env, ...env } : process.env;
19015
- return new Promise((resolve32) => {
19776
+ return new Promise((resolve33) => {
19016
19777
  const start = Date.now();
19017
19778
  let timedOut = false;
19018
19779
  const child = spawn13(command, args, {
@@ -19036,7 +19797,7 @@ async function runShell(options) {
19036
19797
  clearTimeout(timer);
19037
19798
  const durationMs = Date.now() - start;
19038
19799
  const exitCode = timedOut ? -1 : code ?? -1;
19039
- resolve32({
19800
+ resolve33({
19040
19801
  stdout,
19041
19802
  stderr,
19042
19803
  exitCode,
@@ -19048,7 +19809,7 @@ async function runShell(options) {
19048
19809
  child.on("error", (err) => {
19049
19810
  clearTimeout(timer);
19050
19811
  const durationMs = Date.now() - start;
19051
- resolve32({
19812
+ resolve33({
19052
19813
  stdout,
19053
19814
  stderr: stderr + err.message,
19054
19815
  exitCode: -1,
@@ -19163,7 +19924,7 @@ async function applyUnifiedDiff(patch) {
19163
19924
  }
19164
19925
  function runWithStdin(options) {
19165
19926
  const { command, args, cwd: cwd4, stdin } = options;
19166
- return new Promise((resolve32) => {
19927
+ return new Promise((resolve33) => {
19167
19928
  const child = spawn14(command, args, {
19168
19929
  cwd: cwd4,
19169
19930
  stdio: ["pipe", "pipe", "pipe"]
@@ -19180,10 +19941,10 @@ function runWithStdin(options) {
19180
19941
  child.stdin.end();
19181
19942
  child.on("close", (code) => {
19182
19943
  const exitCode = code ?? -1;
19183
- resolve32({ success: exitCode === 0, exitCode, stdout, stderr });
19944
+ resolve33({ success: exitCode === 0, exitCode, stdout, stderr });
19184
19945
  });
19185
19946
  child.on("error", (err) => {
19186
- resolve32({ success: false, exitCode: -1, stdout, stderr: err.message });
19947
+ resolve33({ success: false, exitCode: -1, stdout, stderr: err.message });
19187
19948
  });
19188
19949
  });
19189
19950
  }
@@ -19631,6 +20392,7 @@ __export(dist_exports, {
19631
20392
  ExploreToolsTool: () => ExploreToolsTool,
19632
20393
  FactoryTool: () => FactoryTool,
19633
20394
  FileEditTool: () => FileEditTool,
20395
+ FileExploreTool: () => FileExploreTool,
19634
20396
  FilePatchTool: () => FilePatchTool,
19635
20397
  FileReadTool: () => FileReadTool,
19636
20398
  FileWriteTool: () => FileWriteTool,
@@ -19673,10 +20435,13 @@ __export(dist_exports, {
19673
20435
  WebCrawlTool: () => WebCrawlTool,
19674
20436
  WebFetchTool: () => WebFetchTool,
19675
20437
  WebSearchTool: () => WebSearchTool,
20438
+ WorkingNotesTool: () => WorkingNotesTool,
19676
20439
  applyPatch: () => applyPatch,
19677
20440
  buildCustomTools: () => buildCustomTools,
19678
20441
  buildSkillsSummary: () => buildSkillsSummary,
19679
20442
  checkDesktopDeps: () => checkDesktopDeps,
20443
+ clearExploreNotes: () => clearExploreNotes,
20444
+ clearWorkingNotes: () => clearWorkingNotes,
19680
20445
  createFortemiBridgeTools: () => createFortemiBridgeTools,
19681
20446
  createWorktree: () => createWorktree,
19682
20447
  detectSearchProvider: () => detectSearchProvider,
@@ -19686,6 +20451,9 @@ __export(dist_exports, {
19686
20451
  ensureDepsForGroup: () => ensureDepsForGroup,
19687
20452
  getActiveAttentionItems: () => getActiveAttentionItems,
19688
20453
  getDueReminders: () => getDueReminders,
20454
+ getExploreNotes: () => getExploreNotes,
20455
+ getWorkingNotes: () => getWorkingNotes,
20456
+ getWorkingNotesSummary: () => getWorkingNotesSummary,
19689
20457
  isFortemiAvailable: () => isFortemiAvailable,
19690
20458
  isImagePath: () => isImagePath,
19691
20459
  listCustomToolFiles: () => listCustomToolFiles,
@@ -19762,6 +20530,8 @@ var init_dist2 = __esm({
19762
20530
  init_opencode();
19763
20531
  init_factory();
19764
20532
  init_cron_agent();
20533
+ init_file_explore();
20534
+ init_working_notes();
19765
20535
  init_nexus();
19766
20536
  init_fortemi_bridge();
19767
20537
  init_system_deps();
@@ -20745,13 +21515,13 @@ var init_plannerRunner = __esm({
20745
21515
  });
20746
21516
 
20747
21517
  // packages/retrieval/dist/grep-search.js
20748
- import { execFile as execFile4 } from "node:child_process";
20749
- import { promisify as promisify3 } from "node:util";
20750
- var execFileAsync3, GrepSearch;
21518
+ import { execFile as execFile5 } from "node:child_process";
21519
+ import { promisify as promisify4 } from "node:util";
21520
+ var execFileAsync4, GrepSearch;
20751
21521
  var init_grep_search2 = __esm({
20752
21522
  "packages/retrieval/dist/grep-search.js"() {
20753
21523
  "use strict";
20754
- execFileAsync3 = promisify3(execFile4);
21524
+ execFileAsync4 = promisify4(execFile5);
20755
21525
  GrepSearch = class {
20756
21526
  rootDir;
20757
21527
  constructor(rootDir) {
@@ -20773,7 +21543,7 @@ var init_grep_search2 = __esm({
20773
21543
  }
20774
21544
  args.push(pattern, this.rootDir);
20775
21545
  try {
20776
- const { stdout } = await execFileAsync3("rg", args, {
21546
+ const { stdout } = await execFileAsync4("rg", args, {
20777
21547
  maxBuffer: 10 * 1024 * 1024
20778
21548
  });
20779
21549
  return this.parseRipgrepOutput(stdout);
@@ -20834,8 +21604,8 @@ var init_code_retriever = __esm({
20834
21604
  });
20835
21605
  }
20836
21606
  async getFileContent(filePath, startLine, endLine) {
20837
- const { readFile: readFile23 } = await import("node:fs/promises");
20838
- const content = await readFile23(filePath, "utf-8");
21607
+ const { readFile: readFile24 } = await import("node:fs/promises");
21608
+ const content = await readFile24(filePath, "utf-8");
20839
21609
  if (startLine === void 0)
20840
21610
  return content;
20841
21611
  const lines = content.split("\n");
@@ -20848,9 +21618,9 @@ var init_code_retriever = __esm({
20848
21618
  });
20849
21619
 
20850
21620
  // packages/retrieval/dist/lexicalSearch.js
20851
- import { execFile as execFile5 } from "node:child_process";
20852
- import { promisify as promisify4 } from "node:util";
20853
- import { readFile as readFile19, readdir as readdir5, stat as stat3 } from "node:fs/promises";
21621
+ import { execFile as execFile6 } from "node:child_process";
21622
+ import { promisify as promisify5 } from "node:util";
21623
+ import { readFile as readFile20, readdir as readdir5, stat as stat3 } from "node:fs/promises";
20854
21624
  import { join as join40, extname as extname7 } from "node:path";
20855
21625
  async function searchByPath(pathPattern, options) {
20856
21626
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
@@ -20893,7 +21663,7 @@ async function runSearch(pattern, kind, options) {
20893
21663
  }
20894
21664
  async function isRipgrepAvailable() {
20895
21665
  try {
20896
- await execFileAsync4("rg", ["--version"], { timeout: 2e3 });
21666
+ await execFileAsync5("rg", ["--version"], { timeout: 2e3 });
20897
21667
  return true;
20898
21668
  } catch {
20899
21669
  return false;
@@ -20913,7 +21683,7 @@ async function searchWithRipgrep(pattern, kind, options) {
20913
21683
  args.push(pattern, options.rootDir);
20914
21684
  let stdout;
20915
21685
  try {
20916
- const result = await execFileAsync4("rg", args, {
21686
+ const result = await execFileAsync5("rg", args, {
20917
21687
  maxBuffer: 20 * 1024 * 1024,
20918
21688
  timeout: 1e4
20919
21689
  });
@@ -20956,7 +21726,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
20956
21726
  if (results.length >= maxMatches)
20957
21727
  break;
20958
21728
  try {
20959
- const content = await readFile19(filePath, "utf-8");
21729
+ const content = await readFile20(filePath, "utf-8");
20960
21730
  const contentLines = content.split("\n");
20961
21731
  for (let i = 0; i < contentLines.length; i++) {
20962
21732
  if (results.length >= maxMatches)
@@ -21023,11 +21793,11 @@ function matchesGlob(filePath, glob2) {
21023
21793
  return false;
21024
21794
  }
21025
21795
  }
21026
- var execFileAsync4, DEFAULT_INCLUDE_GLOBS, DEFAULT_EXCLUDE_GLOBS, DEFAULT_MAX_MATCHES, ALWAYS_SKIP, ALL_CODE_EXTS;
21796
+ var execFileAsync5, DEFAULT_INCLUDE_GLOBS, DEFAULT_EXCLUDE_GLOBS, DEFAULT_MAX_MATCHES, ALWAYS_SKIP, ALL_CODE_EXTS;
21027
21797
  var init_lexicalSearch = __esm({
21028
21798
  "packages/retrieval/dist/lexicalSearch.js"() {
21029
21799
  "use strict";
21030
- execFileAsync4 = promisify4(execFile5);
21800
+ execFileAsync5 = promisify5(execFile6);
21031
21801
  DEFAULT_INCLUDE_GLOBS = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.py"];
21032
21802
  DEFAULT_EXCLUDE_GLOBS = ["node_modules", "dist", ".git", "build", "coverage"];
21033
21803
  DEFAULT_MAX_MATCHES = 50;
@@ -21299,7 +22069,7 @@ var init_graphExpand = __esm({
21299
22069
  });
21300
22070
 
21301
22071
  // packages/retrieval/dist/snippetPacker.js
21302
- import { readFile as readFile20 } from "node:fs/promises";
22072
+ import { readFile as readFile21 } from "node:fs/promises";
21303
22073
  import { join as join41 } from "node:path";
21304
22074
  async function packSnippets(requests, opts = {}) {
21305
22075
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
@@ -21329,7 +22099,7 @@ async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINE
21329
22099
  const absPath = req.filePath.startsWith("/") ? req.filePath : join41(repoRoot, req.filePath);
21330
22100
  let content;
21331
22101
  try {
21332
- content = await readFile20(absPath, "utf-8");
22102
+ content = await readFile21(absPath, "utf-8");
21333
22103
  } catch {
21334
22104
  return null;
21335
22105
  }
@@ -21864,9 +22634,9 @@ var init_verifierRunner = __esm({
21864
22634
  async executeTests(patch, repoRoot) {
21865
22635
  if (patch.testsToRun.length === 0)
21866
22636
  return "(no tests specified)";
21867
- const { execFile: execFile6 } = await import("node:child_process");
21868
- const { promisify: promisify6 } = await import("node:util");
21869
- const execFileAsync5 = promisify6(execFile6);
22637
+ const { execFile: execFile7 } = await import("node:child_process");
22638
+ const { promisify: promisify7 } = await import("node:util");
22639
+ const execFileAsync6 = promisify7(execFile7);
21870
22640
  const outputs = [];
21871
22641
  const workDir = this.options.workingDir || repoRoot;
21872
22642
  for (const cmd of patch.testsToRun.slice(0, 3)) {
@@ -21875,7 +22645,7 @@ var init_verifierRunner = __esm({
21875
22645
  const [bin, ...args] = parts;
21876
22646
  if (!bin)
21877
22647
  continue;
21878
- const { stdout, stderr } = await execFileAsync5(bin, args, {
22648
+ const { stdout, stderr } = await execFileAsync6(bin, args, {
21879
22649
  cwd: workDir,
21880
22650
  timeout: 6e4,
21881
22651
  maxBuffer: 1024 * 1024
@@ -22555,6 +23325,7 @@ var init_agenticRunner = __esm({
22555
23325
  init_dist();
22556
23326
  init_personality();
22557
23327
  init_promptLoader();
23328
+ init_dist2();
22558
23329
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
22559
23330
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
22560
23331
  SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
@@ -22875,8 +23646,8 @@ ${this.options.dynamicContext}`,
22875
23646
  async waitIfPaused() {
22876
23647
  if (!this._paused)
22877
23648
  return true;
22878
- await new Promise((resolve32) => {
22879
- this._pauseResolve = resolve32;
23649
+ await new Promise((resolve33) => {
23650
+ this._pauseResolve = resolve33;
22880
23651
  });
22881
23652
  return !this.aborted;
22882
23653
  }
@@ -23909,14 +24680,14 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
23909
24680
  waitForSudoPassword(timeoutMs = 12e4) {
23910
24681
  if (this._sudoPassword)
23911
24682
  return Promise.resolve(this._sudoPassword);
23912
- return new Promise((resolve32) => {
24683
+ return new Promise((resolve33) => {
23913
24684
  const timer = setTimeout(() => {
23914
24685
  this._sudoResolve = null;
23915
- resolve32(null);
24686
+ resolve33(null);
23916
24687
  }, timeoutMs);
23917
24688
  this._sudoResolve = (pw) => {
23918
24689
  clearTimeout(timer);
23919
- resolve32(pw);
24690
+ resolve33(pw);
23920
24691
  };
23921
24692
  });
23922
24693
  }
@@ -24224,6 +24995,18 @@ ${tail}`;
24224
24995
  const fileRegistryStr = this.formatFileRegistry();
24225
24996
  if (fileRegistryStr)
24226
24997
  enrichments.push(fileRegistryStr);
24998
+ try {
24999
+ const notesSummary = getWorkingNotesSummary();
25000
+ if (notesSummary)
25001
+ enrichments.push(notesSummary);
25002
+ const exploreNotes = getExploreNotes();
25003
+ if (exploreNotes.length > 0) {
25004
+ const exploreStr = `File exploration notes (${exploreNotes.length}):
25005
+ ` + exploreNotes.map((n) => `- ${n.file} lines ${n.lineRange[0]}-${n.lineRange[1]}: ${n.finding}`).join("\n");
25006
+ enrichments.push(exploreStr);
25007
+ }
25008
+ } catch {
25009
+ }
24227
25010
  if (tier === "large") {
24228
25011
  const memexIndexStr = this.formatMemexIndex();
24229
25012
  if (memexIndexStr)
@@ -25616,12 +26399,12 @@ var init_nexusBackend = __esm({
25616
26399
  const deadline = Date.now() + (request.timeoutMs ?? 12e4);
25617
26400
  try {
25618
26401
  while (!done && Date.now() < deadline) {
25619
- await new Promise((resolve32) => {
26402
+ await new Promise((resolve33) => {
25620
26403
  let resolved = false;
25621
26404
  const finish = () => {
25622
26405
  if (!resolved) {
25623
26406
  resolved = true;
25624
- resolve32();
26407
+ resolve33();
25625
26408
  }
25626
26409
  };
25627
26410
  let watcher = null;
@@ -26561,7 +27344,7 @@ __export(listen_exports, {
26561
27344
  import { spawn as spawn15, execSync as execSync22 } from "node:child_process";
26562
27345
  import { existsSync as existsSync28, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, readdirSync as readdirSync6 } from "node:fs";
26563
27346
  import { join as join43, dirname as dirname13 } from "node:path";
26564
- import { homedir as homedir8 } from "node:os";
27347
+ import { homedir as homedir10 } from "node:os";
26565
27348
  import { fileURLToPath as fileURLToPath8 } from "node:url";
26566
27349
  import { EventEmitter } from "node:events";
26567
27350
  import { createInterface as createInterface2 } from "node:readline";
@@ -26673,7 +27456,7 @@ function findLiveWhisperScript() {
26673
27456
  }
26674
27457
  } catch {
26675
27458
  }
26676
- const nvmBase = join43(homedir8(), ".nvm", "versions", "node");
27459
+ const nvmBase = join43(homedir10(), ".nvm", "versions", "node");
26677
27460
  if (existsSync28(nvmBase)) {
26678
27461
  try {
26679
27462
  for (const ver of readdirSync6(nvmBase)) {
@@ -26703,9 +27486,9 @@ function ensureTranscribeCliBackground() {
26703
27486
  }
26704
27487
  try {
26705
27488
  const { exec: exec4 } = await import("node:child_process");
26706
- return new Promise((resolve32) => {
27489
+ return new Promise((resolve33) => {
26707
27490
  exec4("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
26708
- resolve32(!err);
27491
+ resolve33(!err);
26709
27492
  });
26710
27493
  });
26711
27494
  } catch {
@@ -26764,7 +27547,7 @@ var init_listen = __esm({
26764
27547
  return this._ready;
26765
27548
  }
26766
27549
  async start() {
26767
- return new Promise((resolve32, reject) => {
27550
+ return new Promise((resolve33, reject) => {
26768
27551
  const timeout = setTimeout(() => {
26769
27552
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
26770
27553
  }, 3e5);
@@ -26792,7 +27575,7 @@ var init_listen = __esm({
26792
27575
  this._ready = true;
26793
27576
  clearTimeout(timeout);
26794
27577
  this.emit("ready");
26795
- resolve32();
27578
+ resolve33();
26796
27579
  break;
26797
27580
  case "transcript":
26798
27581
  this.emit("transcript", {
@@ -26927,7 +27710,7 @@ var init_listen = __esm({
26927
27710
  }
26928
27711
  } catch {
26929
27712
  }
26930
- const nvmBase = join43(homedir8(), ".nvm", "versions", "node");
27713
+ const nvmBase = join43(homedir10(), ".nvm", "versions", "node");
26931
27714
  if (existsSync28(nvmBase)) {
26932
27715
  try {
26933
27716
  const { readdirSync: readdirSync18 } = await import("node:fs");
@@ -26996,11 +27779,11 @@ var init_listen = __esm({
26996
27779
  this.liveTranscriber.on("error", (err) => {
26997
27780
  this.emit("error", err);
26998
27781
  });
26999
- await new Promise((resolve32, reject) => {
27782
+ await new Promise((resolve33, reject) => {
27000
27783
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
27001
27784
  this.liveTranscriber.on("ready", () => {
27002
27785
  clearTimeout(timeout);
27003
- resolve32();
27786
+ resolve33();
27004
27787
  });
27005
27788
  this.liveTranscriber.on("error", (err) => {
27006
27789
  clearTimeout(timeout);
@@ -27162,11 +27945,11 @@ transcribe-cli error: ${transcribeCliError}` : "";
27162
27945
  sampleWidth: 2,
27163
27946
  chunkDuration: 3
27164
27947
  });
27165
- await new Promise((resolve32, reject) => {
27948
+ await new Promise((resolve33, reject) => {
27166
27949
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
27167
27950
  transcriber.on("ready", () => {
27168
27951
  clearTimeout(timeout);
27169
- resolve32();
27952
+ resolve33();
27170
27953
  });
27171
27954
  transcriber.on("error", (err) => {
27172
27955
  clearTimeout(timeout);
@@ -32137,8 +32920,8 @@ var init_voice_session = __esm({
32137
32920
  this.server.keepAliveTimeout = 0;
32138
32921
  this.wss = new import_websocket_server.default({ server: this.server, path: "/ws" });
32139
32922
  this.wss.on("connection", (ws, req) => this.handleWSConnection(ws, req));
32140
- await new Promise((resolve32, reject) => {
32141
- this.server.listen(port, "127.0.0.1", () => resolve32());
32923
+ await new Promise((resolve33, reject) => {
32924
+ this.server.listen(port, "127.0.0.1", () => resolve33());
32142
32925
  this.server.on("error", reject);
32143
32926
  });
32144
32927
  try {
@@ -32356,7 +33139,7 @@ var init_voice_session = __esm({
32356
33139
  }
32357
33140
  // ── Cloudflared tunnel ────────────────────────────────────────────────
32358
33141
  startCloudflared(port) {
32359
- return new Promise((resolve32, reject) => {
33142
+ return new Promise((resolve33, reject) => {
32360
33143
  const timeout = setTimeout(() => {
32361
33144
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
32362
33145
  }, 3e4);
@@ -32374,7 +33157,7 @@ var init_voice_session = __esm({
32374
33157
  if (urlMatch && !urlFound) {
32375
33158
  urlFound = true;
32376
33159
  clearTimeout(timeout);
32377
- resolve32(urlMatch[0]);
33160
+ resolve33(urlMatch[0]);
32378
33161
  }
32379
33162
  };
32380
33163
  this.cloudflaredProcess.stdout?.on("data", handleOutput);
@@ -32414,13 +33197,13 @@ var init_voice_session = __esm({
32414
33197
  }
32415
33198
  // ── Helpers ───────────────────────────────────────────────────────────
32416
33199
  findFreePort() {
32417
- return new Promise((resolve32, reject) => {
33200
+ return new Promise((resolve33, reject) => {
32418
33201
  const srv = createServer2();
32419
33202
  srv.listen(0, "127.0.0.1", () => {
32420
33203
  const addr = srv.address();
32421
33204
  if (addr && typeof addr === "object") {
32422
33205
  const port = addr.port;
32423
- srv.close(() => resolve32(port));
33206
+ srv.close(() => resolve33(port));
32424
33207
  } else {
32425
33208
  srv.close(() => reject(new Error("Could not find free port")));
32426
33209
  }
@@ -32543,8 +33326,8 @@ async function collectSystemMetricsAsync() {
32543
33326
  vramUtilization: 0
32544
33327
  };
32545
33328
  try {
32546
- const smi = await new Promise((resolve32, reject) => {
32547
- exec("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve32(stdout));
33329
+ const smi = await new Promise((resolve33, reject) => {
33330
+ exec("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve33(stdout));
32548
33331
  });
32549
33332
  const line = smi.trim().split("\n")[0];
32550
33333
  if (line) {
@@ -32692,8 +33475,8 @@ var init_expose = __esm({
32692
33475
  throw new Error("Gateway already running");
32693
33476
  const port = await this.findFreePort();
32694
33477
  this.server = this.createProxyServer(port);
32695
- await new Promise((resolve32, reject) => {
32696
- this.server.listen(port, "127.0.0.1", () => resolve32());
33478
+ await new Promise((resolve33, reject) => {
33479
+ this.server.listen(port, "127.0.0.1", () => resolve33());
32697
33480
  this.server.on("error", reject);
32698
33481
  });
32699
33482
  let lastStartErr;
@@ -32755,8 +33538,8 @@ var init_expose = __esm({
32755
33538
  this._cloudflaredPid = state.pid;
32756
33539
  this._proxyPort = state.proxyPort;
32757
33540
  this.server = this.createProxyServer(state.proxyPort);
32758
- await new Promise((resolve32, reject) => {
32759
- this.server.listen(state.proxyPort, "127.0.0.1", () => resolve32());
33541
+ await new Promise((resolve33, reject) => {
33542
+ this.server.listen(state.proxyPort, "127.0.0.1", () => resolve33());
32760
33543
  this.server.on("error", reject);
32761
33544
  });
32762
33545
  this._stats.status = "active";
@@ -32781,8 +33564,8 @@ var init_expose = __esm({
32781
33564
  }
32782
33565
  this._cloudflaredPid = null;
32783
33566
  if (this.server) {
32784
- await new Promise((resolve32) => {
32785
- this.server.close(() => resolve32());
33567
+ await new Promise((resolve33) => {
33568
+ this.server.close(() => resolve33());
32786
33569
  });
32787
33570
  this.server = null;
32788
33571
  }
@@ -33114,7 +33897,7 @@ var init_expose = __esm({
33114
33897
  _proxyPort = 0;
33115
33898
  startCloudflared(port) {
33116
33899
  this._proxyPort = port;
33117
- return new Promise((resolve32, reject) => {
33900
+ return new Promise((resolve33, reject) => {
33118
33901
  const timeout = setTimeout(() => {
33119
33902
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
33120
33903
  }, 3e4);
@@ -33143,7 +33926,7 @@ var init_expose = __esm({
33143
33926
  this.cloudflaredProcess?.unref();
33144
33927
  this.cloudflaredProcess?.stdout?.destroy();
33145
33928
  this.cloudflaredProcess?.stderr?.destroy();
33146
- resolve32(urlMatch[0]);
33929
+ resolve33(urlMatch[0]);
33147
33930
  }
33148
33931
  };
33149
33932
  this.cloudflaredProcess.stdout?.on("data", handleOutput);
@@ -33232,13 +34015,13 @@ ${this.formatConnectionInfo()}`);
33232
34015
  }
33233
34016
  // ── Helpers ─────────────────────────────────────────────────────────────
33234
34017
  findFreePort() {
33235
- return new Promise((resolve32, reject) => {
34018
+ return new Promise((resolve33, reject) => {
33236
34019
  const srv = createServer3();
33237
34020
  srv.listen(0, "127.0.0.1", () => {
33238
34021
  const addr = srv.address();
33239
34022
  if (addr && typeof addr === "object") {
33240
34023
  const port = addr.port;
33241
- srv.close(() => resolve32(port));
34024
+ srv.close(() => resolve33(port));
33242
34025
  } else {
33243
34026
  srv.close(() => reject(new Error("Could not find free port")));
33244
34027
  }
@@ -34185,8 +34968,8 @@ var init_peer_mesh = __esm({
34185
34968
  this.wss.on("connection", (ws, req) => {
34186
34969
  this.handleInboundConnection(ws, req.url ?? "");
34187
34970
  });
34188
- await new Promise((resolve32, reject) => {
34189
- this.server.listen(port, "127.0.0.1", () => resolve32());
34971
+ await new Promise((resolve33, reject) => {
34972
+ this.server.listen(port, "127.0.0.1", () => resolve33());
34190
34973
  this.server.on("error", reject);
34191
34974
  });
34192
34975
  this.pingTimer = setInterval(() => this.pingAll(), PING_INTERVAL_MS);
@@ -34225,7 +35008,7 @@ var init_peer_mesh = __esm({
34225
35008
  this.wss = null;
34226
35009
  }
34227
35010
  if (this.server) {
34228
- await new Promise((resolve32) => this.server.close(() => resolve32()));
35011
+ await new Promise((resolve33) => this.server.close(() => resolve33()));
34229
35012
  this.server = null;
34230
35013
  }
34231
35014
  this.emit("stopped");
@@ -34243,7 +35026,7 @@ var init_peer_mesh = __esm({
34243
35026
  if (!wsUrl.includes("/p2p"))
34244
35027
  wsUrl += "/p2p";
34245
35028
  wsUrl += `?key=${encodeURIComponent(this._authKey)}`;
34246
- return new Promise((resolve32, reject) => {
35029
+ return new Promise((resolve33, reject) => {
34247
35030
  const ws = new import_websocket.default(wsUrl, { handshakeTimeout: 1e4 });
34248
35031
  let resolved = false;
34249
35032
  const timeout = setTimeout(() => {
@@ -34283,7 +35066,7 @@ var init_peer_mesh = __esm({
34283
35066
  this.connections.set(peer.peerId, ws);
34284
35067
  this.setupPeerHandlers(ws, peer.peerId);
34285
35068
  this.emit("peer_connected", peer);
34286
- resolve32(peer);
35069
+ resolve33(peer);
34287
35070
  } else {
34288
35071
  this.handleMessage(msg, ws);
34289
35072
  }
@@ -34338,12 +35121,12 @@ var init_peer_mesh = __esm({
34338
35121
  throw new Error(`Peer ${peerId} not connected`);
34339
35122
  }
34340
35123
  const msgId = randomBytes11(8).toString("hex");
34341
- return new Promise((resolve32, reject) => {
35124
+ return new Promise((resolve33, reject) => {
34342
35125
  const timeout = setTimeout(() => {
34343
35126
  this.pendingRequests.delete(msgId);
34344
35127
  reject(new Error(`Inference timeout (${timeoutMs}ms)`));
34345
35128
  }, timeoutMs);
34346
- this.pendingRequests.set(msgId, { resolve: resolve32, reject, timeout, chunks: [] });
35129
+ this.pendingRequests.set(msgId, { resolve: resolve33, reject, timeout, chunks: [] });
34347
35130
  this.sendMsg(ws, "infer_request", request, msgId);
34348
35131
  });
34349
35132
  }
@@ -34565,13 +35348,13 @@ var init_peer_mesh = __esm({
34565
35348
  ws.send(JSON.stringify(msg));
34566
35349
  }
34567
35350
  findFreePort() {
34568
- return new Promise((resolve32, reject) => {
35351
+ return new Promise((resolve33, reject) => {
34569
35352
  const srv = createServer4();
34570
35353
  srv.listen(0, "127.0.0.1", () => {
34571
35354
  const addr = srv.address();
34572
35355
  if (addr && typeof addr === "object") {
34573
35356
  const port = addr.port;
34574
- srv.close(() => resolve32(port));
35357
+ srv.close(() => resolve33(port));
34575
35358
  } else {
34576
35359
  srv.close(() => reject(new Error("Could not find free port")));
34577
35360
  }
@@ -35817,7 +36600,7 @@ __export(oa_directory_exports, {
35817
36600
  });
35818
36601
  import { existsSync as existsSync32, mkdirSync as mkdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync12, readdirSync as readdirSync8, statSync as statSync11, unlinkSync as unlinkSync6 } from "node:fs";
35819
36602
  import { join as join48, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
35820
- import { homedir as homedir9 } from "node:os";
36603
+ import { homedir as homedir11 } from "node:os";
35821
36604
  function initOaDirectory(repoRoot) {
35822
36605
  const oaPath = join48(repoRoot, OA_DIR);
35823
36606
  for (const sub of SUBDIRS) {
@@ -35857,7 +36640,7 @@ function saveProjectSettings(repoRoot, settings) {
35857
36640
  writeFileSync12(join48(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
35858
36641
  }
35859
36642
  function loadGlobalSettings() {
35860
- const settingsPath = join48(homedir9(), ".open-agents", "settings.json");
36643
+ const settingsPath = join48(homedir11(), ".open-agents", "settings.json");
35861
36644
  try {
35862
36645
  if (existsSync32(settingsPath)) {
35863
36646
  return JSON.parse(readFileSync23(settingsPath, "utf-8"));
@@ -35867,7 +36650,7 @@ function loadGlobalSettings() {
35867
36650
  return {};
35868
36651
  }
35869
36652
  function saveGlobalSettings(settings) {
35870
- const dir = join48(homedir9(), ".open-agents");
36653
+ const dir = join48(homedir11(), ".open-agents");
35871
36654
  mkdirSync11(dir, { recursive: true });
35872
36655
  const existing = loadGlobalSettings();
35873
36656
  const merged = { ...existing, ...settings };
@@ -36247,13 +37030,13 @@ function recordUsage(kind, value, opts) {
36247
37030
  }
36248
37031
  saveUsageFile(filePath, data);
36249
37032
  };
36250
- update(join48(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
37033
+ update(join48(homedir11(), ".open-agents", USAGE_HISTORY_FILE));
36251
37034
  if (opts?.repoRoot) {
36252
37035
  update(join48(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
36253
37036
  }
36254
37037
  }
36255
37038
  function loadUsageHistory(kind, repoRoot) {
36256
- const globalPath = join48(homedir9(), ".open-agents", USAGE_HISTORY_FILE);
37039
+ const globalPath = join48(homedir11(), ".open-agents", USAGE_HISTORY_FILE);
36257
37040
  const globalData = loadUsageFile(globalPath);
36258
37041
  const localData = repoRoot ? loadUsageFile(join48(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
36259
37042
  const map = /* @__PURE__ */ new Map();
@@ -36286,7 +37069,7 @@ function deleteUsageRecord(kind, value, repoRoot) {
36286
37069
  saveUsageFile(filePath, data);
36287
37070
  }
36288
37071
  };
36289
- remove(join48(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
37072
+ remove(join48(homedir11(), ".open-agents", USAGE_HISTORY_FILE));
36290
37073
  if (repoRoot) {
36291
37074
  remove(join48(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
36292
37075
  }
@@ -36337,10 +37120,10 @@ var init_oa_directory = __esm({
36337
37120
  // packages/cli/dist/tui/setup.js
36338
37121
  import * as readline from "node:readline";
36339
37122
  import { execSync as execSync24, spawn as spawn18, exec as exec2 } from "node:child_process";
36340
- import { promisify as promisify5 } from "node:util";
37123
+ import { promisify as promisify6 } from "node:util";
36341
37124
  import { existsSync as existsSync33, writeFileSync as writeFileSync13, readFileSync as readFileSync24, appendFileSync as appendFileSync2, mkdirSync as mkdirSync12 } from "node:fs";
36342
37125
  import { join as join49 } from "node:path";
36343
- import { homedir as homedir10, platform } from "node:os";
37126
+ import { homedir as homedir12, platform } from "node:os";
36344
37127
  function detectSystemSpecs() {
36345
37128
  let totalRamGB = 0;
36346
37129
  let availableRamGB = 0;
@@ -36477,12 +37260,12 @@ function modelSupportsToolCalling(modelName) {
36477
37260
  return false;
36478
37261
  }
36479
37262
  function ask(rl, question) {
36480
- return new Promise((resolve32) => {
36481
- rl.question(question, (answer) => resolve32(answer.trim()));
37263
+ return new Promise((resolve33) => {
37264
+ rl.question(question, (answer) => resolve33(answer.trim()));
36482
37265
  });
36483
37266
  }
36484
37267
  function askSecret(rl, question) {
36485
- return new Promise((resolve32) => {
37268
+ return new Promise((resolve33) => {
36486
37269
  process.stdout.write(question);
36487
37270
  let secret = "";
36488
37271
  const stdin = process.stdin;
@@ -36500,7 +37283,7 @@ function askSecret(rl, question) {
36500
37283
  stdin.setRawMode(hadRawMode ?? false);
36501
37284
  }
36502
37285
  process.stdout.write("\n");
36503
- resolve32(secret.trim());
37286
+ resolve33(secret.trim());
36504
37287
  return;
36505
37288
  } else if (c3 === "") {
36506
37289
  stdin.removeListener("data", onData);
@@ -36508,7 +37291,7 @@ function askSecret(rl, question) {
36508
37291
  stdin.setRawMode(hadRawMode ?? false);
36509
37292
  }
36510
37293
  process.stdout.write("\n");
36511
- resolve32("");
37294
+ resolve33("");
36512
37295
  return;
36513
37296
  } else if (c3 === "\x7F" || c3 === "\b") {
36514
37297
  if (secret.length > 0) {
@@ -36743,7 +37526,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
36743
37526
  return false;
36744
37527
  }
36745
37528
  for (let i = 0; i < 5; i++) {
36746
- await new Promise((resolve32) => setTimeout(resolve32, 2e3));
37529
+ await new Promise((resolve33) => setTimeout(resolve33, 2e3));
36747
37530
  try {
36748
37531
  const resp = await fetch(`${backendUrl}/api/tags`, {
36749
37532
  signal: AbortSignal.timeout(3e3)
@@ -37204,7 +37987,7 @@ async function doSetup(config, rl) {
37204
37987
  try {
37205
37988
  const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
37206
37989
  child.unref();
37207
- await new Promise((resolve32) => setTimeout(resolve32, 3e3));
37990
+ await new Promise((resolve33) => setTimeout(resolve33, 3e3));
37208
37991
  try {
37209
37992
  models = await fetchOllamaModels(config.backendUrl);
37210
37993
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -37232,7 +38015,7 @@ async function doSetup(config, rl) {
37232
38015
  try {
37233
38016
  const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
37234
38017
  child.unref();
37235
- await new Promise((resolve32) => setTimeout(resolve32, 3e3));
38018
+ await new Promise((resolve33) => setTimeout(resolve33, 3e3));
37236
38019
  try {
37237
38020
  models = await fetchOllamaModels(config.backendUrl);
37238
38021
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -37380,7 +38163,7 @@ async function doSetup(config, rl) {
37380
38163
  `PARAMETER num_predict ${numPredict}`,
37381
38164
  `PARAMETER stop "<|endoftext|>"`
37382
38165
  ].join("\n");
37383
- const modelDir2 = join49(homedir10(), ".open-agents", "models");
38166
+ const modelDir2 = join49(homedir12(), ".open-agents", "models");
37384
38167
  mkdirSync12(modelDir2, { recursive: true });
37385
38168
  const modelfilePath = join49(modelDir2, `Modelfile.${customName}`);
37386
38169
  writeFileSync13(modelfilePath, modelfileContent + "\n", "utf8");
@@ -37428,7 +38211,7 @@ async function isModelAvailable(config) {
37428
38211
  }
37429
38212
  function isFirstRun() {
37430
38213
  try {
37431
- return !existsSync33(join49(homedir10(), ".open-agents", "config.json"));
38214
+ return !existsSync33(join49(homedir12(), ".open-agents", "config.json"));
37432
38215
  } catch {
37433
38216
  return true;
37434
38217
  }
@@ -37465,7 +38248,7 @@ function detectPkgManager() {
37465
38248
  return null;
37466
38249
  }
37467
38250
  function getVenvDir() {
37468
- return join49(homedir10(), ".open-agents", "venv");
38251
+ return join49(homedir12(), ".open-agents", "venv");
37469
38252
  }
37470
38253
  function hasVenvModule() {
37471
38254
  try {
@@ -37490,7 +38273,7 @@ function ensureVenv(log) {
37490
38273
  return null;
37491
38274
  }
37492
38275
  try {
37493
- mkdirSync12(join49(homedir10(), ".open-agents"), { recursive: true });
38276
+ mkdirSync12(join49(homedir12(), ".open-agents"), { recursive: true });
37494
38277
  execSync24(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
37495
38278
  execSync24(`"${join49(venvDir, "bin", "pip")}" install --upgrade pip`, {
37496
38279
  stdio: "pipe",
@@ -37756,9 +38539,9 @@ function ensureCloudflaredBackground(onInfo) {
37756
38539
  const archMap = { x64: "amd64", arm64: "arm64", arm: "arm" };
37757
38540
  const cfArch = archMap[arch] ?? "amd64";
37758
38541
  try {
37759
- execSync24(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir10()}/.local/bin" && mv /tmp/cloudflared "${homedir10()}/.local/bin/cloudflared"`, { stdio: "pipe", timeout: 6e4 });
37760
- if (!process.env.PATH?.includes(`${homedir10()}/.local/bin`)) {
37761
- process.env.PATH = `${homedir10()}/.local/bin:${process.env.PATH}`;
38542
+ execSync24(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir12()}/.local/bin" && mv /tmp/cloudflared "${homedir12()}/.local/bin/cloudflared"`, { stdio: "pipe", timeout: 6e4 });
38543
+ if (!process.env.PATH?.includes(`${homedir12()}/.local/bin`)) {
38544
+ process.env.PATH = `${homedir12()}/.local/bin:${process.env.PATH}`;
37762
38545
  }
37763
38546
  if (hasCmd("cloudflared")) {
37764
38547
  log("cloudflared installed.");
@@ -37853,7 +38636,7 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
37853
38636
  `PARAMETER num_predict ${numPredict}`,
37854
38637
  `PARAMETER stop "<|endoftext|>"`
37855
38638
  ].join("\n");
37856
- const modelDir2 = join49(homedir10(), ".open-agents", "models");
38639
+ const modelDir2 = join49(homedir12(), ".open-agents", "models");
37857
38640
  mkdirSync12(modelDir2, { recursive: true });
37858
38641
  const modelfilePath = join49(modelDir2, `Modelfile.${customName}`);
37859
38642
  writeFileSync13(modelfilePath, modelfileContent + "\n", "utf8");
@@ -37930,7 +38713,7 @@ async function ensureNeovim() {
37930
38713
  const platform5 = process.platform;
37931
38714
  const arch = process.arch;
37932
38715
  if (platform5 === "linux") {
37933
- const binDir = join49(homedir10(), ".local", "bin");
38716
+ const binDir = join49(homedir12(), ".local", "bin");
37934
38717
  const nvimDest = join49(binDir, "nvim");
37935
38718
  try {
37936
38719
  mkdirSync12(binDir, { recursive: true });
@@ -38002,7 +38785,7 @@ async function ensureNeovim() {
38002
38785
  }
38003
38786
  function ensurePathInShellRc(binDir) {
38004
38787
  const shell = process.env.SHELL ?? "";
38005
- const rcFile = shell.includes("zsh") ? join49(homedir10(), ".zshrc") : join49(homedir10(), ".bashrc");
38788
+ const rcFile = shell.includes("zsh") ? join49(homedir12(), ".zshrc") : join49(homedir12(), ".bashrc");
38006
38789
  try {
38007
38790
  const rcContent = existsSync33(rcFile) ? readFileSync24(rcFile, "utf8") : "";
38008
38791
  if (rcContent.includes(binDir))
@@ -38023,7 +38806,7 @@ var init_setup = __esm({
38023
38806
  init_render();
38024
38807
  init_config();
38025
38808
  init_dist();
38026
- execAsync = promisify5(exec2);
38809
+ execAsync = promisify6(exec2);
38027
38810
  QWEN_VARIANTS = [
38028
38811
  { tag: "qwen3.5:0.8b", sizeGB: 1, label: "0.8B params (1.0 GB)", cloud: false },
38029
38812
  { tag: "qwen3.5:2b", sizeGB: 2.7, label: "2B params (2.7 GB)", cloud: false },
@@ -38221,7 +39004,7 @@ function tuiSelect(opts) {
38221
39004
  const maxVisible = opts.maxVisible ?? Math.max(3, contentArea - selectChrome);
38222
39005
  let scrollOffset = 0;
38223
39006
  let lastRenderedLines = 0;
38224
- return new Promise((resolve32) => {
39007
+ return new Promise((resolve33) => {
38225
39008
  const stdin = process.stdin;
38226
39009
  const hadRawMode = stdin.isRaw;
38227
39010
  const savedRlListeners = [];
@@ -38396,7 +39179,7 @@ function tuiSelect(opts) {
38396
39179
  if (!isSkippable(itemIdx) && matchSet.has(itemIdx)) {
38397
39180
  cursor = itemIdx;
38398
39181
  cleanup();
38399
- resolve32({ confirmed: true, key: items[cursor].key, index: cursor });
39182
+ resolve33({ confirmed: true, key: items[cursor].key, index: cursor });
38400
39183
  return;
38401
39184
  } else if (!isSkippable(itemIdx)) {
38402
39185
  cursor = itemIdx;
@@ -38472,7 +39255,7 @@ function tuiSelect(opts) {
38472
39255
  items.splice(deletedIdx, 1);
38473
39256
  if (items.length === 0) {
38474
39257
  cleanup();
38475
- resolve32({ confirmed: false, key: null, index: -1 });
39258
+ resolve33({ confirmed: false, key: null, index: -1 });
38476
39259
  return;
38477
39260
  }
38478
39261
  updateFilter();
@@ -38561,7 +39344,7 @@ function tuiSelect(opts) {
38561
39344
  } else if (seq === "\r" || seq === "\n") {
38562
39345
  if (!isSkippable(cursor) && matchSet.has(cursor)) {
38563
39346
  cleanup();
38564
- resolve32({ confirmed: true, key: items[cursor].key, index: cursor });
39347
+ resolve33({ confirmed: true, key: items[cursor].key, index: cursor });
38565
39348
  }
38566
39349
  } else if (seq === "\x1B" || seq === "\x1B\x1B") {
38567
39350
  if (filter) {
@@ -38574,14 +39357,14 @@ function tuiSelect(opts) {
38574
39357
  render();
38575
39358
  } else if (hasBreadcrumbs) {
38576
39359
  cleanup();
38577
- resolve32({ confirmed: false, key: "__back__", index: cursor });
39360
+ resolve33({ confirmed: false, key: "__back__", index: cursor });
38578
39361
  } else {
38579
39362
  cleanup();
38580
- resolve32({ confirmed: false, key: null, index: cursor });
39363
+ resolve33({ confirmed: false, key: null, index: cursor });
38581
39364
  }
38582
39365
  } else if (seq === "") {
38583
39366
  cleanup();
38584
- resolve32({ confirmed: false, key: null, index: cursor });
39367
+ resolve33({ confirmed: false, key: null, index: cursor });
38585
39368
  } else if (seq === "\x7F" || seq === "\b") {
38586
39369
  if (filter.length > 0) {
38587
39370
  filter = filter.slice(0, -1);
@@ -38595,7 +39378,7 @@ function tuiSelect(opts) {
38595
39378
  render();
38596
39379
  } else if (hasBreadcrumbs) {
38597
39380
  cleanup();
38598
- resolve32({ confirmed: false, key: "__back__", index: cursor });
39381
+ resolve33({ confirmed: false, key: "__back__", index: cursor });
38599
39382
  }
38600
39383
  } else if (seq.length === 1 && seq.charCodeAt(0) >= 32 && seq.charCodeAt(0) < 127) {
38601
39384
  if (opts.onCustomKey && !isSkippable(cursor) && matchSet.has(cursor)) {
@@ -38603,7 +39386,7 @@ function tuiSelect(opts) {
38603
39386
  done: () => render(),
38604
39387
  resolve: (result) => {
38605
39388
  cleanup();
38606
- resolve32(result);
39389
+ resolve33(result);
38607
39390
  },
38608
39391
  getInput: (prompt, prefill) => getInputFromUser(prompt, prefill),
38609
39392
  render: () => render(),
@@ -38720,7 +39503,7 @@ var init_tui_select = __esm({
38720
39503
 
38721
39504
  // packages/cli/dist/tui/drop-panel.js
38722
39505
  import { existsSync as existsSync34 } from "node:fs";
38723
- import { extname as extname9, resolve as resolve27 } from "node:path";
39506
+ import { extname as extname9, resolve as resolve28 } from "node:path";
38724
39507
  function ansi4(code, text) {
38725
39508
  return isTTY4 ? `\x1B[${code}m${text}\x1B[0m` : text;
38726
39509
  }
@@ -38833,7 +39616,7 @@ function showDropPanel(opts) {
38833
39616
  if (filePath.startsWith("file://")) {
38834
39617
  filePath = decodeURIComponent(filePath.slice(7));
38835
39618
  }
38836
- filePath = resolve27(filePath);
39619
+ filePath = resolve28(filePath);
38837
39620
  if (!existsSync34(filePath)) {
38838
39621
  errorMsg = `File not found: ${filePath}`;
38839
39622
  render();
@@ -39145,12 +39928,12 @@ function stopNeovimMode() {
39145
39928
  } catch {
39146
39929
  }
39147
39930
  const s = _state;
39148
- return new Promise((resolve32) => {
39931
+ return new Promise((resolve33) => {
39149
39932
  setTimeout(() => {
39150
39933
  if (s && !s.cleanedUp) {
39151
39934
  doCleanup(s);
39152
39935
  }
39153
- resolve32();
39936
+ resolve33();
39154
39937
  }, 300);
39155
39938
  });
39156
39939
  }
@@ -39386,7 +40169,7 @@ __export(voice_exports, {
39386
40169
  });
39387
40170
  import { existsSync as existsSync36, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync25, unlinkSync as unlinkSync8, readdirSync as readdirSync9, renameSync, statSync as statSync12 } from "node:fs";
39388
40171
  import { join as join51, dirname as dirname17 } from "node:path";
39389
- import { homedir as homedir11, tmpdir as tmpdir9, platform as platform2 } from "node:os";
40172
+ import { homedir as homedir13, tmpdir as tmpdir9, platform as platform2 } from "node:os";
39390
40173
  import { execSync as execSync26, spawn as nodeSpawn } from "node:child_process";
39391
40174
  import { createRequire } from "node:module";
39392
40175
  function sanitizeForTTS(text) {
@@ -39410,7 +40193,7 @@ function listVoiceModels() {
39410
40193
  }));
39411
40194
  }
39412
40195
  function voiceDir() {
39413
- return join51(homedir11(), ".open-agents", "voice");
40196
+ return join51(homedir13(), ".open-agents", "voice");
39414
40197
  }
39415
40198
  function modelsDir() {
39416
40199
  return join51(voiceDir(), "models");
@@ -40406,7 +41189,7 @@ var init_voice = __esm({
40406
41189
  }
40407
41190
  p = p.replace(/\\ /g, " ");
40408
41191
  if (p.startsWith("~/") || p === "~") {
40409
- p = join51(homedir11(), p.slice(1));
41192
+ p = join51(homedir13(), p.slice(1));
40410
41193
  }
40411
41194
  if (!existsSync36(p)) {
40412
41195
  return `File not found: ${p}
@@ -40821,7 +41604,7 @@ var init_voice = __esm({
40821
41604
  this.speaking = false;
40822
41605
  }
40823
41606
  sleep(ms) {
40824
- return new Promise((resolve32) => setTimeout(resolve32, ms));
41607
+ return new Promise((resolve33) => setTimeout(resolve33, ms));
40825
41608
  }
40826
41609
  // -------------------------------------------------------------------------
40827
41610
  // Synthesis pipeline
@@ -41087,7 +41870,7 @@ var init_voice = __esm({
41087
41870
  const cmd = this.getPlayCommand(path);
41088
41871
  if (!cmd)
41089
41872
  return;
41090
- return new Promise((resolve32) => {
41873
+ return new Promise((resolve33) => {
41091
41874
  const child = nodeSpawn(cmd[0], cmd.slice(1), {
41092
41875
  stdio: "ignore",
41093
41876
  detached: false
@@ -41096,12 +41879,12 @@ var init_voice = __esm({
41096
41879
  child.on("close", () => {
41097
41880
  if (this.currentPlayback === child)
41098
41881
  this.currentPlayback = null;
41099
- resolve32();
41882
+ resolve33();
41100
41883
  });
41101
41884
  child.on("error", () => {
41102
41885
  if (this.currentPlayback === child)
41103
41886
  this.currentPlayback = null;
41104
- resolve32();
41887
+ resolve33();
41105
41888
  });
41106
41889
  setTimeout(() => {
41107
41890
  if (this.currentPlayback === child) {
@@ -41111,7 +41894,7 @@ var init_voice = __esm({
41111
41894
  }
41112
41895
  this.currentPlayback = null;
41113
41896
  }
41114
- resolve32();
41897
+ resolve33();
41115
41898
  }, 15e3);
41116
41899
  });
41117
41900
  }
@@ -41186,7 +41969,7 @@ var init_voice = __esm({
41186
41969
  /** Non-blocking shell execution — async alternative to execSync.
41187
41970
  * Returns stdout string on exit 0, rejects otherwise. */
41188
41971
  asyncShell(command, timeoutMs = 3e4) {
41189
- return new Promise((resolve32, reject) => {
41972
+ return new Promise((resolve33, reject) => {
41190
41973
  const proc = nodeSpawn("sh", ["-c", command], {
41191
41974
  stdio: ["ignore", "pipe", "pipe"],
41192
41975
  cwd: tmpdir9()
@@ -41207,7 +41990,7 @@ var init_voice = __esm({
41207
41990
  proc.on("close", (code) => {
41208
41991
  clearTimeout(timer);
41209
41992
  if (code === 0)
41210
- resolve32(stdout.trim());
41993
+ resolve33(stdout.trim());
41211
41994
  else
41212
41995
  reject(new Error(stderr.slice(0, 300) || `Exit code ${code}`));
41213
41996
  });
@@ -41692,7 +42475,7 @@ if __name__ == '__main__':
41692
42475
  const venvPy = luxttsVenvPy();
41693
42476
  if (!existsSync36(venvPy))
41694
42477
  return false;
41695
- return new Promise((resolve32) => {
42478
+ return new Promise((resolve33) => {
41696
42479
  const env = { ...process.env, LUXTTS_REPO_PATH: luxttsRepoDir() };
41697
42480
  const daemon = nodeSpawn(venvPy, [luxttsInferScript()], {
41698
42481
  stdio: ["pipe", "pipe", "pipe"],
@@ -41711,7 +42494,7 @@ if __name__ == '__main__':
41711
42494
  try {
41712
42495
  const msg = JSON.parse(line);
41713
42496
  if (msg.type === "ready") {
41714
- resolve32(true);
42497
+ resolve33(true);
41715
42498
  } else if (msg.type === "result" || msg.type === "error") {
41716
42499
  const pending = this._luxttsPending.get(msg.id);
41717
42500
  if (pending) {
@@ -41735,25 +42518,25 @@ if __name__ == '__main__':
41735
42518
  });
41736
42519
  daemon.on("error", () => {
41737
42520
  this._luxttsDaemon = null;
41738
- resolve32(false);
42521
+ resolve33(false);
41739
42522
  });
41740
42523
  setTimeout(() => {
41741
42524
  if (this._luxttsDaemon === daemon && !this._luxttsPending.has("__ready__")) {
41742
- resolve32(false);
42525
+ resolve33(false);
41743
42526
  }
41744
42527
  }, 6e4);
41745
42528
  });
41746
42529
  }
41747
42530
  /** Send a request to the LuxTTS daemon and await the response */
41748
42531
  luxttsRequest(req) {
41749
- return new Promise((resolve32, reject) => {
42532
+ return new Promise((resolve33, reject) => {
41750
42533
  if (!this._luxttsDaemon || this._luxttsDaemon.killed) {
41751
42534
  reject(new Error("LuxTTS daemon not running"));
41752
42535
  return;
41753
42536
  }
41754
42537
  const id = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
41755
42538
  req.id = id;
41756
- this._luxttsPending.set(id, { resolve: resolve32, reject });
42539
+ this._luxttsPending.set(id, { resolve: resolve33, reject });
41757
42540
  this._luxttsDaemon.stdin.write(JSON.stringify(req) + "\n");
41758
42541
  setTimeout(() => {
41759
42542
  if (this._luxttsPending.has(id)) {
@@ -44777,9 +45560,9 @@ async function handleVoiceMenu(ctx, save, hasLocal) {
44777
45560
  }
44778
45561
  const { basename: basename16, join: pathJoin } = await import("node:path");
44779
45562
  const { copyFileSync: copyFileSync2, mkdirSync: mkdirSync22, existsSync: exists } = await import("node:fs");
44780
- const { homedir: homedir16 } = await import("node:os");
45563
+ const { homedir: homedir18 } = await import("node:os");
44781
45564
  const modelName = basename16(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
44782
- const destDir = pathJoin(homedir16(), ".open-agents", "voice", "models", modelName);
45565
+ const destDir = pathJoin(homedir18(), ".open-agents", "voice", "models", modelName);
44783
45566
  if (!exists(destDir))
44784
45567
  mkdirSync22(destDir, { recursive: true });
44785
45568
  copyFileSync2(onnxDrop.path, pathJoin(destDir, "model.onnx"));
@@ -45680,11 +46463,11 @@ async function handleUpdate(subcommand, ctx) {
45680
46463
  const targetVersion = info?.latestVersion ?? currentVersion;
45681
46464
  const installOverlay = startInstallOverlay(targetVersion);
45682
46465
  let installError = "";
45683
- const runInstall2 = (cmd) => new Promise((resolve32) => {
46466
+ const runInstall2 = (cmd) => new Promise((resolve33) => {
45684
46467
  const child = exec4(cmd, { timeout: 18e4 }, (err, _stdout, stderr) => {
45685
46468
  if (err)
45686
46469
  installError = (stderr || err.message || "").trim();
45687
- resolve32(!err);
46470
+ resolve33(!err);
45688
46471
  });
45689
46472
  child.stdout?.on("data", (chunk) => {
45690
46473
  const text = String(chunk);
@@ -45778,8 +46561,8 @@ async function handleUpdate(subcommand, ctx) {
45778
46561
  }
45779
46562
  if (doRebuild) {
45780
46563
  installOverlay.setStatus("Rebuilding native modules...");
45781
- await new Promise((resolve32) => {
45782
- const child = exec4(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve32(true));
46564
+ await new Promise((resolve33) => {
46565
+ const child = exec4(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve33(true));
45783
46566
  child.stdout?.resume();
45784
46567
  child.stderr?.resume();
45785
46568
  });
@@ -45810,8 +46593,8 @@ async function handleUpdate(subcommand, ctx) {
45810
46593
  const venvPip = pathJoin(venvDir, "bin", "pip");
45811
46594
  if (fsExists(venvPip)) {
45812
46595
  installOverlay.setStatus("Upgrading Python packages...");
45813
- await new Promise((resolve32) => {
45814
- const child = exec4(`"${venvPip}" install --upgrade moondream-station pytesseract Pillow opencv-python-headless numpy 2>/dev/null || true`, { timeout: 3e5 }, (err) => resolve32(!err));
46596
+ await new Promise((resolve33) => {
46597
+ const child = exec4(`"${venvPip}" install --upgrade moondream-station pytesseract Pillow opencv-python-headless numpy 2>/dev/null || true`, { timeout: 3e5 }, (err) => resolve33(!err));
45815
46598
  child.stdout?.resume();
45816
46599
  child.stderr?.resume();
45817
46600
  });
@@ -46207,16 +46990,16 @@ async function showExposeDashboard(gateway, rl, ctx) {
46207
46990
  renderDashboard();
46208
46991
  }, 1e3);
46209
46992
  let stopGateway = false;
46210
- await new Promise((resolve32) => {
46993
+ await new Promise((resolve33) => {
46211
46994
  const onData = (data) => {
46212
46995
  const key = data.toString();
46213
46996
  if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
46214
- resolve32();
46997
+ resolve33();
46215
46998
  return;
46216
46999
  }
46217
47000
  if (key === "s" || key === "S") {
46218
47001
  stopGateway = true;
46219
- resolve32();
47002
+ resolve33();
46220
47003
  return;
46221
47004
  }
46222
47005
  if (key === "c" || key === "C") {
@@ -46267,8 +47050,8 @@ async function showExposeDashboard(gateway, rl, ctx) {
46267
47050
  process.stdout.write("\x1B[?1002h\x1B[?1006h");
46268
47051
  }
46269
47052
  };
46270
- const origResolve = resolve32;
46271
- resolve32 = (() => {
47053
+ const origResolve = resolve33;
47054
+ resolve33 = (() => {
46272
47055
  cleanup();
46273
47056
  origResolve();
46274
47057
  });
@@ -46326,7 +47109,7 @@ var init_commands = __esm({
46326
47109
  import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync11 } from "node:fs";
46327
47110
  import { join as join53, basename as basename10 } from "node:path";
46328
47111
  import { execSync as execSync27 } from "node:child_process";
46329
- import { homedir as homedir13, platform as platform3, release } from "node:os";
47112
+ import { homedir as homedir15, platform as platform3, release } from "node:os";
46330
47113
  function getModelTier(modelName) {
46331
47114
  const m = modelName.toLowerCase();
46332
47115
  const sizeMatch = m.match(/\b(\d+)b\b/);
@@ -46413,7 +47196,7 @@ function loadMemoryContext(repoRoot) {
46413
47196
  if (legacyEntries)
46414
47197
  sections.push(legacyEntries);
46415
47198
  }
46416
- const globalMemDir = join53(homedir13(), ".open-agents", "memory");
47199
+ const globalMemDir = join53(homedir15(), ".open-agents", "memory");
46417
47200
  const globalEntries = loadMemoryDir(globalMemDir, "global");
46418
47201
  if (globalEntries)
46419
47202
  sections.push(globalEntries);
@@ -52133,7 +52916,7 @@ var init_tool_policy = __esm({
52133
52916
 
52134
52917
  // packages/cli/dist/tui/telegram-bridge.js
52135
52918
  import { mkdirSync as mkdirSync19, existsSync as existsSync44, unlinkSync as unlinkSync10, readdirSync as readdirSync16, statSync as statSync14 } from "node:fs";
52136
- import { join as join60, resolve as resolve28 } from "node:path";
52919
+ import { join as join60, resolve as resolve29 } from "node:path";
52137
52920
  import { writeFile as writeFileAsync } from "node:fs/promises";
52138
52921
  function convertMarkdownToTelegramHTML(md) {
52139
52922
  let html = md;
@@ -52376,7 +53159,7 @@ with summary "no_reply" to silently skip without responding.
52376
53159
  this.agentConfig = agentConfig;
52377
53160
  this.repoRoot = repoRoot;
52378
53161
  this.toolPolicyConfig = toolPolicyConfig;
52379
- this.mediaCacheDir = resolve28(repoRoot || ".", ".oa", "telegram-media-cache");
53162
+ this.mediaCacheDir = resolve29(repoRoot || ".", ".oa", "telegram-media-cache");
52380
53163
  }
52381
53164
  /** Set admin user ID filter */
52382
53165
  setAdmin(userId) {
@@ -53612,7 +54395,7 @@ var init_braille_spinner = __esm({
53612
54395
  // packages/cli/dist/tui/system-metrics.js
53613
54396
  import { loadavg as loadavg3, cpus as cpus3, totalmem as totalmem4, freemem as freemem3, platform as platform4 } from "node:os";
53614
54397
  import { exec as exec3 } from "node:child_process";
53615
- import { readFile as readFile21 } from "node:fs/promises";
54398
+ import { readFile as readFile22 } from "node:fs/promises";
53616
54399
  function formatRate(bytesPerSec) {
53617
54400
  if (bytesPerSec < 1024)
53618
54401
  return `${Math.round(bytesPerSec)}B`;
@@ -53624,7 +54407,7 @@ function formatRate(bytesPerSec) {
53624
54407
  }
53625
54408
  async function readProcNetDev() {
53626
54409
  try {
53627
- const data = await readFile21("/proc/net/dev", "utf8");
54410
+ const data = await readFile22("/proc/net/dev", "utf8");
53628
54411
  let rxTotal = 0;
53629
54412
  let txTotal = 0;
53630
54413
  for (const line of data.split("\n")) {
@@ -53662,8 +54445,8 @@ async function collectNetworkMetrics() {
53662
54445
  }
53663
54446
  if (plat === "darwin") {
53664
54447
  try {
53665
- const output = await new Promise((resolve32, reject) => {
53666
- exec3("netstat -ib 2>/dev/null | head -30", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve32(stdout));
54448
+ const output = await new Promise((resolve33, reject) => {
54449
+ exec3("netstat -ib 2>/dev/null | head -30", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve33(stdout));
53667
54450
  });
53668
54451
  let rxBytes = 0, txBytes = 0;
53669
54452
  for (const line of output.split("\n")) {
@@ -53697,8 +54480,8 @@ async function collectGpuMetrics() {
53697
54480
  if (_nvidiaSmiAvailable === false)
53698
54481
  return noGpu;
53699
54482
  try {
53700
- const smi = await new Promise((resolve32, reject) => {
53701
- exec3("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve32(stdout));
54483
+ const smi = await new Promise((resolve33, reject) => {
54484
+ exec3("nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve33(stdout));
53702
54485
  });
53703
54486
  _nvidiaSmiAvailable = true;
53704
54487
  const line = smi.trim().split("\n")[0];
@@ -56347,13 +57130,13 @@ var init_mouse_filter = __esm({
56347
57130
  import * as readline2 from "node:readline";
56348
57131
  import { Writable } from "node:stream";
56349
57132
  import { cwd } from "node:process";
56350
- import { resolve as resolve29, join as join61, dirname as dirname19, extname as extname10 } from "node:path";
57133
+ import { resolve as resolve30, join as join61, dirname as dirname19, extname as extname10 } from "node:path";
56351
57134
  import { createRequire as createRequire2 } from "node:module";
56352
57135
  import { fileURLToPath as fileURLToPath12 } from "node:url";
56353
57136
  import { readFileSync as readFileSync34, writeFileSync as writeFileSync19, appendFileSync as appendFileSync4, rmSync as rmSync3, readdirSync as readdirSync17, mkdirSync as mkdirSync20 } from "node:fs";
56354
57137
  import { existsSync as existsSync45 } from "node:fs";
56355
57138
  import { execSync as execSync30 } from "node:child_process";
56356
- import { homedir as homedir14 } from "node:os";
57139
+ import { homedir as homedir16 } from "node:os";
56357
57140
  function formatTimeAgo(date) {
56358
57141
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
56359
57142
  if (seconds < 60)
@@ -56502,6 +57285,9 @@ function buildTools(repoRoot, config, contextWindowSize) {
56502
57285
  new OpenCodeTool(repoRoot),
56503
57286
  new FactoryTool(repoRoot),
56504
57287
  new CronAgentTool(repoRoot),
57288
+ // Chunked file exploration + working notes
57289
+ new FileExploreTool(repoRoot),
57290
+ new WorkingNotesTool(),
56505
57291
  // Nexus P2P networking + x402 micropayments
56506
57292
  new NexusTool(repoRoot)
56507
57293
  ];
@@ -57651,7 +58437,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
57651
58437
  } };
57652
58438
  }
57653
58439
  async function startInteractive(config, repoPath) {
57654
- const repoRoot = resolve29(repoPath ?? cwd());
58440
+ const repoRoot = resolve30(repoPath ?? cwd());
57655
58441
  const resumeFlag = process.env.__OA_RESUMED ?? "";
57656
58442
  const isResumed = resumeFlag !== "";
57657
58443
  const hasTaskToResume = resumeFlag === "1";
@@ -57823,14 +58609,14 @@ async function startInteractive(config, repoPath) {
57823
58609
  renderInfo(msg);
57824
58610
  statusBar.endContentWrite();
57825
58611
  }
57826
- }, () => new Promise((resolve32) => {
58612
+ }, () => new Promise((resolve33) => {
57827
58613
  depSudoPromptPending = true;
57828
58614
  depSudoResolver = (pw) => {
57829
58615
  depSudoPromptPending = false;
57830
58616
  depSudoResolver = null;
57831
58617
  if (pw)
57832
58618
  sessionSudoPassword = pw;
57833
- resolve32(pw);
58619
+ resolve33(pw);
57834
58620
  };
57835
58621
  const pwPrompt1 = ` ${c2.bold(c2.yellow("\u{1F511} Password needed for dependency install:"))}
57836
58622
  `;
@@ -58118,7 +58904,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
58118
58904
  const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
58119
58905
  return [hits, line];
58120
58906
  }
58121
- const HISTORY_DIR = join61(homedir14(), ".open-agents");
58907
+ const HISTORY_DIR = join61(homedir16(), ".open-agents");
58122
58908
  const HISTORY_FILE = join61(HISTORY_DIR, "repl-history");
58123
58909
  const MAX_HISTORY_LINES = 500;
58124
58910
  let savedHistory = [];
@@ -59634,7 +60420,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
59634
60420
  } catch {
59635
60421
  }
59636
60422
  try {
59637
- const voiceDir2 = join61(homedir14(), ".open-agents", "voice");
60423
+ const voiceDir2 = join61(homedir16(), ".open-agents", "voice");
59638
60424
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
59639
60425
  for (const pf of voicePidFiles) {
59640
60426
  const pidPath = join61(voiceDir2, pf);
@@ -60037,8 +60823,8 @@ Execute this skill now. Follow the behavioral guidance above.`;
60037
60823
  }
60038
60824
  }
60039
60825
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
60040
- const isImage = isImagePath(cleanPath) && existsSync45(resolve29(repoRoot, cleanPath));
60041
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync45(resolve29(repoRoot, cleanPath));
60826
+ const isImage = isImagePath(cleanPath) && existsSync45(resolve30(repoRoot, cleanPath));
60827
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync45(resolve30(repoRoot, cleanPath));
60042
60828
  if (activeTask) {
60043
60829
  if (activeTask.runner.isPaused) {
60044
60830
  activeTask.runner.resume();
@@ -60046,7 +60832,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
60046
60832
  }
60047
60833
  if (isImage) {
60048
60834
  try {
60049
- const imgPath = resolve29(repoRoot, cleanPath);
60835
+ const imgPath = resolve30(repoRoot, cleanPath);
60050
60836
  const imgBuffer = readFileSync34(imgPath);
60051
60837
  const base64 = imgBuffer.toString("base64");
60052
60838
  const ext = extname10(cleanPath).toLowerCase();
@@ -60060,7 +60846,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
60060
60846
  } else if (isMedia) {
60061
60847
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
60062
60848
  const engine = getListenEngine();
60063
- const result = await engine.transcribeFile(resolve29(repoRoot, cleanPath), repoRoot);
60849
+ const result = await engine.transcribeFile(resolve30(repoRoot, cleanPath), repoRoot);
60064
60850
  if (result) {
60065
60851
  const transcript = `[Transcription of ${cleanPath}]
60066
60852
  ${result.text}`;
@@ -60204,7 +60990,7 @@ ${result.text}`;
60204
60990
  const ext = cleanPath.toLowerCase().split(".").pop() || "";
60205
60991
  if (cloneExts.includes("." + ext)) {
60206
60992
  writeContent(() => renderInfo(`Setting voice clone reference: ${cleanPath}`));
60207
- const msg = await voiceEngine.setCloneVoice(resolve29(repoRoot, cleanPath));
60993
+ const msg = await voiceEngine.setCloneVoice(resolve30(repoRoot, cleanPath));
60208
60994
  writeContent(() => renderInfo(msg));
60209
60995
  showPrompt();
60210
60996
  return;
@@ -60213,7 +60999,7 @@ ${result.text}`;
60213
60999
  if (isMedia && fullInput === input) {
60214
61000
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
60215
61001
  const engine = getListenEngine();
60216
- const result = await engine.transcribeFile(resolve29(repoRoot, cleanPath), repoRoot);
61002
+ const result = await engine.transcribeFile(resolve30(repoRoot, cleanPath), repoRoot);
60217
61003
  if (result) {
60218
61004
  fullInput = `The user has provided an audio/video file: ${cleanPath}.
60219
61005
 
@@ -60499,7 +61285,7 @@ ${c2.dim("(Use /quit to exit)")}
60499
61285
  };
60500
61286
  }
60501
61287
  async function runWithTUI(task, config, repoPath) {
60502
- const repoRoot = resolve29(repoPath ?? cwd());
61288
+ const repoRoot = resolve30(repoPath ?? cwd());
60503
61289
  const needsSetup = isFirstRun() || !await isModelAvailable(config);
60504
61290
  if (needsSetup && config.backendType === "ollama") {
60505
61291
  const setupModel = await runSetupWizard(config);
@@ -60882,7 +61668,7 @@ var init_run = __esm({
60882
61668
  // packages/indexer/dist/codebase-indexer.js
60883
61669
  import { glob } from "glob";
60884
61670
  import ignore from "ignore";
60885
- import { readFile as readFile22, stat as stat4 } from "node:fs/promises";
61671
+ import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
60886
61672
  import { createHash as createHash4 } from "node:crypto";
60887
61673
  import { join as join62, relative as relative3, extname as extname11, basename as basename15 } from "node:path";
60888
61674
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
@@ -60928,7 +61714,7 @@ var init_codebase_indexer = __esm({
60928
61714
  const ig = ignore.default();
60929
61715
  if (this.config.respectGitignore) {
60930
61716
  try {
60931
- const gitignoreContent = await readFile22(join62(this.config.rootDir, ".gitignore"), "utf-8");
61717
+ const gitignoreContent = await readFile23(join62(this.config.rootDir, ".gitignore"), "utf-8");
60932
61718
  ig.add(gitignoreContent);
60933
61719
  } catch {
60934
61720
  }
@@ -60948,7 +61734,7 @@ var init_codebase_indexer = __esm({
60948
61734
  const fileStat = await stat4(fullPath);
60949
61735
  if (fileStat.size > this.config.maxFileSize)
60950
61736
  continue;
60951
- const content = await readFile22(fullPath);
61737
+ const content = await readFile23(fullPath);
60952
61738
  const hash = createHash4("sha256").update(content).digest("hex");
60953
61739
  const ext = extname11(relativePath);
60954
61740
  indexed.push({
@@ -61071,11 +61857,11 @@ var index_repo_exports = {};
61071
61857
  __export(index_repo_exports, {
61072
61858
  indexRepoCommand: () => indexRepoCommand
61073
61859
  });
61074
- import { resolve as resolve30 } from "node:path";
61860
+ import { resolve as resolve31 } from "node:path";
61075
61861
  import { existsSync as existsSync46, statSync as statSync15 } from "node:fs";
61076
61862
  import { cwd as cwd2 } from "node:process";
61077
61863
  async function indexRepoCommand(opts, _config) {
61078
- const repoRoot = resolve30(opts.repoPath ?? cwd2());
61864
+ const repoRoot = resolve31(opts.repoPath ?? cwd2());
61079
61865
  printHeader("Index Repository");
61080
61866
  printInfo(`Indexing: ${repoRoot}`);
61081
61867
  if (!existsSync46(repoRoot)) {
@@ -61330,8 +62116,8 @@ var config_exports = {};
61330
62116
  __export(config_exports, {
61331
62117
  configCommand: () => configCommand
61332
62118
  });
61333
- import { join as join63, resolve as resolve31 } from "node:path";
61334
- import { homedir as homedir15 } from "node:os";
62119
+ import { join as join63, resolve as resolve32 } from "node:path";
62120
+ import { homedir as homedir17 } from "node:os";
61335
62121
  import { cwd as cwd3 } from "node:process";
61336
62122
  function redactIfSensitive(key, value) {
61337
62123
  if (SENSITIVE_KEYS.has(key) && typeof value === "string" && value.length > 0) {
@@ -61363,7 +62149,7 @@ async function configCommand(opts, config) {
61363
62149
  return handleShow(opts, config);
61364
62150
  }
61365
62151
  function handleShow(opts, config) {
61366
- const repoRoot = resolve31(opts.repoPath ?? cwd3());
62152
+ const repoRoot = resolve32(opts.repoPath ?? cwd3());
61367
62153
  printHeader("Configuration");
61368
62154
  const resolved = resolveSettings(repoRoot);
61369
62155
  printSection("Core Inference");
@@ -61413,7 +62199,7 @@ function handleShow(opts, config) {
61413
62199
  }
61414
62200
  }
61415
62201
  printSection("Config File");
61416
- printInfo(`~/.open-agents/config.json (${join63(homedir15(), ".open-agents", "config.json")})`);
62202
+ printInfo(`~/.open-agents/config.json (${join63(homedir17(), ".open-agents", "config.json")})`);
61417
62203
  printSection("Priority Chain");
61418
62204
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
61419
62205
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -61446,7 +62232,7 @@ function handleSet(opts, _config) {
61446
62232
  process.exit(1);
61447
62233
  }
61448
62234
  if (opts.local) {
61449
- const repoRoot = resolve31(opts.repoPath ?? cwd3());
62235
+ const repoRoot = resolve32(opts.repoPath ?? cwd3());
61450
62236
  try {
61451
62237
  initOaDirectory(repoRoot);
61452
62238
  const coerced = coerceForSettings(key, value);
@@ -61644,7 +62430,7 @@ async function serveVllm(opts, config) {
61644
62430
  await runVllmServer(args, opts.verbose ?? false);
61645
62431
  }
61646
62432
  async function runVllmServer(args, verbose) {
61647
- return new Promise((resolve32, reject) => {
62433
+ return new Promise((resolve33, reject) => {
61648
62434
  const child = spawn19("python", args, {
61649
62435
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
61650
62436
  env: { ...process.env }
@@ -61679,10 +62465,10 @@ async function runVllmServer(args, verbose) {
61679
62465
  child.once("exit", (code, signal) => {
61680
62466
  if (signal) {
61681
62467
  printInfo(`vLLM server stopped by signal ${signal}`);
61682
- resolve32();
62468
+ resolve33();
61683
62469
  } else if (code === 0) {
61684
62470
  printSuccess("vLLM server exited cleanly");
61685
- resolve32();
62471
+ resolve33();
61686
62472
  } else {
61687
62473
  printError(`vLLM server exited with code ${code}`);
61688
62474
  reject(new Error(`vLLM exited with code ${code}`));