open-agents-ai 0.142.1 → 0.143.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;
@@ -2556,7 +2556,7 @@ ${JSON.stringify(extracted, null, 2)}`);
2556
2556
  return null;
2557
2557
  }
2558
2558
  runProcess(cmd, args, timeoutMs) {
2559
- return new Promise((resolve32, reject) => {
2559
+ return new Promise((resolve33, reject) => {
2560
2560
  const proc = execFile3(cmd, args, {
2561
2561
  timeout: timeoutMs,
2562
2562
  maxBuffer: 10 * 1024 * 1024,
@@ -2566,7 +2566,7 @@ ${JSON.stringify(extracted, null, 2)}`);
2566
2566
  reject(new Error(`Process timeout after ${timeoutMs}ms`));
2567
2567
  return;
2568
2568
  }
2569
- resolve32({
2569
+ resolve33({
2570
2570
  stdout: String(stdout),
2571
2571
  stderr: String(stderr),
2572
2572
  exitCode: error ? error.code ?? 1 : 0
@@ -7142,6 +7142,58 @@ process.on('unhandledRejection', (reason) => {
7142
7142
  timestamp: Date.now(),
7143
7143
  };
7144
7144
  _natsConn.publish('nexus.agents.capacity', _natsCodec.encode(JSON.stringify(announcement)));
7145
+
7146
+ // Also publish enriched discovery announcement so the dashboard sees
7147
+ // IPFS/memory/identity/emotional state in sidebar cards (WO-VIS1 fields)
7148
+ try {
7149
+ // Gather memory metrics
7150
+ var _memCount = 0;
7151
+ var _memSentiment = 'neutral';
7152
+ var _ipfsBytes = 0;
7153
+ try {
7154
+ var _metaFile = join(nexusDir, '..', 'memory', 'metabolism', 'store.json');
7155
+ if (existsSync(_metaFile)) {
7156
+ var _mStore = JSON.parse(readFileSync(_metaFile, 'utf8'));
7157
+ _memCount = _mStore.filter(function(m) { return m.type !== 'quarantine'; }).length;
7158
+ var _recov = _mStore.filter(function(m) { return m.content && m.content.startsWith('[recovery]'); }).length;
7159
+ var _strat = _mStore.filter(function(m) { return m.content && m.content.startsWith('[strategy]'); }).length;
7160
+ _memSentiment = _strat > _recov ? 'proactive' : _recov > 0 ? 'defensive' : 'neutral';
7161
+ }
7162
+ } catch {}
7163
+ try {
7164
+ var _blocksDir = join(nexusDir, 'ipfs', 'blocks');
7165
+ if (existsSync(_blocksDir)) {
7166
+ var _walkBytes = function(d) { var t = 0; try { var ent = readdirSync(d, {withFileTypes:true}); for (var i=0;i<ent.length;i++) { if (ent[i].isDirectory()) t += _walkBytes(join(d,ent[i].name)); else try { t += statSync(join(d,ent[i].name)).size; } catch {} } } catch {} return t; };
7167
+ _ipfsBytes = _walkBytes(_blocksDir);
7168
+ }
7169
+ } catch {}
7170
+ // Identity CID
7171
+ var _idCid = '';
7172
+ try {
7173
+ var _cidFile = join(nexusDir, '..', 'identity', 'cids.json');
7174
+ if (existsSync(_cidFile)) { var _cids = JSON.parse(readFileSync(_cidFile, 'utf8')); _idCid = _cids.latest || ''; }
7175
+ } catch {}
7176
+
7177
+ var discoveryAnn = {
7178
+ type: 'nexus.announce',
7179
+ peerId: nexus.peerId,
7180
+ agentName: agentName,
7181
+ rooms: [],
7182
+ multiaddrs: [],
7183
+ timestamp: Date.now(),
7184
+ capabilities: _capModels.map(function(m) { return m.name; }),
7185
+ identityCid: _idCid || undefined,
7186
+ identityCoherence: 0.9,
7187
+ memoryCount: _memCount,
7188
+ memorySentiment: _memSentiment,
7189
+ ipfsStorageBytes: _ipfsBytes,
7190
+ emotionalState: cohereActive ? 'focused' : 'neutral',
7191
+ taskRate: (_cohereStats.queriesAnswered || 0) / Math.max(1, (Date.now() - (_cohereStats._startTime || Date.now())) / 3600000),
7192
+ cohereLearnings: _cohereStats.queriesSent || 0,
7193
+ };
7194
+ _natsConn.publish('nexus.agents.discovery', _natsCodec.encode(JSON.stringify(discoveryAnn)));
7195
+ } catch (e) { dlog('Discovery announcement error: ' + (e.message || e)); }
7196
+
7145
7197
  dlog('Capacity announcement published: ' + _capModels.length + ' models, warm=' + (_cLastModel || 'none'));
7146
7198
  } catch (e) {
7147
7199
  dlog('Capacity announcement error: ' + (e.message || e));
@@ -9923,7 +9975,7 @@ var init_custom_tool = __esm({
9923
9975
  }
9924
9976
  /** Execute a single shell command and return output */
9925
9977
  runCommand(command) {
9926
- return new Promise((resolve32) => {
9978
+ return new Promise((resolve33) => {
9927
9979
  const child = spawn4("bash", ["-c", command], {
9928
9980
  cwd: this.workingDir,
9929
9981
  env: { ...process.env, CI: "true", NO_COLOR: "1" },
@@ -9948,11 +10000,11 @@ var init_custom_tool = __esm({
9948
10000
  child.kill("SIGTERM");
9949
10001
  } catch {
9950
10002
  }
9951
- resolve32({ success: false, output: stdout, error: "Command timed out after 60s" });
10003
+ resolve33({ success: false, output: stdout, error: "Command timed out after 60s" });
9952
10004
  }, 6e4);
9953
10005
  child.on("close", (code) => {
9954
10006
  clearTimeout(timer);
9955
- resolve32({
10007
+ resolve33({
9956
10008
  success: code === 0,
9957
10009
  output: stdout + (stderr && code === 0 ? `
9958
10010
  STDERR:
@@ -9962,7 +10014,7 @@ ${stderr}` : ""),
9962
10014
  });
9963
10015
  child.on("error", (err) => {
9964
10016
  clearTimeout(timer);
9965
- resolve32({ success: false, output: stdout, error: err.message });
10017
+ resolve33({ success: false, output: stdout, error: err.message });
9966
10018
  });
9967
10019
  });
9968
10020
  }
@@ -11429,7 +11481,7 @@ import { writeFile as writeFile8, mkdtemp, rm, readdir as readdir3, stat } from
11429
11481
  import { join as join18 } from "node:path";
11430
11482
  import { tmpdir as tmpdir2 } from "node:os";
11431
11483
  function runProcess(cmd, args, options) {
11432
- return new Promise((resolve32) => {
11484
+ return new Promise((resolve33) => {
11433
11485
  const proc = spawn6(cmd, args, {
11434
11486
  cwd: options.cwd,
11435
11487
  timeout: options.timeout,
@@ -11459,7 +11511,7 @@ function runProcess(cmd, args, options) {
11459
11511
  }
11460
11512
  });
11461
11513
  proc.on("error", (err) => {
11462
- resolve32({
11514
+ resolve33({
11463
11515
  stdout,
11464
11516
  stderr: stderr || err.message,
11465
11517
  exitCode: 1,
@@ -11471,7 +11523,7 @@ function runProcess(cmd, args, options) {
11471
11523
  if (signal === "SIGTERM" || signal === "SIGKILL") {
11472
11524
  timedOut = true;
11473
11525
  }
11474
- resolve32({
11526
+ resolve33({
11475
11527
  stdout,
11476
11528
  stderr,
11477
11529
  exitCode: code ?? (timedOut ? 124 : 1),
@@ -11954,7 +12006,7 @@ Justification: ${justification || "(none provided)"}`,
11954
12006
  })();
11955
12007
  const ipfsResult = await Promise.race([
11956
12008
  ipfsPromise,
11957
- new Promise((resolve32) => setTimeout(() => resolve32(null), 2e3))
12009
+ new Promise((resolve33) => setTimeout(() => resolve33(null), 2e3))
11958
12010
  ]);
11959
12011
  if (ipfsResult && ipfsResult.success) {
11960
12012
  const cidData = JSON.parse(ipfsResult.output);
@@ -12398,7 +12450,7 @@ print("__OA_REPL_READY__")
12398
12450
  return;
12399
12451
  const sockId = randomBytes3(8).toString("hex");
12400
12452
  this.ipcPath = join20(tmpdir3(), `oa-repl-ipc-${sockId}.sock`);
12401
- return new Promise((resolve32, reject) => {
12453
+ return new Promise((resolve33, reject) => {
12402
12454
  this.ipcServer = createServer((conn) => {
12403
12455
  let buffer = new Uint8Array(0);
12404
12456
  conn.on("data", (chunk) => {
@@ -12414,7 +12466,7 @@ print("__OA_REPL_READY__")
12414
12466
  });
12415
12467
  });
12416
12468
  this.ipcServer.on("error", reject);
12417
- this.ipcServer.listen(this.ipcPath, () => resolve32());
12469
+ this.ipcServer.listen(this.ipcPath, () => resolve33());
12418
12470
  });
12419
12471
  }
12420
12472
  async processIpcBuffer(conn, input) {
@@ -12477,9 +12529,9 @@ print("__OA_REPL_READY__")
12477
12529
  }
12478
12530
  // ── Code execution ─────────────────────────────────────────────────────
12479
12531
  executeCode(code, isInit = false) {
12480
- return new Promise((resolve32) => {
12532
+ return new Promise((resolve33) => {
12481
12533
  if (!this.proc?.stdin || !this.proc?.stdout || !this.proc?.stderr) {
12482
- resolve32({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
12534
+ resolve33({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
12483
12535
  return;
12484
12536
  }
12485
12537
  const sentinel = `__OA_SENTINEL_${randomBytes3(6).toString("hex")}__`;
@@ -12489,7 +12541,7 @@ print("__OA_REPL_READY__")
12489
12541
  const timeout = setTimeout(() => {
12490
12542
  if (!resolved) {
12491
12543
  resolved = true;
12492
- resolve32({
12544
+ resolve33({
12493
12545
  success: false,
12494
12546
  output: stdout || "Execution timed out",
12495
12547
  error: `Timeout after ${this.execTimeout / 1e3}s`,
@@ -12506,13 +12558,13 @@ print("__OA_REPL_READY__")
12506
12558
  if (isInit) {
12507
12559
  const ready = cleanOutput.includes("__OA_REPL_READY__");
12508
12560
  const displayOutput = cleanOutput.replace("__OA_REPL_READY__", "").trim();
12509
- resolve32({
12561
+ resolve33({
12510
12562
  success: ready,
12511
12563
  output: displayOutput || "REPL initialized",
12512
12564
  durationMs: 0
12513
12565
  });
12514
12566
  } else {
12515
- resolve32({
12567
+ resolve33({
12516
12568
  success: true,
12517
12569
  output: cleanOutput || "(no output)",
12518
12570
  durationMs: 0
@@ -12521,7 +12573,7 @@ print("__OA_REPL_READY__")
12521
12573
  }
12522
12574
  if (stdout.length > 2e5) {
12523
12575
  cleanup();
12524
- resolve32({
12576
+ resolve33({
12525
12577
  success: true,
12526
12578
  output: stdout.slice(0, 2e5) + "\n[output truncated at 200KB]",
12527
12579
  durationMs: 0
@@ -16760,6 +16812,7 @@ train.py reverted to last kept state. Ready for next experiment.`,
16760
16812
  import { execSync as execSync18, exec as execCb } from "node:child_process";
16761
16813
  import { readFile as readFile15, writeFile as writeFile15, mkdir as mkdir11 } from "node:fs/promises";
16762
16814
  import { resolve as resolve22, join as join32 } from "node:path";
16815
+ import { homedir as homedir8 } from "node:os";
16763
16816
  import { randomBytes as randomBytes4 } from "node:crypto";
16764
16817
  function isValidCron(expr) {
16765
16818
  const parts = expr.trim().split(/\s+/);
@@ -16889,6 +16942,31 @@ async function saveStore(workingDir, store) {
16889
16942
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
16890
16943
  await writeFile15(join32(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
16891
16944
  }
16945
+ function globalStoreDir() {
16946
+ return join32(homedir8(), ".open-agents", "scheduled");
16947
+ }
16948
+ async function loadGlobalStore() {
16949
+ try {
16950
+ const raw = await readFile15(join32(globalStoreDir(), "tasks.json"), "utf-8");
16951
+ return JSON.parse(raw);
16952
+ } catch {
16953
+ return { tasks: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
16954
+ }
16955
+ }
16956
+ async function saveGlobalStore(store) {
16957
+ const dir = globalStoreDir();
16958
+ await mkdir11(dir, { recursive: true });
16959
+ await mkdir11(join32(dir, "logs"), { recursive: true });
16960
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
16961
+ await writeFile15(join32(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
16962
+ }
16963
+ async function loadAllStores(workingDir) {
16964
+ const [local, global] = await Promise.all([
16965
+ loadStore(workingDir),
16966
+ loadGlobalStore()
16967
+ ]);
16968
+ return { local, global };
16969
+ }
16892
16970
  var SCHEDULE_PRESETS, CRON_MARKER, SchedulerTool;
16893
16971
  var init_scheduler = __esm({
16894
16972
  "packages/execution/dist/tools/scheduler.js"() {
@@ -16912,7 +16990,7 @@ var init_scheduler = __esm({
16912
16990
  CRON_MARKER = "# OPEN-AGENTS-SCHEDULED:";
16913
16991
  SchedulerTool = class {
16914
16992
  name = "scheduler";
16915
- 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.";
16993
+ 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.";
16916
16994
  parameters = {
16917
16995
  type: "object",
16918
16996
  properties: {
@@ -16940,6 +17018,11 @@ var init_scheduler = __esm({
16940
17018
  one_shot: {
16941
17019
  type: "boolean",
16942
17020
  description: "If true, task auto-removes after first execution"
17021
+ },
17022
+ scope: {
17023
+ type: "string",
17024
+ enum: ["local", "global"],
17025
+ description: "Scope: 'local' (project .oa/, default) or 'global' (~/.open-agents/, visible from all projects)"
16943
17026
  }
16944
17027
  },
16945
17028
  required: ["action"]
@@ -17001,6 +17084,7 @@ var init_scheduler = __esm({
17001
17084
  const id = `sched-${randomBytes4(4).toString("hex")}`;
17002
17085
  const oneShot = Boolean(args["one_shot"]);
17003
17086
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : void 0;
17087
+ const scope = String(args["scope"] ?? "local");
17004
17088
  const newTask = {
17005
17089
  id,
17006
17090
  task,
@@ -17010,11 +17094,19 @@ var init_scheduler = __esm({
17010
17094
  enabled: true,
17011
17095
  runCount: 0,
17012
17096
  maxRuns,
17013
- oneShot: oneShot || void 0
17097
+ oneShot: oneShot || void 0,
17098
+ scope,
17099
+ projectDir: resolve22(this.workingDir)
17014
17100
  };
17015
- const store = await loadStore(this.workingDir);
17016
- store.tasks.push(newTask);
17017
- await saveStore(this.workingDir, store);
17101
+ if (scope === "global") {
17102
+ const store = await loadGlobalStore();
17103
+ store.tasks.push(newTask);
17104
+ await saveGlobalStore(store);
17105
+ } else {
17106
+ const store = await loadStore(this.workingDir);
17107
+ store.tasks.push(newTask);
17108
+ await saveStore(this.workingDir, store);
17109
+ }
17018
17110
  installCronJob(newTask, this.workingDir);
17019
17111
  return {
17020
17112
  success: true,
@@ -17023,6 +17115,7 @@ var init_scheduler = __esm({
17023
17115
  ` ID: ${id}`,
17024
17116
  ` Task: ${task}`,
17025
17117
  ` Schedule: ${describeCron(cronExpr)} (${cronExpr})`,
17118
+ ` Scope: ${scope}${scope === "global" ? " (visible from all projects)" : " (this project only)"}`,
17026
17119
  oneShot ? ` Mode: one-shot (auto-removes after first run)` : "",
17027
17120
  maxRuns ? ` Max runs: ${maxRuns}` : "",
17028
17121
  ` Status: enabled`,
@@ -17034,28 +17127,53 @@ var init_scheduler = __esm({
17034
17127
  };
17035
17128
  }
17036
17129
  async listTasks(start) {
17037
- const store = await loadStore(this.workingDir);
17130
+ const { local, global } = await loadAllStores(this.workingDir);
17038
17131
  const cronJobs = listCronJobs();
17039
- if (store.tasks.length === 0) {
17132
+ const totalCount = local.tasks.length + global.tasks.length;
17133
+ if (totalCount === 0) {
17040
17134
  return {
17041
17135
  success: true,
17042
17136
  output: "No scheduled tasks. Use scheduler(action='create', task='...', schedule='daily') to create one.",
17043
17137
  durationMs: performance.now() - start
17044
17138
  };
17045
17139
  }
17046
- const lines = [`Scheduled Tasks (${store.tasks.length}):
17047
- `];
17048
- for (const t of store.tasks) {
17049
- const status = t.enabled ? "enabled" : "PAUSED";
17050
- const cronInstalled = cronJobs.some((j) => j.id === t.id);
17051
- const cronStatus = cronInstalled ? "" : " [cron not installed]";
17052
- lines.push(` [${t.id}] ${status}${cronStatus}`);
17053
- lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
17054
- lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
17055
- lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
17056
- if (t.lastRun)
17057
- lines.push(` Last run: ${t.lastRun}`);
17058
- lines.push("");
17140
+ const lines = [];
17141
+ if (local.tasks.length > 0) {
17142
+ lines.push(`Local Tasks \u2014 this project (${local.tasks.length}):
17143
+ `);
17144
+ for (const t of local.tasks) {
17145
+ const status = t.enabled ? "enabled" : "PAUSED";
17146
+ const cronInstalled = cronJobs.some((j) => j.id === t.id);
17147
+ const cronStatus = cronInstalled ? "" : " [cron not installed]";
17148
+ lines.push(` [${t.id}] ${status}${cronStatus} [local]`);
17149
+ lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
17150
+ lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
17151
+ lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
17152
+ if (t.lastRun)
17153
+ lines.push(` Last run: ${t.lastRun}`);
17154
+ lines.push("");
17155
+ }
17156
+ }
17157
+ if (global.tasks.length > 0) {
17158
+ lines.push(`Global Tasks \u2014 shared across projects (${global.tasks.length}):
17159
+ `);
17160
+ for (const t of global.tasks) {
17161
+ const status = t.enabled ? "enabled" : "PAUSED";
17162
+ const cronInstalled = cronJobs.some((j) => j.id === t.id);
17163
+ const cronStatus = cronInstalled ? "" : " [cron not installed]";
17164
+ const isThisProject = t.projectDir === resolve22(this.workingDir);
17165
+ const origin = isThisProject ? " [this project]" : t.projectDir ? ` [from: ${t.projectDir}]` : "";
17166
+ lines.push(` [${t.id}] ${status}${cronStatus} [global]${origin}`);
17167
+ lines.push(` Task: ${t.task.slice(0, 100)}${t.task.length > 100 ? "..." : ""}`);
17168
+ lines.push(` Schedule: ${t.nextRunDescription} (${t.schedule})`);
17169
+ lines.push(` Runs: ${t.runCount}${t.maxRuns ? `/${t.maxRuns}` : ""}${t.oneShot ? " (one-shot)" : ""}`);
17170
+ if (t.lastRun)
17171
+ lines.push(` Last run: ${t.lastRun}`);
17172
+ if (!isThisProject && t.projectDir) {
17173
+ lines.push(` \u26A0 NOT scoped to this project \u2014 override with caution`);
17174
+ }
17175
+ lines.push("");
17176
+ }
17059
17177
  }
17060
17178
  return {
17061
17179
  success: true,
@@ -17616,7 +17734,7 @@ ${sections.join("\n")}`,
17616
17734
  const description = String(args["description"] ?? "");
17617
17735
  const category = args["category"] ?? "followup";
17618
17736
  const priority = args["priority"] ?? "normal";
17619
- const notes = args["notes"] ?? void 0;
17737
+ const notes2 = args["notes"] ?? void 0;
17620
17738
  const relatedFilesStr = args["related_files"] ?? "";
17621
17739
  const relatedFiles = relatedFilesStr ? relatedFilesStr.split(",").map((f) => f.trim()).filter(Boolean) : void 0;
17622
17740
  let expiresAt;
@@ -17649,7 +17767,7 @@ ${sections.join("\n")}`,
17649
17767
  expiresAt,
17650
17768
  relatedFiles,
17651
17769
  status: "active",
17652
- notes
17770
+ notes: notes2
17653
17771
  };
17654
17772
  const store = await loadAttentionStore(this.workingDir);
17655
17773
  store.items.push(item);
@@ -18343,6 +18461,7 @@ var init_factory = __esm({
18343
18461
  import { execSync as execSync21 } from "node:child_process";
18344
18462
  import { readFile as readFile18, writeFile as writeFile18, mkdir as mkdir14 } from "node:fs/promises";
18345
18463
  import { resolve as resolve26, join as join37 } from "node:path";
18464
+ import { homedir as homedir9 } from "node:os";
18346
18465
  import { randomBytes as randomBytes7 } from "node:crypto";
18347
18466
  function isValidCron2(expr) {
18348
18467
  const parts = expr.trim().split(/\s+/);
@@ -18471,6 +18590,31 @@ async function saveStore2(workingDir, store) {
18471
18590
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
18472
18591
  await writeFile18(join37(dir, "store.json"), JSON.stringify(store, null, 2), "utf-8");
18473
18592
  }
18593
+ function globalCronDir() {
18594
+ return join37(homedir9(), ".open-agents", "cron-agents");
18595
+ }
18596
+ async function loadGlobalCronStore() {
18597
+ try {
18598
+ const raw = await readFile18(join37(globalCronDir(), "store.json"), "utf-8");
18599
+ return JSON.parse(raw);
18600
+ } catch {
18601
+ return { jobs: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
18602
+ }
18603
+ }
18604
+ async function saveGlobalCronStore(store) {
18605
+ const dir = globalCronDir();
18606
+ await mkdir14(dir, { recursive: true });
18607
+ await mkdir14(join37(dir, "logs"), { recursive: true });
18608
+ store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
18609
+ await writeFile18(join37(dir, "store.json"), JSON.stringify(store, null, 2), "utf-8");
18610
+ }
18611
+ async function loadAllCronStores(workingDir) {
18612
+ const [local, global] = await Promise.all([
18613
+ loadStore2(workingDir),
18614
+ loadGlobalCronStore()
18615
+ ]);
18616
+ return { local, global };
18617
+ }
18474
18618
  var LONG_HORIZON_PRESETS, CRON_AGENT_MARKER, CronAgentTool;
18475
18619
  var init_cron_agent = __esm({
18476
18620
  "packages/execution/dist/tools/cron-agent.js"() {
@@ -18539,6 +18683,11 @@ var init_cron_agent = __esm({
18539
18683
  type: "array",
18540
18684
  items: { type: "string" },
18541
18685
  description: "Tags for organizing jobs (for 'create')"
18686
+ },
18687
+ scope: {
18688
+ type: "string",
18689
+ enum: ["local", "global"],
18690
+ description: "Scope: 'local' (project .oa/, default) or 'global' (~/.open-agents/, visible from all projects)"
18542
18691
  }
18543
18692
  },
18544
18693
  required: ["action"]
@@ -18607,6 +18756,7 @@ var init_cron_agent = __esm({
18607
18756
  const verifyCommand = args["verify_command"] ? String(args["verify_command"]) : void 0;
18608
18757
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : 0;
18609
18758
  const tags = Array.isArray(args["tags"]) ? args["tags"] : [];
18759
+ const scope = String(args["scope"] ?? "local");
18610
18760
  const job = {
18611
18761
  id,
18612
18762
  task,
@@ -18620,11 +18770,19 @@ var init_cron_agent = __esm({
18620
18770
  runCount: 0,
18621
18771
  maxRuns,
18622
18772
  history: [],
18623
- tags
18773
+ tags,
18774
+ scope,
18775
+ projectDir: resolve26(this.workingDir)
18624
18776
  };
18625
- const store = await loadStore2(this.workingDir);
18626
- store.jobs.push(job);
18627
- await saveStore2(this.workingDir, store);
18777
+ if (scope === "global") {
18778
+ const store = await loadGlobalCronStore();
18779
+ store.jobs.push(job);
18780
+ await saveGlobalCronStore(store);
18781
+ } else {
18782
+ const store = await loadStore2(this.workingDir);
18783
+ store.jobs.push(job);
18784
+ await saveStore2(this.workingDir, store);
18785
+ }
18628
18786
  installCronAgentJob(job, this.workingDir);
18629
18787
  return {
18630
18788
  success: true,
@@ -18648,19 +18806,19 @@ var init_cron_agent = __esm({
18648
18806
  };
18649
18807
  }
18650
18808
  async listJobs(start) {
18651
- const store = await loadStore2(this.workingDir);
18652
- if (store.jobs.length === 0) {
18809
+ const { local, global } = await loadAllCronStores(this.workingDir);
18810
+ const totalCount = local.jobs.length + global.jobs.length;
18811
+ if (totalCount === 0) {
18653
18812
  return {
18654
18813
  success: true,
18655
18814
  output: "No cron agent jobs. Use cron_agent(action='create', ...) to schedule one.",
18656
18815
  durationMs: performance.now() - start
18657
18816
  };
18658
18817
  }
18659
- const lines = [`Cron Agent Jobs (${store.jobs.length}):
18660
- `];
18661
- for (const job of store.jobs) {
18818
+ const lines = [];
18819
+ const formatJob = (job, scopeLabel, isThisProject) => {
18662
18820
  const statusIcon = job.status === "active" ? "\u25CF" : job.status === "completed" ? "\u2714" : job.status === "paused" ? "\u23F8" : "\u2716";
18663
- lines.push(` ${statusIcon} [${job.id}] ${job.status.toUpperCase()}`);
18821
+ lines.push(` ${statusIcon} [${job.id}] ${job.status.toUpperCase()} [${scopeLabel}]`);
18664
18822
  lines.push(` Goal: ${job.goal.slice(0, 80)}${job.goal.length > 80 ? "..." : ""}`);
18665
18823
  lines.push(` Schedule: ${job.scheduleDescription}`);
18666
18824
  lines.push(` Runs: ${job.runCount}${job.maxRuns > 0 ? `/${job.maxRuns}` : ""}`);
@@ -18668,7 +18826,25 @@ var init_cron_agent = __esm({
18668
18826
  lines.push(` Last run: ${job.lastRunAt}`);
18669
18827
  if (job.tags.length > 0)
18670
18828
  lines.push(` Tags: ${job.tags.join(", ")}`);
18829
+ if (!isThisProject && job.projectDir) {
18830
+ lines.push(` Origin: ${job.projectDir}`);
18831
+ lines.push(` \u26A0 NOT scoped to this project \u2014 override with caution`);
18832
+ }
18671
18833
  lines.push("");
18834
+ };
18835
+ if (local.jobs.length > 0) {
18836
+ lines.push(`Local Cron Jobs \u2014 this project (${local.jobs.length}):
18837
+ `);
18838
+ for (const job of local.jobs)
18839
+ formatJob(job, "local", true);
18840
+ }
18841
+ if (global.jobs.length > 0) {
18842
+ lines.push(`Global Cron Jobs \u2014 shared (${global.jobs.length}):
18843
+ `);
18844
+ for (const job of global.jobs) {
18845
+ const isThisProject = job.projectDir === resolve26(this.workingDir);
18846
+ formatJob(job, isThisProject ? "global, this project" : "global", isThisProject);
18847
+ }
18672
18848
  }
18673
18849
  return {
18674
18850
  success: true,
@@ -18804,6 +18980,575 @@ ${truncated}`, durationMs: performance.now() - start };
18804
18980
  }
18805
18981
  });
18806
18982
 
18983
+ // packages/execution/dist/tools/file-explore.js
18984
+ import { readFile as readFile19 } from "node:fs/promises";
18985
+ import { resolve as resolve27 } from "node:path";
18986
+ import { execFile as execFile4 } from "node:child_process";
18987
+ import { promisify as promisify3 } from "node:util";
18988
+ function getPatterns(filePath) {
18989
+ if (/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(filePath))
18990
+ return SIG_PATTERNS.ts;
18991
+ if (/\.py$/.test(filePath))
18992
+ return SIG_PATTERNS.py;
18993
+ if (/\.rs$/.test(filePath))
18994
+ return SIG_PATTERNS.rs;
18995
+ if (/\.go$/.test(filePath))
18996
+ return SIG_PATTERNS.go;
18997
+ return SIG_PATTERNS.default;
18998
+ }
18999
+ function clearExploreNotes() {
19000
+ sessionNotes.length = 0;
19001
+ }
19002
+ function getExploreNotes() {
19003
+ return sessionNotes;
19004
+ }
19005
+ var execFileAsync3, sessionNotes, SIG_PATTERNS, FileExploreTool;
19006
+ var init_file_explore = __esm({
19007
+ "packages/execution/dist/tools/file-explore.js"() {
19008
+ "use strict";
19009
+ execFileAsync3 = promisify3(execFile4);
19010
+ sessionNotes = [];
19011
+ SIG_PATTERNS = {
19012
+ ts: [
19013
+ /^\s*(export\s+)?(async\s+)?function\s+\w+/,
19014
+ /^\s*(export\s+)?(abstract\s+)?class\s+\w+/,
19015
+ /^\s*(export\s+)?(const|let|var)\s+\w+\s*[:=]/,
19016
+ /^\s*(export\s+)?interface\s+\w+/,
19017
+ /^\s*(export\s+)?type\s+\w+\s*=/,
19018
+ /^\s*(export\s+)?enum\s+\w+/,
19019
+ /^\s*(?:public|private|protected|static|async|get|set)\s+\w+\s*[(<]/
19020
+ ],
19021
+ py: [
19022
+ /^\s*def\s+\w+/,
19023
+ /^\s*class\s+\w+/,
19024
+ /^\s*async\s+def\s+\w+/,
19025
+ /^[A-Z_][A-Z_0-9]*\s*=/
19026
+ ],
19027
+ rs: [
19028
+ /^\s*(pub\s+)?(async\s+)?fn\s+\w+/,
19029
+ /^\s*(pub\s+)?struct\s+\w+/,
19030
+ /^\s*(pub\s+)?enum\s+\w+/,
19031
+ /^\s*(pub\s+)?trait\s+\w+/,
19032
+ /^\s*impl\s+/
19033
+ ],
19034
+ go: [
19035
+ /^\s*func\s+/,
19036
+ /^\s*type\s+\w+\s+struct/,
19037
+ /^\s*type\s+\w+\s+interface/
19038
+ ],
19039
+ default: [
19040
+ /^\s*(export\s+)?(function|class|const|let|var|def|fn|pub|type|interface|enum|struct|trait|impl)\s+/
19041
+ ]
19042
+ };
19043
+ FileExploreTool = class {
19044
+ name = "file_explore";
19045
+ 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.";
19046
+ parameters = {
19047
+ type: "object",
19048
+ properties: {
19049
+ path: {
19050
+ type: "string",
19051
+ description: "File path to explore"
19052
+ },
19053
+ strategy: {
19054
+ type: "string",
19055
+ enum: ["overview", "search", "chunk", "outline", "notes"],
19056
+ description: "Exploration strategy"
19057
+ },
19058
+ query: {
19059
+ type: "string",
19060
+ description: "Search pattern (for 'search' strategy) or note text (for 'chunk' with note)"
19061
+ },
19062
+ offset: {
19063
+ type: "number",
19064
+ description: "Starting line number, 1-based (for 'chunk' strategy)"
19065
+ },
19066
+ limit: {
19067
+ type: "number",
19068
+ description: "Number of lines to read (for 'chunk', default 50)"
19069
+ },
19070
+ context_lines: {
19071
+ type: "number",
19072
+ description: "Lines of context around each match (for 'search', default 5)"
19073
+ },
19074
+ note: {
19075
+ type: "string",
19076
+ description: "Working note to save about this chunk (for 'chunk' strategy)"
19077
+ }
19078
+ },
19079
+ required: ["strategy"]
19080
+ };
19081
+ workingDir;
19082
+ constructor(workingDir) {
19083
+ this.workingDir = workingDir;
19084
+ }
19085
+ async execute(args) {
19086
+ const strategy = String(args["strategy"] ?? "overview");
19087
+ const filePath = String(args["path"] ?? "");
19088
+ const start = performance.now();
19089
+ switch (strategy) {
19090
+ case "overview":
19091
+ return this.overview(filePath, start);
19092
+ case "search":
19093
+ return this.search(filePath, String(args["query"] ?? ""), args, start);
19094
+ case "chunk":
19095
+ return this.chunk(filePath, args, start);
19096
+ case "outline":
19097
+ return this.outline(filePath, start);
19098
+ case "notes":
19099
+ return this.showNotes(filePath, start);
19100
+ default:
19101
+ return {
19102
+ success: false,
19103
+ output: "",
19104
+ error: `Unknown strategy '${strategy}'. Use: overview, search, chunk, outline, notes`,
19105
+ durationMs: performance.now() - start
19106
+ };
19107
+ }
19108
+ }
19109
+ /**
19110
+ * overview: Read structural skeleton — first 30 lines (imports/config),
19111
+ * all signature lines, last 20 lines (exports/module boundary).
19112
+ */
19113
+ async overview(filePath, start) {
19114
+ if (!filePath)
19115
+ return { success: false, output: "", error: "path required for overview", durationMs: performance.now() - start };
19116
+ try {
19117
+ const fullPath = resolve27(this.workingDir, filePath);
19118
+ const content = await readFile19(fullPath, "utf-8");
19119
+ const lines = content.split("\n");
19120
+ const total = lines.length;
19121
+ const HEAD = Math.min(30, total);
19122
+ const TAIL = Math.min(20, Math.max(0, total - HEAD));
19123
+ const parts = [];
19124
+ parts.push(`# ${filePath} (${total} lines)
19125
+ `);
19126
+ parts.push("## Head (lines 1-" + HEAD + ")");
19127
+ for (let i = 0; i < HEAD; i++) {
19128
+ parts.push(`${String(i + 1).padStart(6)} | ${lines[i]}`);
19129
+ }
19130
+ if (total > HEAD + TAIL) {
19131
+ const patterns = getPatterns(filePath);
19132
+ const sigs = [];
19133
+ for (let i = HEAD; i < total - TAIL; i++) {
19134
+ const line = lines[i];
19135
+ if (patterns.some((p) => p.test(line))) {
19136
+ sigs.push(`${String(i + 1).padStart(6)} | ${line}`);
19137
+ }
19138
+ }
19139
+ if (sigs.length > 0) {
19140
+ parts.push(`
19141
+ ## Signatures (lines ${HEAD + 1}-${total - TAIL}) \u2014 ${sigs.length} found`);
19142
+ parts.push(...sigs);
19143
+ } else {
19144
+ parts.push(`
19145
+ ## Middle (lines ${HEAD + 1}-${total - TAIL}) \u2014 ${total - HEAD - TAIL} lines, no signatures detected`);
19146
+ }
19147
+ }
19148
+ if (TAIL > 0) {
19149
+ const tailStart = total - TAIL;
19150
+ parts.push(`
19151
+ ## Tail (lines ${tailStart + 1}-${total})`);
19152
+ for (let i = tailStart; i < total; i++) {
19153
+ parts.push(`${String(i + 1).padStart(6)} | ${lines[i]}`);
19154
+ }
19155
+ }
19156
+ parts.push(`
19157
+ [Use file_explore(strategy='search', query='...') to find specific sections]`);
19158
+ parts.push(`[Use file_explore(strategy='chunk', offset=N, limit=50) to read a section]`);
19159
+ return {
19160
+ success: true,
19161
+ output: parts.join("\n"),
19162
+ durationMs: performance.now() - start
19163
+ };
19164
+ } catch (error) {
19165
+ return {
19166
+ success: false,
19167
+ output: "",
19168
+ error: error instanceof Error ? error.message : String(error),
19169
+ durationMs: performance.now() - start
19170
+ };
19171
+ }
19172
+ }
19173
+ /**
19174
+ * search: Grep for pattern with context lines around each match.
19175
+ */
19176
+ async search(filePath, query, args, start) {
19177
+ if (!query)
19178
+ return { success: false, output: "", error: "query required for search strategy", durationMs: performance.now() - start };
19179
+ const contextLines = Number(args["context_lines"] ?? 5);
19180
+ const searchPath = filePath ? resolve27(this.workingDir, filePath) : this.workingDir;
19181
+ try {
19182
+ const rgArgs = [
19183
+ "--line-number",
19184
+ "--no-heading",
19185
+ "--color=never",
19186
+ "-C",
19187
+ String(contextLines)
19188
+ ];
19189
+ if (filePath) {
19190
+ rgArgs.push(query, searchPath);
19191
+ } else {
19192
+ rgArgs.push(query, this.workingDir);
19193
+ }
19194
+ const { stdout } = await execFileAsync3("rg", rgArgs, {
19195
+ cwd: this.workingDir,
19196
+ maxBuffer: 1024 * 1024
19197
+ });
19198
+ const lines = stdout.split("\n").filter((l) => l.length > 0);
19199
+ const matchCount = lines.filter((l) => /^\d+:/.test(l) || /:\d+:/.test(l)).length;
19200
+ const MAX = 80;
19201
+ const truncated = lines.length > MAX;
19202
+ const output = lines.slice(0, MAX).join("\n");
19203
+ const result = [
19204
+ `Found ${matchCount} matches for "${query}"${filePath ? ` in ${filePath}` : ""}:`,
19205
+ "",
19206
+ truncated ? output + `
19207
+
19208
+ [Truncated \u2014 ${lines.length - MAX} more lines]` : output,
19209
+ "",
19210
+ `[Use file_explore(strategy='chunk', path='...', offset=N) to read around a specific match]`
19211
+ ].join("\n");
19212
+ return {
19213
+ success: true,
19214
+ output: result,
19215
+ durationMs: performance.now() - start
19216
+ };
19217
+ } catch (error) {
19218
+ const err = error;
19219
+ if (err.code === 1) {
19220
+ return {
19221
+ success: true,
19222
+ output: `No matches for "${query}"${filePath ? ` in ${filePath}` : ""}.`,
19223
+ durationMs: performance.now() - start
19224
+ };
19225
+ }
19226
+ try {
19227
+ const grepArgs = ["-rn", "--color=never", `-C${contextLines}`];
19228
+ if (filePath) {
19229
+ grepArgs.push(query, searchPath);
19230
+ } else {
19231
+ grepArgs.push(query, this.workingDir);
19232
+ }
19233
+ const { stdout } = await execFileAsync3("grep", grepArgs, {
19234
+ cwd: this.workingDir,
19235
+ maxBuffer: 1024 * 1024
19236
+ });
19237
+ return {
19238
+ success: true,
19239
+ output: stdout.split("\n").slice(0, 80).join("\n"),
19240
+ durationMs: performance.now() - start
19241
+ };
19242
+ } catch {
19243
+ return {
19244
+ success: true,
19245
+ output: `No matches for "${query}".`,
19246
+ durationMs: performance.now() - start
19247
+ };
19248
+ }
19249
+ }
19250
+ }
19251
+ /**
19252
+ * chunk: Read a specific line range and optionally save a working note.
19253
+ */
19254
+ async chunk(filePath, args, start) {
19255
+ if (!filePath)
19256
+ return { success: false, output: "", error: "path required for chunk strategy", durationMs: performance.now() - start };
19257
+ const offset = Number(args["offset"] ?? 1);
19258
+ const limit = Number(args["limit"] ?? 50);
19259
+ const note = args["note"];
19260
+ try {
19261
+ const fullPath = resolve27(this.workingDir, filePath);
19262
+ const content = await readFile19(fullPath, "utf-8");
19263
+ const allLines = content.split("\n");
19264
+ const total = allLines.length;
19265
+ const startIdx = Math.max(0, offset - 1);
19266
+ const endIdx = Math.min(total, startIdx + limit);
19267
+ const chunk = allLines.slice(startIdx, endIdx);
19268
+ const numbered = chunk.map((line, i) => `${String(startIdx + i + 1).padStart(6)} | ${line}`).join("\n");
19269
+ if (note) {
19270
+ sessionNotes.push({
19271
+ file: filePath,
19272
+ lineRange: [startIdx + 1, endIdx],
19273
+ finding: note,
19274
+ timestamp: Date.now()
19275
+ });
19276
+ }
19277
+ const nav = [];
19278
+ if (startIdx > 0) {
19279
+ nav.push(`[Previous: file_explore(strategy='chunk', path='${filePath}', offset=${Math.max(1, startIdx + 1 - limit)}, limit=${limit})]`);
19280
+ }
19281
+ if (endIdx < total) {
19282
+ nav.push(`[Next: file_explore(strategy='chunk', path='${filePath}', offset=${endIdx + 1}, limit=${limit})]`);
19283
+ }
19284
+ nav.push(`[${total} total lines \u2014 showing ${startIdx + 1}-${endIdx}]`);
19285
+ if (sessionNotes.length > 0) {
19286
+ nav.push(`[${sessionNotes.length} working notes \u2014 file_explore(strategy='notes') to review]`);
19287
+ }
19288
+ return {
19289
+ success: true,
19290
+ output: numbered + "\n\n" + nav.join("\n"),
19291
+ durationMs: performance.now() - start
19292
+ };
19293
+ } catch (error) {
19294
+ return {
19295
+ success: false,
19296
+ output: "",
19297
+ error: error instanceof Error ? error.message : String(error),
19298
+ durationMs: performance.now() - start
19299
+ };
19300
+ }
19301
+ }
19302
+ /**
19303
+ * outline: Extract only function/class/method/export signatures.
19304
+ */
19305
+ async outline(filePath, start) {
19306
+ if (!filePath)
19307
+ return { success: false, output: "", error: "path required for outline", durationMs: performance.now() - start };
19308
+ try {
19309
+ const fullPath = resolve27(this.workingDir, filePath);
19310
+ const content = await readFile19(fullPath, "utf-8");
19311
+ const lines = content.split("\n");
19312
+ const patterns = getPatterns(filePath);
19313
+ const sigs = [];
19314
+ for (let i = 0; i < lines.length; i++) {
19315
+ const line = lines[i];
19316
+ if (patterns.some((p) => p.test(line))) {
19317
+ sigs.push(`${String(i + 1).padStart(6)} | ${line.trimEnd()}`);
19318
+ }
19319
+ }
19320
+ if (sigs.length === 0) {
19321
+ return {
19322
+ success: true,
19323
+ output: `${filePath}: ${lines.length} lines, no recognizable signatures found.
19324
+ [Use file_explore(strategy='overview') for a broader view]`,
19325
+ durationMs: performance.now() - start
19326
+ };
19327
+ }
19328
+ return {
19329
+ success: true,
19330
+ output: `# ${filePath} \u2014 ${sigs.length} signatures (${lines.length} total lines)
19331
+
19332
+ ` + sigs.join("\n") + `
19333
+
19334
+ [Use file_explore(strategy='chunk', offset=N) to read around a specific signature]`,
19335
+ durationMs: performance.now() - start
19336
+ };
19337
+ } catch (error) {
19338
+ return {
19339
+ success: false,
19340
+ output: "",
19341
+ error: error instanceof Error ? error.message : String(error),
19342
+ durationMs: performance.now() - start
19343
+ };
19344
+ }
19345
+ }
19346
+ /**
19347
+ * notes: Show accumulated working notes from this exploration session.
19348
+ */
19349
+ showNotes(filePath, start) {
19350
+ const notes2 = filePath ? sessionNotes.filter((n) => n.file === filePath) : sessionNotes;
19351
+ if (notes2.length === 0) {
19352
+ return {
19353
+ success: true,
19354
+ output: "No working notes yet. Use file_explore(strategy='chunk', note='your finding') to save notes as you explore.",
19355
+ durationMs: performance.now() - start
19356
+ };
19357
+ }
19358
+ const parts = [`# Working Notes (${notes2.length})
19359
+ `];
19360
+ for (const n of notes2) {
19361
+ parts.push(`- **${n.file}** lines ${n.lineRange[0]}-${n.lineRange[1]}: ${n.finding}`);
19362
+ }
19363
+ return {
19364
+ success: true,
19365
+ output: parts.join("\n"),
19366
+ durationMs: performance.now() - start
19367
+ };
19368
+ }
19369
+ };
19370
+ }
19371
+ });
19372
+
19373
+ // packages/execution/dist/tools/working-notes.js
19374
+ function getWorkingNotes() {
19375
+ return notes;
19376
+ }
19377
+ function getWorkingNotesSummary() {
19378
+ if (notes.length === 0)
19379
+ return "";
19380
+ const parts = [`Working notes (${notes.length}):`];
19381
+ for (const n of notes) {
19382
+ const loc = n.file ? ` [${n.file}${n.line ? `:${n.line}` : ""}]` : "";
19383
+ parts.push(`- [${n.category}] ${n.content.slice(0, 150)}${loc}`);
19384
+ }
19385
+ return parts.join("\n");
19386
+ }
19387
+ function clearWorkingNotes() {
19388
+ notes.length = 0;
19389
+ noteCounter = 0;
19390
+ }
19391
+ var noteCounter, notes, WorkingNotesTool;
19392
+ var init_working_notes = __esm({
19393
+ "packages/execution/dist/tools/working-notes.js"() {
19394
+ "use strict";
19395
+ noteCounter = 0;
19396
+ notes = [];
19397
+ WorkingNotesTool = class {
19398
+ name = "working_notes";
19399
+ 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.";
19400
+ parameters = {
19401
+ type: "object",
19402
+ properties: {
19403
+ action: {
19404
+ type: "string",
19405
+ enum: ["add", "list", "search", "clear", "summary"],
19406
+ description: "Action to perform (default: 'list')"
19407
+ },
19408
+ content: {
19409
+ type: "string",
19410
+ description: "Note content (for 'add') or search query (for 'search')"
19411
+ },
19412
+ category: {
19413
+ type: "string",
19414
+ enum: ["finding", "todo", "question", "decision", "blocker"],
19415
+ description: "Note category (for 'add', default: 'finding')"
19416
+ },
19417
+ file: {
19418
+ type: "string",
19419
+ description: "Related file path (for 'add')"
19420
+ },
19421
+ line: {
19422
+ type: "number",
19423
+ description: "Related line number (for 'add')"
19424
+ }
19425
+ },
19426
+ required: []
19427
+ };
19428
+ async execute(args) {
19429
+ const action = String(args["action"] ?? "list");
19430
+ const start = performance.now();
19431
+ switch (action) {
19432
+ case "add": {
19433
+ const content = String(args["content"] ?? "");
19434
+ if (!content)
19435
+ return { success: false, output: "", error: "content required", durationMs: performance.now() - start };
19436
+ const note = {
19437
+ id: ++noteCounter,
19438
+ category: String(args["category"] ?? "finding"),
19439
+ content,
19440
+ file: args["file"],
19441
+ line: args["line"],
19442
+ timestamp: Date.now()
19443
+ };
19444
+ notes.push(note);
19445
+ return {
19446
+ success: true,
19447
+ output: `Note #${note.id} added [${note.category}]${note.file ? ` (${note.file}${note.line ? `:${note.line}` : ""})` : ""}: ${content.slice(0, 100)}`,
19448
+ durationMs: performance.now() - start
19449
+ };
19450
+ }
19451
+ case "list": {
19452
+ if (notes.length === 0) {
19453
+ return {
19454
+ success: true,
19455
+ output: "No working notes. Use working_notes(action='add', content='...') to start tracking findings.",
19456
+ durationMs: performance.now() - start
19457
+ };
19458
+ }
19459
+ const lines = [`Working Notes (${notes.length}):
19460
+ `];
19461
+ for (const n of notes) {
19462
+ const loc = n.file ? ` @ ${n.file}${n.line ? `:${n.line}` : ""}` : "";
19463
+ lines.push(` #${n.id} [${n.category}]${loc}: ${n.content}`);
19464
+ }
19465
+ return {
19466
+ success: true,
19467
+ output: lines.join("\n"),
19468
+ durationMs: performance.now() - start
19469
+ };
19470
+ }
19471
+ case "search": {
19472
+ const query = String(args["content"] ?? "").toLowerCase();
19473
+ if (!query)
19474
+ return { success: false, output: "", error: "content (search query) required", durationMs: performance.now() - start };
19475
+ const matches = notes.filter((n) => n.content.toLowerCase().includes(query) || n.file && n.file.toLowerCase().includes(query) || n.category.toLowerCase().includes(query));
19476
+ if (matches.length === 0) {
19477
+ return {
19478
+ success: true,
19479
+ output: `No notes matching "${query}".`,
19480
+ durationMs: performance.now() - start
19481
+ };
19482
+ }
19483
+ const lines = [`Notes matching "${query}" (${matches.length}):
19484
+ `];
19485
+ for (const n of matches) {
19486
+ const loc = n.file ? ` @ ${n.file}${n.line ? `:${n.line}` : ""}` : "";
19487
+ lines.push(` #${n.id} [${n.category}]${loc}: ${n.content}`);
19488
+ }
19489
+ return {
19490
+ success: true,
19491
+ output: lines.join("\n"),
19492
+ durationMs: performance.now() - start
19493
+ };
19494
+ }
19495
+ case "clear": {
19496
+ const count = notes.length;
19497
+ notes.length = 0;
19498
+ noteCounter = 0;
19499
+ return {
19500
+ success: true,
19501
+ output: `Cleared ${count} working notes.`,
19502
+ durationMs: performance.now() - start
19503
+ };
19504
+ }
19505
+ case "summary": {
19506
+ if (notes.length === 0) {
19507
+ return {
19508
+ success: true,
19509
+ output: "No working notes to summarize.",
19510
+ durationMs: performance.now() - start
19511
+ };
19512
+ }
19513
+ const groups = /* @__PURE__ */ new Map();
19514
+ for (const n of notes) {
19515
+ const list = groups.get(n.category) ?? [];
19516
+ list.push(n);
19517
+ groups.set(n.category, list);
19518
+ }
19519
+ const parts = [`Working Notes Summary (${notes.length} total):
19520
+ `];
19521
+ for (const [cat, items] of groups) {
19522
+ parts.push(` ${cat.toUpperCase()} (${items.length}):`);
19523
+ for (const n of items) {
19524
+ const loc = n.file ? ` [${n.file}${n.line ? `:${n.line}` : ""}]` : "";
19525
+ parts.push(` - ${n.content.slice(0, 120)}${loc}`);
19526
+ }
19527
+ }
19528
+ const files = new Set(notes.filter((n) => n.file).map((n) => n.file));
19529
+ if (files.size > 0) {
19530
+ parts.push(`
19531
+ Files referenced: ${[...files].join(", ")}`);
19532
+ }
19533
+ return {
19534
+ success: true,
19535
+ output: parts.join("\n"),
19536
+ durationMs: performance.now() - start
19537
+ };
19538
+ }
19539
+ default:
19540
+ return {
19541
+ success: false,
19542
+ output: "",
19543
+ error: `Unknown action '${action}'. Use: add, list, search, clear, summary`,
19544
+ durationMs: performance.now() - start
19545
+ };
19546
+ }
19547
+ }
19548
+ };
19549
+ }
19550
+ });
19551
+
18807
19552
  // packages/execution/dist/tools/fortemi-bridge.js
18808
19553
  import { existsSync as existsSync24, readFileSync as readFileSync17 } from "node:fs";
18809
19554
  import { join as join38 } from "node:path";
@@ -18960,7 +19705,7 @@ import { spawn as spawn13 } from "node:child_process";
18960
19705
  async function runShell(options) {
18961
19706
  const { command, args = [], cwd: cwd4, env, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
18962
19707
  const mergedEnv = env ? { ...process.env, ...env } : process.env;
18963
- return new Promise((resolve32) => {
19708
+ return new Promise((resolve33) => {
18964
19709
  const start = Date.now();
18965
19710
  let timedOut = false;
18966
19711
  const child = spawn13(command, args, {
@@ -18984,7 +19729,7 @@ async function runShell(options) {
18984
19729
  clearTimeout(timer);
18985
19730
  const durationMs = Date.now() - start;
18986
19731
  const exitCode = timedOut ? -1 : code ?? -1;
18987
- resolve32({
19732
+ resolve33({
18988
19733
  stdout,
18989
19734
  stderr,
18990
19735
  exitCode,
@@ -18996,7 +19741,7 @@ async function runShell(options) {
18996
19741
  child.on("error", (err) => {
18997
19742
  clearTimeout(timer);
18998
19743
  const durationMs = Date.now() - start;
18999
- resolve32({
19744
+ resolve33({
19000
19745
  stdout,
19001
19746
  stderr: stderr + err.message,
19002
19747
  exitCode: -1,
@@ -19111,7 +19856,7 @@ async function applyUnifiedDiff(patch) {
19111
19856
  }
19112
19857
  function runWithStdin(options) {
19113
19858
  const { command, args, cwd: cwd4, stdin } = options;
19114
- return new Promise((resolve32) => {
19859
+ return new Promise((resolve33) => {
19115
19860
  const child = spawn14(command, args, {
19116
19861
  cwd: cwd4,
19117
19862
  stdio: ["pipe", "pipe", "pipe"]
@@ -19128,10 +19873,10 @@ function runWithStdin(options) {
19128
19873
  child.stdin.end();
19129
19874
  child.on("close", (code) => {
19130
19875
  const exitCode = code ?? -1;
19131
- resolve32({ success: exitCode === 0, exitCode, stdout, stderr });
19876
+ resolve33({ success: exitCode === 0, exitCode, stdout, stderr });
19132
19877
  });
19133
19878
  child.on("error", (err) => {
19134
- resolve32({ success: false, exitCode: -1, stdout, stderr: err.message });
19879
+ resolve33({ success: false, exitCode: -1, stdout, stderr: err.message });
19135
19880
  });
19136
19881
  });
19137
19882
  }
@@ -19579,6 +20324,7 @@ __export(dist_exports, {
19579
20324
  ExploreToolsTool: () => ExploreToolsTool,
19580
20325
  FactoryTool: () => FactoryTool,
19581
20326
  FileEditTool: () => FileEditTool,
20327
+ FileExploreTool: () => FileExploreTool,
19582
20328
  FilePatchTool: () => FilePatchTool,
19583
20329
  FileReadTool: () => FileReadTool,
19584
20330
  FileWriteTool: () => FileWriteTool,
@@ -19621,10 +20367,13 @@ __export(dist_exports, {
19621
20367
  WebCrawlTool: () => WebCrawlTool,
19622
20368
  WebFetchTool: () => WebFetchTool,
19623
20369
  WebSearchTool: () => WebSearchTool,
20370
+ WorkingNotesTool: () => WorkingNotesTool,
19624
20371
  applyPatch: () => applyPatch,
19625
20372
  buildCustomTools: () => buildCustomTools,
19626
20373
  buildSkillsSummary: () => buildSkillsSummary,
19627
20374
  checkDesktopDeps: () => checkDesktopDeps,
20375
+ clearExploreNotes: () => clearExploreNotes,
20376
+ clearWorkingNotes: () => clearWorkingNotes,
19628
20377
  createFortemiBridgeTools: () => createFortemiBridgeTools,
19629
20378
  createWorktree: () => createWorktree,
19630
20379
  detectSearchProvider: () => detectSearchProvider,
@@ -19634,6 +20383,9 @@ __export(dist_exports, {
19634
20383
  ensureDepsForGroup: () => ensureDepsForGroup,
19635
20384
  getActiveAttentionItems: () => getActiveAttentionItems,
19636
20385
  getDueReminders: () => getDueReminders,
20386
+ getExploreNotes: () => getExploreNotes,
20387
+ getWorkingNotes: () => getWorkingNotes,
20388
+ getWorkingNotesSummary: () => getWorkingNotesSummary,
19637
20389
  isFortemiAvailable: () => isFortemiAvailable,
19638
20390
  isImagePath: () => isImagePath,
19639
20391
  listCustomToolFiles: () => listCustomToolFiles,
@@ -19710,6 +20462,8 @@ var init_dist2 = __esm({
19710
20462
  init_opencode();
19711
20463
  init_factory();
19712
20464
  init_cron_agent();
20465
+ init_file_explore();
20466
+ init_working_notes();
19713
20467
  init_nexus();
19714
20468
  init_fortemi_bridge();
19715
20469
  init_system_deps();
@@ -20693,13 +21447,13 @@ var init_plannerRunner = __esm({
20693
21447
  });
20694
21448
 
20695
21449
  // packages/retrieval/dist/grep-search.js
20696
- import { execFile as execFile4 } from "node:child_process";
20697
- import { promisify as promisify3 } from "node:util";
20698
- var execFileAsync3, GrepSearch;
21450
+ import { execFile as execFile5 } from "node:child_process";
21451
+ import { promisify as promisify4 } from "node:util";
21452
+ var execFileAsync4, GrepSearch;
20699
21453
  var init_grep_search2 = __esm({
20700
21454
  "packages/retrieval/dist/grep-search.js"() {
20701
21455
  "use strict";
20702
- execFileAsync3 = promisify3(execFile4);
21456
+ execFileAsync4 = promisify4(execFile5);
20703
21457
  GrepSearch = class {
20704
21458
  rootDir;
20705
21459
  constructor(rootDir) {
@@ -20721,7 +21475,7 @@ var init_grep_search2 = __esm({
20721
21475
  }
20722
21476
  args.push(pattern, this.rootDir);
20723
21477
  try {
20724
- const { stdout } = await execFileAsync3("rg", args, {
21478
+ const { stdout } = await execFileAsync4("rg", args, {
20725
21479
  maxBuffer: 10 * 1024 * 1024
20726
21480
  });
20727
21481
  return this.parseRipgrepOutput(stdout);
@@ -20782,8 +21536,8 @@ var init_code_retriever = __esm({
20782
21536
  });
20783
21537
  }
20784
21538
  async getFileContent(filePath, startLine, endLine) {
20785
- const { readFile: readFile23 } = await import("node:fs/promises");
20786
- const content = await readFile23(filePath, "utf-8");
21539
+ const { readFile: readFile24 } = await import("node:fs/promises");
21540
+ const content = await readFile24(filePath, "utf-8");
20787
21541
  if (startLine === void 0)
20788
21542
  return content;
20789
21543
  const lines = content.split("\n");
@@ -20796,9 +21550,9 @@ var init_code_retriever = __esm({
20796
21550
  });
20797
21551
 
20798
21552
  // packages/retrieval/dist/lexicalSearch.js
20799
- import { execFile as execFile5 } from "node:child_process";
20800
- import { promisify as promisify4 } from "node:util";
20801
- import { readFile as readFile19, readdir as readdir5, stat as stat3 } from "node:fs/promises";
21553
+ import { execFile as execFile6 } from "node:child_process";
21554
+ import { promisify as promisify5 } from "node:util";
21555
+ import { readFile as readFile20, readdir as readdir5, stat as stat3 } from "node:fs/promises";
20802
21556
  import { join as join40, extname as extname7 } from "node:path";
20803
21557
  async function searchByPath(pathPattern, options) {
20804
21558
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
@@ -20841,7 +21595,7 @@ async function runSearch(pattern, kind, options) {
20841
21595
  }
20842
21596
  async function isRipgrepAvailable() {
20843
21597
  try {
20844
- await execFileAsync4("rg", ["--version"], { timeout: 2e3 });
21598
+ await execFileAsync5("rg", ["--version"], { timeout: 2e3 });
20845
21599
  return true;
20846
21600
  } catch {
20847
21601
  return false;
@@ -20861,7 +21615,7 @@ async function searchWithRipgrep(pattern, kind, options) {
20861
21615
  args.push(pattern, options.rootDir);
20862
21616
  let stdout;
20863
21617
  try {
20864
- const result = await execFileAsync4("rg", args, {
21618
+ const result = await execFileAsync5("rg", args, {
20865
21619
  maxBuffer: 20 * 1024 * 1024,
20866
21620
  timeout: 1e4
20867
21621
  });
@@ -20904,7 +21658,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
20904
21658
  if (results.length >= maxMatches)
20905
21659
  break;
20906
21660
  try {
20907
- const content = await readFile19(filePath, "utf-8");
21661
+ const content = await readFile20(filePath, "utf-8");
20908
21662
  const contentLines = content.split("\n");
20909
21663
  for (let i = 0; i < contentLines.length; i++) {
20910
21664
  if (results.length >= maxMatches)
@@ -20971,11 +21725,11 @@ function matchesGlob(filePath, glob2) {
20971
21725
  return false;
20972
21726
  }
20973
21727
  }
20974
- var execFileAsync4, DEFAULT_INCLUDE_GLOBS, DEFAULT_EXCLUDE_GLOBS, DEFAULT_MAX_MATCHES, ALWAYS_SKIP, ALL_CODE_EXTS;
21728
+ var execFileAsync5, DEFAULT_INCLUDE_GLOBS, DEFAULT_EXCLUDE_GLOBS, DEFAULT_MAX_MATCHES, ALWAYS_SKIP, ALL_CODE_EXTS;
20975
21729
  var init_lexicalSearch = __esm({
20976
21730
  "packages/retrieval/dist/lexicalSearch.js"() {
20977
21731
  "use strict";
20978
- execFileAsync4 = promisify4(execFile5);
21732
+ execFileAsync5 = promisify5(execFile6);
20979
21733
  DEFAULT_INCLUDE_GLOBS = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.py"];
20980
21734
  DEFAULT_EXCLUDE_GLOBS = ["node_modules", "dist", ".git", "build", "coverage"];
20981
21735
  DEFAULT_MAX_MATCHES = 50;
@@ -21247,7 +22001,7 @@ var init_graphExpand = __esm({
21247
22001
  });
21248
22002
 
21249
22003
  // packages/retrieval/dist/snippetPacker.js
21250
- import { readFile as readFile20 } from "node:fs/promises";
22004
+ import { readFile as readFile21 } from "node:fs/promises";
21251
22005
  import { join as join41 } from "node:path";
21252
22006
  async function packSnippets(requests, opts = {}) {
21253
22007
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
@@ -21277,7 +22031,7 @@ async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINE
21277
22031
  const absPath = req.filePath.startsWith("/") ? req.filePath : join41(repoRoot, req.filePath);
21278
22032
  let content;
21279
22033
  try {
21280
- content = await readFile20(absPath, "utf-8");
22034
+ content = await readFile21(absPath, "utf-8");
21281
22035
  } catch {
21282
22036
  return null;
21283
22037
  }
@@ -21812,9 +22566,9 @@ var init_verifierRunner = __esm({
21812
22566
  async executeTests(patch, repoRoot) {
21813
22567
  if (patch.testsToRun.length === 0)
21814
22568
  return "(no tests specified)";
21815
- const { execFile: execFile6 } = await import("node:child_process");
21816
- const { promisify: promisify6 } = await import("node:util");
21817
- const execFileAsync5 = promisify6(execFile6);
22569
+ const { execFile: execFile7 } = await import("node:child_process");
22570
+ const { promisify: promisify7 } = await import("node:util");
22571
+ const execFileAsync6 = promisify7(execFile7);
21818
22572
  const outputs = [];
21819
22573
  const workDir = this.options.workingDir || repoRoot;
21820
22574
  for (const cmd of patch.testsToRun.slice(0, 3)) {
@@ -21823,7 +22577,7 @@ var init_verifierRunner = __esm({
21823
22577
  const [bin, ...args] = parts;
21824
22578
  if (!bin)
21825
22579
  continue;
21826
- const { stdout, stderr } = await execFileAsync5(bin, args, {
22580
+ const { stdout, stderr } = await execFileAsync6(bin, args, {
21827
22581
  cwd: workDir,
21828
22582
  timeout: 6e4,
21829
22583
  maxBuffer: 1024 * 1024
@@ -22503,6 +23257,7 @@ var init_agenticRunner = __esm({
22503
23257
  init_dist();
22504
23258
  init_personality();
22505
23259
  init_promptLoader();
23260
+ init_dist2();
22506
23261
  SYSTEM_PROMPT = loadPrompt("agentic/system-large.md");
22507
23262
  SYSTEM_PROMPT_MEDIUM = loadPrompt("agentic/system-medium.md");
22508
23263
  SYSTEM_PROMPT_SMALL = loadPrompt("agentic/system-small.md");
@@ -22823,8 +23578,8 @@ ${this.options.dynamicContext}`,
22823
23578
  async waitIfPaused() {
22824
23579
  if (!this._paused)
22825
23580
  return true;
22826
- await new Promise((resolve32) => {
22827
- this._pauseResolve = resolve32;
23581
+ await new Promise((resolve33) => {
23582
+ this._pauseResolve = resolve33;
22828
23583
  });
22829
23584
  return !this.aborted;
22830
23585
  }
@@ -23857,14 +24612,14 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
23857
24612
  waitForSudoPassword(timeoutMs = 12e4) {
23858
24613
  if (this._sudoPassword)
23859
24614
  return Promise.resolve(this._sudoPassword);
23860
- return new Promise((resolve32) => {
24615
+ return new Promise((resolve33) => {
23861
24616
  const timer = setTimeout(() => {
23862
24617
  this._sudoResolve = null;
23863
- resolve32(null);
24618
+ resolve33(null);
23864
24619
  }, timeoutMs);
23865
24620
  this._sudoResolve = (pw) => {
23866
24621
  clearTimeout(timer);
23867
- resolve32(pw);
24622
+ resolve33(pw);
23868
24623
  };
23869
24624
  });
23870
24625
  }
@@ -24172,6 +24927,18 @@ ${tail}`;
24172
24927
  const fileRegistryStr = this.formatFileRegistry();
24173
24928
  if (fileRegistryStr)
24174
24929
  enrichments.push(fileRegistryStr);
24930
+ try {
24931
+ const notesSummary = getWorkingNotesSummary();
24932
+ if (notesSummary)
24933
+ enrichments.push(notesSummary);
24934
+ const exploreNotes = getExploreNotes();
24935
+ if (exploreNotes.length > 0) {
24936
+ const exploreStr = `File exploration notes (${exploreNotes.length}):
24937
+ ` + exploreNotes.map((n) => `- ${n.file} lines ${n.lineRange[0]}-${n.lineRange[1]}: ${n.finding}`).join("\n");
24938
+ enrichments.push(exploreStr);
24939
+ }
24940
+ } catch {
24941
+ }
24175
24942
  if (tier === "large") {
24176
24943
  const memexIndexStr = this.formatMemexIndex();
24177
24944
  if (memexIndexStr)
@@ -25564,12 +26331,12 @@ var init_nexusBackend = __esm({
25564
26331
  const deadline = Date.now() + (request.timeoutMs ?? 12e4);
25565
26332
  try {
25566
26333
  while (!done && Date.now() < deadline) {
25567
- await new Promise((resolve32) => {
26334
+ await new Promise((resolve33) => {
25568
26335
  let resolved = false;
25569
26336
  const finish = () => {
25570
26337
  if (!resolved) {
25571
26338
  resolved = true;
25572
- resolve32();
26339
+ resolve33();
25573
26340
  }
25574
26341
  };
25575
26342
  let watcher = null;
@@ -26509,7 +27276,7 @@ __export(listen_exports, {
26509
27276
  import { spawn as spawn15, execSync as execSync22 } from "node:child_process";
26510
27277
  import { existsSync as existsSync28, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, readdirSync as readdirSync6 } from "node:fs";
26511
27278
  import { join as join43, dirname as dirname13 } from "node:path";
26512
- import { homedir as homedir8 } from "node:os";
27279
+ import { homedir as homedir10 } from "node:os";
26513
27280
  import { fileURLToPath as fileURLToPath8 } from "node:url";
26514
27281
  import { EventEmitter } from "node:events";
26515
27282
  import { createInterface as createInterface2 } from "node:readline";
@@ -26621,7 +27388,7 @@ function findLiveWhisperScript() {
26621
27388
  }
26622
27389
  } catch {
26623
27390
  }
26624
- const nvmBase = join43(homedir8(), ".nvm", "versions", "node");
27391
+ const nvmBase = join43(homedir10(), ".nvm", "versions", "node");
26625
27392
  if (existsSync28(nvmBase)) {
26626
27393
  try {
26627
27394
  for (const ver of readdirSync6(nvmBase)) {
@@ -26651,9 +27418,9 @@ function ensureTranscribeCliBackground() {
26651
27418
  }
26652
27419
  try {
26653
27420
  const { exec: exec4 } = await import("node:child_process");
26654
- return new Promise((resolve32) => {
27421
+ return new Promise((resolve33) => {
26655
27422
  exec4("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
26656
- resolve32(!err);
27423
+ resolve33(!err);
26657
27424
  });
26658
27425
  });
26659
27426
  } catch {
@@ -26712,7 +27479,7 @@ var init_listen = __esm({
26712
27479
  return this._ready;
26713
27480
  }
26714
27481
  async start() {
26715
- return new Promise((resolve32, reject) => {
27482
+ return new Promise((resolve33, reject) => {
26716
27483
  const timeout = setTimeout(() => {
26717
27484
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
26718
27485
  }, 3e5);
@@ -26740,7 +27507,7 @@ var init_listen = __esm({
26740
27507
  this._ready = true;
26741
27508
  clearTimeout(timeout);
26742
27509
  this.emit("ready");
26743
- resolve32();
27510
+ resolve33();
26744
27511
  break;
26745
27512
  case "transcript":
26746
27513
  this.emit("transcript", {
@@ -26875,7 +27642,7 @@ var init_listen = __esm({
26875
27642
  }
26876
27643
  } catch {
26877
27644
  }
26878
- const nvmBase = join43(homedir8(), ".nvm", "versions", "node");
27645
+ const nvmBase = join43(homedir10(), ".nvm", "versions", "node");
26879
27646
  if (existsSync28(nvmBase)) {
26880
27647
  try {
26881
27648
  const { readdirSync: readdirSync18 } = await import("node:fs");
@@ -26944,11 +27711,11 @@ var init_listen = __esm({
26944
27711
  this.liveTranscriber.on("error", (err) => {
26945
27712
  this.emit("error", err);
26946
27713
  });
26947
- await new Promise((resolve32, reject) => {
27714
+ await new Promise((resolve33, reject) => {
26948
27715
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
26949
27716
  this.liveTranscriber.on("ready", () => {
26950
27717
  clearTimeout(timeout);
26951
- resolve32();
27718
+ resolve33();
26952
27719
  });
26953
27720
  this.liveTranscriber.on("error", (err) => {
26954
27721
  clearTimeout(timeout);
@@ -27110,11 +27877,11 @@ transcribe-cli error: ${transcribeCliError}` : "";
27110
27877
  sampleWidth: 2,
27111
27878
  chunkDuration: 3
27112
27879
  });
27113
- await new Promise((resolve32, reject) => {
27880
+ await new Promise((resolve33, reject) => {
27114
27881
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
27115
27882
  transcriber.on("ready", () => {
27116
27883
  clearTimeout(timeout);
27117
- resolve32();
27884
+ resolve33();
27118
27885
  });
27119
27886
  transcriber.on("error", (err) => {
27120
27887
  clearTimeout(timeout);
@@ -32085,8 +32852,8 @@ var init_voice_session = __esm({
32085
32852
  this.server.keepAliveTimeout = 0;
32086
32853
  this.wss = new import_websocket_server.default({ server: this.server, path: "/ws" });
32087
32854
  this.wss.on("connection", (ws, req) => this.handleWSConnection(ws, req));
32088
- await new Promise((resolve32, reject) => {
32089
- this.server.listen(port, "127.0.0.1", () => resolve32());
32855
+ await new Promise((resolve33, reject) => {
32856
+ this.server.listen(port, "127.0.0.1", () => resolve33());
32090
32857
  this.server.on("error", reject);
32091
32858
  });
32092
32859
  try {
@@ -32304,7 +33071,7 @@ var init_voice_session = __esm({
32304
33071
  }
32305
33072
  // ── Cloudflared tunnel ────────────────────────────────────────────────
32306
33073
  startCloudflared(port) {
32307
- return new Promise((resolve32, reject) => {
33074
+ return new Promise((resolve33, reject) => {
32308
33075
  const timeout = setTimeout(() => {
32309
33076
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
32310
33077
  }, 3e4);
@@ -32322,7 +33089,7 @@ var init_voice_session = __esm({
32322
33089
  if (urlMatch && !urlFound) {
32323
33090
  urlFound = true;
32324
33091
  clearTimeout(timeout);
32325
- resolve32(urlMatch[0]);
33092
+ resolve33(urlMatch[0]);
32326
33093
  }
32327
33094
  };
32328
33095
  this.cloudflaredProcess.stdout?.on("data", handleOutput);
@@ -32362,13 +33129,13 @@ var init_voice_session = __esm({
32362
33129
  }
32363
33130
  // ── Helpers ───────────────────────────────────────────────────────────
32364
33131
  findFreePort() {
32365
- return new Promise((resolve32, reject) => {
33132
+ return new Promise((resolve33, reject) => {
32366
33133
  const srv = createServer2();
32367
33134
  srv.listen(0, "127.0.0.1", () => {
32368
33135
  const addr = srv.address();
32369
33136
  if (addr && typeof addr === "object") {
32370
33137
  const port = addr.port;
32371
- srv.close(() => resolve32(port));
33138
+ srv.close(() => resolve33(port));
32372
33139
  } else {
32373
33140
  srv.close(() => reject(new Error("Could not find free port")));
32374
33141
  }
@@ -32491,8 +33258,8 @@ async function collectSystemMetricsAsync() {
32491
33258
  vramUtilization: 0
32492
33259
  };
32493
33260
  try {
32494
- const smi = await new Promise((resolve32, reject) => {
32495
- 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));
33261
+ const smi = await new Promise((resolve33, reject) => {
33262
+ 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));
32496
33263
  });
32497
33264
  const line = smi.trim().split("\n")[0];
32498
33265
  if (line) {
@@ -32640,8 +33407,8 @@ var init_expose = __esm({
32640
33407
  throw new Error("Gateway already running");
32641
33408
  const port = await this.findFreePort();
32642
33409
  this.server = this.createProxyServer(port);
32643
- await new Promise((resolve32, reject) => {
32644
- this.server.listen(port, "127.0.0.1", () => resolve32());
33410
+ await new Promise((resolve33, reject) => {
33411
+ this.server.listen(port, "127.0.0.1", () => resolve33());
32645
33412
  this.server.on("error", reject);
32646
33413
  });
32647
33414
  let lastStartErr;
@@ -32703,8 +33470,8 @@ var init_expose = __esm({
32703
33470
  this._cloudflaredPid = state.pid;
32704
33471
  this._proxyPort = state.proxyPort;
32705
33472
  this.server = this.createProxyServer(state.proxyPort);
32706
- await new Promise((resolve32, reject) => {
32707
- this.server.listen(state.proxyPort, "127.0.0.1", () => resolve32());
33473
+ await new Promise((resolve33, reject) => {
33474
+ this.server.listen(state.proxyPort, "127.0.0.1", () => resolve33());
32708
33475
  this.server.on("error", reject);
32709
33476
  });
32710
33477
  this._stats.status = "active";
@@ -32729,8 +33496,8 @@ var init_expose = __esm({
32729
33496
  }
32730
33497
  this._cloudflaredPid = null;
32731
33498
  if (this.server) {
32732
- await new Promise((resolve32) => {
32733
- this.server.close(() => resolve32());
33499
+ await new Promise((resolve33) => {
33500
+ this.server.close(() => resolve33());
32734
33501
  });
32735
33502
  this.server = null;
32736
33503
  }
@@ -33062,7 +33829,7 @@ var init_expose = __esm({
33062
33829
  _proxyPort = 0;
33063
33830
  startCloudflared(port) {
33064
33831
  this._proxyPort = port;
33065
- return new Promise((resolve32, reject) => {
33832
+ return new Promise((resolve33, reject) => {
33066
33833
  const timeout = setTimeout(() => {
33067
33834
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
33068
33835
  }, 3e4);
@@ -33091,7 +33858,7 @@ var init_expose = __esm({
33091
33858
  this.cloudflaredProcess?.unref();
33092
33859
  this.cloudflaredProcess?.stdout?.destroy();
33093
33860
  this.cloudflaredProcess?.stderr?.destroy();
33094
- resolve32(urlMatch[0]);
33861
+ resolve33(urlMatch[0]);
33095
33862
  }
33096
33863
  };
33097
33864
  this.cloudflaredProcess.stdout?.on("data", handleOutput);
@@ -33180,13 +33947,13 @@ ${this.formatConnectionInfo()}`);
33180
33947
  }
33181
33948
  // ── Helpers ─────────────────────────────────────────────────────────────
33182
33949
  findFreePort() {
33183
- return new Promise((resolve32, reject) => {
33950
+ return new Promise((resolve33, reject) => {
33184
33951
  const srv = createServer3();
33185
33952
  srv.listen(0, "127.0.0.1", () => {
33186
33953
  const addr = srv.address();
33187
33954
  if (addr && typeof addr === "object") {
33188
33955
  const port = addr.port;
33189
- srv.close(() => resolve32(port));
33956
+ srv.close(() => resolve33(port));
33190
33957
  } else {
33191
33958
  srv.close(() => reject(new Error("Could not find free port")));
33192
33959
  }
@@ -34133,8 +34900,8 @@ var init_peer_mesh = __esm({
34133
34900
  this.wss.on("connection", (ws, req) => {
34134
34901
  this.handleInboundConnection(ws, req.url ?? "");
34135
34902
  });
34136
- await new Promise((resolve32, reject) => {
34137
- this.server.listen(port, "127.0.0.1", () => resolve32());
34903
+ await new Promise((resolve33, reject) => {
34904
+ this.server.listen(port, "127.0.0.1", () => resolve33());
34138
34905
  this.server.on("error", reject);
34139
34906
  });
34140
34907
  this.pingTimer = setInterval(() => this.pingAll(), PING_INTERVAL_MS);
@@ -34173,7 +34940,7 @@ var init_peer_mesh = __esm({
34173
34940
  this.wss = null;
34174
34941
  }
34175
34942
  if (this.server) {
34176
- await new Promise((resolve32) => this.server.close(() => resolve32()));
34943
+ await new Promise((resolve33) => this.server.close(() => resolve33()));
34177
34944
  this.server = null;
34178
34945
  }
34179
34946
  this.emit("stopped");
@@ -34191,7 +34958,7 @@ var init_peer_mesh = __esm({
34191
34958
  if (!wsUrl.includes("/p2p"))
34192
34959
  wsUrl += "/p2p";
34193
34960
  wsUrl += `?key=${encodeURIComponent(this._authKey)}`;
34194
- return new Promise((resolve32, reject) => {
34961
+ return new Promise((resolve33, reject) => {
34195
34962
  const ws = new import_websocket.default(wsUrl, { handshakeTimeout: 1e4 });
34196
34963
  let resolved = false;
34197
34964
  const timeout = setTimeout(() => {
@@ -34231,7 +34998,7 @@ var init_peer_mesh = __esm({
34231
34998
  this.connections.set(peer.peerId, ws);
34232
34999
  this.setupPeerHandlers(ws, peer.peerId);
34233
35000
  this.emit("peer_connected", peer);
34234
- resolve32(peer);
35001
+ resolve33(peer);
34235
35002
  } else {
34236
35003
  this.handleMessage(msg, ws);
34237
35004
  }
@@ -34286,12 +35053,12 @@ var init_peer_mesh = __esm({
34286
35053
  throw new Error(`Peer ${peerId} not connected`);
34287
35054
  }
34288
35055
  const msgId = randomBytes11(8).toString("hex");
34289
- return new Promise((resolve32, reject) => {
35056
+ return new Promise((resolve33, reject) => {
34290
35057
  const timeout = setTimeout(() => {
34291
35058
  this.pendingRequests.delete(msgId);
34292
35059
  reject(new Error(`Inference timeout (${timeoutMs}ms)`));
34293
35060
  }, timeoutMs);
34294
- this.pendingRequests.set(msgId, { resolve: resolve32, reject, timeout, chunks: [] });
35061
+ this.pendingRequests.set(msgId, { resolve: resolve33, reject, timeout, chunks: [] });
34295
35062
  this.sendMsg(ws, "infer_request", request, msgId);
34296
35063
  });
34297
35064
  }
@@ -34513,13 +35280,13 @@ var init_peer_mesh = __esm({
34513
35280
  ws.send(JSON.stringify(msg));
34514
35281
  }
34515
35282
  findFreePort() {
34516
- return new Promise((resolve32, reject) => {
35283
+ return new Promise((resolve33, reject) => {
34517
35284
  const srv = createServer4();
34518
35285
  srv.listen(0, "127.0.0.1", () => {
34519
35286
  const addr = srv.address();
34520
35287
  if (addr && typeof addr === "object") {
34521
35288
  const port = addr.port;
34522
- srv.close(() => resolve32(port));
35289
+ srv.close(() => resolve33(port));
34523
35290
  } else {
34524
35291
  srv.close(() => reject(new Error("Could not find free port")));
34525
35292
  }
@@ -35765,7 +36532,7 @@ __export(oa_directory_exports, {
35765
36532
  });
35766
36533
  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";
35767
36534
  import { join as join48, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
35768
- import { homedir as homedir9 } from "node:os";
36535
+ import { homedir as homedir11 } from "node:os";
35769
36536
  function initOaDirectory(repoRoot) {
35770
36537
  const oaPath = join48(repoRoot, OA_DIR);
35771
36538
  for (const sub of SUBDIRS) {
@@ -35805,7 +36572,7 @@ function saveProjectSettings(repoRoot, settings) {
35805
36572
  writeFileSync12(join48(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
35806
36573
  }
35807
36574
  function loadGlobalSettings() {
35808
- const settingsPath = join48(homedir9(), ".open-agents", "settings.json");
36575
+ const settingsPath = join48(homedir11(), ".open-agents", "settings.json");
35809
36576
  try {
35810
36577
  if (existsSync32(settingsPath)) {
35811
36578
  return JSON.parse(readFileSync23(settingsPath, "utf-8"));
@@ -35815,7 +36582,7 @@ function loadGlobalSettings() {
35815
36582
  return {};
35816
36583
  }
35817
36584
  function saveGlobalSettings(settings) {
35818
- const dir = join48(homedir9(), ".open-agents");
36585
+ const dir = join48(homedir11(), ".open-agents");
35819
36586
  mkdirSync11(dir, { recursive: true });
35820
36587
  const existing = loadGlobalSettings();
35821
36588
  const merged = { ...existing, ...settings };
@@ -36195,13 +36962,13 @@ function recordUsage(kind, value, opts) {
36195
36962
  }
36196
36963
  saveUsageFile(filePath, data);
36197
36964
  };
36198
- update(join48(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
36965
+ update(join48(homedir11(), ".open-agents", USAGE_HISTORY_FILE));
36199
36966
  if (opts?.repoRoot) {
36200
36967
  update(join48(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
36201
36968
  }
36202
36969
  }
36203
36970
  function loadUsageHistory(kind, repoRoot) {
36204
- const globalPath = join48(homedir9(), ".open-agents", USAGE_HISTORY_FILE);
36971
+ const globalPath = join48(homedir11(), ".open-agents", USAGE_HISTORY_FILE);
36205
36972
  const globalData = loadUsageFile(globalPath);
36206
36973
  const localData = repoRoot ? loadUsageFile(join48(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
36207
36974
  const map = /* @__PURE__ */ new Map();
@@ -36234,7 +37001,7 @@ function deleteUsageRecord(kind, value, repoRoot) {
36234
37001
  saveUsageFile(filePath, data);
36235
37002
  }
36236
37003
  };
36237
- remove(join48(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
37004
+ remove(join48(homedir11(), ".open-agents", USAGE_HISTORY_FILE));
36238
37005
  if (repoRoot) {
36239
37006
  remove(join48(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
36240
37007
  }
@@ -36285,10 +37052,10 @@ var init_oa_directory = __esm({
36285
37052
  // packages/cli/dist/tui/setup.js
36286
37053
  import * as readline from "node:readline";
36287
37054
  import { execSync as execSync24, spawn as spawn18, exec as exec2 } from "node:child_process";
36288
- import { promisify as promisify5 } from "node:util";
37055
+ import { promisify as promisify6 } from "node:util";
36289
37056
  import { existsSync as existsSync33, writeFileSync as writeFileSync13, readFileSync as readFileSync24, appendFileSync as appendFileSync2, mkdirSync as mkdirSync12 } from "node:fs";
36290
37057
  import { join as join49 } from "node:path";
36291
- import { homedir as homedir10, platform } from "node:os";
37058
+ import { homedir as homedir12, platform } from "node:os";
36292
37059
  function detectSystemSpecs() {
36293
37060
  let totalRamGB = 0;
36294
37061
  let availableRamGB = 0;
@@ -36425,12 +37192,12 @@ function modelSupportsToolCalling(modelName) {
36425
37192
  return false;
36426
37193
  }
36427
37194
  function ask(rl, question) {
36428
- return new Promise((resolve32) => {
36429
- rl.question(question, (answer) => resolve32(answer.trim()));
37195
+ return new Promise((resolve33) => {
37196
+ rl.question(question, (answer) => resolve33(answer.trim()));
36430
37197
  });
36431
37198
  }
36432
37199
  function askSecret(rl, question) {
36433
- return new Promise((resolve32) => {
37200
+ return new Promise((resolve33) => {
36434
37201
  process.stdout.write(question);
36435
37202
  let secret = "";
36436
37203
  const stdin = process.stdin;
@@ -36448,7 +37215,7 @@ function askSecret(rl, question) {
36448
37215
  stdin.setRawMode(hadRawMode ?? false);
36449
37216
  }
36450
37217
  process.stdout.write("\n");
36451
- resolve32(secret.trim());
37218
+ resolve33(secret.trim());
36452
37219
  return;
36453
37220
  } else if (c3 === "") {
36454
37221
  stdin.removeListener("data", onData);
@@ -36456,7 +37223,7 @@ function askSecret(rl, question) {
36456
37223
  stdin.setRawMode(hadRawMode ?? false);
36457
37224
  }
36458
37225
  process.stdout.write("\n");
36459
- resolve32("");
37226
+ resolve33("");
36460
37227
  return;
36461
37228
  } else if (c3 === "\x7F" || c3 === "\b") {
36462
37229
  if (secret.length > 0) {
@@ -36691,7 +37458,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
36691
37458
  return false;
36692
37459
  }
36693
37460
  for (let i = 0; i < 5; i++) {
36694
- await new Promise((resolve32) => setTimeout(resolve32, 2e3));
37461
+ await new Promise((resolve33) => setTimeout(resolve33, 2e3));
36695
37462
  try {
36696
37463
  const resp = await fetch(`${backendUrl}/api/tags`, {
36697
37464
  signal: AbortSignal.timeout(3e3)
@@ -37152,7 +37919,7 @@ async function doSetup(config, rl) {
37152
37919
  try {
37153
37920
  const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
37154
37921
  child.unref();
37155
- await new Promise((resolve32) => setTimeout(resolve32, 3e3));
37922
+ await new Promise((resolve33) => setTimeout(resolve33, 3e3));
37156
37923
  try {
37157
37924
  models = await fetchOllamaModels(config.backendUrl);
37158
37925
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -37180,7 +37947,7 @@ async function doSetup(config, rl) {
37180
37947
  try {
37181
37948
  const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
37182
37949
  child.unref();
37183
- await new Promise((resolve32) => setTimeout(resolve32, 3e3));
37950
+ await new Promise((resolve33) => setTimeout(resolve33, 3e3));
37184
37951
  try {
37185
37952
  models = await fetchOllamaModels(config.backendUrl);
37186
37953
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -37328,7 +38095,7 @@ async function doSetup(config, rl) {
37328
38095
  `PARAMETER num_predict ${numPredict}`,
37329
38096
  `PARAMETER stop "<|endoftext|>"`
37330
38097
  ].join("\n");
37331
- const modelDir2 = join49(homedir10(), ".open-agents", "models");
38098
+ const modelDir2 = join49(homedir12(), ".open-agents", "models");
37332
38099
  mkdirSync12(modelDir2, { recursive: true });
37333
38100
  const modelfilePath = join49(modelDir2, `Modelfile.${customName}`);
37334
38101
  writeFileSync13(modelfilePath, modelfileContent + "\n", "utf8");
@@ -37376,7 +38143,7 @@ async function isModelAvailable(config) {
37376
38143
  }
37377
38144
  function isFirstRun() {
37378
38145
  try {
37379
- return !existsSync33(join49(homedir10(), ".open-agents", "config.json"));
38146
+ return !existsSync33(join49(homedir12(), ".open-agents", "config.json"));
37380
38147
  } catch {
37381
38148
  return true;
37382
38149
  }
@@ -37413,7 +38180,7 @@ function detectPkgManager() {
37413
38180
  return null;
37414
38181
  }
37415
38182
  function getVenvDir() {
37416
- return join49(homedir10(), ".open-agents", "venv");
38183
+ return join49(homedir12(), ".open-agents", "venv");
37417
38184
  }
37418
38185
  function hasVenvModule() {
37419
38186
  try {
@@ -37438,7 +38205,7 @@ function ensureVenv(log) {
37438
38205
  return null;
37439
38206
  }
37440
38207
  try {
37441
- mkdirSync12(join49(homedir10(), ".open-agents"), { recursive: true });
38208
+ mkdirSync12(join49(homedir12(), ".open-agents"), { recursive: true });
37442
38209
  execSync24(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
37443
38210
  execSync24(`"${join49(venvDir, "bin", "pip")}" install --upgrade pip`, {
37444
38211
  stdio: "pipe",
@@ -37704,9 +38471,9 @@ function ensureCloudflaredBackground(onInfo) {
37704
38471
  const archMap = { x64: "amd64", arm64: "arm64", arm: "arm" };
37705
38472
  const cfArch = archMap[arch] ?? "amd64";
37706
38473
  try {
37707
- 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 });
37708
- if (!process.env.PATH?.includes(`${homedir10()}/.local/bin`)) {
37709
- process.env.PATH = `${homedir10()}/.local/bin:${process.env.PATH}`;
38474
+ 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 });
38475
+ if (!process.env.PATH?.includes(`${homedir12()}/.local/bin`)) {
38476
+ process.env.PATH = `${homedir12()}/.local/bin:${process.env.PATH}`;
37710
38477
  }
37711
38478
  if (hasCmd("cloudflared")) {
37712
38479
  log("cloudflared installed.");
@@ -37801,7 +38568,7 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
37801
38568
  `PARAMETER num_predict ${numPredict}`,
37802
38569
  `PARAMETER stop "<|endoftext|>"`
37803
38570
  ].join("\n");
37804
- const modelDir2 = join49(homedir10(), ".open-agents", "models");
38571
+ const modelDir2 = join49(homedir12(), ".open-agents", "models");
37805
38572
  mkdirSync12(modelDir2, { recursive: true });
37806
38573
  const modelfilePath = join49(modelDir2, `Modelfile.${customName}`);
37807
38574
  writeFileSync13(modelfilePath, modelfileContent + "\n", "utf8");
@@ -37878,7 +38645,7 @@ async function ensureNeovim() {
37878
38645
  const platform5 = process.platform;
37879
38646
  const arch = process.arch;
37880
38647
  if (platform5 === "linux") {
37881
- const binDir = join49(homedir10(), ".local", "bin");
38648
+ const binDir = join49(homedir12(), ".local", "bin");
37882
38649
  const nvimDest = join49(binDir, "nvim");
37883
38650
  try {
37884
38651
  mkdirSync12(binDir, { recursive: true });
@@ -37950,7 +38717,7 @@ async function ensureNeovim() {
37950
38717
  }
37951
38718
  function ensurePathInShellRc(binDir) {
37952
38719
  const shell = process.env.SHELL ?? "";
37953
- const rcFile = shell.includes("zsh") ? join49(homedir10(), ".zshrc") : join49(homedir10(), ".bashrc");
38720
+ const rcFile = shell.includes("zsh") ? join49(homedir12(), ".zshrc") : join49(homedir12(), ".bashrc");
37954
38721
  try {
37955
38722
  const rcContent = existsSync33(rcFile) ? readFileSync24(rcFile, "utf8") : "";
37956
38723
  if (rcContent.includes(binDir))
@@ -37971,7 +38738,7 @@ var init_setup = __esm({
37971
38738
  init_render();
37972
38739
  init_config();
37973
38740
  init_dist();
37974
- execAsync = promisify5(exec2);
38741
+ execAsync = promisify6(exec2);
37975
38742
  QWEN_VARIANTS = [
37976
38743
  { tag: "qwen3.5:0.8b", sizeGB: 1, label: "0.8B params (1.0 GB)", cloud: false },
37977
38744
  { tag: "qwen3.5:2b", sizeGB: 2.7, label: "2B params (2.7 GB)", cloud: false },
@@ -38169,7 +38936,7 @@ function tuiSelect(opts) {
38169
38936
  const maxVisible = opts.maxVisible ?? Math.max(3, contentArea - selectChrome);
38170
38937
  let scrollOffset = 0;
38171
38938
  let lastRenderedLines = 0;
38172
- return new Promise((resolve32) => {
38939
+ return new Promise((resolve33) => {
38173
38940
  const stdin = process.stdin;
38174
38941
  const hadRawMode = stdin.isRaw;
38175
38942
  const savedRlListeners = [];
@@ -38344,7 +39111,7 @@ function tuiSelect(opts) {
38344
39111
  if (!isSkippable(itemIdx) && matchSet.has(itemIdx)) {
38345
39112
  cursor = itemIdx;
38346
39113
  cleanup();
38347
- resolve32({ confirmed: true, key: items[cursor].key, index: cursor });
39114
+ resolve33({ confirmed: true, key: items[cursor].key, index: cursor });
38348
39115
  return;
38349
39116
  } else if (!isSkippable(itemIdx)) {
38350
39117
  cursor = itemIdx;
@@ -38420,7 +39187,7 @@ function tuiSelect(opts) {
38420
39187
  items.splice(deletedIdx, 1);
38421
39188
  if (items.length === 0) {
38422
39189
  cleanup();
38423
- resolve32({ confirmed: false, key: null, index: -1 });
39190
+ resolve33({ confirmed: false, key: null, index: -1 });
38424
39191
  return;
38425
39192
  }
38426
39193
  updateFilter();
@@ -38509,7 +39276,7 @@ function tuiSelect(opts) {
38509
39276
  } else if (seq === "\r" || seq === "\n") {
38510
39277
  if (!isSkippable(cursor) && matchSet.has(cursor)) {
38511
39278
  cleanup();
38512
- resolve32({ confirmed: true, key: items[cursor].key, index: cursor });
39279
+ resolve33({ confirmed: true, key: items[cursor].key, index: cursor });
38513
39280
  }
38514
39281
  } else if (seq === "\x1B" || seq === "\x1B\x1B") {
38515
39282
  if (filter) {
@@ -38522,14 +39289,14 @@ function tuiSelect(opts) {
38522
39289
  render();
38523
39290
  } else if (hasBreadcrumbs) {
38524
39291
  cleanup();
38525
- resolve32({ confirmed: false, key: "__back__", index: cursor });
39292
+ resolve33({ confirmed: false, key: "__back__", index: cursor });
38526
39293
  } else {
38527
39294
  cleanup();
38528
- resolve32({ confirmed: false, key: null, index: cursor });
39295
+ resolve33({ confirmed: false, key: null, index: cursor });
38529
39296
  }
38530
39297
  } else if (seq === "") {
38531
39298
  cleanup();
38532
- resolve32({ confirmed: false, key: null, index: cursor });
39299
+ resolve33({ confirmed: false, key: null, index: cursor });
38533
39300
  } else if (seq === "\x7F" || seq === "\b") {
38534
39301
  if (filter.length > 0) {
38535
39302
  filter = filter.slice(0, -1);
@@ -38543,7 +39310,7 @@ function tuiSelect(opts) {
38543
39310
  render();
38544
39311
  } else if (hasBreadcrumbs) {
38545
39312
  cleanup();
38546
- resolve32({ confirmed: false, key: "__back__", index: cursor });
39313
+ resolve33({ confirmed: false, key: "__back__", index: cursor });
38547
39314
  }
38548
39315
  } else if (seq.length === 1 && seq.charCodeAt(0) >= 32 && seq.charCodeAt(0) < 127) {
38549
39316
  if (opts.onCustomKey && !isSkippable(cursor) && matchSet.has(cursor)) {
@@ -38551,7 +39318,7 @@ function tuiSelect(opts) {
38551
39318
  done: () => render(),
38552
39319
  resolve: (result) => {
38553
39320
  cleanup();
38554
- resolve32(result);
39321
+ resolve33(result);
38555
39322
  },
38556
39323
  getInput: (prompt, prefill) => getInputFromUser(prompt, prefill),
38557
39324
  render: () => render(),
@@ -38668,7 +39435,7 @@ var init_tui_select = __esm({
38668
39435
 
38669
39436
  // packages/cli/dist/tui/drop-panel.js
38670
39437
  import { existsSync as existsSync34 } from "node:fs";
38671
- import { extname as extname9, resolve as resolve27 } from "node:path";
39438
+ import { extname as extname9, resolve as resolve28 } from "node:path";
38672
39439
  function ansi4(code, text) {
38673
39440
  return isTTY4 ? `\x1B[${code}m${text}\x1B[0m` : text;
38674
39441
  }
@@ -38781,7 +39548,7 @@ function showDropPanel(opts) {
38781
39548
  if (filePath.startsWith("file://")) {
38782
39549
  filePath = decodeURIComponent(filePath.slice(7));
38783
39550
  }
38784
- filePath = resolve27(filePath);
39551
+ filePath = resolve28(filePath);
38785
39552
  if (!existsSync34(filePath)) {
38786
39553
  errorMsg = `File not found: ${filePath}`;
38787
39554
  render();
@@ -39093,12 +39860,12 @@ function stopNeovimMode() {
39093
39860
  } catch {
39094
39861
  }
39095
39862
  const s = _state;
39096
- return new Promise((resolve32) => {
39863
+ return new Promise((resolve33) => {
39097
39864
  setTimeout(() => {
39098
39865
  if (s && !s.cleanedUp) {
39099
39866
  doCleanup(s);
39100
39867
  }
39101
- resolve32();
39868
+ resolve33();
39102
39869
  }, 300);
39103
39870
  });
39104
39871
  }
@@ -39334,7 +40101,7 @@ __export(voice_exports, {
39334
40101
  });
39335
40102
  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";
39336
40103
  import { join as join51, dirname as dirname17 } from "node:path";
39337
- import { homedir as homedir11, tmpdir as tmpdir9, platform as platform2 } from "node:os";
40104
+ import { homedir as homedir13, tmpdir as tmpdir9, platform as platform2 } from "node:os";
39338
40105
  import { execSync as execSync26, spawn as nodeSpawn } from "node:child_process";
39339
40106
  import { createRequire } from "node:module";
39340
40107
  function sanitizeForTTS(text) {
@@ -39358,7 +40125,7 @@ function listVoiceModels() {
39358
40125
  }));
39359
40126
  }
39360
40127
  function voiceDir() {
39361
- return join51(homedir11(), ".open-agents", "voice");
40128
+ return join51(homedir13(), ".open-agents", "voice");
39362
40129
  }
39363
40130
  function modelsDir() {
39364
40131
  return join51(voiceDir(), "models");
@@ -40354,7 +41121,7 @@ var init_voice = __esm({
40354
41121
  }
40355
41122
  p = p.replace(/\\ /g, " ");
40356
41123
  if (p.startsWith("~/") || p === "~") {
40357
- p = join51(homedir11(), p.slice(1));
41124
+ p = join51(homedir13(), p.slice(1));
40358
41125
  }
40359
41126
  if (!existsSync36(p)) {
40360
41127
  return `File not found: ${p}
@@ -40769,7 +41536,7 @@ var init_voice = __esm({
40769
41536
  this.speaking = false;
40770
41537
  }
40771
41538
  sleep(ms) {
40772
- return new Promise((resolve32) => setTimeout(resolve32, ms));
41539
+ return new Promise((resolve33) => setTimeout(resolve33, ms));
40773
41540
  }
40774
41541
  // -------------------------------------------------------------------------
40775
41542
  // Synthesis pipeline
@@ -41035,7 +41802,7 @@ var init_voice = __esm({
41035
41802
  const cmd = this.getPlayCommand(path);
41036
41803
  if (!cmd)
41037
41804
  return;
41038
- return new Promise((resolve32) => {
41805
+ return new Promise((resolve33) => {
41039
41806
  const child = nodeSpawn(cmd[0], cmd.slice(1), {
41040
41807
  stdio: "ignore",
41041
41808
  detached: false
@@ -41044,12 +41811,12 @@ var init_voice = __esm({
41044
41811
  child.on("close", () => {
41045
41812
  if (this.currentPlayback === child)
41046
41813
  this.currentPlayback = null;
41047
- resolve32();
41814
+ resolve33();
41048
41815
  });
41049
41816
  child.on("error", () => {
41050
41817
  if (this.currentPlayback === child)
41051
41818
  this.currentPlayback = null;
41052
- resolve32();
41819
+ resolve33();
41053
41820
  });
41054
41821
  setTimeout(() => {
41055
41822
  if (this.currentPlayback === child) {
@@ -41059,7 +41826,7 @@ var init_voice = __esm({
41059
41826
  }
41060
41827
  this.currentPlayback = null;
41061
41828
  }
41062
- resolve32();
41829
+ resolve33();
41063
41830
  }, 15e3);
41064
41831
  });
41065
41832
  }
@@ -41134,7 +41901,7 @@ var init_voice = __esm({
41134
41901
  /** Non-blocking shell execution — async alternative to execSync.
41135
41902
  * Returns stdout string on exit 0, rejects otherwise. */
41136
41903
  asyncShell(command, timeoutMs = 3e4) {
41137
- return new Promise((resolve32, reject) => {
41904
+ return new Promise((resolve33, reject) => {
41138
41905
  const proc = nodeSpawn("sh", ["-c", command], {
41139
41906
  stdio: ["ignore", "pipe", "pipe"],
41140
41907
  cwd: tmpdir9()
@@ -41155,7 +41922,7 @@ var init_voice = __esm({
41155
41922
  proc.on("close", (code) => {
41156
41923
  clearTimeout(timer);
41157
41924
  if (code === 0)
41158
- resolve32(stdout.trim());
41925
+ resolve33(stdout.trim());
41159
41926
  else
41160
41927
  reject(new Error(stderr.slice(0, 300) || `Exit code ${code}`));
41161
41928
  });
@@ -41640,7 +42407,7 @@ if __name__ == '__main__':
41640
42407
  const venvPy = luxttsVenvPy();
41641
42408
  if (!existsSync36(venvPy))
41642
42409
  return false;
41643
- return new Promise((resolve32) => {
42410
+ return new Promise((resolve33) => {
41644
42411
  const env = { ...process.env, LUXTTS_REPO_PATH: luxttsRepoDir() };
41645
42412
  const daemon = nodeSpawn(venvPy, [luxttsInferScript()], {
41646
42413
  stdio: ["pipe", "pipe", "pipe"],
@@ -41659,7 +42426,7 @@ if __name__ == '__main__':
41659
42426
  try {
41660
42427
  const msg = JSON.parse(line);
41661
42428
  if (msg.type === "ready") {
41662
- resolve32(true);
42429
+ resolve33(true);
41663
42430
  } else if (msg.type === "result" || msg.type === "error") {
41664
42431
  const pending = this._luxttsPending.get(msg.id);
41665
42432
  if (pending) {
@@ -41683,25 +42450,25 @@ if __name__ == '__main__':
41683
42450
  });
41684
42451
  daemon.on("error", () => {
41685
42452
  this._luxttsDaemon = null;
41686
- resolve32(false);
42453
+ resolve33(false);
41687
42454
  });
41688
42455
  setTimeout(() => {
41689
42456
  if (this._luxttsDaemon === daemon && !this._luxttsPending.has("__ready__")) {
41690
- resolve32(false);
42457
+ resolve33(false);
41691
42458
  }
41692
42459
  }, 6e4);
41693
42460
  });
41694
42461
  }
41695
42462
  /** Send a request to the LuxTTS daemon and await the response */
41696
42463
  luxttsRequest(req) {
41697
- return new Promise((resolve32, reject) => {
42464
+ return new Promise((resolve33, reject) => {
41698
42465
  if (!this._luxttsDaemon || this._luxttsDaemon.killed) {
41699
42466
  reject(new Error("LuxTTS daemon not running"));
41700
42467
  return;
41701
42468
  }
41702
42469
  const id = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
41703
42470
  req.id = id;
41704
- this._luxttsPending.set(id, { resolve: resolve32, reject });
42471
+ this._luxttsPending.set(id, { resolve: resolve33, reject });
41705
42472
  this._luxttsDaemon.stdin.write(JSON.stringify(req) + "\n");
41706
42473
  setTimeout(() => {
41707
42474
  if (this._luxttsPending.has(id)) {
@@ -44725,9 +45492,9 @@ async function handleVoiceMenu(ctx, save, hasLocal) {
44725
45492
  }
44726
45493
  const { basename: basename16, join: pathJoin } = await import("node:path");
44727
45494
  const { copyFileSync: copyFileSync2, mkdirSync: mkdirSync22, existsSync: exists } = await import("node:fs");
44728
- const { homedir: homedir16 } = await import("node:os");
45495
+ const { homedir: homedir18 } = await import("node:os");
44729
45496
  const modelName = basename16(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
44730
- const destDir = pathJoin(homedir16(), ".open-agents", "voice", "models", modelName);
45497
+ const destDir = pathJoin(homedir18(), ".open-agents", "voice", "models", modelName);
44731
45498
  if (!exists(destDir))
44732
45499
  mkdirSync22(destDir, { recursive: true });
44733
45500
  copyFileSync2(onnxDrop.path, pathJoin(destDir, "model.onnx"));
@@ -45628,11 +46395,11 @@ async function handleUpdate(subcommand, ctx) {
45628
46395
  const targetVersion = info?.latestVersion ?? currentVersion;
45629
46396
  const installOverlay = startInstallOverlay(targetVersion);
45630
46397
  let installError = "";
45631
- const runInstall2 = (cmd) => new Promise((resolve32) => {
46398
+ const runInstall2 = (cmd) => new Promise((resolve33) => {
45632
46399
  const child = exec4(cmd, { timeout: 18e4 }, (err, _stdout, stderr) => {
45633
46400
  if (err)
45634
46401
  installError = (stderr || err.message || "").trim();
45635
- resolve32(!err);
46402
+ resolve33(!err);
45636
46403
  });
45637
46404
  child.stdout?.on("data", (chunk) => {
45638
46405
  const text = String(chunk);
@@ -45726,8 +46493,8 @@ async function handleUpdate(subcommand, ctx) {
45726
46493
  }
45727
46494
  if (doRebuild) {
45728
46495
  installOverlay.setStatus("Rebuilding native modules...");
45729
- await new Promise((resolve32) => {
45730
- const child = exec4(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve32(true));
46496
+ await new Promise((resolve33) => {
46497
+ const child = exec4(`${sudoPrefix}npm rebuild -g open-agents-ai 2>/dev/null || true`, { timeout: 12e4 }, () => resolve33(true));
45731
46498
  child.stdout?.resume();
45732
46499
  child.stderr?.resume();
45733
46500
  });
@@ -45758,8 +46525,8 @@ async function handleUpdate(subcommand, ctx) {
45758
46525
  const venvPip = pathJoin(venvDir, "bin", "pip");
45759
46526
  if (fsExists(venvPip)) {
45760
46527
  installOverlay.setStatus("Upgrading Python packages...");
45761
- await new Promise((resolve32) => {
45762
- const child = exec4(`"${venvPip}" install --upgrade moondream-station pytesseract Pillow opencv-python-headless numpy 2>/dev/null || true`, { timeout: 3e5 }, (err) => resolve32(!err));
46528
+ await new Promise((resolve33) => {
46529
+ const child = exec4(`"${venvPip}" install --upgrade moondream-station pytesseract Pillow opencv-python-headless numpy 2>/dev/null || true`, { timeout: 3e5 }, (err) => resolve33(!err));
45763
46530
  child.stdout?.resume();
45764
46531
  child.stderr?.resume();
45765
46532
  });
@@ -46155,16 +46922,16 @@ async function showExposeDashboard(gateway, rl, ctx) {
46155
46922
  renderDashboard();
46156
46923
  }, 1e3);
46157
46924
  let stopGateway = false;
46158
- await new Promise((resolve32) => {
46925
+ await new Promise((resolve33) => {
46159
46926
  const onData = (data) => {
46160
46927
  const key = data.toString();
46161
46928
  if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
46162
- resolve32();
46929
+ resolve33();
46163
46930
  return;
46164
46931
  }
46165
46932
  if (key === "s" || key === "S") {
46166
46933
  stopGateway = true;
46167
- resolve32();
46934
+ resolve33();
46168
46935
  return;
46169
46936
  }
46170
46937
  if (key === "c" || key === "C") {
@@ -46215,8 +46982,8 @@ async function showExposeDashboard(gateway, rl, ctx) {
46215
46982
  process.stdout.write("\x1B[?1002h\x1B[?1006h");
46216
46983
  }
46217
46984
  };
46218
- const origResolve = resolve32;
46219
- resolve32 = (() => {
46985
+ const origResolve = resolve33;
46986
+ resolve33 = (() => {
46220
46987
  cleanup();
46221
46988
  origResolve();
46222
46989
  });
@@ -46274,7 +47041,7 @@ var init_commands = __esm({
46274
47041
  import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync11 } from "node:fs";
46275
47042
  import { join as join53, basename as basename10 } from "node:path";
46276
47043
  import { execSync as execSync27 } from "node:child_process";
46277
- import { homedir as homedir13, platform as platform3, release } from "node:os";
47044
+ import { homedir as homedir15, platform as platform3, release } from "node:os";
46278
47045
  function getModelTier(modelName) {
46279
47046
  const m = modelName.toLowerCase();
46280
47047
  const sizeMatch = m.match(/\b(\d+)b\b/);
@@ -46361,7 +47128,7 @@ function loadMemoryContext(repoRoot) {
46361
47128
  if (legacyEntries)
46362
47129
  sections.push(legacyEntries);
46363
47130
  }
46364
- const globalMemDir = join53(homedir13(), ".open-agents", "memory");
47131
+ const globalMemDir = join53(homedir15(), ".open-agents", "memory");
46365
47132
  const globalEntries = loadMemoryDir(globalMemDir, "global");
46366
47133
  if (globalEntries)
46367
47134
  sections.push(globalEntries);
@@ -52081,7 +52848,7 @@ var init_tool_policy = __esm({
52081
52848
 
52082
52849
  // packages/cli/dist/tui/telegram-bridge.js
52083
52850
  import { mkdirSync as mkdirSync19, existsSync as existsSync44, unlinkSync as unlinkSync10, readdirSync as readdirSync16, statSync as statSync14 } from "node:fs";
52084
- import { join as join60, resolve as resolve28 } from "node:path";
52851
+ import { join as join60, resolve as resolve29 } from "node:path";
52085
52852
  import { writeFile as writeFileAsync } from "node:fs/promises";
52086
52853
  function convertMarkdownToTelegramHTML(md) {
52087
52854
  let html = md;
@@ -52324,7 +53091,7 @@ with summary "no_reply" to silently skip without responding.
52324
53091
  this.agentConfig = agentConfig;
52325
53092
  this.repoRoot = repoRoot;
52326
53093
  this.toolPolicyConfig = toolPolicyConfig;
52327
- this.mediaCacheDir = resolve28(repoRoot || ".", ".oa", "telegram-media-cache");
53094
+ this.mediaCacheDir = resolve29(repoRoot || ".", ".oa", "telegram-media-cache");
52328
53095
  }
52329
53096
  /** Set admin user ID filter */
52330
53097
  setAdmin(userId) {
@@ -53560,7 +54327,7 @@ var init_braille_spinner = __esm({
53560
54327
  // packages/cli/dist/tui/system-metrics.js
53561
54328
  import { loadavg as loadavg3, cpus as cpus3, totalmem as totalmem4, freemem as freemem3, platform as platform4 } from "node:os";
53562
54329
  import { exec as exec3 } from "node:child_process";
53563
- import { readFile as readFile21 } from "node:fs/promises";
54330
+ import { readFile as readFile22 } from "node:fs/promises";
53564
54331
  function formatRate(bytesPerSec) {
53565
54332
  if (bytesPerSec < 1024)
53566
54333
  return `${Math.round(bytesPerSec)}B`;
@@ -53572,7 +54339,7 @@ function formatRate(bytesPerSec) {
53572
54339
  }
53573
54340
  async function readProcNetDev() {
53574
54341
  try {
53575
- const data = await readFile21("/proc/net/dev", "utf8");
54342
+ const data = await readFile22("/proc/net/dev", "utf8");
53576
54343
  let rxTotal = 0;
53577
54344
  let txTotal = 0;
53578
54345
  for (const line of data.split("\n")) {
@@ -53610,8 +54377,8 @@ async function collectNetworkMetrics() {
53610
54377
  }
53611
54378
  if (plat === "darwin") {
53612
54379
  try {
53613
- const output = await new Promise((resolve32, reject) => {
53614
- exec3("netstat -ib 2>/dev/null | head -30", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve32(stdout));
54380
+ const output = await new Promise((resolve33, reject) => {
54381
+ exec3("netstat -ib 2>/dev/null | head -30", { encoding: "utf8", timeout: 3e3 }, (err, stdout) => err ? reject(err) : resolve33(stdout));
53615
54382
  });
53616
54383
  let rxBytes = 0, txBytes = 0;
53617
54384
  for (const line of output.split("\n")) {
@@ -53645,8 +54412,8 @@ async function collectGpuMetrics() {
53645
54412
  if (_nvidiaSmiAvailable === false)
53646
54413
  return noGpu;
53647
54414
  try {
53648
- const smi = await new Promise((resolve32, reject) => {
53649
- 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));
54415
+ const smi = await new Promise((resolve33, reject) => {
54416
+ 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));
53650
54417
  });
53651
54418
  _nvidiaSmiAvailable = true;
53652
54419
  const line = smi.trim().split("\n")[0];
@@ -56295,13 +57062,13 @@ var init_mouse_filter = __esm({
56295
57062
  import * as readline2 from "node:readline";
56296
57063
  import { Writable } from "node:stream";
56297
57064
  import { cwd } from "node:process";
56298
- import { resolve as resolve29, join as join61, dirname as dirname19, extname as extname10 } from "node:path";
57065
+ import { resolve as resolve30, join as join61, dirname as dirname19, extname as extname10 } from "node:path";
56299
57066
  import { createRequire as createRequire2 } from "node:module";
56300
57067
  import { fileURLToPath as fileURLToPath12 } from "node:url";
56301
57068
  import { readFileSync as readFileSync34, writeFileSync as writeFileSync19, appendFileSync as appendFileSync4, rmSync as rmSync3, readdirSync as readdirSync17, mkdirSync as mkdirSync20 } from "node:fs";
56302
57069
  import { existsSync as existsSync45 } from "node:fs";
56303
57070
  import { execSync as execSync30 } from "node:child_process";
56304
- import { homedir as homedir14 } from "node:os";
57071
+ import { homedir as homedir16 } from "node:os";
56305
57072
  function formatTimeAgo(date) {
56306
57073
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
56307
57074
  if (seconds < 60)
@@ -56450,6 +57217,9 @@ function buildTools(repoRoot, config, contextWindowSize) {
56450
57217
  new OpenCodeTool(repoRoot),
56451
57218
  new FactoryTool(repoRoot),
56452
57219
  new CronAgentTool(repoRoot),
57220
+ // Chunked file exploration + working notes
57221
+ new FileExploreTool(repoRoot),
57222
+ new WorkingNotesTool(),
56453
57223
  // Nexus P2P networking + x402 micropayments
56454
57224
  new NexusTool(repoRoot)
56455
57225
  ];
@@ -57599,7 +58369,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
57599
58369
  } };
57600
58370
  }
57601
58371
  async function startInteractive(config, repoPath) {
57602
- const repoRoot = resolve29(repoPath ?? cwd());
58372
+ const repoRoot = resolve30(repoPath ?? cwd());
57603
58373
  const resumeFlag = process.env.__OA_RESUMED ?? "";
57604
58374
  const isResumed = resumeFlag !== "";
57605
58375
  const hasTaskToResume = resumeFlag === "1";
@@ -57771,14 +58541,14 @@ async function startInteractive(config, repoPath) {
57771
58541
  renderInfo(msg);
57772
58542
  statusBar.endContentWrite();
57773
58543
  }
57774
- }, () => new Promise((resolve32) => {
58544
+ }, () => new Promise((resolve33) => {
57775
58545
  depSudoPromptPending = true;
57776
58546
  depSudoResolver = (pw) => {
57777
58547
  depSudoPromptPending = false;
57778
58548
  depSudoResolver = null;
57779
58549
  if (pw)
57780
58550
  sessionSudoPassword = pw;
57781
- resolve32(pw);
58551
+ resolve33(pw);
57782
58552
  };
57783
58553
  const pwPrompt1 = ` ${c2.bold(c2.yellow("\u{1F511} Password needed for dependency install:"))}
57784
58554
  `;
@@ -58066,7 +58836,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
58066
58836
  const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
58067
58837
  return [hits, line];
58068
58838
  }
58069
- const HISTORY_DIR = join61(homedir14(), ".open-agents");
58839
+ const HISTORY_DIR = join61(homedir16(), ".open-agents");
58070
58840
  const HISTORY_FILE = join61(HISTORY_DIR, "repl-history");
58071
58841
  const MAX_HISTORY_LINES = 500;
58072
58842
  let savedHistory = [];
@@ -59582,7 +60352,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
59582
60352
  } catch {
59583
60353
  }
59584
60354
  try {
59585
- const voiceDir2 = join61(homedir14(), ".open-agents", "voice");
60355
+ const voiceDir2 = join61(homedir16(), ".open-agents", "voice");
59586
60356
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
59587
60357
  for (const pf of voicePidFiles) {
59588
60358
  const pidPath = join61(voiceDir2, pf);
@@ -59985,8 +60755,8 @@ Execute this skill now. Follow the behavioral guidance above.`;
59985
60755
  }
59986
60756
  }
59987
60757
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
59988
- const isImage = isImagePath(cleanPath) && existsSync45(resolve29(repoRoot, cleanPath));
59989
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync45(resolve29(repoRoot, cleanPath));
60758
+ const isImage = isImagePath(cleanPath) && existsSync45(resolve30(repoRoot, cleanPath));
60759
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync45(resolve30(repoRoot, cleanPath));
59990
60760
  if (activeTask) {
59991
60761
  if (activeTask.runner.isPaused) {
59992
60762
  activeTask.runner.resume();
@@ -59994,7 +60764,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
59994
60764
  }
59995
60765
  if (isImage) {
59996
60766
  try {
59997
- const imgPath = resolve29(repoRoot, cleanPath);
60767
+ const imgPath = resolve30(repoRoot, cleanPath);
59998
60768
  const imgBuffer = readFileSync34(imgPath);
59999
60769
  const base64 = imgBuffer.toString("base64");
60000
60770
  const ext = extname10(cleanPath).toLowerCase();
@@ -60008,7 +60778,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
60008
60778
  } else if (isMedia) {
60009
60779
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
60010
60780
  const engine = getListenEngine();
60011
- const result = await engine.transcribeFile(resolve29(repoRoot, cleanPath), repoRoot);
60781
+ const result = await engine.transcribeFile(resolve30(repoRoot, cleanPath), repoRoot);
60012
60782
  if (result) {
60013
60783
  const transcript = `[Transcription of ${cleanPath}]
60014
60784
  ${result.text}`;
@@ -60152,7 +60922,7 @@ ${result.text}`;
60152
60922
  const ext = cleanPath.toLowerCase().split(".").pop() || "";
60153
60923
  if (cloneExts.includes("." + ext)) {
60154
60924
  writeContent(() => renderInfo(`Setting voice clone reference: ${cleanPath}`));
60155
- const msg = await voiceEngine.setCloneVoice(resolve29(repoRoot, cleanPath));
60925
+ const msg = await voiceEngine.setCloneVoice(resolve30(repoRoot, cleanPath));
60156
60926
  writeContent(() => renderInfo(msg));
60157
60927
  showPrompt();
60158
60928
  return;
@@ -60161,7 +60931,7 @@ ${result.text}`;
60161
60931
  if (isMedia && fullInput === input) {
60162
60932
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
60163
60933
  const engine = getListenEngine();
60164
- const result = await engine.transcribeFile(resolve29(repoRoot, cleanPath), repoRoot);
60934
+ const result = await engine.transcribeFile(resolve30(repoRoot, cleanPath), repoRoot);
60165
60935
  if (result) {
60166
60936
  fullInput = `The user has provided an audio/video file: ${cleanPath}.
60167
60937
 
@@ -60447,7 +61217,7 @@ ${c2.dim("(Use /quit to exit)")}
60447
61217
  };
60448
61218
  }
60449
61219
  async function runWithTUI(task, config, repoPath) {
60450
- const repoRoot = resolve29(repoPath ?? cwd());
61220
+ const repoRoot = resolve30(repoPath ?? cwd());
60451
61221
  const needsSetup = isFirstRun() || !await isModelAvailable(config);
60452
61222
  if (needsSetup && config.backendType === "ollama") {
60453
61223
  const setupModel = await runSetupWizard(config);
@@ -60830,7 +61600,7 @@ var init_run = __esm({
60830
61600
  // packages/indexer/dist/codebase-indexer.js
60831
61601
  import { glob } from "glob";
60832
61602
  import ignore from "ignore";
60833
- import { readFile as readFile22, stat as stat4 } from "node:fs/promises";
61603
+ import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
60834
61604
  import { createHash as createHash4 } from "node:crypto";
60835
61605
  import { join as join62, relative as relative3, extname as extname11, basename as basename15 } from "node:path";
60836
61606
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
@@ -60876,7 +61646,7 @@ var init_codebase_indexer = __esm({
60876
61646
  const ig = ignore.default();
60877
61647
  if (this.config.respectGitignore) {
60878
61648
  try {
60879
- const gitignoreContent = await readFile22(join62(this.config.rootDir, ".gitignore"), "utf-8");
61649
+ const gitignoreContent = await readFile23(join62(this.config.rootDir, ".gitignore"), "utf-8");
60880
61650
  ig.add(gitignoreContent);
60881
61651
  } catch {
60882
61652
  }
@@ -60896,7 +61666,7 @@ var init_codebase_indexer = __esm({
60896
61666
  const fileStat = await stat4(fullPath);
60897
61667
  if (fileStat.size > this.config.maxFileSize)
60898
61668
  continue;
60899
- const content = await readFile22(fullPath);
61669
+ const content = await readFile23(fullPath);
60900
61670
  const hash = createHash4("sha256").update(content).digest("hex");
60901
61671
  const ext = extname11(relativePath);
60902
61672
  indexed.push({
@@ -61019,11 +61789,11 @@ var index_repo_exports = {};
61019
61789
  __export(index_repo_exports, {
61020
61790
  indexRepoCommand: () => indexRepoCommand
61021
61791
  });
61022
- import { resolve as resolve30 } from "node:path";
61792
+ import { resolve as resolve31 } from "node:path";
61023
61793
  import { existsSync as existsSync46, statSync as statSync15 } from "node:fs";
61024
61794
  import { cwd as cwd2 } from "node:process";
61025
61795
  async function indexRepoCommand(opts, _config) {
61026
- const repoRoot = resolve30(opts.repoPath ?? cwd2());
61796
+ const repoRoot = resolve31(opts.repoPath ?? cwd2());
61027
61797
  printHeader("Index Repository");
61028
61798
  printInfo(`Indexing: ${repoRoot}`);
61029
61799
  if (!existsSync46(repoRoot)) {
@@ -61278,8 +62048,8 @@ var config_exports = {};
61278
62048
  __export(config_exports, {
61279
62049
  configCommand: () => configCommand
61280
62050
  });
61281
- import { join as join63, resolve as resolve31 } from "node:path";
61282
- import { homedir as homedir15 } from "node:os";
62051
+ import { join as join63, resolve as resolve32 } from "node:path";
62052
+ import { homedir as homedir17 } from "node:os";
61283
62053
  import { cwd as cwd3 } from "node:process";
61284
62054
  function redactIfSensitive(key, value) {
61285
62055
  if (SENSITIVE_KEYS.has(key) && typeof value === "string" && value.length > 0) {
@@ -61311,7 +62081,7 @@ async function configCommand(opts, config) {
61311
62081
  return handleShow(opts, config);
61312
62082
  }
61313
62083
  function handleShow(opts, config) {
61314
- const repoRoot = resolve31(opts.repoPath ?? cwd3());
62084
+ const repoRoot = resolve32(opts.repoPath ?? cwd3());
61315
62085
  printHeader("Configuration");
61316
62086
  const resolved = resolveSettings(repoRoot);
61317
62087
  printSection("Core Inference");
@@ -61361,7 +62131,7 @@ function handleShow(opts, config) {
61361
62131
  }
61362
62132
  }
61363
62133
  printSection("Config File");
61364
- printInfo(`~/.open-agents/config.json (${join63(homedir15(), ".open-agents", "config.json")})`);
62134
+ printInfo(`~/.open-agents/config.json (${join63(homedir17(), ".open-agents", "config.json")})`);
61365
62135
  printSection("Priority Chain");
61366
62136
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
61367
62137
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -61394,7 +62164,7 @@ function handleSet(opts, _config) {
61394
62164
  process.exit(1);
61395
62165
  }
61396
62166
  if (opts.local) {
61397
- const repoRoot = resolve31(opts.repoPath ?? cwd3());
62167
+ const repoRoot = resolve32(opts.repoPath ?? cwd3());
61398
62168
  try {
61399
62169
  initOaDirectory(repoRoot);
61400
62170
  const coerced = coerceForSettings(key, value);
@@ -61592,7 +62362,7 @@ async function serveVllm(opts, config) {
61592
62362
  await runVllmServer(args, opts.verbose ?? false);
61593
62363
  }
61594
62364
  async function runVllmServer(args, verbose) {
61595
- return new Promise((resolve32, reject) => {
62365
+ return new Promise((resolve33, reject) => {
61596
62366
  const child = spawn19("python", args, {
61597
62367
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
61598
62368
  env: { ...process.env }
@@ -61627,10 +62397,10 @@ async function runVllmServer(args, verbose) {
61627
62397
  child.once("exit", (code, signal) => {
61628
62398
  if (signal) {
61629
62399
  printInfo(`vLLM server stopped by signal ${signal}`);
61630
- resolve32();
62400
+ resolve33();
61631
62401
  } else if (code === 0) {
61632
62402
  printSuccess("vLLM server exited cleanly");
61633
- resolve32();
62403
+ resolve33();
61634
62404
  } else {
61635
62405
  printError(`vLLM server exited with code ${code}`);
61636
62406
  reject(new Error(`vLLM exited with code ${code}`));