open-agents-ai 0.187.230 → 0.187.232

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +221 -49
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10159,7 +10159,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
10159
10159
  ];
10160
10160
  NexusTool = class {
10161
10161
  name = "nexus";
10162
- description = "P2P agent mesh networking. IMPORTANT: You MUST call action='connect' FIRST — it spawns the daemon. Nothing works without it. After connect: join_room, send_message, discover_peers, expose (share models), remote_infer (use remote models). Quick start: connect → join_room → send_message. Also: wallet_create, wallet_status, ledger_status, budget_set, spend, invoke_capability, store_content.";
10162
+ description = "P2P agent mesh networking — invoked ONLY via this tool call. ⚠ DO NOT run 'nexus' as a shell command. DO NOT run 'npm install open-agents-nexus' — it's ALREADY embedded in this binary. DO NOT use the shell tool to look for a 'nexus' binary — there isn't one. Use THIS tool interface. All nexus actions are dispatched through tool calls of the form: nexus({ action: 'connect', agent_name: '...' }). IMPORTANT: You MUST call action='connect' FIRST — it spawns the daemon. Nothing works without it. After connect: join_room, send_message, discover_peers, expose (share models), remote_infer (use remote models). Voice: voice_listen_start (ASR on room audio), voice_publish, voice_speak, jibberlink_send (encrypted data-over-audio). Quick start: connect → join_room → send_message. Also: wallet_create, wallet_status, ledger_status, budget_set, spend, invoke_capability, store_content.";
10163
10163
  parameters = {
10164
10164
  type: "object",
10165
10165
  properties: {
@@ -251346,7 +251346,7 @@ train.py reverted to last kept state. Ready for next experiment.`,
251346
251346
  });
251347
251347
 
251348
251348
  // packages/execution/dist/tools/scheduler.js
251349
- import { execSync as execSync22, exec as execCb } from "node:child_process";
251349
+ import { execSync as execSync22, exec as execCb, spawnSync as spawnSync2 } from "node:child_process";
251350
251350
  import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir12 } from "node:fs/promises";
251351
251351
  import { resolve as resolve24, join as join37 } from "node:path";
251352
251352
  import { homedir as homedir10 } from "node:os";
@@ -251416,7 +251416,18 @@ function getCurrentCrontab() {
251416
251416
  }
251417
251417
  function writeCrontab(lines) {
251418
251418
  const content = lines.join("\n") + "\n";
251419
- execSync22(`echo ${JSON.stringify(content)} | crontab -`, { stdio: "pipe" });
251419
+ const result = spawnSync2("crontab", ["-"], {
251420
+ input: content,
251421
+ stdio: ["pipe", "pipe", "pipe"],
251422
+ encoding: "utf8"
251423
+ });
251424
+ if (result.error) {
251425
+ throw new Error(`writeCrontab: ${result.error.message}`);
251426
+ }
251427
+ if (result.status !== 0) {
251428
+ const stderr = (result.stderr || "").toString().trim();
251429
+ throw new Error(`writeCrontab: crontab exited ${result.status}${stderr ? `: ${stderr}` : ""}`);
251430
+ }
251420
251431
  }
251421
251432
  function findOaBinary() {
251422
251433
  for (const cmd of ["oa", "open-agents"]) {
@@ -257631,7 +257642,7 @@ ${output}`, durationMs: performance.now() - start2 };
257631
257642
  });
257632
257643
 
257633
257644
  // packages/execution/dist/tools/gps-location.js
257634
- import { execSync as execSync36, spawnSync as spawnSync2 } from "node:child_process";
257645
+ import { execSync as execSync36, spawnSync as spawnSync3 } from "node:child_process";
257635
257646
  import { existsSync as existsSync35, readFileSync as readFileSync27, writeFileSync as writeFileSync15, mkdirSync as mkdirSync16 } from "node:fs";
257636
257647
  import { join as join50 } from "node:path";
257637
257648
  import { tmpdir as tmpdir13, homedir as homedir15 } from "node:os";
@@ -270898,7 +270909,13 @@ ${memoryLines.join("\n")}`
270898
270909
  // list) but the dedup detector was flagging it as a wasted call
270899
270910
  // and blocking the planning workflow. The agent uses todo_write
270900
270911
  // as its primary checkpoint mechanism so it MUST always execute.
270901
- "todo_write"
270912
+ "todo_write",
270913
+ // nexus is also a state tool — connect is idempotent but the
270914
+ // dedup warning was causing confused agents to bail out to
270915
+ // shell workarounds (npm install, find /bin, etc.) when they
270916
+ // saw "DUPLICATE CALL" after their first connect. Let the
270917
+ // tool see every call and return the cached state itself.
270918
+ "nexus"
270902
270919
  ].includes(tc.name);
270903
270920
  const cachedResult = recentToolResults.get(toolFingerprint);
270904
270921
  if (isReadLike && cachedResult !== void 0) {
@@ -290797,6 +290814,25 @@ var init_status_bar = __esm({
290797
290814
  } else if (type === "release") {
290798
290815
  this._textSelection.onMouseRelease(row, col);
290799
290816
  this.repaintContent();
290817
+ if (this._textSelection.hasSelection) {
290818
+ try {
290819
+ const ok2 = this._textSelection.copyToClipboard();
290820
+ if (ok2) {
290821
+ const pos2 = this.rowPositions(termRows());
290822
+ if (pos2.metricsRow > 0) {
290823
+ const origWrite = this._origWrite ?? process.stdout.write.bind(process.stdout);
290824
+ origWrite(`\x1B[${pos2.metricsRow};1H\x1B[2K\x1B[38;5;${TEXT_PRIMARY}m ✓ Copied to clipboard\x1B[0m`);
290825
+ setTimeout(() => {
290826
+ try {
290827
+ this.renderFooterAndPositionInput();
290828
+ } catch {
290829
+ }
290830
+ }, 1200);
290831
+ }
290832
+ }
290833
+ } catch {
290834
+ }
290835
+ }
290800
290836
  }
290801
290837
  }
290802
290838
  /** Copy current selection to clipboard. Returns true if copied. */
@@ -300291,15 +300327,15 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
300291
300327
  renderInfo(" ARM device detected — installing build prerequisites then deps individually.");
300292
300328
  const isMac = process.platform === "darwin";
300293
300329
  try {
300294
- const { spawnSync: spawnSync3 } = await import("node:child_process");
300330
+ const { spawnSync: spawnSync4 } = await import("node:child_process");
300295
300331
  if (process.stdout.isTTY) {
300296
300332
  process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l");
300297
300333
  }
300298
300334
  if (isMac) {
300299
300335
  renderInfo(" macOS ARM detected — installing build deps via Homebrew...");
300300
- const brewCheck = spawnSync3("which", ["brew"], { stdio: "pipe", timeout: 5e3 });
300336
+ const brewCheck = spawnSync4("which", ["brew"], { stdio: "pipe", timeout: 5e3 });
300301
300337
  if (brewCheck.status === 0) {
300302
- const brewResult = spawnSync3("brew", ["install", "llvm", "gcc", "openblas", "libsndfile"], {
300338
+ const brewResult = spawnSync4("brew", ["install", "llvm", "gcc", "openblas", "libsndfile"], {
300303
300339
  stdio: "pipe",
300304
300340
  timeout: 3e5
300305
300341
  });
@@ -300308,11 +300344,11 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
300308
300344
  const { renderVerbose: renderVerbose2 } = await Promise.resolve().then(() => (init_render(), render_exports));
300309
300345
  renderVerbose2(brewResult.stderr.toString());
300310
300346
  }
300311
- const llvmPrefix = spawnSync3("brew", ["--prefix", "llvm"], { stdio: "pipe", timeout: 5e3 });
300347
+ const llvmPrefix = spawnSync4("brew", ["--prefix", "llvm"], { stdio: "pipe", timeout: 5e3 });
300312
300348
  if (llvmPrefix.stdout) {
300313
300349
  const prefix = llvmPrefix.stdout.toString().trim();
300314
300350
  process.env.LLVM_CONFIG = `${prefix}/bin/llvm-config`;
300315
- const openblas = spawnSync3("brew", ["--prefix", "openblas"], { stdio: "pipe", timeout: 5e3 });
300351
+ const openblas = spawnSync4("brew", ["--prefix", "openblas"], { stdio: "pipe", timeout: 5e3 });
300316
300352
  if (openblas.stdout) {
300317
300353
  const obPrefix = openblas.stdout.toString().trim();
300318
300354
  process.env.LDFLAGS = `${process.env.LDFLAGS ?? ""} -L${obPrefix}/lib`.trim();
@@ -300325,10 +300361,10 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
300325
300361
  }
300326
300362
  } else {
300327
300363
  renderInfo(" System build tools needed (llvm, gcc). Requesting sudo access...");
300328
- const sudoCheck = spawnSync3("sudo", ["-v"], { stdio: "inherit", timeout: 6e4 });
300364
+ const sudoCheck = spawnSync4("sudo", ["-v"], { stdio: "inherit", timeout: 6e4 });
300329
300365
  if (sudoCheck.status === 0) {
300330
300366
  renderInfo(" Installing system build dependencies (this may take a minute)...");
300331
- const aptResult = spawnSync3("sudo", [
300367
+ const aptResult = spawnSync4("sudo", [
300332
300368
  "apt-get",
300333
300369
  "install",
300334
300370
  "-y",
@@ -306567,8 +306603,8 @@ async function handleUpdate(subcommand, ctx3) {
306567
306603
  renderInfo("Enter your password if prompted...");
306568
306604
  safeWrite("\n");
306569
306605
  try {
306570
- const { spawnSync: spawnSync3 } = await import("node:child_process");
306571
- const sudoResult = spawnSync3("sudo", ["-v"], { stdio: "inherit", timeout: 6e4 });
306606
+ const { spawnSync: spawnSync4 } = await import("node:child_process");
306607
+ const sudoResult = spawnSync4("sudo", ["-v"], { stdio: "inherit", timeout: 6e4 });
306572
306608
  if (sudoResult.status !== 0) throw new Error("sudo failed");
306573
306609
  } catch {
306574
306610
  renderWarning("Could not acquire sudo credentials. Try: sudo npm i -g open-agents-ai");
@@ -314969,6 +315005,65 @@ var init_direct_input = __esm({
314969
315005
  }
314970
315006
  });
314971
315007
 
315008
+ // packages/cli/src/api/access-policy.ts
315009
+ function defaultAccessMode(bindHost) {
315010
+ if (bindHost === "0.0.0.0" || bindHost === "::" || bindHost === "::0") {
315011
+ return "lan";
315012
+ }
315013
+ return "loopback";
315014
+ }
315015
+ function resolveAccessMode(envValue, bindHost) {
315016
+ const v = (envValue || "").toLowerCase().trim();
315017
+ if (v === "loopback" || v === "lan" || v === "any") return v;
315018
+ return defaultAccessMode(bindHost);
315019
+ }
315020
+ function stripMappedPrefix(ip) {
315021
+ return ip.replace(/^::ffff:/i, "");
315022
+ }
315023
+ function isLoopbackIP(ip) {
315024
+ if (!ip) return false;
315025
+ const clean3 = stripMappedPrefix(ip);
315026
+ if (clean3 === "::1") return true;
315027
+ if (/^127\./.test(clean3)) return true;
315028
+ return false;
315029
+ }
315030
+ function isPrivateIP(ip) {
315031
+ if (!ip) return false;
315032
+ const clean3 = stripMappedPrefix(ip);
315033
+ if (/^10\./.test(clean3)) return true;
315034
+ if (/^192\.168\./.test(clean3)) return true;
315035
+ const m2 = /^172\.(\d{1,3})\./.exec(clean3);
315036
+ if (m2) {
315037
+ const second3 = parseInt(m2[1], 10);
315038
+ if (second3 >= 16 && second3 <= 31) return true;
315039
+ }
315040
+ if (/^169\.254\./.test(clean3)) return true;
315041
+ if (/^f[cd][0-9a-f]{2}:/i.test(clean3)) return true;
315042
+ if (/^fe[89ab][0-9a-f]:/i.test(clean3)) return true;
315043
+ return false;
315044
+ }
315045
+ function isAllowedIP(ip, mode) {
315046
+ if (mode === "any") return true;
315047
+ if (isLoopbackIP(ip)) return true;
315048
+ if (mode === "lan" && isPrivateIP(ip)) return true;
315049
+ return false;
315050
+ }
315051
+ function describeAccessMode(mode) {
315052
+ switch (mode) {
315053
+ case "loopback":
315054
+ return "loopback only";
315055
+ case "lan":
315056
+ return "loopback + RFC 1918";
315057
+ case "any":
315058
+ return "any — WIDE OPEN";
315059
+ }
315060
+ }
315061
+ var init_access_policy = __esm({
315062
+ "packages/cli/src/api/access-policy.ts"() {
315063
+ "use strict";
315064
+ }
315065
+ });
315066
+
314972
315067
  // packages/cli/src/api/audit-log.ts
314973
315068
  var audit_log_exports = {};
314974
315069
  __export(audit_log_exports, {
@@ -325781,7 +325876,7 @@ function startApiServer(options2 = {}) {
325781
325876
  if (options2.quiet) setQuiet(true);
325782
325877
  const log22 = options2.quiet ? (_msg) => {
325783
325878
  } : (msg) => process.stderr.write(msg);
325784
- let host = "127.0.0.1";
325879
+ let host = "0.0.0.0";
325785
325880
  let port = 11435;
325786
325881
  const envHost = process.env["OA_HOST"];
325787
325882
  if (envHost) {
@@ -325957,7 +326052,23 @@ function startApiServer(options2 = {}) {
325957
326052
  process.exit(1);
325958
326053
  }
325959
326054
  }
326055
+ const accessMode = resolveAccessMode(process.env["OA_ACCESS"], host);
326056
+ let _accessRejected = 0;
325960
326057
  const handler = (req2, res) => {
326058
+ const rawIp = req2.socket?.remoteAddress ?? "";
326059
+ if (!isAllowedIP(rawIp, accessMode)) {
326060
+ _accessRejected++;
326061
+ metrics.totalErrors++;
326062
+ try {
326063
+ res.writeHead(403, { "Content-Type": "application/json" });
326064
+ res.end(JSON.stringify({
326065
+ error: "access_denied",
326066
+ message: `Address ${rawIp} is not in the allowed network (mode: ${accessMode}). Set OA_ACCESS=any to disable.`
326067
+ }));
326068
+ } catch {
326069
+ }
326070
+ return;
326071
+ }
325961
326072
  handleRequest(req2, res, ollamaUrl, verbose).catch((err) => {
325962
326073
  metrics.totalErrors++;
325963
326074
  try {
@@ -326028,6 +326139,8 @@ function startApiServer(options2 = {}) {
326028
326139
  `);
326029
326140
  const proto = useTls ? "https" : "http";
326030
326141
  log22(` Listening on ${proto}://${host}:${port}
326142
+ `);
326143
+ log22(` Access: ${accessMode} (${describeAccessMode(accessMode)})
326031
326144
  `);
326032
326145
  log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
326033
326146
  `);
@@ -326116,6 +326229,7 @@ var init_serve = __esm({
326116
326229
  "packages/cli/src/api/serve.ts"() {
326117
326230
  "use strict";
326118
326231
  init_config();
326232
+ init_access_policy();
326119
326233
  init_audit_log();
326120
326234
  init_task_manager_singleton();
326121
326235
  init_disk_task_output();
@@ -326247,6 +326361,91 @@ ${incompleteList}${more}`
326247
326361
  }
326248
326362
  };
326249
326363
  }
326364
+ function buildSubAgentTools(repoRoot, config) {
326365
+ return [
326366
+ // File + search
326367
+ new FileReadTool(repoRoot),
326368
+ new FileWriteTool(repoRoot),
326369
+ new FileEditTool(repoRoot),
326370
+ new ShellTool(repoRoot),
326371
+ new GrepSearchTool(repoRoot),
326372
+ new GlobFindTool(repoRoot),
326373
+ new ListDirectoryTool(repoRoot),
326374
+ new FileExploreTool(repoRoot),
326375
+ new FilePatchTool(repoRoot),
326376
+ new BatchEditTool(repoRoot),
326377
+ new NotebookEditTool(),
326378
+ // Memory
326379
+ new MemoryReadTool(repoRoot),
326380
+ new MemoryWriteTool(repoRoot),
326381
+ new MemorySearchTool(repoRoot),
326382
+ // Checklist — the critical regression we're closing here
326383
+ new TodoWriteTool(),
326384
+ new TodoReadTool(),
326385
+ new WorkingNotesTool(),
326386
+ // Code understanding + navigation
326387
+ new CodebaseMapTool(repoRoot),
326388
+ new SemanticMapTool(repoRoot),
326389
+ new RepoMapTool(repoRoot),
326390
+ new ImportGraphTool(repoRoot),
326391
+ new DiagnosticTool(repoRoot),
326392
+ new GitInfoTool(repoRoot),
326393
+ new ExploreToolsTool(),
326394
+ new ProcessHealthTool(),
326395
+ // Web research
326396
+ new WebFetchTool(),
326397
+ new WebSearchTool(),
326398
+ new WebCrawlTool(repoRoot),
326399
+ new BrowserActionTool(),
326400
+ new PlaywrightBrowserTool(),
326401
+ // Documents + media reading
326402
+ new ImageReadTool(repoRoot),
326403
+ new OCRTool(repoRoot),
326404
+ new OcrImageAdvancedTool(repoRoot),
326405
+ new OcrPdfTool(repoRoot),
326406
+ new PdfToTextTool(repoRoot),
326407
+ new ScreenshotTool(repoRoot),
326408
+ new StructuredReadTool(repoRoot),
326409
+ new StructuredFileTool(repoRoot),
326410
+ // Audio
326411
+ new AudioPlaybackTool(),
326412
+ new AudioCaptureTool(),
326413
+ new AudioAnalyzeTool(),
326414
+ new AsrListenTool(),
326415
+ new TranscribeFileTool(repoRoot),
326416
+ new TranscribeUrlTool(repoRoot),
326417
+ new YouTubeDownloadTool(repoRoot),
326418
+ // Code execution (sandboxed)
326419
+ new CodeSandboxTool(repoRoot),
326420
+ new ReplTool(repoRoot),
326421
+ // AIWG / SDLC workflow
326422
+ new AiwgSetupTool(repoRoot),
326423
+ new AiwgHealthTool(repoRoot),
326424
+ new AiwgWorkflowTool(repoRoot),
326425
+ // Scheduler + agenda (time-based tooling)
326426
+ new SchedulerTool(repoRoot),
326427
+ new ReminderTool(repoRoot),
326428
+ new AgendaTool(repoRoot),
326429
+ // Vision + multimodal memory
326430
+ new VisionTool(repoRoot),
326431
+ new DesktopClickTool(repoRoot),
326432
+ new DesktopDescribeTool(repoRoot),
326433
+ new VisualMemoryTool(),
326434
+ new MultimodalMemoryTool(),
326435
+ new VideoUnderstandTool(repoRoot),
326436
+ new CameraCaptureTool(),
326437
+ new ImageGenerateTool(repoRoot, config.backendUrl),
326438
+ // Hardware sensors + radios (read-only scans)
326439
+ new GpsLocationTool(),
326440
+ new WifiControlTool(),
326441
+ new BluetoothScanTool(),
326442
+ new SdrScanTool(),
326443
+ new FlipperZeroTool(),
326444
+ new MeshtasticTool(),
326445
+ // Autoresearch (independent ML experiment loop)
326446
+ new AutoresearchTool(repoRoot)
326447
+ ];
326448
+ }
326250
326449
  function buildTools(repoRoot, config, contextWindowSize, modelTier) {
326251
326450
  const shellTool = new ShellTool(repoRoot);
326252
326451
  _shellToolRef = shellTool;
@@ -326468,19 +326667,7 @@ function createSubAgentTool(config, repoRoot, ctxWindowSize) {
326468
326667
  recursionDepth: parentDepth + 1,
326469
326668
  maxRecursionDepth: maxDepth
326470
326669
  });
326471
- const subTools = [
326472
- new FileReadTool(repoRoot),
326473
- new FileWriteTool(repoRoot),
326474
- new FileEditTool(repoRoot),
326475
- new ShellTool(repoRoot),
326476
- new GrepSearchTool(repoRoot),
326477
- new GlobFindTool(repoRoot),
326478
- new ListDirectoryTool(repoRoot),
326479
- new WebFetchTool(),
326480
- new WebSearchTool(),
326481
- new MemoryReadTool(repoRoot),
326482
- new MemoryWriteTool(repoRoot)
326483
- ];
326670
+ const subTools = buildSubAgentTools(repoRoot, config);
326484
326671
  subRunner.registerTools(subTools.map(adaptTool6));
326485
326672
  subRunner.registerTool(createTaskCompleteTool());
326486
326673
  if (background) {
@@ -328354,27 +328541,12 @@ Review its full output in the [${id}] tab or via sub_agent(action='output', id='
328354
328541
  // sub-agents discover their own context window
328355
328542
  modelTier: subTier
328356
328543
  });
328357
- const subToolInstances = [];
328358
- const nameSet = new Set(opts.toolNames);
328359
- const toolMap = {
328360
- file_read: () => new FileReadTool(repoRoot),
328361
- file_write: () => new FileWriteTool(repoRoot),
328362
- file_edit: () => new FileEditTool(repoRoot),
328363
- shell: () => new ShellTool(repoRoot),
328364
- grep: () => new GrepSearchTool(repoRoot),
328365
- glob: () => new GlobFindTool(repoRoot),
328366
- list_directory: () => new ListDirectoryTool(repoRoot),
328367
- web_fetch: () => new WebFetchTool(),
328368
- web_search: () => new WebSearchTool(),
328369
- memory_read: () => new MemoryReadTool(repoRoot),
328370
- memory_write: () => new MemoryWriteTool(repoRoot),
328371
- batch_edit: () => new BatchEditTool(repoRoot),
328372
- file_patch: () => new FilePatchTool(repoRoot),
328373
- git_info: () => new GitInfoTool(repoRoot)
328374
- };
328375
- for (const [name10, factory] of Object.entries(toolMap)) {
328376
- if (nameSet.has(name10)) subToolInstances.push(factory());
328377
- }
328544
+ const allSafe = buildSubAgentTools(repoRoot, config);
328545
+ const nameSet = new Set(opts.toolNames || []);
328546
+ const subToolInstances = nameSet.size > 0 ? allSafe.filter((t2) => nameSet.has(t2.name)) : allSafe.slice();
328547
+ const nameOf = (t2) => t2.name;
328548
+ if (!subToolInstances.some((t2) => nameOf(t2) === "todo_write")) subToolInstances.push(new TodoWriteTool());
328549
+ if (!subToolInstances.some((t2) => nameOf(t2) === "todo_read")) subToolInstances.push(new TodoReadTool());
328378
328550
  subRunner.registerTools(subToolInstances.map(adaptTool6));
328379
328551
  subRunner.registerTool(createTaskCompleteTool(subTier));
328380
328552
  const systemCtx = opts.systemPromptAddition ? `Working directory: ${repoRoot}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.230",
3
+ "version": "0.187.232",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",