open-agents-ai 0.156.0 → 0.157.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +314 -35
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20678,6 +20678,273 @@ var init_process_health = __esm({
20678
20678
  }
20679
20679
  });
20680
20680
 
20681
+ // packages/execution/dist/tools/full-sub-agent.js
20682
+ import { spawn as spawn13, ChildProcess } from "node:child_process";
20683
+ import { randomBytes as randomBytes10 } from "node:crypto";
20684
+ function buildSubProcessArgs(opts) {
20685
+ const args = [];
20686
+ args.push(opts.task);
20687
+ if (opts.model)
20688
+ args.push("--model", opts.model);
20689
+ if (opts.backendUrl)
20690
+ args.push("--backend-url", opts.backendUrl);
20691
+ if (opts.backendType)
20692
+ args.push("--backend", opts.backendType);
20693
+ if (opts.repoPath)
20694
+ args.push("--repo", opts.repoPath);
20695
+ if (opts.maxRetries !== void 0)
20696
+ args.push("--max-retries", String(opts.maxRetries));
20697
+ if (opts.timeoutMs !== void 0)
20698
+ args.push("--timeout-ms", String(opts.timeoutMs));
20699
+ if (opts.offline)
20700
+ args.push("--offline");
20701
+ return args;
20702
+ }
20703
+ function findOaBinary3() {
20704
+ const running = process.argv[1];
20705
+ if (running && (running.endsWith("/oa") || running.endsWith("/open-agents") || running.includes("bin/oa") || running.includes("dist/index"))) {
20706
+ return running;
20707
+ }
20708
+ return "oa";
20709
+ }
20710
+ function spawnFullSubAgent(task, opts, onOutput, onComplete) {
20711
+ const id = `oa-fl-${randomBytes10(2).toString("hex")}`;
20712
+ const oaBin = findOaBinary3();
20713
+ const cliArgs = buildSubProcessArgs({
20714
+ task,
20715
+ model: opts.model,
20716
+ backendUrl: opts.backendUrl,
20717
+ backendType: opts.backendType,
20718
+ repoPath: opts.workingDir,
20719
+ maxRetries: opts.maxRetries,
20720
+ timeoutMs: opts.timeoutMs,
20721
+ offline: opts.offline
20722
+ });
20723
+ const child = spawn13("node", [oaBin, ...cliArgs], {
20724
+ cwd: opts.workingDir || process.cwd(),
20725
+ env: {
20726
+ ...process.env,
20727
+ OA_SUB_AGENT_ID: id,
20728
+ OA_PARENT_PID: String(process.pid),
20729
+ // Prevent sub-agent from spawning its own TUI
20730
+ NO_COLOR: "1",
20731
+ CI: "true"
20732
+ },
20733
+ stdio: ["pipe", "pipe", "pipe"],
20734
+ detached: true
20735
+ });
20736
+ child.unref();
20737
+ const outputBuffer = [];
20738
+ const entry = {
20739
+ id,
20740
+ process: child,
20741
+ pid: child.pid ?? 0,
20742
+ task,
20743
+ model: opts.model ?? "default",
20744
+ outputBuffer,
20745
+ status: "running",
20746
+ exitCode: null,
20747
+ startedAt: Date.now()
20748
+ };
20749
+ child.stdout?.on("data", (chunk) => {
20750
+ const text = chunk.toString();
20751
+ const lines = text.split("\n").filter((l) => l.length > 0);
20752
+ outputBuffer.push(...lines);
20753
+ if (outputBuffer.length > 5e3)
20754
+ outputBuffer.splice(0, outputBuffer.length - 5e3);
20755
+ onOutput?.(text);
20756
+ });
20757
+ child.stderr?.on("data", (chunk) => {
20758
+ const text = chunk.toString();
20759
+ outputBuffer.push(...text.split("\n").filter((l) => l.length > 0));
20760
+ });
20761
+ child.on("exit", (code) => {
20762
+ entry.status = code === 0 ? "completed" : "failed";
20763
+ entry.exitCode = code;
20764
+ entry.completedAt = Date.now();
20765
+ const output = outputBuffer.join("\n");
20766
+ onComplete?.(id, code, output);
20767
+ });
20768
+ child.on("error", (err) => {
20769
+ entry.status = "failed";
20770
+ entry.exitCode = -1;
20771
+ outputBuffer.push(`Process error: ${err.message}`);
20772
+ onComplete?.(id, -1, outputBuffer.join("\n"));
20773
+ });
20774
+ _activeSubProcesses.set(id, entry);
20775
+ return entry;
20776
+ }
20777
+ function getFullSubAgent(id) {
20778
+ return _activeSubProcesses.get(id);
20779
+ }
20780
+ function getAllFullSubAgents() {
20781
+ return Array.from(_activeSubProcesses.values());
20782
+ }
20783
+ function stopFullSubAgent(id) {
20784
+ const entry = _activeSubProcesses.get(id);
20785
+ if (!entry || entry.status !== "running")
20786
+ return false;
20787
+ try {
20788
+ try {
20789
+ process.kill(-entry.pid, "SIGTERM");
20790
+ } catch {
20791
+ }
20792
+ entry.process.kill("SIGTERM");
20793
+ entry.status = "stopped";
20794
+ setTimeout(() => {
20795
+ try {
20796
+ process.kill(-entry.pid, "SIGKILL");
20797
+ } catch {
20798
+ }
20799
+ try {
20800
+ entry.process.kill("SIGKILL");
20801
+ } catch {
20802
+ }
20803
+ }, 5e3);
20804
+ return true;
20805
+ } catch {
20806
+ return false;
20807
+ }
20808
+ }
20809
+ function killAllFullSubAgents() {
20810
+ for (const [id, entry] of _activeSubProcesses) {
20811
+ if (entry.status === "running") {
20812
+ try {
20813
+ process.kill(-entry.pid, "SIGKILL");
20814
+ } catch {
20815
+ }
20816
+ try {
20817
+ entry.process.kill("SIGKILL");
20818
+ } catch {
20819
+ }
20820
+ entry.status = "stopped";
20821
+ }
20822
+ }
20823
+ }
20824
+ function removeFullSubAgent(id) {
20825
+ _activeSubProcesses.delete(id);
20826
+ }
20827
+ var _activeSubProcesses, FullSubAgentTool;
20828
+ var init_full_sub_agent = __esm({
20829
+ "packages/execution/dist/tools/full-sub-agent.js"() {
20830
+ "use strict";
20831
+ _activeSubProcesses = /* @__PURE__ */ new Map();
20832
+ FullSubAgentTool = class {
20833
+ name = "full_sub_agent";
20834
+ description = "Spawn a COMPLETE OA sub-process with ALL tools and capabilities. Unlike sub_agent (shared process, limited tools), this spawns a separate oa instance with its own clean context window, full tool set, memory, skills, and COHERE access. Use for complex multi-file tasks that benefit from a fresh context. The sub-process runs oa --non-interactive and its output appears in the tab bar. Returns immediately with a process ID for monitoring.";
20835
+ parameters = {
20836
+ type: "object",
20837
+ properties: {
20838
+ task: {
20839
+ type: "string",
20840
+ description: "Comprehensive task description / contract for the sub-agent"
20841
+ },
20842
+ model: {
20843
+ type: "string",
20844
+ description: "Model to use (default: same as parent)"
20845
+ },
20846
+ action: {
20847
+ type: "string",
20848
+ enum: ["spawn", "status", "output", "stop", "list"],
20849
+ description: "Action: spawn (default), status, output, stop, list"
20850
+ },
20851
+ id: {
20852
+ type: "string",
20853
+ description: "Sub-agent process ID (for status/output/stop)"
20854
+ }
20855
+ },
20856
+ required: []
20857
+ };
20858
+ workingDir;
20859
+ model;
20860
+ backendUrl;
20861
+ onViewRegister;
20862
+ onViewWrite;
20863
+ onViewStatus;
20864
+ constructor(workingDir, model, backendUrl, callbacks) {
20865
+ this.workingDir = workingDir;
20866
+ this.model = model ?? "";
20867
+ this.backendUrl = backendUrl ?? "http://localhost:11434";
20868
+ this.onViewRegister = callbacks?.onViewRegister;
20869
+ this.onViewWrite = callbacks?.onViewWrite;
20870
+ this.onViewStatus = callbacks?.onViewStatus;
20871
+ }
20872
+ async execute(args) {
20873
+ const action = String(args["action"] ?? "spawn");
20874
+ const start = performance.now();
20875
+ switch (action) {
20876
+ case "spawn": {
20877
+ const task = String(args["task"] ?? "");
20878
+ if (!task)
20879
+ return { success: false, output: "", error: "task is required", durationMs: performance.now() - start };
20880
+ const model = String(args["model"] ?? this.model);
20881
+ const entry = spawnFullSubAgent(task, { model, backendUrl: this.backendUrl, workingDir: this.workingDir }, (text) => this.onViewWrite?.(entry.id, text), (id, exitCode) => {
20882
+ this.onViewStatus?.(id, exitCode === 0 ? "completed" : "failed");
20883
+ });
20884
+ this.onViewRegister?.(entry.id, entry.id, "full");
20885
+ return {
20886
+ success: true,
20887
+ output: `Full OA sub-agent spawned: ${entry.id}
20888
+ PID: ${entry.pid}
20889
+ Model: ${model}
20890
+ Task: ${task.slice(0, 100)}
20891
+ Use full_sub_agent(action='status', id='${entry.id}') to check progress.
20892
+ Use full_sub_agent(action='output', id='${entry.id}') to see output.
20893
+ Use full_sub_agent(action='stop', id='${entry.id}') to kill it.`,
20894
+ durationMs: performance.now() - start
20895
+ };
20896
+ }
20897
+ case "status": {
20898
+ const id = String(args["id"] ?? "");
20899
+ if (id) {
20900
+ const entry = getFullSubAgent(id);
20901
+ if (!entry)
20902
+ return { success: false, output: "", error: `Unknown sub-agent: ${id}`, durationMs: performance.now() - start };
20903
+ const runtime = ((Date.now() - entry.startedAt) / 1e3).toFixed(0);
20904
+ return {
20905
+ success: true,
20906
+ output: `${id} [${entry.status}] PID:${entry.pid} ${runtime}s
20907
+ Task: ${entry.task.slice(0, 100)}
20908
+ Output lines: ${entry.outputBuffer.length}`,
20909
+ durationMs: performance.now() - start
20910
+ };
20911
+ }
20912
+ const all = getAllFullSubAgents();
20913
+ if (all.length === 0)
20914
+ return { success: true, output: "No full sub-agents running.", durationMs: performance.now() - start };
20915
+ const lines = all.map((e) => {
20916
+ const runtime = ((Date.now() - e.startedAt) / 1e3).toFixed(0);
20917
+ return `${e.id} [${e.status}] PID:${e.pid} ${runtime}s \u2014 ${e.task.slice(0, 60)}`;
20918
+ });
20919
+ return { success: true, output: lines.join("\n"), durationMs: performance.now() - start };
20920
+ }
20921
+ case "list":
20922
+ return this.execute({ ...args, action: "status" });
20923
+ case "output": {
20924
+ const id = String(args["id"] ?? "");
20925
+ const entry = getFullSubAgent(id);
20926
+ if (!entry)
20927
+ return { success: false, output: "", error: `Unknown sub-agent: ${id}`, durationMs: performance.now() - start };
20928
+ const tail = entry.outputBuffer.slice(-50).join("\n");
20929
+ return { success: true, output: `${id} output (last 50 lines):
20930
+ ${tail}`, durationMs: performance.now() - start };
20931
+ }
20932
+ case "stop": {
20933
+ const id = String(args["id"] ?? "");
20934
+ const ok = stopFullSubAgent(id);
20935
+ if (!ok)
20936
+ return { success: false, output: "", error: `Cannot stop ${id} \u2014 not running or not found`, durationMs: performance.now() - start };
20937
+ this.onViewStatus?.(id, "stopped");
20938
+ return { success: true, output: `Stopped ${id}`, durationMs: performance.now() - start };
20939
+ }
20940
+ default:
20941
+ return { success: false, output: "", error: `Unknown action: ${action}`, durationMs: performance.now() - start };
20942
+ }
20943
+ }
20944
+ };
20945
+ }
20946
+ });
20947
+
20681
20948
  // packages/execution/dist/tools/environment-snapshot.js
20682
20949
  import { execSync as execSync23 } from "node:child_process";
20683
20950
  import { cpus, totalmem, freemem, hostname as hostname2, platform, arch, uptime } from "node:os";
@@ -20971,14 +21238,14 @@ var init_fortemi_bridge = __esm({
20971
21238
  });
20972
21239
 
20973
21240
  // packages/execution/dist/shellRunner.js
20974
- import { spawn as spawn13 } from "node:child_process";
21241
+ import { spawn as spawn14 } from "node:child_process";
20975
21242
  async function runShell(options) {
20976
21243
  const { command, args = [], cwd: cwd4, env, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
20977
21244
  const mergedEnv = env ? { ...process.env, ...env } : process.env;
20978
21245
  return new Promise((resolve34) => {
20979
21246
  const start = Date.now();
20980
21247
  let timedOut = false;
20981
- const child = spawn13(command, args, {
21248
+ const child = spawn14(command, args, {
20982
21249
  cwd: cwd4,
20983
21250
  env: mergedEnv
20984
21251
  // Do NOT use shell:true — we pass command + args separately
@@ -21077,7 +21344,7 @@ var init_gitWorktree = __esm({
21077
21344
  // packages/execution/dist/patchApplier.js
21078
21345
  import { readFileSync as readFileSync21, writeFileSync as writeFileSync9, existsSync as existsSync28, mkdirSync as mkdirSync9 } from "node:fs";
21079
21346
  import { dirname as dirname12 } from "node:path";
21080
- import { spawn as spawn14 } from "node:child_process";
21347
+ import { spawn as spawn15 } from "node:child_process";
21081
21348
  async function applyPatch(patch) {
21082
21349
  switch (patch.type) {
21083
21350
  case "block-replace":
@@ -21127,7 +21394,7 @@ async function applyUnifiedDiff(patch) {
21127
21394
  function runWithStdin(options) {
21128
21395
  const { command, args, cwd: cwd4, stdin } = options;
21129
21396
  return new Promise((resolve34) => {
21130
- const child = spawn14(command, args, {
21397
+ const child = spawn15(command, args, {
21131
21398
  cwd: cwd4,
21132
21399
  stdio: ["pipe", "pipe", "pipe"]
21133
21400
  });
@@ -21598,6 +21865,7 @@ __export(dist_exports, {
21598
21865
  FilePatchTool: () => FilePatchTool,
21599
21866
  FileReadTool: () => FileReadTool,
21600
21867
  FileWriteTool: () => FileWriteTool,
21868
+ FullSubAgentTool: () => FullSubAgentTool,
21601
21869
  GitInfoTool: () => GitInfoTool,
21602
21870
  GlobFindTool: () => GlobFindTool,
21603
21871
  GrepSearchTool: () => GrepSearchTool,
@@ -21646,6 +21914,7 @@ __export(dist_exports, {
21646
21914
  buildCustomTools: () => buildCustomTools,
21647
21915
  buildGraph: () => buildGraph,
21648
21916
  buildSkillsSummary: () => buildSkillsSummary,
21917
+ buildSubProcessArgs: () => buildSubProcessArgs,
21649
21918
  checkDesktopDeps: () => checkDesktopDeps,
21650
21919
  clearExploreNotes: () => clearExploreNotes,
21651
21920
  clearWorkingNotes: () => clearWorkingNotes,
@@ -21659,16 +21928,19 @@ __export(dist_exports, {
21659
21928
  ensureDepsForGroup: () => ensureDepsForGroup,
21660
21929
  formatSnapshotForContext: () => formatSnapshotForContext,
21661
21930
  getActiveAttentionItems: () => getActiveAttentionItems,
21931
+ getAllFullSubAgents: () => getAllFullSubAgents,
21662
21932
  getDueReminders: () => getDueReminders,
21663
21933
  getExploreNotes: () => getExploreNotes,
21664
21934
  getFileChanges: () => getFileChanges,
21665
21935
  getFileNotes: () => getFileNotes,
21936
+ getFullSubAgent: () => getFullSubAgent,
21666
21937
  getRecentChangesSummary: () => getRecentChangesSummary,
21667
21938
  getSessionChanges: () => getSessionChanges,
21668
21939
  getWorkingNotes: () => getWorkingNotes,
21669
21940
  getWorkingNotesSummary: () => getWorkingNotesSummary,
21670
21941
  isFortemiAvailable: () => isFortemiAvailable,
21671
21942
  isImagePath: () => isImagePath,
21943
+ killAllFullSubAgents: () => killAllFullSubAgents,
21672
21944
  listCustomToolFiles: () => listCustomToolFiles,
21673
21945
  loadCustomTools: () => loadCustomTools,
21674
21946
  loadReminderStore: () => loadReminderStore,
@@ -21678,6 +21950,7 @@ __export(dist_exports, {
21678
21950
  markSessionValidated: () => markSessionValidated,
21679
21951
  promoteWorkingNotes: () => promoteWorkingNotes,
21680
21952
  recordChange: () => recordChange,
21953
+ removeFullSubAgent: () => removeFullSubAgent,
21681
21954
  removeWorktree: () => removeWorktree,
21682
21955
  resetDepCache: () => resetDepCache,
21683
21956
  resetMoondreamClient: () => resetMoondreamClient,
@@ -21693,6 +21966,8 @@ __export(dist_exports, {
21693
21966
  serializeMap: () => serializeMap,
21694
21967
  setChangeLogSession: () => setChangeLogSession,
21695
21968
  setSudoPassword: () => setSudoPassword,
21969
+ spawnFullSubAgent: () => spawnFullSubAgent,
21970
+ stopFullSubAgent: () => stopFullSubAgent,
21696
21971
  touchFile: () => touchFile
21697
21972
  });
21698
21973
  var init_dist2 = __esm({
@@ -21757,6 +22032,7 @@ var init_dist2 = __esm({
21757
22032
  init_change_log();
21758
22033
  init_repo_map();
21759
22034
  init_process_health();
22035
+ init_full_sub_agent();
21760
22036
  init_environment_snapshot();
21761
22037
  init_nexus();
21762
22038
  init_fortemi_bridge();
@@ -27393,7 +27669,7 @@ import { existsSync as existsSync30, statSync as statSync10, openSync, readSync,
27393
27669
  import { watch as fsWatch } from "node:fs";
27394
27670
  import { join as join45 } from "node:path";
27395
27671
  import { tmpdir as tmpdir7 } from "node:os";
27396
- import { randomBytes as randomBytes10 } from "node:crypto";
27672
+ import { randomBytes as randomBytes11 } from "node:crypto";
27397
27673
  var NexusAgenticBackend;
27398
27674
  var init_nexusBackend = __esm({
27399
27675
  "packages/orchestrator/dist/nexusBackend.js"() {
@@ -27541,7 +27817,7 @@ var init_nexusBackend = __esm({
27541
27817
  * Falls back to unary + word-split if streaming setup fails.
27542
27818
  */
27543
27819
  async *chatCompletionStream(request) {
27544
- const streamFile = join45(tmpdir7(), `nexus-stream-${randomBytes10(6).toString("hex")}.jsonl`);
27820
+ const streamFile = join45(tmpdir7(), `nexus-stream-${randomBytes11(6).toString("hex")}.jsonl`);
27545
27821
  writeFileSync10(streamFile, "", "utf8");
27546
27822
  const daemonArgs = {
27547
27823
  model: this.model,
@@ -28576,7 +28852,7 @@ __export(listen_exports, {
28576
28852
  isVideoPath: () => isVideoPath,
28577
28853
  waitForTranscribeCli: () => waitForTranscribeCli
28578
28854
  });
28579
- import { spawn as spawn15, execSync as execSync24 } from "node:child_process";
28855
+ import { spawn as spawn16, execSync as execSync24 } from "node:child_process";
28580
28856
  import { existsSync as existsSync31, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, readdirSync as readdirSync7 } from "node:fs";
28581
28857
  import { join as join46, dirname as dirname14 } from "node:path";
28582
28858
  import { homedir as homedir10 } from "node:os";
@@ -28786,7 +29062,7 @@ var init_listen = __esm({
28786
29062
  const timeout = setTimeout(() => {
28787
29063
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
28788
29064
  }, 3e5);
28789
- this.process = spawn15("python3", [
29065
+ this.process = spawn16("python3", [
28790
29066
  this.scriptPath,
28791
29067
  "--model",
28792
29068
  this.model,
@@ -29068,7 +29344,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
29068
29344
  return `Failed to start live transcription: ${msg}${tcHint}`;
29069
29345
  }
29070
29346
  }
29071
- this.micProcess = spawn15(micCmd.cmd, micCmd.args, {
29347
+ this.micProcess = spawn16(micCmd.cmd, micCmd.args, {
29072
29348
  stdio: ["pipe", "pipe", "pipe"],
29073
29349
  env: { ...process.env }
29074
29350
  });
@@ -31487,7 +31763,7 @@ var require_websocket = __commonJS({
31487
31763
  var http = __require("http");
31488
31764
  var net = __require("net");
31489
31765
  var tls = __require("tls");
31490
- var { randomBytes: randomBytes14, createHash: createHash5 } = __require("crypto");
31766
+ var { randomBytes: randomBytes15, createHash: createHash5 } = __require("crypto");
31491
31767
  var { Duplex, Readable } = __require("stream");
31492
31768
  var { URL: URL3 } = __require("url");
31493
31769
  var PerMessageDeflate = require_permessage_deflate();
@@ -32017,7 +32293,7 @@ var require_websocket = __commonJS({
32017
32293
  }
32018
32294
  }
32019
32295
  const defaultPort = isSecure ? 443 : 80;
32020
- const key = randomBytes14(16).toString("base64");
32296
+ const key = randomBytes15(16).toString("base64");
32021
32297
  const request = isSecure ? https.request : http.request;
32022
32298
  const protocolSet = /* @__PURE__ */ new Set();
32023
32299
  let perMessageDeflate;
@@ -33726,7 +34002,7 @@ var init_render = __esm({
33726
34002
 
33727
34003
  // packages/cli/dist/tui/voice-session.js
33728
34004
  import { createServer as createServer2 } from "node:http";
33729
- import { spawn as spawn16, execSync as execSync25 } from "node:child_process";
34005
+ import { spawn as spawn17, execSync as execSync25 } from "node:child_process";
33730
34006
  import { EventEmitter as EventEmitter2 } from "node:events";
33731
34007
  function generateFrontendHTML() {
33732
34008
  return `<!DOCTYPE html>
@@ -34380,7 +34656,7 @@ var init_voice_session = __esm({
34380
34656
  const timeout = setTimeout(() => {
34381
34657
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
34382
34658
  }, 3e4);
34383
- this.cloudflaredProcess = spawn16("cloudflared", [
34659
+ this.cloudflaredProcess = spawn17("cloudflared", [
34384
34660
  "tunnel",
34385
34661
  "--url",
34386
34662
  `http://127.0.0.1:${port}`
@@ -34454,9 +34730,9 @@ var init_voice_session = __esm({
34454
34730
 
34455
34731
  // packages/cli/dist/tui/expose.js
34456
34732
  import { createServer as createServer3, request as httpRequest } from "node:http";
34457
- import { spawn as spawn17, exec } from "node:child_process";
34733
+ import { spawn as spawn18, exec } from "node:child_process";
34458
34734
  import { EventEmitter as EventEmitter3 } from "node:events";
34459
- import { randomBytes as randomBytes11 } from "node:crypto";
34735
+ import { randomBytes as randomBytes12 } from "node:crypto";
34460
34736
  import { URL as URL2 } from "node:url";
34461
34737
  import { loadavg, cpus as cpus2, totalmem as totalmem2, freemem as freemem2 } from "node:os";
34462
34738
  import { existsSync as existsSync32, readFileSync as readFileSync23, writeFileSync as writeFileSync12, unlinkSync as unlinkSync5, mkdirSync as mkdirSync11, readdirSync as readdirSync8, statSync as statSync11 } from "node:fs";
@@ -34701,7 +34977,7 @@ var init_expose = __esm({
34701
34977
  this._stateDir = options.stateDir ?? null;
34702
34978
  this._fullAccess = options.fullAccess ?? false;
34703
34979
  if (options.authKey === void 0 || options.authKey === "") {
34704
- this._authKey = randomBytes11(24).toString("base64url");
34980
+ this._authKey = randomBytes12(24).toString("base64url");
34705
34981
  } else {
34706
34982
  this._authKey = options.authKey;
34707
34983
  }
@@ -35138,7 +35414,7 @@ var init_expose = __esm({
35138
35414
  const timeout = setTimeout(() => {
35139
35415
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
35140
35416
  }, 3e4);
35141
- this.cloudflaredProcess = spawn17("cloudflared", [
35417
+ this.cloudflaredProcess = spawn18("cloudflared", [
35142
35418
  "tunnel",
35143
35419
  "--url",
35144
35420
  `http://127.0.0.1:${port}`,
@@ -35429,7 +35705,7 @@ ${this.formatConnectionInfo()}`);
35429
35705
  this._onInfo = options.onInfo;
35430
35706
  this._onError = options.onError;
35431
35707
  if (options.authKey === void 0 || options.authKey === "") {
35432
- this._authKey = randomBytes11(24).toString("base64url");
35708
+ this._authKey = randomBytes12(24).toString("base64url");
35433
35709
  } else {
35434
35710
  this._authKey = options.authKey;
35435
35711
  }
@@ -35875,7 +36151,7 @@ var init_types = __esm({
35875
36151
  });
35876
36152
 
35877
36153
  // packages/cli/dist/tui/p2p/secret-vault.js
35878
- import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes12, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
36154
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes13, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
35879
36155
  import { readFileSync as readFileSync24, writeFileSync as writeFileSync13, existsSync as existsSync33, mkdirSync as mkdirSync12 } from "node:fs";
35880
36156
  import { join as join48, dirname as dirname15 } from "node:path";
35881
36157
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
@@ -36081,9 +36357,9 @@ var init_secret_vault = __esm({
36081
36357
  minTrust: s.minTrust,
36082
36358
  createdAt: s.createdAt
36083
36359
  })));
36084
- const salt = randomBytes12(SALT_LEN);
36360
+ const salt = randomBytes13(SALT_LEN);
36085
36361
  const key = scryptSync2(passphrase, salt, KEY_LEN);
36086
- const iv = randomBytes12(IV_LEN);
36362
+ const iv = randomBytes13(IV_LEN);
36087
36363
  const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
36088
36364
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
36089
36365
  const tag = cipher.getAuthTag();
@@ -36141,7 +36417,7 @@ var init_secret_vault = __esm({
36141
36417
  // packages/cli/dist/tui/p2p/peer-mesh.js
36142
36418
  import { EventEmitter as EventEmitter4 } from "node:events";
36143
36419
  import { createServer as createServer4 } from "node:http";
36144
- import { randomBytes as randomBytes13, createHash as createHash3, generateKeyPairSync } from "node:crypto";
36420
+ import { randomBytes as randomBytes14, createHash as createHash3, generateKeyPairSync } from "node:crypto";
36145
36421
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
36146
36422
  var init_peer_mesh = __esm({
36147
36423
  "packages/cli/dist/tui/p2p/peer-mesh.js"() {
@@ -36193,7 +36469,7 @@ var init_peer_mesh = __esm({
36193
36469
  this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
36194
36470
  this.capabilities = options.capabilities;
36195
36471
  this.displayName = options.displayName;
36196
- this._authKey = options.authKey ?? randomBytes13(24).toString("base64url");
36472
+ this._authKey = options.authKey ?? randomBytes14(24).toString("base64url");
36197
36473
  }
36198
36474
  // ── Lifecycle ───────────────────────────────────────────────────────────
36199
36475
  /** Start the mesh node — creates WS server and connects to bootstrap peers */
@@ -36357,7 +36633,7 @@ var init_peer_mesh = __esm({
36357
36633
  if (!ws || ws.readyState !== import_websocket.default.OPEN) {
36358
36634
  throw new Error(`Peer ${peerId} not connected`);
36359
36635
  }
36360
- const msgId = randomBytes13(8).toString("hex");
36636
+ const msgId = randomBytes14(8).toString("hex");
36361
36637
  return new Promise((resolve34, reject) => {
36362
36638
  const timeout = setTimeout(() => {
36363
36639
  this.pendingRequests.delete(msgId);
@@ -36578,7 +36854,7 @@ var init_peer_mesh = __esm({
36578
36854
  const msg = {
36579
36855
  type,
36580
36856
  from: this.peerId,
36581
- msgId: msgId ?? randomBytes13(8).toString("hex"),
36857
+ msgId: msgId ?? randomBytes14(8).toString("hex"),
36582
36858
  ts: (/* @__PURE__ */ new Date()).toISOString(),
36583
36859
  payload
36584
36860
  };
@@ -38356,7 +38632,7 @@ var init_oa_directory = __esm({
38356
38632
 
38357
38633
  // packages/cli/dist/tui/setup.js
38358
38634
  import * as readline from "node:readline";
38359
- import { execSync as execSync26, spawn as spawn18, exec as exec2 } from "node:child_process";
38635
+ import { execSync as execSync26, spawn as spawn19, exec as exec2 } from "node:child_process";
38360
38636
  import { promisify as promisify6 } from "node:util";
38361
38637
  import { existsSync as existsSync36, writeFileSync as writeFileSync15, readFileSync as readFileSync27, appendFileSync as appendFileSync2, mkdirSync as mkdirSync14 } from "node:fs";
38362
38638
  import { join as join52 } from "node:path";
@@ -38754,7 +39030,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
38754
39030
  process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
38755
39031
  `);
38756
39032
  try {
38757
- const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
39033
+ const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
38758
39034
  child.unref();
38759
39035
  } catch {
38760
39036
  process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
@@ -39222,7 +39498,7 @@ async function doSetup(config, rl) {
39222
39498
  ${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
39223
39499
  `);
39224
39500
  try {
39225
- const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
39501
+ const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
39226
39502
  child.unref();
39227
39503
  await new Promise((resolve34) => setTimeout(resolve34, 3e3));
39228
39504
  try {
@@ -39250,7 +39526,7 @@ async function doSetup(config, rl) {
39250
39526
  ${c2.cyan("\u25CF")} Starting ollama serve...
39251
39527
  `);
39252
39528
  try {
39253
- const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
39529
+ const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
39254
39530
  child.unref();
39255
39531
  await new Promise((resolve34) => setTimeout(resolve34, 3e3));
39256
39532
  try {
@@ -45156,8 +45432,8 @@ async function handleSlashCommand(input, ctx) {
45156
45432
  writeFileSync17(jwtFile, JSON.stringify(jwtPayload, null, 2));
45157
45433
  renderInfo(`Launching fortemi-react from ${fDir}...`);
45158
45434
  try {
45159
- const { spawn: spawn20 } = __require("node:child_process");
45160
- const child = spawn20("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
45435
+ const { spawn: spawn21 } = __require("node:child_process");
45436
+ const child = spawn21("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
45161
45437
  cwd: join55(fDir, "apps", "standalone"),
45162
45438
  stdio: "ignore",
45163
45439
  detached: true,
@@ -47566,8 +47842,8 @@ Environment="OLLAMA_NUM_PARALLEL=${n}"
47566
47842
  }
47567
47843
  await new Promise((r) => setTimeout(r, 1e3));
47568
47844
  process.env.OLLAMA_NUM_PARALLEL = String(n);
47569
- const { spawn: spawn20 } = await import("node:child_process");
47570
- const child = spawn20("ollama", ["serve"], {
47845
+ const { spawn: spawn21 } = await import("node:child_process");
47846
+ const child = spawn21("ollama", ["serve"], {
47571
47847
  stdio: "ignore",
47572
47848
  detached: true,
47573
47849
  env: { ...process.env, OLLAMA_NUM_PARALLEL: String(n) }
@@ -58865,6 +59141,8 @@ function buildTools(repoRoot, config, contextWindowSize) {
58865
59141
  new SemanticMapTool(repoRoot),
58866
59142
  new RepoMapTool(repoRoot),
58867
59143
  new ProcessHealthTool(),
59144
+ // Full OA sub-process spawning (wired to tab bar later via setStatusBar)
59145
+ new FullSubAgentTool(repoRoot, config.model, config.backendUrl),
58868
59146
  // Nexus P2P networking + x402 micropayments
58869
59147
  new NexusTool(repoRoot)
58870
59148
  ];
@@ -60037,6 +60315,7 @@ async function startInteractive(config, repoPath) {
60037
60315
  const cleanupAndExit = (code) => {
60038
60316
  if (_shellToolRef)
60039
60317
  _shellToolRef.killAll();
60318
+ killAllFullSubAgents();
60040
60319
  restoreScreen();
60041
60320
  process.exit(code);
60042
60321
  };
@@ -63924,7 +64203,7 @@ var serve_exports = {};
63924
64203
  __export(serve_exports, {
63925
64204
  serveCommand: () => serveCommand
63926
64205
  });
63927
- import { spawn as spawn19 } from "node:child_process";
64206
+ import { spawn as spawn20 } from "node:child_process";
63928
64207
  async function serveCommand(opts, config) {
63929
64208
  const backendType = config.backendType;
63930
64209
  if (backendType === "ollama") {
@@ -64017,7 +64296,7 @@ async function serveVllm(opts, config) {
64017
64296
  }
64018
64297
  async function runVllmServer(args, verbose) {
64019
64298
  return new Promise((resolve34, reject) => {
64020
- const child = spawn19("python", args, {
64299
+ const child = spawn20("python", args, {
64021
64300
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
64022
64301
  env: { ...process.env }
64023
64302
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.156.0",
3
+ "version": "0.157.0",
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",