open-agents-ai 0.155.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.
- package/dist/index.js +502 -41
- 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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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-${
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
34733
|
+
import { spawn as spawn18, exec } from "node:child_process";
|
|
34458
34734
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
34459
|
-
import { randomBytes as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
36360
|
+
const salt = randomBytes13(SALT_LEN);
|
|
36085
36361
|
const key = scryptSync2(passphrase, salt, KEY_LEN);
|
|
36086
|
-
const iv =
|
|
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
|
|
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 ??
|
|
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 =
|
|
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 ??
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
45160
|
-
const child =
|
|
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:
|
|
47570
|
-
const child =
|
|
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) }
|
|
@@ -56581,8 +56857,15 @@ var init_status_bar = __esm({
|
|
|
56581
56857
|
};
|
|
56582
56858
|
active = false;
|
|
56583
56859
|
scrollRegionTop = 1;
|
|
56860
|
+
// ── Agent View Multiplexing (WO-NA1) ──
|
|
56861
|
+
// Each agent (main + sub-agents) has its own content buffer.
|
|
56862
|
+
// The TUI displays ONE view at a time; tab buttons switch between them.
|
|
56863
|
+
/** Single agent view with independent content buffer */
|
|
56864
|
+
_agentViews = /* @__PURE__ */ new Map();
|
|
56865
|
+
_activeViewId = "main";
|
|
56584
56866
|
// Virtual scrollback buffer — stores content lines for Page Up/Down scrolling.
|
|
56585
56867
|
// Since we're in alternate screen buffer, there's no native scrollback.
|
|
56868
|
+
// NOTE: _contentLines is now a reference to the ACTIVE view's buffer.
|
|
56586
56869
|
_contentLines = [];
|
|
56587
56870
|
_contentScrollOffset = 0;
|
|
56588
56871
|
// 0 = live (bottom), >0 = scrolled back
|
|
@@ -57168,6 +57451,18 @@ var init_status_bar = __esm({
|
|
|
57168
57451
|
activate(scrollRegionTop) {
|
|
57169
57452
|
this.scrollRegionTop = scrollRegionTop ?? 1;
|
|
57170
57453
|
this.active = true;
|
|
57454
|
+
if (!this._agentViews.has("main")) {
|
|
57455
|
+
this._agentViews.set("main", {
|
|
57456
|
+
id: "main",
|
|
57457
|
+
label: "main",
|
|
57458
|
+
type: "main",
|
|
57459
|
+
contentLines: this._contentLines,
|
|
57460
|
+
scrollOffset: 0,
|
|
57461
|
+
status: "running",
|
|
57462
|
+
taskSummary: "",
|
|
57463
|
+
startedAt: Date.now()
|
|
57464
|
+
});
|
|
57465
|
+
}
|
|
57171
57466
|
this._prevTermRows = process.stdout.rows ?? 24;
|
|
57172
57467
|
this._prevTermCols = process.stdout.columns ?? 80;
|
|
57173
57468
|
this.applyScrollRegion();
|
|
@@ -57288,8 +57583,16 @@ var init_status_bar = __esm({
|
|
|
57288
57583
|
return;
|
|
57289
57584
|
}
|
|
57290
57585
|
const rows = process.stdout.rows ?? 24;
|
|
57586
|
+
const pos = this.rowPositions(rows);
|
|
57587
|
+
if (type === "press" && pos.tabBarRow > 0 && row === pos.tabBarRow) {
|
|
57588
|
+
const viewId = this.hitTestTabBar(col);
|
|
57589
|
+
if (viewId)
|
|
57590
|
+
this.switchToView(viewId);
|
|
57591
|
+
return;
|
|
57592
|
+
}
|
|
57291
57593
|
const fh = this._currentFooterHeight;
|
|
57292
|
-
const
|
|
57594
|
+
const tabBarH = this.hasSubAgents ? 1 : 0;
|
|
57595
|
+
const footerStart = rows - fh - tabBarH + 1;
|
|
57293
57596
|
if (row >= footerStart)
|
|
57294
57597
|
return;
|
|
57295
57598
|
if (type === "press") {
|
|
@@ -57342,6 +57645,148 @@ var init_status_bar = __esm({
|
|
|
57342
57645
|
this.renderFooterAndPositionInput();
|
|
57343
57646
|
}, 1500);
|
|
57344
57647
|
}
|
|
57648
|
+
// ── Agent View Management (WO-NA1) ────────────────────────────
|
|
57649
|
+
/** Register a new sub-agent view with its own content buffer */
|
|
57650
|
+
registerAgentView(id, label, type, taskSummary) {
|
|
57651
|
+
this._agentViews.set(id, {
|
|
57652
|
+
id,
|
|
57653
|
+
label,
|
|
57654
|
+
type,
|
|
57655
|
+
contentLines: [],
|
|
57656
|
+
scrollOffset: 0,
|
|
57657
|
+
status: "running",
|
|
57658
|
+
taskSummary: taskSummary ?? "",
|
|
57659
|
+
startedAt: Date.now()
|
|
57660
|
+
});
|
|
57661
|
+
if (this.active) {
|
|
57662
|
+
this.applyScrollRegion();
|
|
57663
|
+
this.renderFooterAndPositionInput();
|
|
57664
|
+
}
|
|
57665
|
+
}
|
|
57666
|
+
/** Remove a sub-agent view */
|
|
57667
|
+
unregisterAgentView(id) {
|
|
57668
|
+
this._agentViews.delete(id);
|
|
57669
|
+
if (this._activeViewId === id)
|
|
57670
|
+
this.switchToView("main");
|
|
57671
|
+
if (this.active) {
|
|
57672
|
+
this.applyScrollRegion();
|
|
57673
|
+
this.renderFooterAndPositionInput();
|
|
57674
|
+
}
|
|
57675
|
+
}
|
|
57676
|
+
/** Update a sub-agent's status */
|
|
57677
|
+
updateAgentViewStatus(id, status) {
|
|
57678
|
+
const view = this._agentViews.get(id);
|
|
57679
|
+
if (!view)
|
|
57680
|
+
return;
|
|
57681
|
+
view.status = status;
|
|
57682
|
+
if (status === "completed" || status === "failed")
|
|
57683
|
+
view.completedAt = Date.now();
|
|
57684
|
+
if (this.active)
|
|
57685
|
+
this.renderAgentTabs();
|
|
57686
|
+
}
|
|
57687
|
+
/** Switch which agent's content buffer is displayed */
|
|
57688
|
+
switchToView(id) {
|
|
57689
|
+
const view = this._agentViews.get(id);
|
|
57690
|
+
if (!view)
|
|
57691
|
+
return;
|
|
57692
|
+
const current = this._agentViews.get(this._activeViewId);
|
|
57693
|
+
if (current)
|
|
57694
|
+
current.scrollOffset = this._contentScrollOffset;
|
|
57695
|
+
this._activeViewId = id;
|
|
57696
|
+
this._contentLines = view.contentLines;
|
|
57697
|
+
this._contentScrollOffset = view.scrollOffset;
|
|
57698
|
+
this.repaintContent();
|
|
57699
|
+
this.renderAgentTabs();
|
|
57700
|
+
}
|
|
57701
|
+
/** Write content to a specific agent's buffer (called from sub-agent event handler) */
|
|
57702
|
+
writeToAgentView(id, text) {
|
|
57703
|
+
const view = this._agentViews.get(id);
|
|
57704
|
+
if (!view)
|
|
57705
|
+
return;
|
|
57706
|
+
const lines = text.split("\n");
|
|
57707
|
+
view.contentLines.push(...lines);
|
|
57708
|
+
if (view.contentLines.length > this._contentMaxLines) {
|
|
57709
|
+
view.contentLines.splice(0, view.contentLines.length - this._contentMaxLines);
|
|
57710
|
+
}
|
|
57711
|
+
if (this._activeViewId === id && this.active && this.writeDepth === 0) {
|
|
57712
|
+
this.repaintContent();
|
|
57713
|
+
}
|
|
57714
|
+
}
|
|
57715
|
+
/** Get the currently active view ID */
|
|
57716
|
+
get activeViewId() {
|
|
57717
|
+
return this._activeViewId;
|
|
57718
|
+
}
|
|
57719
|
+
/** Get all agent views (for external access) */
|
|
57720
|
+
getAgentViews() {
|
|
57721
|
+
return Array.from(this._agentViews.values()).map((v) => ({
|
|
57722
|
+
id: v.id,
|
|
57723
|
+
label: v.label,
|
|
57724
|
+
type: v.type,
|
|
57725
|
+
status: v.status,
|
|
57726
|
+
taskSummary: v.taskSummary
|
|
57727
|
+
}));
|
|
57728
|
+
}
|
|
57729
|
+
/** Whether the tab bar should be visible (more than just main) */
|
|
57730
|
+
get hasSubAgents() {
|
|
57731
|
+
return this._agentViews.size > 1;
|
|
57732
|
+
}
|
|
57733
|
+
// ── Agent Tab Bar (WO-NA2) ───────────────────────────────────
|
|
57734
|
+
/** Render the agent tab bar between input row and braille row */
|
|
57735
|
+
renderAgentTabs() {
|
|
57736
|
+
if (!this.active || !this.hasSubAgents)
|
|
57737
|
+
return;
|
|
57738
|
+
const rows = process.stdout.rows ?? 24;
|
|
57739
|
+
const pos = this.rowPositions(rows);
|
|
57740
|
+
if (pos.tabBarRow < 0)
|
|
57741
|
+
return;
|
|
57742
|
+
const w = process.stdout.columns ?? 80;
|
|
57743
|
+
let buf = `\x1B[${pos.tabBarRow};1H${PANEL_BG_SEQ}\x1B[2K`;
|
|
57744
|
+
let col = 2;
|
|
57745
|
+
for (const view of this._agentViews.values()) {
|
|
57746
|
+
const isActive = view.id === this._activeViewId;
|
|
57747
|
+
if (view.id === "main" && this._activeViewId === "main")
|
|
57748
|
+
continue;
|
|
57749
|
+
const icon = view.status === "running" ? "\u25CF" : (
|
|
57750
|
+
// ●
|
|
57751
|
+
view.status === "completed" ? "\u2713" : (
|
|
57752
|
+
// ✓
|
|
57753
|
+
view.status === "failed" ? "\u2717" : (
|
|
57754
|
+
// ✗
|
|
57755
|
+
view.status === "paused" ? "\u25CB" : "?"
|
|
57756
|
+
)
|
|
57757
|
+
)
|
|
57758
|
+
);
|
|
57759
|
+
const label = ` ${view.label} ${icon} `;
|
|
57760
|
+
const bg = isActive ? 238 : 236;
|
|
57761
|
+
const fg2 = isActive ? 252 : 245;
|
|
57762
|
+
buf += `\x1B[${pos.tabBarRow};${col}H`;
|
|
57763
|
+
buf += `\x1B]8;;oa-view:${view.id}\x07`;
|
|
57764
|
+
buf += `\x1B[38;5;${fg2}m\x1B[48;5;${bg}m${label}\x1B[0m${PANEL_BG_SEQ}`;
|
|
57765
|
+
buf += `\x1B]8;;\x07`;
|
|
57766
|
+
col += label.length + 1;
|
|
57767
|
+
if (col >= w - 5)
|
|
57768
|
+
break;
|
|
57769
|
+
}
|
|
57770
|
+
buf += RESET;
|
|
57771
|
+
this.termWrite(buf);
|
|
57772
|
+
}
|
|
57773
|
+
/** Hit-test the tab bar for click events. Returns view ID or null. */
|
|
57774
|
+
hitTestTabBar(col) {
|
|
57775
|
+
if (!this.hasSubAgents)
|
|
57776
|
+
return null;
|
|
57777
|
+
let testCol = 2;
|
|
57778
|
+
for (const view of this._agentViews.values()) {
|
|
57779
|
+
if (view.id === "main" && this._activeViewId === "main")
|
|
57780
|
+
continue;
|
|
57781
|
+
const icon = view.status === "running" ? "\u25CF" : view.status === "completed" ? "\u2713" : view.status === "failed" ? "\u2717" : "\u25CB";
|
|
57782
|
+
const label = ` ${view.label} ${icon} `;
|
|
57783
|
+
const endCol = testCol + label.length - 1;
|
|
57784
|
+
if (col >= testCol && col <= endCol)
|
|
57785
|
+
return view.id;
|
|
57786
|
+
testCol = endCol + 2;
|
|
57787
|
+
}
|
|
57788
|
+
return null;
|
|
57789
|
+
}
|
|
57345
57790
|
/** Render header buttons overlay on banner row 3 */
|
|
57346
57791
|
renderHeaderButtons() {
|
|
57347
57792
|
if (!this.active)
|
|
@@ -58008,12 +58453,16 @@ ${CONTENT_BG_SEQ}`);
|
|
|
58008
58453
|
rowPositions(rows) {
|
|
58009
58454
|
const fh = this._currentFooterHeight;
|
|
58010
58455
|
const inputLines = fh - 2;
|
|
58456
|
+
const tabBarH = this.hasSubAgents ? 1 : 0;
|
|
58457
|
+
const totalFooter = fh + tabBarH;
|
|
58011
58458
|
return {
|
|
58012
|
-
scrollEnd: Math.max(rows -
|
|
58013
|
-
inputStartRow: rows -
|
|
58459
|
+
scrollEnd: Math.max(rows - totalFooter, this.scrollRegionTop + 1),
|
|
58460
|
+
inputStartRow: rows - totalFooter + 1,
|
|
58014
58461
|
// input at TOP of footer
|
|
58015
|
-
|
|
58016
|
-
// braille
|
|
58462
|
+
tabBarRow: tabBarH > 0 ? rows - 2 : -1,
|
|
58463
|
+
// tab bar ABOVE braille (if visible)
|
|
58464
|
+
bufferRow: rows - 1,
|
|
58465
|
+
// braille always at N-1
|
|
58017
58466
|
metricsRow: rows,
|
|
58018
58467
|
// metrics at BOTTOM
|
|
58019
58468
|
// Legacy (unused but keeps TS happy for any remaining refs)
|
|
@@ -58122,6 +58571,9 @@ ${CONTENT_BG_SEQ}`);
|
|
|
58122
58571
|
buf += `\x1B[${row};1H${PANEL_BG_SEQ}\x1B[2K${prefix}${inputWrap.lines[i]}${RESET}`;
|
|
58123
58572
|
}
|
|
58124
58573
|
const cursorTermRow = pos.inputStartRow + inputWrap.cursorRow;
|
|
58574
|
+
if (pos.tabBarRow > 0) {
|
|
58575
|
+
buf += `\x1B[${pos.tabBarRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET}`;
|
|
58576
|
+
}
|
|
58125
58577
|
buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildBufferContent(w)}${RESET}`;
|
|
58126
58578
|
buf += `\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET}`;
|
|
58127
58579
|
buf += `\x1B[?7h\x1B[${cursorTermRow};${inputWrap.cursorCol}H\x1B[?25h`;
|
|
@@ -58153,9 +58605,15 @@ ${CONTENT_BG_SEQ}`);
|
|
|
58153
58605
|
const rows = process.stdout.rows ?? 24;
|
|
58154
58606
|
const w = getTermWidth();
|
|
58155
58607
|
const pos = this.rowPositions(rows);
|
|
58156
|
-
|
|
58608
|
+
let buf = "\x1B7\x1B[?7l";
|
|
58609
|
+
if (pos.tabBarRow > 0) {
|
|
58610
|
+
buf += `\x1B[${pos.tabBarRow};1H${PANEL_BG_SEQ}\x1B[2K${RESET}`;
|
|
58611
|
+
}
|
|
58612
|
+
buf += `\x1B[${pos.bufferRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildBufferContent(w)}${RESET}\x1B[${pos.metricsRow};1H${PANEL_BG_SEQ}\x1B[2K${this.buildMetricsLine()}${RESET}\x1B[?7h\x1B8` + // DEC restore cursor
|
|
58157
58613
|
(this.writeDepth === 0 ? "\x1B[?25h" : "");
|
|
58158
58614
|
this.termWrite(buf);
|
|
58615
|
+
if (pos.tabBarRow > 0)
|
|
58616
|
+
this.renderAgentTabs();
|
|
58159
58617
|
}
|
|
58160
58618
|
/**
|
|
58161
58619
|
* Render the input rows during an active content write (streaming).
|
|
@@ -58683,6 +59141,8 @@ function buildTools(repoRoot, config, contextWindowSize) {
|
|
|
58683
59141
|
new SemanticMapTool(repoRoot),
|
|
58684
59142
|
new RepoMapTool(repoRoot),
|
|
58685
59143
|
new ProcessHealthTool(),
|
|
59144
|
+
// Full OA sub-process spawning (wired to tab bar later via setStatusBar)
|
|
59145
|
+
new FullSubAgentTool(repoRoot, config.model, config.backendUrl),
|
|
58686
59146
|
// Nexus P2P networking + x402 micropayments
|
|
58687
59147
|
new NexusTool(repoRoot)
|
|
58688
59148
|
];
|
|
@@ -59855,6 +60315,7 @@ async function startInteractive(config, repoPath) {
|
|
|
59855
60315
|
const cleanupAndExit = (code) => {
|
|
59856
60316
|
if (_shellToolRef)
|
|
59857
60317
|
_shellToolRef.killAll();
|
|
60318
|
+
killAllFullSubAgents();
|
|
59858
60319
|
restoreScreen();
|
|
59859
60320
|
process.exit(code);
|
|
59860
60321
|
};
|
|
@@ -63742,7 +64203,7 @@ var serve_exports = {};
|
|
|
63742
64203
|
__export(serve_exports, {
|
|
63743
64204
|
serveCommand: () => serveCommand
|
|
63744
64205
|
});
|
|
63745
|
-
import { spawn as
|
|
64206
|
+
import { spawn as spawn20 } from "node:child_process";
|
|
63746
64207
|
async function serveCommand(opts, config) {
|
|
63747
64208
|
const backendType = config.backendType;
|
|
63748
64209
|
if (backendType === "ollama") {
|
|
@@ -63835,7 +64296,7 @@ async function serveVllm(opts, config) {
|
|
|
63835
64296
|
}
|
|
63836
64297
|
async function runVllmServer(args, verbose) {
|
|
63837
64298
|
return new Promise((resolve34, reject) => {
|
|
63838
|
-
const child =
|
|
64299
|
+
const child = spawn20("python", args, {
|
|
63839
64300
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
63840
64301
|
env: { ...process.env }
|
|
63841
64302
|
});
|
package/package.json
CHANGED