open-agents-ai 0.156.0 → 0.158.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 +366 -37
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20678,6 +20678,285 @@ 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
+ onComplete;
20865
+ /**
20866
+ * Wire callbacks after construction (needed because StatusBar and Runner
20867
+ * are created after the tool array). Call this once from interactive.ts.
20868
+ */
20869
+ setCallbacks(callbacks) {
20870
+ this.onViewRegister = callbacks.onViewRegister;
20871
+ this.onViewWrite = callbacks.onViewWrite;
20872
+ this.onViewStatus = callbacks.onViewStatus;
20873
+ this.onComplete = callbacks.onComplete;
20874
+ }
20875
+ constructor(workingDir, model, backendUrl, callbacks) {
20876
+ this.workingDir = workingDir;
20877
+ this.model = model ?? "";
20878
+ this.backendUrl = backendUrl ?? "http://localhost:11434";
20879
+ this.onViewRegister = callbacks?.onViewRegister;
20880
+ this.onViewWrite = callbacks?.onViewWrite;
20881
+ this.onViewStatus = callbacks?.onViewStatus;
20882
+ }
20883
+ async execute(args) {
20884
+ const action = String(args["action"] ?? "spawn");
20885
+ const start = performance.now();
20886
+ switch (action) {
20887
+ case "spawn": {
20888
+ const task = String(args["task"] ?? "");
20889
+ if (!task)
20890
+ return { success: false, output: "", error: "task is required", durationMs: performance.now() - start };
20891
+ const model = String(args["model"] ?? this.model);
20892
+ const entry = spawnFullSubAgent(task, { model, backendUrl: this.backendUrl, workingDir: this.workingDir }, (text) => this.onViewWrite?.(entry.id, text), (id, exitCode, output) => {
20893
+ this.onViewStatus?.(id, exitCode === 0 ? "completed" : "failed");
20894
+ this.onComplete?.(id, task, exitCode, output);
20895
+ });
20896
+ this.onViewRegister?.(entry.id, entry.id, "full");
20897
+ return {
20898
+ success: true,
20899
+ output: `Full OA sub-agent spawned: ${entry.id}
20900
+ PID: ${entry.pid}
20901
+ Model: ${model}
20902
+ Task: ${task.slice(0, 100)}
20903
+ Use full_sub_agent(action='status', id='${entry.id}') to check progress.
20904
+ Use full_sub_agent(action='output', id='${entry.id}') to see output.
20905
+ Use full_sub_agent(action='stop', id='${entry.id}') to kill it.`,
20906
+ durationMs: performance.now() - start
20907
+ };
20908
+ }
20909
+ case "status": {
20910
+ const id = String(args["id"] ?? "");
20911
+ if (id) {
20912
+ const entry = getFullSubAgent(id);
20913
+ if (!entry)
20914
+ return { success: false, output: "", error: `Unknown sub-agent: ${id}`, durationMs: performance.now() - start };
20915
+ const runtime = ((Date.now() - entry.startedAt) / 1e3).toFixed(0);
20916
+ return {
20917
+ success: true,
20918
+ output: `${id} [${entry.status}] PID:${entry.pid} ${runtime}s
20919
+ Task: ${entry.task.slice(0, 100)}
20920
+ Output lines: ${entry.outputBuffer.length}`,
20921
+ durationMs: performance.now() - start
20922
+ };
20923
+ }
20924
+ const all = getAllFullSubAgents();
20925
+ if (all.length === 0)
20926
+ return { success: true, output: "No full sub-agents running.", durationMs: performance.now() - start };
20927
+ const lines = all.map((e) => {
20928
+ const runtime = ((Date.now() - e.startedAt) / 1e3).toFixed(0);
20929
+ return `${e.id} [${e.status}] PID:${e.pid} ${runtime}s \u2014 ${e.task.slice(0, 60)}`;
20930
+ });
20931
+ return { success: true, output: lines.join("\n"), durationMs: performance.now() - start };
20932
+ }
20933
+ case "list":
20934
+ return this.execute({ ...args, action: "status" });
20935
+ case "output": {
20936
+ const id = String(args["id"] ?? "");
20937
+ const entry = getFullSubAgent(id);
20938
+ if (!entry)
20939
+ return { success: false, output: "", error: `Unknown sub-agent: ${id}`, durationMs: performance.now() - start };
20940
+ const tail = entry.outputBuffer.slice(-50).join("\n");
20941
+ return { success: true, output: `${id} output (last 50 lines):
20942
+ ${tail}`, durationMs: performance.now() - start };
20943
+ }
20944
+ case "stop": {
20945
+ const id = String(args["id"] ?? "");
20946
+ const ok = stopFullSubAgent(id);
20947
+ if (!ok)
20948
+ return { success: false, output: "", error: `Cannot stop ${id} \u2014 not running or not found`, durationMs: performance.now() - start };
20949
+ this.onViewStatus?.(id, "stopped");
20950
+ return { success: true, output: `Stopped ${id}`, durationMs: performance.now() - start };
20951
+ }
20952
+ default:
20953
+ return { success: false, output: "", error: `Unknown action: ${action}`, durationMs: performance.now() - start };
20954
+ }
20955
+ }
20956
+ };
20957
+ }
20958
+ });
20959
+
20681
20960
  // packages/execution/dist/tools/environment-snapshot.js
20682
20961
  import { execSync as execSync23 } from "node:child_process";
20683
20962
  import { cpus, totalmem, freemem, hostname as hostname2, platform, arch, uptime } from "node:os";
@@ -20971,14 +21250,14 @@ var init_fortemi_bridge = __esm({
20971
21250
  });
20972
21251
 
20973
21252
  // packages/execution/dist/shellRunner.js
20974
- import { spawn as spawn13 } from "node:child_process";
21253
+ import { spawn as spawn14 } from "node:child_process";
20975
21254
  async function runShell(options) {
20976
21255
  const { command, args = [], cwd: cwd4, env, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
20977
21256
  const mergedEnv = env ? { ...process.env, ...env } : process.env;
20978
21257
  return new Promise((resolve34) => {
20979
21258
  const start = Date.now();
20980
21259
  let timedOut = false;
20981
- const child = spawn13(command, args, {
21260
+ const child = spawn14(command, args, {
20982
21261
  cwd: cwd4,
20983
21262
  env: mergedEnv
20984
21263
  // Do NOT use shell:true — we pass command + args separately
@@ -21077,7 +21356,7 @@ var init_gitWorktree = __esm({
21077
21356
  // packages/execution/dist/patchApplier.js
21078
21357
  import { readFileSync as readFileSync21, writeFileSync as writeFileSync9, existsSync as existsSync28, mkdirSync as mkdirSync9 } from "node:fs";
21079
21358
  import { dirname as dirname12 } from "node:path";
21080
- import { spawn as spawn14 } from "node:child_process";
21359
+ import { spawn as spawn15 } from "node:child_process";
21081
21360
  async function applyPatch(patch) {
21082
21361
  switch (patch.type) {
21083
21362
  case "block-replace":
@@ -21127,7 +21406,7 @@ async function applyUnifiedDiff(patch) {
21127
21406
  function runWithStdin(options) {
21128
21407
  const { command, args, cwd: cwd4, stdin } = options;
21129
21408
  return new Promise((resolve34) => {
21130
- const child = spawn14(command, args, {
21409
+ const child = spawn15(command, args, {
21131
21410
  cwd: cwd4,
21132
21411
  stdio: ["pipe", "pipe", "pipe"]
21133
21412
  });
@@ -21598,6 +21877,7 @@ __export(dist_exports, {
21598
21877
  FilePatchTool: () => FilePatchTool,
21599
21878
  FileReadTool: () => FileReadTool,
21600
21879
  FileWriteTool: () => FileWriteTool,
21880
+ FullSubAgentTool: () => FullSubAgentTool,
21601
21881
  GitInfoTool: () => GitInfoTool,
21602
21882
  GlobFindTool: () => GlobFindTool,
21603
21883
  GrepSearchTool: () => GrepSearchTool,
@@ -21646,6 +21926,7 @@ __export(dist_exports, {
21646
21926
  buildCustomTools: () => buildCustomTools,
21647
21927
  buildGraph: () => buildGraph,
21648
21928
  buildSkillsSummary: () => buildSkillsSummary,
21929
+ buildSubProcessArgs: () => buildSubProcessArgs,
21649
21930
  checkDesktopDeps: () => checkDesktopDeps,
21650
21931
  clearExploreNotes: () => clearExploreNotes,
21651
21932
  clearWorkingNotes: () => clearWorkingNotes,
@@ -21659,16 +21940,19 @@ __export(dist_exports, {
21659
21940
  ensureDepsForGroup: () => ensureDepsForGroup,
21660
21941
  formatSnapshotForContext: () => formatSnapshotForContext,
21661
21942
  getActiveAttentionItems: () => getActiveAttentionItems,
21943
+ getAllFullSubAgents: () => getAllFullSubAgents,
21662
21944
  getDueReminders: () => getDueReminders,
21663
21945
  getExploreNotes: () => getExploreNotes,
21664
21946
  getFileChanges: () => getFileChanges,
21665
21947
  getFileNotes: () => getFileNotes,
21948
+ getFullSubAgent: () => getFullSubAgent,
21666
21949
  getRecentChangesSummary: () => getRecentChangesSummary,
21667
21950
  getSessionChanges: () => getSessionChanges,
21668
21951
  getWorkingNotes: () => getWorkingNotes,
21669
21952
  getWorkingNotesSummary: () => getWorkingNotesSummary,
21670
21953
  isFortemiAvailable: () => isFortemiAvailable,
21671
21954
  isImagePath: () => isImagePath,
21955
+ killAllFullSubAgents: () => killAllFullSubAgents,
21672
21956
  listCustomToolFiles: () => listCustomToolFiles,
21673
21957
  loadCustomTools: () => loadCustomTools,
21674
21958
  loadReminderStore: () => loadReminderStore,
@@ -21678,6 +21962,7 @@ __export(dist_exports, {
21678
21962
  markSessionValidated: () => markSessionValidated,
21679
21963
  promoteWorkingNotes: () => promoteWorkingNotes,
21680
21964
  recordChange: () => recordChange,
21965
+ removeFullSubAgent: () => removeFullSubAgent,
21681
21966
  removeWorktree: () => removeWorktree,
21682
21967
  resetDepCache: () => resetDepCache,
21683
21968
  resetMoondreamClient: () => resetMoondreamClient,
@@ -21693,6 +21978,8 @@ __export(dist_exports, {
21693
21978
  serializeMap: () => serializeMap,
21694
21979
  setChangeLogSession: () => setChangeLogSession,
21695
21980
  setSudoPassword: () => setSudoPassword,
21981
+ spawnFullSubAgent: () => spawnFullSubAgent,
21982
+ stopFullSubAgent: () => stopFullSubAgent,
21696
21983
  touchFile: () => touchFile
21697
21984
  });
21698
21985
  var init_dist2 = __esm({
@@ -21757,6 +22044,7 @@ var init_dist2 = __esm({
21757
22044
  init_change_log();
21758
22045
  init_repo_map();
21759
22046
  init_process_health();
22047
+ init_full_sub_agent();
21760
22048
  init_environment_snapshot();
21761
22049
  init_nexus();
21762
22050
  init_fortemi_bridge();
@@ -27393,7 +27681,7 @@ import { existsSync as existsSync30, statSync as statSync10, openSync, readSync,
27393
27681
  import { watch as fsWatch } from "node:fs";
27394
27682
  import { join as join45 } from "node:path";
27395
27683
  import { tmpdir as tmpdir7 } from "node:os";
27396
- import { randomBytes as randomBytes10 } from "node:crypto";
27684
+ import { randomBytes as randomBytes11 } from "node:crypto";
27397
27685
  var NexusAgenticBackend;
27398
27686
  var init_nexusBackend = __esm({
27399
27687
  "packages/orchestrator/dist/nexusBackend.js"() {
@@ -27541,7 +27829,7 @@ var init_nexusBackend = __esm({
27541
27829
  * Falls back to unary + word-split if streaming setup fails.
27542
27830
  */
27543
27831
  async *chatCompletionStream(request) {
27544
- const streamFile = join45(tmpdir7(), `nexus-stream-${randomBytes10(6).toString("hex")}.jsonl`);
27832
+ const streamFile = join45(tmpdir7(), `nexus-stream-${randomBytes11(6).toString("hex")}.jsonl`);
27545
27833
  writeFileSync10(streamFile, "", "utf8");
27546
27834
  const daemonArgs = {
27547
27835
  model: this.model,
@@ -28576,7 +28864,7 @@ __export(listen_exports, {
28576
28864
  isVideoPath: () => isVideoPath,
28577
28865
  waitForTranscribeCli: () => waitForTranscribeCli
28578
28866
  });
28579
- import { spawn as spawn15, execSync as execSync24 } from "node:child_process";
28867
+ import { spawn as spawn16, execSync as execSync24 } from "node:child_process";
28580
28868
  import { existsSync as existsSync31, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, readdirSync as readdirSync7 } from "node:fs";
28581
28869
  import { join as join46, dirname as dirname14 } from "node:path";
28582
28870
  import { homedir as homedir10 } from "node:os";
@@ -28786,7 +29074,7 @@ var init_listen = __esm({
28786
29074
  const timeout = setTimeout(() => {
28787
29075
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
28788
29076
  }, 3e5);
28789
- this.process = spawn15("python3", [
29077
+ this.process = spawn16("python3", [
28790
29078
  this.scriptPath,
28791
29079
  "--model",
28792
29080
  this.model,
@@ -29068,7 +29356,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
29068
29356
  return `Failed to start live transcription: ${msg}${tcHint}`;
29069
29357
  }
29070
29358
  }
29071
- this.micProcess = spawn15(micCmd.cmd, micCmd.args, {
29359
+ this.micProcess = spawn16(micCmd.cmd, micCmd.args, {
29072
29360
  stdio: ["pipe", "pipe", "pipe"],
29073
29361
  env: { ...process.env }
29074
29362
  });
@@ -31487,7 +31775,7 @@ var require_websocket = __commonJS({
31487
31775
  var http = __require("http");
31488
31776
  var net = __require("net");
31489
31777
  var tls = __require("tls");
31490
- var { randomBytes: randomBytes14, createHash: createHash5 } = __require("crypto");
31778
+ var { randomBytes: randomBytes15, createHash: createHash5 } = __require("crypto");
31491
31779
  var { Duplex, Readable } = __require("stream");
31492
31780
  var { URL: URL3 } = __require("url");
31493
31781
  var PerMessageDeflate = require_permessage_deflate();
@@ -32017,7 +32305,7 @@ var require_websocket = __commonJS({
32017
32305
  }
32018
32306
  }
32019
32307
  const defaultPort = isSecure ? 443 : 80;
32020
- const key = randomBytes14(16).toString("base64");
32308
+ const key = randomBytes15(16).toString("base64");
32021
32309
  const request = isSecure ? https.request : http.request;
32022
32310
  const protocolSet = /* @__PURE__ */ new Set();
32023
32311
  let perMessageDeflate;
@@ -33726,7 +34014,7 @@ var init_render = __esm({
33726
34014
 
33727
34015
  // packages/cli/dist/tui/voice-session.js
33728
34016
  import { createServer as createServer2 } from "node:http";
33729
- import { spawn as spawn16, execSync as execSync25 } from "node:child_process";
34017
+ import { spawn as spawn17, execSync as execSync25 } from "node:child_process";
33730
34018
  import { EventEmitter as EventEmitter2 } from "node:events";
33731
34019
  function generateFrontendHTML() {
33732
34020
  return `<!DOCTYPE html>
@@ -34380,7 +34668,7 @@ var init_voice_session = __esm({
34380
34668
  const timeout = setTimeout(() => {
34381
34669
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
34382
34670
  }, 3e4);
34383
- this.cloudflaredProcess = spawn16("cloudflared", [
34671
+ this.cloudflaredProcess = spawn17("cloudflared", [
34384
34672
  "tunnel",
34385
34673
  "--url",
34386
34674
  `http://127.0.0.1:${port}`
@@ -34454,9 +34742,9 @@ var init_voice_session = __esm({
34454
34742
 
34455
34743
  // packages/cli/dist/tui/expose.js
34456
34744
  import { createServer as createServer3, request as httpRequest } from "node:http";
34457
- import { spawn as spawn17, exec } from "node:child_process";
34745
+ import { spawn as spawn18, exec } from "node:child_process";
34458
34746
  import { EventEmitter as EventEmitter3 } from "node:events";
34459
- import { randomBytes as randomBytes11 } from "node:crypto";
34747
+ import { randomBytes as randomBytes12 } from "node:crypto";
34460
34748
  import { URL as URL2 } from "node:url";
34461
34749
  import { loadavg, cpus as cpus2, totalmem as totalmem2, freemem as freemem2 } from "node:os";
34462
34750
  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 +34989,7 @@ var init_expose = __esm({
34701
34989
  this._stateDir = options.stateDir ?? null;
34702
34990
  this._fullAccess = options.fullAccess ?? false;
34703
34991
  if (options.authKey === void 0 || options.authKey === "") {
34704
- this._authKey = randomBytes11(24).toString("base64url");
34992
+ this._authKey = randomBytes12(24).toString("base64url");
34705
34993
  } else {
34706
34994
  this._authKey = options.authKey;
34707
34995
  }
@@ -35138,7 +35426,7 @@ var init_expose = __esm({
35138
35426
  const timeout = setTimeout(() => {
35139
35427
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
35140
35428
  }, 3e4);
35141
- this.cloudflaredProcess = spawn17("cloudflared", [
35429
+ this.cloudflaredProcess = spawn18("cloudflared", [
35142
35430
  "tunnel",
35143
35431
  "--url",
35144
35432
  `http://127.0.0.1:${port}`,
@@ -35429,7 +35717,7 @@ ${this.formatConnectionInfo()}`);
35429
35717
  this._onInfo = options.onInfo;
35430
35718
  this._onError = options.onError;
35431
35719
  if (options.authKey === void 0 || options.authKey === "") {
35432
- this._authKey = randomBytes11(24).toString("base64url");
35720
+ this._authKey = randomBytes12(24).toString("base64url");
35433
35721
  } else {
35434
35722
  this._authKey = options.authKey;
35435
35723
  }
@@ -35875,7 +36163,7 @@ var init_types = __esm({
35875
36163
  });
35876
36164
 
35877
36165
  // 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";
36166
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes13, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
35879
36167
  import { readFileSync as readFileSync24, writeFileSync as writeFileSync13, existsSync as existsSync33, mkdirSync as mkdirSync12 } from "node:fs";
35880
36168
  import { join as join48, dirname as dirname15 } from "node:path";
35881
36169
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
@@ -36081,9 +36369,9 @@ var init_secret_vault = __esm({
36081
36369
  minTrust: s.minTrust,
36082
36370
  createdAt: s.createdAt
36083
36371
  })));
36084
- const salt = randomBytes12(SALT_LEN);
36372
+ const salt = randomBytes13(SALT_LEN);
36085
36373
  const key = scryptSync2(passphrase, salt, KEY_LEN);
36086
- const iv = randomBytes12(IV_LEN);
36374
+ const iv = randomBytes13(IV_LEN);
36087
36375
  const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
36088
36376
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
36089
36377
  const tag = cipher.getAuthTag();
@@ -36141,7 +36429,7 @@ var init_secret_vault = __esm({
36141
36429
  // packages/cli/dist/tui/p2p/peer-mesh.js
36142
36430
  import { EventEmitter as EventEmitter4 } from "node:events";
36143
36431
  import { createServer as createServer4 } from "node:http";
36144
- import { randomBytes as randomBytes13, createHash as createHash3, generateKeyPairSync } from "node:crypto";
36432
+ import { randomBytes as randomBytes14, createHash as createHash3, generateKeyPairSync } from "node:crypto";
36145
36433
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
36146
36434
  var init_peer_mesh = __esm({
36147
36435
  "packages/cli/dist/tui/p2p/peer-mesh.js"() {
@@ -36193,7 +36481,7 @@ var init_peer_mesh = __esm({
36193
36481
  this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
36194
36482
  this.capabilities = options.capabilities;
36195
36483
  this.displayName = options.displayName;
36196
- this._authKey = options.authKey ?? randomBytes13(24).toString("base64url");
36484
+ this._authKey = options.authKey ?? randomBytes14(24).toString("base64url");
36197
36485
  }
36198
36486
  // ── Lifecycle ───────────────────────────────────────────────────────────
36199
36487
  /** Start the mesh node — creates WS server and connects to bootstrap peers */
@@ -36357,7 +36645,7 @@ var init_peer_mesh = __esm({
36357
36645
  if (!ws || ws.readyState !== import_websocket.default.OPEN) {
36358
36646
  throw new Error(`Peer ${peerId} not connected`);
36359
36647
  }
36360
- const msgId = randomBytes13(8).toString("hex");
36648
+ const msgId = randomBytes14(8).toString("hex");
36361
36649
  return new Promise((resolve34, reject) => {
36362
36650
  const timeout = setTimeout(() => {
36363
36651
  this.pendingRequests.delete(msgId);
@@ -36578,7 +36866,7 @@ var init_peer_mesh = __esm({
36578
36866
  const msg = {
36579
36867
  type,
36580
36868
  from: this.peerId,
36581
- msgId: msgId ?? randomBytes13(8).toString("hex"),
36869
+ msgId: msgId ?? randomBytes14(8).toString("hex"),
36582
36870
  ts: (/* @__PURE__ */ new Date()).toISOString(),
36583
36871
  payload
36584
36872
  };
@@ -38356,7 +38644,7 @@ var init_oa_directory = __esm({
38356
38644
 
38357
38645
  // packages/cli/dist/tui/setup.js
38358
38646
  import * as readline from "node:readline";
38359
- import { execSync as execSync26, spawn as spawn18, exec as exec2 } from "node:child_process";
38647
+ import { execSync as execSync26, spawn as spawn19, exec as exec2 } from "node:child_process";
38360
38648
  import { promisify as promisify6 } from "node:util";
38361
38649
  import { existsSync as existsSync36, writeFileSync as writeFileSync15, readFileSync as readFileSync27, appendFileSync as appendFileSync2, mkdirSync as mkdirSync14 } from "node:fs";
38362
38650
  import { join as join52 } from "node:path";
@@ -38754,7 +39042,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
38754
39042
  process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
38755
39043
  `);
38756
39044
  try {
38757
- const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
39045
+ const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
38758
39046
  child.unref();
38759
39047
  } catch {
38760
39048
  process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
@@ -39222,7 +39510,7 @@ async function doSetup(config, rl) {
39222
39510
  ${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
39223
39511
  `);
39224
39512
  try {
39225
- const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
39513
+ const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
39226
39514
  child.unref();
39227
39515
  await new Promise((resolve34) => setTimeout(resolve34, 3e3));
39228
39516
  try {
@@ -39250,7 +39538,7 @@ async function doSetup(config, rl) {
39250
39538
  ${c2.cyan("\u25CF")} Starting ollama serve...
39251
39539
  `);
39252
39540
  try {
39253
- const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
39541
+ const child = spawn19("ollama", ["serve"], { stdio: "ignore", detached: true });
39254
39542
  child.unref();
39255
39543
  await new Promise((resolve34) => setTimeout(resolve34, 3e3));
39256
39544
  try {
@@ -45156,8 +45444,8 @@ async function handleSlashCommand(input, ctx) {
45156
45444
  writeFileSync17(jwtFile, JSON.stringify(jwtPayload, null, 2));
45157
45445
  renderInfo(`Launching fortemi-react from ${fDir}...`);
45158
45446
  try {
45159
- const { spawn: spawn20 } = __require("node:child_process");
45160
- const child = spawn20("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
45447
+ const { spawn: spawn21 } = __require("node:child_process");
45448
+ const child = spawn21("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
45161
45449
  cwd: join55(fDir, "apps", "standalone"),
45162
45450
  stdio: "ignore",
45163
45451
  detached: true,
@@ -47566,8 +47854,8 @@ Environment="OLLAMA_NUM_PARALLEL=${n}"
47566
47854
  }
47567
47855
  await new Promise((r) => setTimeout(r, 1e3));
47568
47856
  process.env.OLLAMA_NUM_PARALLEL = String(n);
47569
- const { spawn: spawn20 } = await import("node:child_process");
47570
- const child = spawn20("ollama", ["serve"], {
47857
+ const { spawn: spawn21 } = await import("node:child_process");
47858
+ const child = spawn21("ollama", ["serve"], {
47571
47859
  stdio: "ignore",
47572
47860
  detached: true,
47573
47861
  env: { ...process.env, OLLAMA_NUM_PARALLEL: String(n) }
@@ -58865,6 +59153,11 @@ function buildTools(repoRoot, config, contextWindowSize) {
58865
59153
  new SemanticMapTool(repoRoot),
58866
59154
  new RepoMapTool(repoRoot),
58867
59155
  new ProcessHealthTool(),
59156
+ // Full OA sub-process — callbacks wired after runner + statusBar created
59157
+ (() => {
59158
+ _fullSubAgentToolRef = new FullSubAgentTool(repoRoot, config.model, config.backendUrl);
59159
+ return _fullSubAgentToolRef;
59160
+ })(),
58868
59161
  // Nexus P2P networking + x402 micropayments
58869
59162
  new NexusTool(repoRoot)
58870
59163
  ];
@@ -59091,7 +59384,22 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
59091
59384
  let dynamicContext = formatContextForPrompt(projectCtx, modelTier);
59092
59385
  const environmentProvider = () => {
59093
59386
  try {
59094
- return formatSnapshotForContext(collectSnapshot(repoRoot));
59387
+ let env = formatSnapshotForContext(collectSnapshot(repoRoot));
59388
+ const fullSubs = getAllFullSubAgents();
59389
+ if (fullSubs.length > 0) {
59390
+ const lines = ["\n<sub-agents>"];
59391
+ for (const sub of fullSubs) {
59392
+ const runtime = ((Date.now() - sub.startedAt) / 1e3).toFixed(0);
59393
+ const lastLine = sub.outputBuffer.length > 0 ? sub.outputBuffer[sub.outputBuffer.length - 1].slice(0, 80) : "";
59394
+ lines.push(` ${sub.id} [${sub.status}] PID:${sub.pid} ${runtime}s \u2014 ${sub.task.slice(0, 60)}`);
59395
+ if (lastLine)
59396
+ lines.push(` latest: ${lastLine}`);
59397
+ }
59398
+ lines.push(" Actions: full_sub_agent(action='status'|'output'|'stop', id='...')");
59399
+ lines.push("</sub-agents>");
59400
+ env += lines.join("\n");
59401
+ }
59402
+ return env;
59095
59403
  } catch {
59096
59404
  return "";
59097
59405
  }
@@ -59294,6 +59602,7 @@ ${lines.join("\n")}
59294
59602
  environmentProvider
59295
59603
  });
59296
59604
  runner.setWorkingDirectory(repoRoot);
59605
+ _activeRunnerRef = runner;
59297
59606
  const tools = buildTools(repoRoot, config, contextWindowSize);
59298
59607
  if (contextWindowSize && contextWindowSize > 0) {
59299
59608
  for (const tool of tools) {
@@ -60037,6 +60346,7 @@ async function startInteractive(config, repoPath) {
60037
60346
  const cleanupAndExit = (code) => {
60038
60347
  if (_shellToolRef)
60039
60348
  _shellToolRef.killAll();
60349
+ killAllFullSubAgents();
60040
60350
  restoreScreen();
60041
60351
  process.exit(code);
60042
60352
  };
@@ -60120,6 +60430,23 @@ async function startInteractive(config, repoPath) {
60120
60430
  statusBar.activate(scrollTop);
60121
60431
  setTerminalTitle(void 0, version);
60122
60432
  banner.onAfterRender = () => statusBar.renderHeaderButtons();
60433
+ if (_fullSubAgentToolRef) {
60434
+ _fullSubAgentToolRef.setCallbacks({
60435
+ onViewRegister: (id, label, type) => statusBar.registerAgentView(id, label, type),
60436
+ onViewWrite: (id, text) => statusBar.writeToAgentView(id, text),
60437
+ onViewStatus: (id, status) => statusBar.updateAgentViewStatus(id, status),
60438
+ onComplete: (id, task, exitCode, output) => {
60439
+ const summary = output.split("\n").filter((l) => l.trim()).slice(-5).join("\n");
60440
+ const status = exitCode === 0 ? "COMPLETED" : "FAILED";
60441
+ _activeRunnerRef?.injectUserMessage(`[Full sub-agent ${id} ${status}]
60442
+ Task: ${task.slice(0, 100)}
60443
+ Exit code: ${exitCode}
60444
+ Last output:
60445
+ ${summary}
60446
+ Review its full output in the [${id}] tab or via full_sub_agent(action='output', id='${id}')`);
60447
+ }
60448
+ });
60449
+ }
60123
60450
  statusBar.setBannerRefresh(() => {
60124
60451
  banner.renderCurrentFrame();
60125
60452
  });
@@ -63179,7 +63506,7 @@ Rules:
63179
63506
  process.exit(1);
63180
63507
  }
63181
63508
  }
63182
- var taskManager, _shellToolRef, SELF_IMPROVE_INTERVAL, _tasksSinceImprove;
63509
+ var taskManager, _shellToolRef, _fullSubAgentToolRef, _activeRunnerRef, SELF_IMPROVE_INTERVAL, _tasksSinceImprove;
63183
63510
  var init_interactive = __esm({
63184
63511
  "packages/cli/dist/tui/interactive.js"() {
63185
63512
  "use strict";
@@ -63220,6 +63547,8 @@ var init_interactive = __esm({
63220
63547
  init_neovim_mode();
63221
63548
  taskManager = new BackgroundTaskManager();
63222
63549
  _shellToolRef = null;
63550
+ _fullSubAgentToolRef = null;
63551
+ _activeRunnerRef = null;
63223
63552
  SELF_IMPROVE_INTERVAL = 5;
63224
63553
  _tasksSinceImprove = 0;
63225
63554
  }
@@ -63924,7 +64253,7 @@ var serve_exports = {};
63924
64253
  __export(serve_exports, {
63925
64254
  serveCommand: () => serveCommand
63926
64255
  });
63927
- import { spawn as spawn19 } from "node:child_process";
64256
+ import { spawn as spawn20 } from "node:child_process";
63928
64257
  async function serveCommand(opts, config) {
63929
64258
  const backendType = config.backendType;
63930
64259
  if (backendType === "ollama") {
@@ -64017,7 +64346,7 @@ async function serveVllm(opts, config) {
64017
64346
  }
64018
64347
  async function runVllmServer(args, verbose) {
64019
64348
  return new Promise((resolve34, reject) => {
64020
- const child = spawn19("python", args, {
64349
+ const child = spawn20("python", args, {
64021
64350
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
64022
64351
  env: { ...process.env }
64023
64352
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.156.0",
3
+ "version": "0.158.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",