open-agents-ai 0.13.5 → 0.14.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 +1128 -223
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1170,7 +1170,7 @@ var init_shell = __esm({
|
|
|
1170
1170
|
const timeout = args["timeout"] ?? this.defaultTimeout;
|
|
1171
1171
|
const stdinInput = args["stdin"];
|
|
1172
1172
|
const start = performance.now();
|
|
1173
|
-
return new Promise((
|
|
1173
|
+
return new Promise((resolve16) => {
|
|
1174
1174
|
const child = spawn("bash", ["-c", command], {
|
|
1175
1175
|
cwd: this.workingDir,
|
|
1176
1176
|
env: {
|
|
@@ -1223,7 +1223,7 @@ var init_shell = __esm({
|
|
|
1223
1223
|
const combined = stdout + stderr;
|
|
1224
1224
|
const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
|
|
1225
1225
|
const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : "";
|
|
1226
|
-
|
|
1226
|
+
resolve16({
|
|
1227
1227
|
success: false,
|
|
1228
1228
|
output: stdout,
|
|
1229
1229
|
error: `Command timed out after ${timeout}ms.${hint}`,
|
|
@@ -1232,7 +1232,7 @@ var init_shell = __esm({
|
|
|
1232
1232
|
return;
|
|
1233
1233
|
}
|
|
1234
1234
|
const success = code === 0;
|
|
1235
|
-
|
|
1235
|
+
resolve16({
|
|
1236
1236
|
success,
|
|
1237
1237
|
output: stdout + (stderr && success ? `
|
|
1238
1238
|
STDERR:
|
|
@@ -1243,7 +1243,7 @@ ${stderr}` : ""),
|
|
|
1243
1243
|
});
|
|
1244
1244
|
child.on("error", (err) => {
|
|
1245
1245
|
clearTimeout(timer);
|
|
1246
|
-
|
|
1246
|
+
resolve16({
|
|
1247
1247
|
success: false,
|
|
1248
1248
|
output: stdout,
|
|
1249
1249
|
error: err.message,
|
|
@@ -4031,8 +4031,8 @@ function deleteCustomToolDefinition(name, scope, repoRoot) {
|
|
|
4031
4031
|
const dir = scope === "project" && repoRoot ? projectToolsDir(repoRoot) : globalToolsDir();
|
|
4032
4032
|
const filePath = join11(dir, `${name}.json`);
|
|
4033
4033
|
if (existsSync8(filePath)) {
|
|
4034
|
-
const { unlinkSync:
|
|
4035
|
-
|
|
4034
|
+
const { unlinkSync: unlinkSync4 } = __require("node:fs");
|
|
4035
|
+
unlinkSync4(filePath);
|
|
4036
4036
|
return true;
|
|
4037
4037
|
}
|
|
4038
4038
|
return false;
|
|
@@ -4150,7 +4150,7 @@ var init_custom_tool = __esm({
|
|
|
4150
4150
|
}
|
|
4151
4151
|
/** Execute a single shell command and return output */
|
|
4152
4152
|
runCommand(command) {
|
|
4153
|
-
return new Promise((
|
|
4153
|
+
return new Promise((resolve16) => {
|
|
4154
4154
|
const child = spawn3("bash", ["-c", command], {
|
|
4155
4155
|
cwd: this.workingDir,
|
|
4156
4156
|
env: { ...process.env, CI: "true", NO_COLOR: "1" },
|
|
@@ -4175,11 +4175,11 @@ var init_custom_tool = __esm({
|
|
|
4175
4175
|
child.kill("SIGTERM");
|
|
4176
4176
|
} catch {
|
|
4177
4177
|
}
|
|
4178
|
-
|
|
4178
|
+
resolve16({ success: false, output: stdout, error: "Command timed out after 60s" });
|
|
4179
4179
|
}, 6e4);
|
|
4180
4180
|
child.on("close", (code) => {
|
|
4181
4181
|
clearTimeout(timer);
|
|
4182
|
-
|
|
4182
|
+
resolve16({
|
|
4183
4183
|
success: code === 0,
|
|
4184
4184
|
output: stdout + (stderr && code === 0 ? `
|
|
4185
4185
|
STDERR:
|
|
@@ -4189,7 +4189,7 @@ ${stderr}` : ""),
|
|
|
4189
4189
|
});
|
|
4190
4190
|
child.on("error", (err) => {
|
|
4191
4191
|
clearTimeout(timer);
|
|
4192
|
-
|
|
4192
|
+
resolve16({ success: false, output: stdout, error: err.message });
|
|
4193
4193
|
});
|
|
4194
4194
|
});
|
|
4195
4195
|
}
|
|
@@ -4840,6 +4840,300 @@ ${content}`,
|
|
|
4840
4840
|
}
|
|
4841
4841
|
});
|
|
4842
4842
|
|
|
4843
|
+
// packages/execution/dist/tools/transcribe-tool.js
|
|
4844
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync9, unlinkSync } from "node:fs";
|
|
4845
|
+
import { join as join13, basename as basename3, extname as extname3, resolve as resolve12 } from "node:path";
|
|
4846
|
+
import { homedir as homedir5 } from "node:os";
|
|
4847
|
+
import { execSync as execSync9, spawn as spawn4 } from "node:child_process";
|
|
4848
|
+
function isTranscribable(path) {
|
|
4849
|
+
const ext = extname3(path).toLowerCase();
|
|
4850
|
+
return AUDIO_EXTS.has(ext) || VIDEO_EXTS.has(ext);
|
|
4851
|
+
}
|
|
4852
|
+
async function loadTranscribeCli() {
|
|
4853
|
+
if (_tcChecked)
|
|
4854
|
+
return _tcModule;
|
|
4855
|
+
_tcChecked = true;
|
|
4856
|
+
try {
|
|
4857
|
+
const globalRoot = execSync9("npm root -g", {
|
|
4858
|
+
encoding: "utf-8",
|
|
4859
|
+
timeout: 5e3,
|
|
4860
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
4861
|
+
}).trim();
|
|
4862
|
+
const tcPath = join13(globalRoot, "transcribe-cli");
|
|
4863
|
+
if (existsSync10(join13(tcPath, "dist", "index.js"))) {
|
|
4864
|
+
const { createRequire: createRequire4 } = await import("node:module");
|
|
4865
|
+
const req = createRequire4(import.meta.url);
|
|
4866
|
+
_tcModule = req(join13(tcPath, "dist", "index.js"));
|
|
4867
|
+
return _tcModule;
|
|
4868
|
+
}
|
|
4869
|
+
} catch {
|
|
4870
|
+
}
|
|
4871
|
+
const nvmBase = join13(homedir5(), ".nvm", "versions", "node");
|
|
4872
|
+
if (existsSync10(nvmBase)) {
|
|
4873
|
+
try {
|
|
4874
|
+
const { readdirSync: readdirSync9 } = await import("node:fs");
|
|
4875
|
+
for (const ver of readdirSync9(nvmBase)) {
|
|
4876
|
+
const tcPath = join13(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
4877
|
+
if (existsSync10(join13(tcPath, "dist", "index.js"))) {
|
|
4878
|
+
const { createRequire: createRequire4 } = await import("node:module");
|
|
4879
|
+
const req = createRequire4(import.meta.url);
|
|
4880
|
+
_tcModule = req(join13(tcPath, "dist", "index.js"));
|
|
4881
|
+
return _tcModule;
|
|
4882
|
+
}
|
|
4883
|
+
}
|
|
4884
|
+
} catch {
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
4887
|
+
return null;
|
|
4888
|
+
}
|
|
4889
|
+
function formatTime(seconds) {
|
|
4890
|
+
const m = Math.floor(seconds / 60);
|
|
4891
|
+
const s = Math.floor(seconds % 60);
|
|
4892
|
+
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
4893
|
+
}
|
|
4894
|
+
var AUDIO_EXTS, VIDEO_EXTS, _tcModule, _tcChecked, TranscribeFileTool, TranscribeUrlTool;
|
|
4895
|
+
var init_transcribe_tool = __esm({
|
|
4896
|
+
"packages/execution/dist/tools/transcribe-tool.js"() {
|
|
4897
|
+
"use strict";
|
|
4898
|
+
AUDIO_EXTS = /* @__PURE__ */ new Set([
|
|
4899
|
+
".mp3",
|
|
4900
|
+
".wav",
|
|
4901
|
+
".flac",
|
|
4902
|
+
".aac",
|
|
4903
|
+
".m4a",
|
|
4904
|
+
".ogg",
|
|
4905
|
+
".wma",
|
|
4906
|
+
".opus"
|
|
4907
|
+
]);
|
|
4908
|
+
VIDEO_EXTS = /* @__PURE__ */ new Set([
|
|
4909
|
+
".mp4",
|
|
4910
|
+
".mkv",
|
|
4911
|
+
".avi",
|
|
4912
|
+
".mov",
|
|
4913
|
+
".webm",
|
|
4914
|
+
".flv",
|
|
4915
|
+
".wmv",
|
|
4916
|
+
".m4v",
|
|
4917
|
+
".ts"
|
|
4918
|
+
]);
|
|
4919
|
+
_tcModule = null;
|
|
4920
|
+
_tcChecked = false;
|
|
4921
|
+
TranscribeFileTool = class {
|
|
4922
|
+
name = "transcribe_file";
|
|
4923
|
+
description = "Transcribe a local audio or video file to text using Whisper (faster-whisper). Supports MP3, WAV, FLAC, AAC, M4A, OGG, MP4, MKV, AVI, MOV, WebM. Returns the full transcription text with optional speaker diarization. Transcription is 100% local \u2014 no API keys needed.";
|
|
4924
|
+
parameters = {
|
|
4925
|
+
type: "object",
|
|
4926
|
+
properties: {
|
|
4927
|
+
path: {
|
|
4928
|
+
type: "string",
|
|
4929
|
+
description: "Path to the audio or video file to transcribe"
|
|
4930
|
+
},
|
|
4931
|
+
model: {
|
|
4932
|
+
type: "string",
|
|
4933
|
+
description: "Whisper model size: tiny, base, small, medium, large-v3 (default: base)",
|
|
4934
|
+
enum: ["tiny", "base", "small", "medium", "large-v3"]
|
|
4935
|
+
},
|
|
4936
|
+
diarize: {
|
|
4937
|
+
type: "boolean",
|
|
4938
|
+
description: "Enable speaker diarization (identify who said what). Default: false"
|
|
4939
|
+
}
|
|
4940
|
+
},
|
|
4941
|
+
required: ["path"]
|
|
4942
|
+
};
|
|
4943
|
+
workingDir;
|
|
4944
|
+
constructor(workingDir) {
|
|
4945
|
+
this.workingDir = workingDir;
|
|
4946
|
+
}
|
|
4947
|
+
async execute(args) {
|
|
4948
|
+
const start = performance.now();
|
|
4949
|
+
const filePath = resolve12(this.workingDir, String(args["path"] ?? ""));
|
|
4950
|
+
const model = String(args["model"] ?? "base");
|
|
4951
|
+
const diarize = Boolean(args["diarize"] ?? false);
|
|
4952
|
+
if (!existsSync10(filePath)) {
|
|
4953
|
+
return {
|
|
4954
|
+
success: false,
|
|
4955
|
+
output: "",
|
|
4956
|
+
error: `File not found: ${filePath}`,
|
|
4957
|
+
durationMs: performance.now() - start
|
|
4958
|
+
};
|
|
4959
|
+
}
|
|
4960
|
+
if (!isTranscribable(filePath)) {
|
|
4961
|
+
return {
|
|
4962
|
+
success: false,
|
|
4963
|
+
output: "",
|
|
4964
|
+
error: `Unsupported file type: ${extname3(filePath)}. Supported: ${[...AUDIO_EXTS, ...VIDEO_EXTS].join(", ")}`,
|
|
4965
|
+
durationMs: performance.now() - start
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
const tc = await loadTranscribeCli();
|
|
4969
|
+
if (!tc) {
|
|
4970
|
+
return this.execViaCli(filePath, model, diarize, start);
|
|
4971
|
+
}
|
|
4972
|
+
try {
|
|
4973
|
+
const result = await tc.transcribe(filePath, {
|
|
4974
|
+
model,
|
|
4975
|
+
format: "json",
|
|
4976
|
+
diarize,
|
|
4977
|
+
wordTimestamps: false
|
|
4978
|
+
});
|
|
4979
|
+
const transcriptDir = join13(this.workingDir, ".oa", "transcripts");
|
|
4980
|
+
mkdirSync4(transcriptDir, { recursive: true });
|
|
4981
|
+
const outFile = join13(transcriptDir, `${basename3(filePath)}.txt`);
|
|
4982
|
+
writeFileSync4(outFile, result.text, "utf-8");
|
|
4983
|
+
const lines = [
|
|
4984
|
+
`Transcription of: ${basename3(filePath)}`,
|
|
4985
|
+
`Model: ${model} | Language: ${result.language} | Duration: ${result.duration ? `${result.duration.toFixed(1)}s` : "unknown"}`,
|
|
4986
|
+
`Words: ${result.wordCount} | Saved to: ${outFile}`,
|
|
4987
|
+
""
|
|
4988
|
+
];
|
|
4989
|
+
if (result.speakers.length > 1) {
|
|
4990
|
+
lines.push(`Speakers: ${result.speakers.join(", ")}`);
|
|
4991
|
+
lines.push("");
|
|
4992
|
+
}
|
|
4993
|
+
if (diarize && result.segments.length > 0) {
|
|
4994
|
+
for (const seg of result.segments) {
|
|
4995
|
+
const ts = `[${formatTime(seg.start)} \u2192 ${formatTime(seg.end)}]`;
|
|
4996
|
+
const speaker = seg.speaker ? `${seg.speaker}: ` : "";
|
|
4997
|
+
lines.push(`${ts} ${speaker}${seg.text}`);
|
|
4998
|
+
}
|
|
4999
|
+
} else {
|
|
5000
|
+
lines.push(result.text);
|
|
5001
|
+
}
|
|
5002
|
+
return {
|
|
5003
|
+
success: true,
|
|
5004
|
+
output: lines.join("\n"),
|
|
5005
|
+
durationMs: performance.now() - start
|
|
5006
|
+
};
|
|
5007
|
+
} catch (err) {
|
|
5008
|
+
return {
|
|
5009
|
+
success: false,
|
|
5010
|
+
output: "",
|
|
5011
|
+
error: `Transcription failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
5012
|
+
durationMs: performance.now() - start
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
/** Fallback: invoke transcribe-cli as a subprocess. */
|
|
5017
|
+
async execViaCli(filePath, model, diarize, start) {
|
|
5018
|
+
try {
|
|
5019
|
+
const args = [filePath, "-m", model, "-f", "txt"];
|
|
5020
|
+
if (diarize)
|
|
5021
|
+
args.push("--diarize");
|
|
5022
|
+
const output = execSync9(`transcribe-cli ${args.join(" ")}`, {
|
|
5023
|
+
encoding: "utf-8",
|
|
5024
|
+
timeout: 3e5,
|
|
5025
|
+
// 5 min max
|
|
5026
|
+
cwd: this.workingDir,
|
|
5027
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5028
|
+
});
|
|
5029
|
+
return {
|
|
5030
|
+
success: true,
|
|
5031
|
+
output: output.trim() || "(empty transcription)",
|
|
5032
|
+
durationMs: performance.now() - start
|
|
5033
|
+
};
|
|
5034
|
+
} catch (err) {
|
|
5035
|
+
const stderr = err.stderr || "";
|
|
5036
|
+
return {
|
|
5037
|
+
success: false,
|
|
5038
|
+
output: err.stdout || "",
|
|
5039
|
+
error: `transcribe-cli failed: ${stderr || err.message}`,
|
|
5040
|
+
durationMs: performance.now() - start
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
}
|
|
5044
|
+
};
|
|
5045
|
+
TranscribeUrlTool = class {
|
|
5046
|
+
name = "transcribe_url";
|
|
5047
|
+
description = "Download an audio or video file from a URL and transcribe it to text. Supports direct links to MP3, WAV, MP4, and other media files. The file is downloaded to a temp location, transcribed locally, then cleaned up.";
|
|
5048
|
+
parameters = {
|
|
5049
|
+
type: "object",
|
|
5050
|
+
properties: {
|
|
5051
|
+
url: {
|
|
5052
|
+
type: "string",
|
|
5053
|
+
description: "URL of the audio or video file to download and transcribe"
|
|
5054
|
+
},
|
|
5055
|
+
model: {
|
|
5056
|
+
type: "string",
|
|
5057
|
+
description: "Whisper model size: tiny, base, small, medium, large-v3 (default: base)",
|
|
5058
|
+
enum: ["tiny", "base", "small", "medium", "large-v3"]
|
|
5059
|
+
}
|
|
5060
|
+
},
|
|
5061
|
+
required: ["url"]
|
|
5062
|
+
};
|
|
5063
|
+
workingDir;
|
|
5064
|
+
constructor(workingDir) {
|
|
5065
|
+
this.workingDir = workingDir;
|
|
5066
|
+
}
|
|
5067
|
+
async execute(args) {
|
|
5068
|
+
const start = performance.now();
|
|
5069
|
+
const url = String(args["url"] ?? "");
|
|
5070
|
+
const model = String(args["model"] ?? "base");
|
|
5071
|
+
if (!url) {
|
|
5072
|
+
return {
|
|
5073
|
+
success: false,
|
|
5074
|
+
output: "",
|
|
5075
|
+
error: "URL is required.",
|
|
5076
|
+
durationMs: performance.now() - start
|
|
5077
|
+
};
|
|
5078
|
+
}
|
|
5079
|
+
const tmpDir = join13(this.workingDir, ".oa", "tmp");
|
|
5080
|
+
mkdirSync4(tmpDir, { recursive: true });
|
|
5081
|
+
const urlPath = new URL(url).pathname;
|
|
5082
|
+
let ext = extname3(urlPath).toLowerCase();
|
|
5083
|
+
if (!ext || !AUDIO_EXTS.has(ext) && !VIDEO_EXTS.has(ext)) {
|
|
5084
|
+
ext = ".mp3";
|
|
5085
|
+
}
|
|
5086
|
+
const tmpFile = join13(tmpDir, `download-${Date.now()}${ext}`);
|
|
5087
|
+
try {
|
|
5088
|
+
try {
|
|
5089
|
+
execSync9(`curl -sL -o "${tmpFile}" "${url}"`, {
|
|
5090
|
+
timeout: 12e4,
|
|
5091
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5092
|
+
});
|
|
5093
|
+
} catch {
|
|
5094
|
+
execSync9(`wget -q -O "${tmpFile}" "${url}"`, {
|
|
5095
|
+
timeout: 12e4,
|
|
5096
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5097
|
+
});
|
|
5098
|
+
}
|
|
5099
|
+
if (!existsSync10(tmpFile)) {
|
|
5100
|
+
return {
|
|
5101
|
+
success: false,
|
|
5102
|
+
output: "",
|
|
5103
|
+
error: "Download failed \u2014 file not created.",
|
|
5104
|
+
durationMs: performance.now() - start
|
|
5105
|
+
};
|
|
5106
|
+
}
|
|
5107
|
+
const fileTool = new TranscribeFileTool(this.workingDir);
|
|
5108
|
+
const result = await fileTool.execute({ path: tmpFile, model });
|
|
5109
|
+
try {
|
|
5110
|
+
unlinkSync(tmpFile);
|
|
5111
|
+
} catch {
|
|
5112
|
+
}
|
|
5113
|
+
return {
|
|
5114
|
+
success: result.success,
|
|
5115
|
+
output: `Source: ${url}
|
|
5116
|
+
${result.output}`,
|
|
5117
|
+
error: result.error,
|
|
5118
|
+
durationMs: performance.now() - start
|
|
5119
|
+
};
|
|
5120
|
+
} catch (err) {
|
|
5121
|
+
try {
|
|
5122
|
+
unlinkSync(tmpFile);
|
|
5123
|
+
} catch {
|
|
5124
|
+
}
|
|
5125
|
+
return {
|
|
5126
|
+
success: false,
|
|
5127
|
+
output: "",
|
|
5128
|
+
error: `Failed to download/transcribe: ${err instanceof Error ? err.message : String(err)}`,
|
|
5129
|
+
durationMs: performance.now() - start
|
|
5130
|
+
};
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
};
|
|
5134
|
+
}
|
|
5135
|
+
});
|
|
5136
|
+
|
|
4843
5137
|
// packages/execution/dist/shellRunner.js
|
|
4844
5138
|
var init_shellRunner = __esm({
|
|
4845
5139
|
"packages/execution/dist/shellRunner.js"() {
|
|
@@ -4943,6 +5237,7 @@ var init_dist2 = __esm({
|
|
|
4943
5237
|
init_custom_tool();
|
|
4944
5238
|
init_tool_creator();
|
|
4945
5239
|
init_skill_tools();
|
|
5240
|
+
init_transcribe_tool();
|
|
4946
5241
|
init_shellRunner();
|
|
4947
5242
|
init_gitWorktree();
|
|
4948
5243
|
init_patchApplier();
|
|
@@ -6074,7 +6369,7 @@ var init_code_retriever = __esm({
|
|
|
6074
6369
|
import { execFile as execFile4 } from "node:child_process";
|
|
6075
6370
|
import { promisify as promisify4 } from "node:util";
|
|
6076
6371
|
import { readFile as readFile7, readdir, stat } from "node:fs/promises";
|
|
6077
|
-
import { join as
|
|
6372
|
+
import { join as join14, extname as extname4 } from "node:path";
|
|
6078
6373
|
async function searchByPath(pathPattern, options) {
|
|
6079
6374
|
const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
|
|
6080
6375
|
const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
|
|
@@ -6216,11 +6511,11 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
|
6216
6511
|
continue;
|
|
6217
6512
|
if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
|
|
6218
6513
|
continue;
|
|
6219
|
-
const absPath =
|
|
6514
|
+
const absPath = join14(dir, entry.name);
|
|
6220
6515
|
if (entry.isDirectory()) {
|
|
6221
6516
|
await walkForFiles(rootDir, absPath, excludeGlobs, results);
|
|
6222
6517
|
} else if (entry.isFile()) {
|
|
6223
|
-
const ext =
|
|
6518
|
+
const ext = extname4(entry.name);
|
|
6224
6519
|
if (!ALL_CODE_EXTS.has(ext))
|
|
6225
6520
|
continue;
|
|
6226
6521
|
const relativePath = absPath.startsWith(rootDir) ? absPath.slice(rootDir.length).replace(/^\//, "") : absPath;
|
|
@@ -6391,7 +6686,7 @@ var init_graphExpand = __esm({
|
|
|
6391
6686
|
|
|
6392
6687
|
// packages/retrieval/dist/snippetPacker.js
|
|
6393
6688
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
6394
|
-
import { join as
|
|
6689
|
+
import { join as join15 } from "node:path";
|
|
6395
6690
|
async function packSnippets(requests, opts = {}) {
|
|
6396
6691
|
const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
6397
6692
|
const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
|
|
@@ -6417,7 +6712,7 @@ async function packSnippets(requests, opts = {}) {
|
|
|
6417
6712
|
return { packed, dropped, totalTokens };
|
|
6418
6713
|
}
|
|
6419
6714
|
async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
|
|
6420
|
-
const absPath = req.filePath.startsWith("/") ? req.filePath :
|
|
6715
|
+
const absPath = req.filePath.startsWith("/") ? req.filePath : join15(repoRoot, req.filePath);
|
|
6421
6716
|
let content;
|
|
6422
6717
|
try {
|
|
6423
6718
|
content = await readFile8(absPath, "utf-8");
|
|
@@ -8726,6 +9021,408 @@ var init_dist5 = __esm({
|
|
|
8726
9021
|
}
|
|
8727
9022
|
});
|
|
8728
9023
|
|
|
9024
|
+
// packages/cli/dist/tui/listen.js
|
|
9025
|
+
import { spawn as spawn5, execSync as execSync10 } from "node:child_process";
|
|
9026
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9027
|
+
import { join as join16 } from "node:path";
|
|
9028
|
+
import { homedir as homedir6 } from "node:os";
|
|
9029
|
+
import { EventEmitter } from "node:events";
|
|
9030
|
+
function isAudioPath(path) {
|
|
9031
|
+
const ext = path.toLowerCase().split(".").pop();
|
|
9032
|
+
return ext ? AUDIO_EXTENSIONS.has(`.${ext}`) : false;
|
|
9033
|
+
}
|
|
9034
|
+
function isVideoPath(path) {
|
|
9035
|
+
const ext = path.toLowerCase().split(".").pop();
|
|
9036
|
+
return ext ? VIDEO_EXTENSIONS.has(`.${ext}`) : false;
|
|
9037
|
+
}
|
|
9038
|
+
function isTranscribablePath(path) {
|
|
9039
|
+
return isAudioPath(path) || isVideoPath(path);
|
|
9040
|
+
}
|
|
9041
|
+
function findMicCaptureCommand() {
|
|
9042
|
+
const platform3 = process.platform;
|
|
9043
|
+
if (platform3 === "linux") {
|
|
9044
|
+
try {
|
|
9045
|
+
execSync10("which arecord", { stdio: "pipe" });
|
|
9046
|
+
return {
|
|
9047
|
+
cmd: "arecord",
|
|
9048
|
+
args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
|
|
9049
|
+
};
|
|
9050
|
+
} catch {
|
|
9051
|
+
}
|
|
9052
|
+
}
|
|
9053
|
+
if (platform3 === "darwin") {
|
|
9054
|
+
try {
|
|
9055
|
+
execSync10("which sox", { stdio: "pipe" });
|
|
9056
|
+
return {
|
|
9057
|
+
cmd: "sox",
|
|
9058
|
+
args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
|
|
9059
|
+
};
|
|
9060
|
+
} catch {
|
|
9061
|
+
}
|
|
9062
|
+
}
|
|
9063
|
+
try {
|
|
9064
|
+
execSync10("which ffmpeg", { stdio: "pipe" });
|
|
9065
|
+
if (platform3 === "linux") {
|
|
9066
|
+
return {
|
|
9067
|
+
cmd: "ffmpeg",
|
|
9068
|
+
args: [
|
|
9069
|
+
"-f",
|
|
9070
|
+
"pulse",
|
|
9071
|
+
"-i",
|
|
9072
|
+
"default",
|
|
9073
|
+
"-ar",
|
|
9074
|
+
"16000",
|
|
9075
|
+
"-ac",
|
|
9076
|
+
"1",
|
|
9077
|
+
"-f",
|
|
9078
|
+
"s16le",
|
|
9079
|
+
"-loglevel",
|
|
9080
|
+
"quiet",
|
|
9081
|
+
"pipe:1"
|
|
9082
|
+
]
|
|
9083
|
+
};
|
|
9084
|
+
} else if (platform3 === "darwin") {
|
|
9085
|
+
return {
|
|
9086
|
+
cmd: "ffmpeg",
|
|
9087
|
+
args: [
|
|
9088
|
+
"-f",
|
|
9089
|
+
"avfoundation",
|
|
9090
|
+
"-i",
|
|
9091
|
+
":0",
|
|
9092
|
+
"-ar",
|
|
9093
|
+
"16000",
|
|
9094
|
+
"-ac",
|
|
9095
|
+
"1",
|
|
9096
|
+
"-f",
|
|
9097
|
+
"s16le",
|
|
9098
|
+
"-loglevel",
|
|
9099
|
+
"quiet",
|
|
9100
|
+
"pipe:1"
|
|
9101
|
+
]
|
|
9102
|
+
};
|
|
9103
|
+
}
|
|
9104
|
+
} catch {
|
|
9105
|
+
}
|
|
9106
|
+
return null;
|
|
9107
|
+
}
|
|
9108
|
+
function getListenEngine(config) {
|
|
9109
|
+
if (!_engine) {
|
|
9110
|
+
_engine = new ListenEngine(config);
|
|
9111
|
+
}
|
|
9112
|
+
return _engine;
|
|
9113
|
+
}
|
|
9114
|
+
var AUDIO_EXTENSIONS, VIDEO_EXTENSIONS, ListenEngine, _engine;
|
|
9115
|
+
var init_listen = __esm({
|
|
9116
|
+
"packages/cli/dist/tui/listen.js"() {
|
|
9117
|
+
"use strict";
|
|
9118
|
+
AUDIO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9119
|
+
".mp3",
|
|
9120
|
+
".wav",
|
|
9121
|
+
".flac",
|
|
9122
|
+
".aac",
|
|
9123
|
+
".m4a",
|
|
9124
|
+
".ogg",
|
|
9125
|
+
".wma",
|
|
9126
|
+
".opus"
|
|
9127
|
+
]);
|
|
9128
|
+
VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9129
|
+
".mp4",
|
|
9130
|
+
".mkv",
|
|
9131
|
+
".avi",
|
|
9132
|
+
".mov",
|
|
9133
|
+
".webm",
|
|
9134
|
+
".flv",
|
|
9135
|
+
".wmv",
|
|
9136
|
+
".m4v",
|
|
9137
|
+
".ts"
|
|
9138
|
+
]);
|
|
9139
|
+
ListenEngine = class extends EventEmitter {
|
|
9140
|
+
config;
|
|
9141
|
+
micProcess = null;
|
|
9142
|
+
liveTranscriber = null;
|
|
9143
|
+
// TranscribeLive from transcribe-cli
|
|
9144
|
+
active = false;
|
|
9145
|
+
silenceTimer = null;
|
|
9146
|
+
countdownInterval = null;
|
|
9147
|
+
lastTranscriptTime = 0;
|
|
9148
|
+
pendingText = "";
|
|
9149
|
+
blinkTimer = null;
|
|
9150
|
+
blinkState = false;
|
|
9151
|
+
transcribeCliAvailable = null;
|
|
9152
|
+
constructor(config) {
|
|
9153
|
+
super();
|
|
9154
|
+
this.config = {
|
|
9155
|
+
model: config?.model ?? "base",
|
|
9156
|
+
mode: config?.mode ?? "confirm",
|
|
9157
|
+
silenceTimeoutMs: config?.silenceTimeoutMs ?? 3e3
|
|
9158
|
+
};
|
|
9159
|
+
}
|
|
9160
|
+
get isActive() {
|
|
9161
|
+
return this.active;
|
|
9162
|
+
}
|
|
9163
|
+
get isBlinking() {
|
|
9164
|
+
return this.active && this.blinkState;
|
|
9165
|
+
}
|
|
9166
|
+
get currentModel() {
|
|
9167
|
+
return this.config.model;
|
|
9168
|
+
}
|
|
9169
|
+
get currentMode() {
|
|
9170
|
+
return this.config.mode;
|
|
9171
|
+
}
|
|
9172
|
+
get pendingTranscript() {
|
|
9173
|
+
return this.pendingText;
|
|
9174
|
+
}
|
|
9175
|
+
setModel(model) {
|
|
9176
|
+
this.config.model = model;
|
|
9177
|
+
}
|
|
9178
|
+
setMode(mode) {
|
|
9179
|
+
this.config.mode = mode;
|
|
9180
|
+
}
|
|
9181
|
+
/** Check if transcribe-cli is available. */
|
|
9182
|
+
async isAvailable() {
|
|
9183
|
+
if (this.transcribeCliAvailable !== null)
|
|
9184
|
+
return this.transcribeCliAvailable;
|
|
9185
|
+
try {
|
|
9186
|
+
const mod = await this.loadTranscribeCli();
|
|
9187
|
+
this.transcribeCliAvailable = mod !== null;
|
|
9188
|
+
} catch {
|
|
9189
|
+
this.transcribeCliAvailable = false;
|
|
9190
|
+
}
|
|
9191
|
+
if (!this.transcribeCliAvailable) {
|
|
9192
|
+
try {
|
|
9193
|
+
execSync10("which transcribe-cli", { stdio: "pipe" });
|
|
9194
|
+
this.transcribeCliAvailable = true;
|
|
9195
|
+
} catch {
|
|
9196
|
+
this.transcribeCliAvailable = false;
|
|
9197
|
+
}
|
|
9198
|
+
}
|
|
9199
|
+
return this.transcribeCliAvailable;
|
|
9200
|
+
}
|
|
9201
|
+
/** Load transcribe-cli dynamically (it may not be installed). */
|
|
9202
|
+
async loadTranscribeCli() {
|
|
9203
|
+
try {
|
|
9204
|
+
const globalRoot = execSync10("npm root -g", {
|
|
9205
|
+
encoding: "utf-8",
|
|
9206
|
+
timeout: 5e3,
|
|
9207
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
9208
|
+
}).trim();
|
|
9209
|
+
const tcPath = join16(globalRoot, "transcribe-cli");
|
|
9210
|
+
if (existsSync11(join16(tcPath, "dist", "index.js"))) {
|
|
9211
|
+
const { createRequire: createRequire4 } = await import("node:module");
|
|
9212
|
+
const req = createRequire4(import.meta.url);
|
|
9213
|
+
return req(join16(tcPath, "dist", "index.js"));
|
|
9214
|
+
}
|
|
9215
|
+
} catch {
|
|
9216
|
+
}
|
|
9217
|
+
const nvmBase = join16(homedir6(), ".nvm", "versions", "node");
|
|
9218
|
+
if (existsSync11(nvmBase)) {
|
|
9219
|
+
try {
|
|
9220
|
+
const { readdirSync: readdirSync9 } = await import("node:fs");
|
|
9221
|
+
for (const ver of readdirSync9(nvmBase)) {
|
|
9222
|
+
const tcPath = join16(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
9223
|
+
if (existsSync11(join16(tcPath, "dist", "index.js"))) {
|
|
9224
|
+
const { createRequire: createRequire4 } = await import("node:module");
|
|
9225
|
+
const req = createRequire4(import.meta.url);
|
|
9226
|
+
return req(join16(tcPath, "dist", "index.js"));
|
|
9227
|
+
}
|
|
9228
|
+
}
|
|
9229
|
+
} catch {
|
|
9230
|
+
}
|
|
9231
|
+
}
|
|
9232
|
+
return null;
|
|
9233
|
+
}
|
|
9234
|
+
/**
|
|
9235
|
+
* Start listening — captures microphone audio and feeds to TranscribeLive.
|
|
9236
|
+
*/
|
|
9237
|
+
async start() {
|
|
9238
|
+
if (this.active)
|
|
9239
|
+
return "Already listening.";
|
|
9240
|
+
const micCmd = findMicCaptureCommand();
|
|
9241
|
+
if (!micCmd) {
|
|
9242
|
+
return "No microphone capture tool found. Install arecord (Linux), sox (macOS), or ffmpeg.";
|
|
9243
|
+
}
|
|
9244
|
+
const tc = await this.loadTranscribeCli();
|
|
9245
|
+
if (!tc) {
|
|
9246
|
+
return "transcribe-cli not installed. Run: npm i -g transcribe-cli";
|
|
9247
|
+
}
|
|
9248
|
+
const TranscribeLive = tc.TranscribeLive;
|
|
9249
|
+
this.liveTranscriber = new TranscribeLive({
|
|
9250
|
+
model: this.config.model,
|
|
9251
|
+
sampleRate: 16e3,
|
|
9252
|
+
channels: 1,
|
|
9253
|
+
sampleWidth: 2,
|
|
9254
|
+
chunkDuration: 3
|
|
9255
|
+
// 3s chunks for responsive transcription
|
|
9256
|
+
});
|
|
9257
|
+
this.liveTranscriber.on("transcript", (evt) => {
|
|
9258
|
+
if (!evt.text.trim())
|
|
9259
|
+
return;
|
|
9260
|
+
this.lastTranscriptTime = Date.now();
|
|
9261
|
+
this.pendingText = evt.text.trim();
|
|
9262
|
+
this.emit("transcript", this.pendingText, evt.isFinal);
|
|
9263
|
+
if (this.config.mode === "auto") {
|
|
9264
|
+
this.resetSilenceTimer();
|
|
9265
|
+
}
|
|
9266
|
+
});
|
|
9267
|
+
this.liveTranscriber.on("error", (err) => {
|
|
9268
|
+
this.emit("error", err);
|
|
9269
|
+
});
|
|
9270
|
+
await new Promise((resolve16, reject) => {
|
|
9271
|
+
const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
|
|
9272
|
+
this.liveTranscriber.on("ready", () => {
|
|
9273
|
+
clearTimeout(timeout);
|
|
9274
|
+
resolve16();
|
|
9275
|
+
});
|
|
9276
|
+
this.liveTranscriber.on("error", (err) => {
|
|
9277
|
+
clearTimeout(timeout);
|
|
9278
|
+
reject(err);
|
|
9279
|
+
});
|
|
9280
|
+
});
|
|
9281
|
+
this.micProcess = spawn5(micCmd.cmd, micCmd.args, {
|
|
9282
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
9283
|
+
env: { ...process.env }
|
|
9284
|
+
});
|
|
9285
|
+
this.micProcess.stdout?.on("data", (chunk) => {
|
|
9286
|
+
if (this.active && this.liveTranscriber) {
|
|
9287
|
+
this.liveTranscriber.write(chunk);
|
|
9288
|
+
}
|
|
9289
|
+
});
|
|
9290
|
+
this.micProcess.stderr?.on("data", () => {
|
|
9291
|
+
});
|
|
9292
|
+
this.micProcess.on("error", (err) => {
|
|
9293
|
+
this.emit("error", new Error(`Mic capture failed: ${err.message}`));
|
|
9294
|
+
this.stop();
|
|
9295
|
+
});
|
|
9296
|
+
this.micProcess.on("close", () => {
|
|
9297
|
+
if (this.active) {
|
|
9298
|
+
this.stop();
|
|
9299
|
+
}
|
|
9300
|
+
});
|
|
9301
|
+
this.active = true;
|
|
9302
|
+
this.blinkState = true;
|
|
9303
|
+
this.blinkTimer = setInterval(() => {
|
|
9304
|
+
this.blinkState = !this.blinkState;
|
|
9305
|
+
this.emit("recording", this.blinkState);
|
|
9306
|
+
}, 500);
|
|
9307
|
+
this.lastTranscriptTime = Date.now();
|
|
9308
|
+
this.emit("started");
|
|
9309
|
+
this.emit("recording", true);
|
|
9310
|
+
const modeDesc = this.config.mode === "auto" ? `auto (${this.config.silenceTimeoutMs / 1e3}s timeout)` : "confirm (press Enter to submit)";
|
|
9311
|
+
return `Listening with ${this.config.model} model (${modeDesc})`;
|
|
9312
|
+
}
|
|
9313
|
+
/**
|
|
9314
|
+
* Stop listening — cleanup mic, transcriber, timers.
|
|
9315
|
+
*/
|
|
9316
|
+
async stop() {
|
|
9317
|
+
if (!this.active)
|
|
9318
|
+
return "Not listening.";
|
|
9319
|
+
this.active = false;
|
|
9320
|
+
this.blinkState = false;
|
|
9321
|
+
if (this.blinkTimer) {
|
|
9322
|
+
clearInterval(this.blinkTimer);
|
|
9323
|
+
this.blinkTimer = null;
|
|
9324
|
+
}
|
|
9325
|
+
if (this.silenceTimer) {
|
|
9326
|
+
clearTimeout(this.silenceTimer);
|
|
9327
|
+
this.silenceTimer = null;
|
|
9328
|
+
}
|
|
9329
|
+
if (this.countdownInterval) {
|
|
9330
|
+
clearInterval(this.countdownInterval);
|
|
9331
|
+
this.countdownInterval = null;
|
|
9332
|
+
}
|
|
9333
|
+
if (this.micProcess) {
|
|
9334
|
+
try {
|
|
9335
|
+
this.micProcess.kill("SIGTERM");
|
|
9336
|
+
} catch {
|
|
9337
|
+
}
|
|
9338
|
+
this.micProcess = null;
|
|
9339
|
+
}
|
|
9340
|
+
if (this.liveTranscriber) {
|
|
9341
|
+
try {
|
|
9342
|
+
this.liveTranscriber.stop();
|
|
9343
|
+
} catch {
|
|
9344
|
+
}
|
|
9345
|
+
this.liveTranscriber = null;
|
|
9346
|
+
}
|
|
9347
|
+
this.emit("recording", false);
|
|
9348
|
+
this.emit("stopped");
|
|
9349
|
+
const result = this.pendingText;
|
|
9350
|
+
this.pendingText = "";
|
|
9351
|
+
return result || "Stopped listening.";
|
|
9352
|
+
}
|
|
9353
|
+
/**
|
|
9354
|
+
* Accept the current pending transcript (for confirm mode).
|
|
9355
|
+
* Returns the text to inject into the input line.
|
|
9356
|
+
*/
|
|
9357
|
+
acceptTranscript() {
|
|
9358
|
+
const text = this.pendingText;
|
|
9359
|
+
this.pendingText = "";
|
|
9360
|
+
return text;
|
|
9361
|
+
}
|
|
9362
|
+
/**
|
|
9363
|
+
* Transcribe a file (audio or video) using transcribe-cli.
|
|
9364
|
+
* Returns the transcription result.
|
|
9365
|
+
*/
|
|
9366
|
+
async transcribeFile(filePath, outputDir) {
|
|
9367
|
+
const tc = await this.loadTranscribeCli();
|
|
9368
|
+
if (!tc)
|
|
9369
|
+
return null;
|
|
9370
|
+
try {
|
|
9371
|
+
const result = await tc.transcribe(filePath, {
|
|
9372
|
+
model: this.config.model,
|
|
9373
|
+
format: "json",
|
|
9374
|
+
diarize: false,
|
|
9375
|
+
wordTimestamps: false
|
|
9376
|
+
});
|
|
9377
|
+
if (outputDir) {
|
|
9378
|
+
const { basename: basename8 } = await import("node:path");
|
|
9379
|
+
const transcriptDir = join16(outputDir, ".oa", "transcripts");
|
|
9380
|
+
mkdirSync5(transcriptDir, { recursive: true });
|
|
9381
|
+
const outFile = join16(transcriptDir, `${basename8(filePath)}.txt`);
|
|
9382
|
+
writeFileSync5(outFile, result.text, "utf-8");
|
|
9383
|
+
}
|
|
9384
|
+
return {
|
|
9385
|
+
text: result.text,
|
|
9386
|
+
duration: result.duration,
|
|
9387
|
+
speakers: result.speakers,
|
|
9388
|
+
segments: result.segments
|
|
9389
|
+
};
|
|
9390
|
+
} catch (err) {
|
|
9391
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
9392
|
+
return null;
|
|
9393
|
+
}
|
|
9394
|
+
}
|
|
9395
|
+
// -------------------------------------------------------------------------
|
|
9396
|
+
// Auto-mode silence detection
|
|
9397
|
+
// -------------------------------------------------------------------------
|
|
9398
|
+
resetSilenceTimer() {
|
|
9399
|
+
if (this.silenceTimer)
|
|
9400
|
+
clearTimeout(this.silenceTimer);
|
|
9401
|
+
if (this.countdownInterval)
|
|
9402
|
+
clearInterval(this.countdownInterval);
|
|
9403
|
+
const timeoutMs = this.config.silenceTimeoutMs;
|
|
9404
|
+
const startTime = Date.now();
|
|
9405
|
+
this.countdownInterval = setInterval(() => {
|
|
9406
|
+
const elapsed = Date.now() - startTime;
|
|
9407
|
+
const remaining = Math.max(0, Math.ceil((timeoutMs - elapsed) / 1e3));
|
|
9408
|
+
this.emit("countdown", remaining);
|
|
9409
|
+
if (remaining <= 0 && this.countdownInterval) {
|
|
9410
|
+
clearInterval(this.countdownInterval);
|
|
9411
|
+
this.countdownInterval = null;
|
|
9412
|
+
}
|
|
9413
|
+
}, 1e3);
|
|
9414
|
+
this.silenceTimer = setTimeout(() => {
|
|
9415
|
+
if (this.active && this.pendingText) {
|
|
9416
|
+
this.emit("countdown", 0);
|
|
9417
|
+
this.emit("transcript", this.pendingText, true);
|
|
9418
|
+
}
|
|
9419
|
+
}, timeoutMs);
|
|
9420
|
+
}
|
|
9421
|
+
};
|
|
9422
|
+
_engine = null;
|
|
9423
|
+
}
|
|
9424
|
+
});
|
|
9425
|
+
|
|
8729
9426
|
// packages/cli/dist/tui/model-picker.js
|
|
8730
9427
|
async function fetchOllamaModels(baseUrl) {
|
|
8731
9428
|
const url = `${baseUrl.replace(/\/$/, "")}/api/tags`;
|
|
@@ -9016,10 +9713,16 @@ function renderSlashHelp() {
|
|
|
9016
9713
|
["/dream deep", "Deep dream \u2014 multi-cycle exploration with sleep architecture"],
|
|
9017
9714
|
["/dream lucid", "Lucid dream \u2014 implements proposals, tests, evaluates in cycles"],
|
|
9018
9715
|
["/dream stop", "Wake up \u2014 stop dreaming"],
|
|
9716
|
+
["/listen", "Toggle live microphone transcription (Whisper)"],
|
|
9717
|
+
["/listen <model>", "Set model: tiny, base, small, medium, large"],
|
|
9718
|
+
["/listen confirm", "Require Enter to submit transcription"],
|
|
9719
|
+
["/listen auto", "Auto-submit after 3s silence (blinking \u25CF indicator)"],
|
|
9720
|
+
["/listen stop", "Stop listening"],
|
|
9019
9721
|
["/bruteforce", "Toggle brute-force mode (auto re-engage on turn limit)"],
|
|
9020
9722
|
["/tools", "List agent-created custom tools"],
|
|
9021
9723
|
["/skills", "List available AIWG skills"],
|
|
9022
9724
|
["/skills <keyword>", "Filter skills by name or trigger"],
|
|
9725
|
+
["/<skill-name> [args]", "Invoke an AIWG skill directly"],
|
|
9023
9726
|
["/verbose", "Toggle verbose mode"],
|
|
9024
9727
|
["/clear", "Clear the screen"],
|
|
9025
9728
|
["/help", "Show this help"],
|
|
@@ -9149,6 +9852,10 @@ function formatToolArgs(toolName, args) {
|
|
|
9149
9852
|
return String(args["region"] ?? "full screen");
|
|
9150
9853
|
case "ocr":
|
|
9151
9854
|
return `${args["path"] ?? ""}${args["region"] ? ` (${args["region"]})` : ""}`;
|
|
9855
|
+
case "transcribe_file":
|
|
9856
|
+
return `${args["path"] ?? ""}${args["model"] ? ` (${args["model"]})` : ""}`;
|
|
9857
|
+
case "transcribe_url":
|
|
9858
|
+
return truncStr(String(args["url"] ?? ""), 60);
|
|
9152
9859
|
default:
|
|
9153
9860
|
return Object.entries(args).map(([k, v]) => `${k}=${truncStr(String(v), 30)}`).join(", ");
|
|
9154
9861
|
}
|
|
@@ -9214,7 +9921,10 @@ var init_render = __esm({
|
|
|
9214
9921
|
// Image tools
|
|
9215
9922
|
image_read: "\u{1F5BC}\uFE0F",
|
|
9216
9923
|
screenshot: "\u{1F4F8}",
|
|
9217
|
-
ocr: "\u{1F441}\uFE0F"
|
|
9924
|
+
ocr: "\u{1F441}\uFE0F",
|
|
9925
|
+
// Transcription tools
|
|
9926
|
+
transcribe_file: "\u{1F399}\uFE0F",
|
|
9927
|
+
transcribe_url: "\u{1F399}\uFE0F"
|
|
9218
9928
|
};
|
|
9219
9929
|
TOOL_LABELS = {
|
|
9220
9930
|
file_read: "Read",
|
|
@@ -9245,7 +9955,10 @@ var init_render = __esm({
|
|
|
9245
9955
|
// Image tools
|
|
9246
9956
|
image_read: "Image read",
|
|
9247
9957
|
screenshot: "Screenshot",
|
|
9248
|
-
ocr: "OCR"
|
|
9958
|
+
ocr: "OCR",
|
|
9959
|
+
// Transcription tools
|
|
9960
|
+
transcribe_file: "Transcribe",
|
|
9961
|
+
transcribe_url: "Transcribe URL"
|
|
9249
9962
|
};
|
|
9250
9963
|
_contentWriteHook = null;
|
|
9251
9964
|
HINTS = [
|
|
@@ -9287,6 +10000,8 @@ var init_render = __esm({
|
|
|
9287
10000
|
"image_read",
|
|
9288
10001
|
"screenshot",
|
|
9289
10002
|
"ocr",
|
|
10003
|
+
"transcribe_file",
|
|
10004
|
+
"transcribe_url",
|
|
9290
10005
|
"aiwg_setup",
|
|
9291
10006
|
"aiwg_health",
|
|
9292
10007
|
"aiwg_workflow",
|
|
@@ -9301,11 +10016,13 @@ var init_render = __esm({
|
|
|
9301
10016
|
"/config",
|
|
9302
10017
|
"/update",
|
|
9303
10018
|
"/voice",
|
|
10019
|
+
"/listen",
|
|
9304
10020
|
"/stream",
|
|
9305
10021
|
"/verbose",
|
|
9306
10022
|
"/dream",
|
|
9307
10023
|
"/bruteforce",
|
|
9308
10024
|
"/tools",
|
|
10025
|
+
"/skills",
|
|
9309
10026
|
"/clear",
|
|
9310
10027
|
"/help",
|
|
9311
10028
|
"/quit"
|
|
@@ -9314,52 +10031,52 @@ var init_render = __esm({
|
|
|
9314
10031
|
});
|
|
9315
10032
|
|
|
9316
10033
|
// packages/cli/dist/tui/oa-directory.js
|
|
9317
|
-
import { existsSync as
|
|
9318
|
-
import { join as
|
|
9319
|
-
import { homedir as
|
|
10034
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6, readdirSync as readdirSync6, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
10035
|
+
import { join as join17, relative as relative2, basename as basename4, extname as extname5 } from "node:path";
|
|
10036
|
+
import { homedir as homedir7 } from "node:os";
|
|
9320
10037
|
function initOaDirectory(repoRoot) {
|
|
9321
|
-
const oaPath =
|
|
10038
|
+
const oaPath = join17(repoRoot, OA_DIR);
|
|
9322
10039
|
for (const sub of SUBDIRS) {
|
|
9323
|
-
|
|
10040
|
+
mkdirSync6(join17(oaPath, sub), { recursive: true });
|
|
9324
10041
|
}
|
|
9325
10042
|
return oaPath;
|
|
9326
10043
|
}
|
|
9327
10044
|
function hasOaDirectory(repoRoot) {
|
|
9328
|
-
return
|
|
10045
|
+
return existsSync12(join17(repoRoot, OA_DIR, "index"));
|
|
9329
10046
|
}
|
|
9330
10047
|
function loadProjectSettings(repoRoot) {
|
|
9331
|
-
const settingsPath =
|
|
10048
|
+
const settingsPath = join17(repoRoot, OA_DIR, "settings.json");
|
|
9332
10049
|
try {
|
|
9333
|
-
if (
|
|
9334
|
-
return JSON.parse(
|
|
10050
|
+
if (existsSync12(settingsPath)) {
|
|
10051
|
+
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
9335
10052
|
}
|
|
9336
10053
|
} catch {
|
|
9337
10054
|
}
|
|
9338
10055
|
return {};
|
|
9339
10056
|
}
|
|
9340
10057
|
function saveProjectSettings(repoRoot, settings) {
|
|
9341
|
-
const oaPath =
|
|
9342
|
-
|
|
10058
|
+
const oaPath = join17(repoRoot, OA_DIR);
|
|
10059
|
+
mkdirSync6(oaPath, { recursive: true });
|
|
9343
10060
|
const existing = loadProjectSettings(repoRoot);
|
|
9344
10061
|
const merged = { ...existing, ...settings };
|
|
9345
|
-
|
|
10062
|
+
writeFileSync6(join17(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
9346
10063
|
}
|
|
9347
10064
|
function loadGlobalSettings() {
|
|
9348
|
-
const settingsPath =
|
|
10065
|
+
const settingsPath = join17(homedir7(), ".open-agents", "settings.json");
|
|
9349
10066
|
try {
|
|
9350
|
-
if (
|
|
9351
|
-
return JSON.parse(
|
|
10067
|
+
if (existsSync12(settingsPath)) {
|
|
10068
|
+
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
9352
10069
|
}
|
|
9353
10070
|
} catch {
|
|
9354
10071
|
}
|
|
9355
10072
|
return {};
|
|
9356
10073
|
}
|
|
9357
10074
|
function saveGlobalSettings(settings) {
|
|
9358
|
-
const dir =
|
|
9359
|
-
|
|
10075
|
+
const dir = join17(homedir7(), ".open-agents");
|
|
10076
|
+
mkdirSync6(dir, { recursive: true });
|
|
9360
10077
|
const existing = loadGlobalSettings();
|
|
9361
10078
|
const merged = { ...existing, ...settings };
|
|
9362
|
-
|
|
10079
|
+
writeFileSync6(join17(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
9363
10080
|
}
|
|
9364
10081
|
function resolveSettings(repoRoot) {
|
|
9365
10082
|
const global = loadGlobalSettings();
|
|
@@ -9374,12 +10091,12 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
9374
10091
|
while (dir && !visited.has(dir)) {
|
|
9375
10092
|
visited.add(dir);
|
|
9376
10093
|
for (const name of CONTEXT_FILES) {
|
|
9377
|
-
const filePath =
|
|
10094
|
+
const filePath = join17(dir, name);
|
|
9378
10095
|
const normalizedName = name.toLowerCase();
|
|
9379
|
-
if (
|
|
10096
|
+
if (existsSync12(filePath) && !seen.has(filePath)) {
|
|
9380
10097
|
seen.add(filePath);
|
|
9381
10098
|
try {
|
|
9382
|
-
let content =
|
|
10099
|
+
let content = readFileSync10(filePath, "utf-8");
|
|
9383
10100
|
if (content.length > maxContentLen) {
|
|
9384
10101
|
content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
|
|
9385
10102
|
}
|
|
@@ -9393,11 +10110,11 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
9393
10110
|
}
|
|
9394
10111
|
}
|
|
9395
10112
|
}
|
|
9396
|
-
const projectMap =
|
|
9397
|
-
if (
|
|
10113
|
+
const projectMap = join17(dir, OA_DIR, "context", "project-map.md");
|
|
10114
|
+
if (existsSync12(projectMap) && !seen.has(projectMap)) {
|
|
9398
10115
|
seen.add(projectMap);
|
|
9399
10116
|
try {
|
|
9400
|
-
let content =
|
|
10117
|
+
let content = readFileSync10(projectMap, "utf-8");
|
|
9401
10118
|
if (content.length > maxContentLen) {
|
|
9402
10119
|
content = content.slice(0, maxContentLen) + "\n\n...(truncated)";
|
|
9403
10120
|
}
|
|
@@ -9409,7 +10126,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
9409
10126
|
} catch {
|
|
9410
10127
|
}
|
|
9411
10128
|
}
|
|
9412
|
-
const parent =
|
|
10129
|
+
const parent = join17(dir, "..");
|
|
9413
10130
|
if (parent === dir)
|
|
9414
10131
|
break;
|
|
9415
10132
|
dir = parent;
|
|
@@ -9427,16 +10144,16 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
9427
10144
|
return found;
|
|
9428
10145
|
}
|
|
9429
10146
|
function readIndexMeta(repoRoot) {
|
|
9430
|
-
const metaPath =
|
|
10147
|
+
const metaPath = join17(repoRoot, OA_DIR, "index", "meta.json");
|
|
9431
10148
|
try {
|
|
9432
|
-
return JSON.parse(
|
|
10149
|
+
return JSON.parse(readFileSync10(metaPath, "utf-8"));
|
|
9433
10150
|
} catch {
|
|
9434
10151
|
return null;
|
|
9435
10152
|
}
|
|
9436
10153
|
}
|
|
9437
10154
|
function generateProjectMap(repoRoot) {
|
|
9438
10155
|
const sections = [];
|
|
9439
|
-
const repoName2 =
|
|
10156
|
+
const repoName2 = basename4(repoRoot);
|
|
9440
10157
|
sections.push(`# Project Map: ${repoName2}
|
|
9441
10158
|
`);
|
|
9442
10159
|
sections.push(`> Auto-generated by open-agents. Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
@@ -9480,28 +10197,28 @@ ${tree}\`\`\`
|
|
|
9480
10197
|
sections.push("");
|
|
9481
10198
|
}
|
|
9482
10199
|
const content = sections.join("\n");
|
|
9483
|
-
const contextDir =
|
|
9484
|
-
|
|
9485
|
-
|
|
10200
|
+
const contextDir = join17(repoRoot, OA_DIR, "context");
|
|
10201
|
+
mkdirSync6(contextDir, { recursive: true });
|
|
10202
|
+
writeFileSync6(join17(contextDir, "project-map.md"), content, "utf-8");
|
|
9486
10203
|
return content;
|
|
9487
10204
|
}
|
|
9488
10205
|
function saveSession(repoRoot, session) {
|
|
9489
|
-
const historyDir =
|
|
9490
|
-
|
|
9491
|
-
|
|
10206
|
+
const historyDir = join17(repoRoot, OA_DIR, "history");
|
|
10207
|
+
mkdirSync6(historyDir, { recursive: true });
|
|
10208
|
+
writeFileSync6(join17(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
|
|
9492
10209
|
}
|
|
9493
10210
|
function loadRecentSessions(repoRoot, limit = 5) {
|
|
9494
|
-
const historyDir =
|
|
9495
|
-
if (!
|
|
10211
|
+
const historyDir = join17(repoRoot, OA_DIR, "history");
|
|
10212
|
+
if (!existsSync12(historyDir))
|
|
9496
10213
|
return [];
|
|
9497
10214
|
try {
|
|
9498
10215
|
const files = readdirSync6(historyDir).filter((f) => f.endsWith(".json")).map((f) => {
|
|
9499
|
-
const stat3 = statSync5(
|
|
10216
|
+
const stat3 = statSync5(join17(historyDir, f));
|
|
9500
10217
|
return { file: f, mtime: stat3.mtimeMs };
|
|
9501
10218
|
}).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
|
|
9502
10219
|
return files.map((f) => {
|
|
9503
10220
|
try {
|
|
9504
|
-
return JSON.parse(
|
|
10221
|
+
return JSON.parse(readFileSync10(join17(historyDir, f.file), "utf-8"));
|
|
9505
10222
|
} catch {
|
|
9506
10223
|
return null;
|
|
9507
10224
|
}
|
|
@@ -9511,18 +10228,18 @@ function loadRecentSessions(repoRoot, limit = 5) {
|
|
|
9511
10228
|
}
|
|
9512
10229
|
}
|
|
9513
10230
|
function savePendingTask(repoRoot, task) {
|
|
9514
|
-
const historyDir =
|
|
9515
|
-
|
|
9516
|
-
|
|
10231
|
+
const historyDir = join17(repoRoot, OA_DIR, "history");
|
|
10232
|
+
mkdirSync6(historyDir, { recursive: true });
|
|
10233
|
+
writeFileSync6(join17(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
|
|
9517
10234
|
}
|
|
9518
10235
|
function loadPendingTask(repoRoot) {
|
|
9519
|
-
const filePath =
|
|
10236
|
+
const filePath = join17(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
|
|
9520
10237
|
try {
|
|
9521
|
-
if (!
|
|
10238
|
+
if (!existsSync12(filePath))
|
|
9522
10239
|
return null;
|
|
9523
|
-
const data = JSON.parse(
|
|
10240
|
+
const data = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
9524
10241
|
try {
|
|
9525
|
-
|
|
10242
|
+
unlinkSync2(filePath);
|
|
9526
10243
|
} catch {
|
|
9527
10244
|
}
|
|
9528
10245
|
return data;
|
|
@@ -9548,12 +10265,12 @@ function detectManifests(repoRoot) {
|
|
|
9548
10265
|
{ file: "docker-compose.yaml", type: "Docker Compose" }
|
|
9549
10266
|
];
|
|
9550
10267
|
for (const check of checks) {
|
|
9551
|
-
const filePath =
|
|
9552
|
-
if (
|
|
10268
|
+
const filePath = join17(repoRoot, check.file);
|
|
10269
|
+
if (existsSync12(filePath)) {
|
|
9553
10270
|
let name;
|
|
9554
10271
|
if (check.nameField) {
|
|
9555
10272
|
try {
|
|
9556
|
-
const data = JSON.parse(
|
|
10273
|
+
const data = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
9557
10274
|
name = data[check.nameField];
|
|
9558
10275
|
} catch {
|
|
9559
10276
|
}
|
|
@@ -9582,7 +10299,7 @@ function findKeyFiles(repoRoot) {
|
|
|
9582
10299
|
{ pattern: "CLAUDE.md", description: "Claude Code context" }
|
|
9583
10300
|
];
|
|
9584
10301
|
for (const check of checks) {
|
|
9585
|
-
if (
|
|
10302
|
+
if (existsSync12(join17(repoRoot, check.pattern))) {
|
|
9586
10303
|
keyFiles.push({ path: check.pattern, description: check.description });
|
|
9587
10304
|
}
|
|
9588
10305
|
}
|
|
@@ -9608,12 +10325,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
|
|
|
9608
10325
|
if (entry.isDirectory()) {
|
|
9609
10326
|
let fileCount = 0;
|
|
9610
10327
|
try {
|
|
9611
|
-
fileCount = readdirSync6(
|
|
10328
|
+
fileCount = readdirSync6(join17(root, entry.name)).filter((f) => !f.startsWith(".")).length;
|
|
9612
10329
|
} catch {
|
|
9613
10330
|
}
|
|
9614
10331
|
result += `${prefix}${connector}${entry.name}/ (${fileCount})
|
|
9615
10332
|
`;
|
|
9616
|
-
result += buildDirTree(
|
|
10333
|
+
result += buildDirTree(join17(root, entry.name), maxDepth, childPrefix, depth + 1);
|
|
9617
10334
|
} else if (depth < maxDepth) {
|
|
9618
10335
|
result += `${prefix}${connector}${entry.name}
|
|
9619
10336
|
`;
|
|
@@ -9808,7 +10525,7 @@ async function handleSlashCommand(input, ctx) {
|
|
|
9808
10525
|
}
|
|
9809
10526
|
}
|
|
9810
10527
|
process.stdout.write("\n");
|
|
9811
|
-
renderInfo(
|
|
10528
|
+
renderInfo('Invoke directly: /<skill-name> [args] (e.g. /ralph "fix tests" --completion "npm test passes")');
|
|
9812
10529
|
renderInfo("Filter with: /skills <keyword>");
|
|
9813
10530
|
}
|
|
9814
10531
|
return "handled";
|
|
@@ -9829,6 +10546,38 @@ async function handleSlashCommand(input, ctx) {
|
|
|
9829
10546
|
}
|
|
9830
10547
|
return "handled";
|
|
9831
10548
|
}
|
|
10549
|
+
case "listen":
|
|
10550
|
+
case "mic": {
|
|
10551
|
+
if (!ctx.listenToggle) {
|
|
10552
|
+
renderWarning("Listen mode not available in this context.");
|
|
10553
|
+
return "handled";
|
|
10554
|
+
}
|
|
10555
|
+
if (arg === "stop" || arg === "off") {
|
|
10556
|
+
const msg2 = await (ctx.listenStop?.() ?? Promise.resolve("Not listening."));
|
|
10557
|
+
renderInfo(msg2);
|
|
10558
|
+
return "handled";
|
|
10559
|
+
}
|
|
10560
|
+
if (arg === "confirm") {
|
|
10561
|
+
const msg2 = ctx.listenSetMode?.("confirm") ?? "Confirm mode set.";
|
|
10562
|
+
renderInfo(msg2);
|
|
10563
|
+
return "handled";
|
|
10564
|
+
}
|
|
10565
|
+
if (arg === "auto") {
|
|
10566
|
+
const msg2 = ctx.listenSetMode?.("auto") ?? "Auto mode set.";
|
|
10567
|
+
renderInfo(msg2);
|
|
10568
|
+
return "handled";
|
|
10569
|
+
}
|
|
10570
|
+
const modelSizes = ["tiny", "base", "small", "medium", "large", "large-v3"];
|
|
10571
|
+
if (arg && modelSizes.includes(arg.toLowerCase())) {
|
|
10572
|
+
const model = arg.toLowerCase() === "large" ? "large-v3" : arg.toLowerCase();
|
|
10573
|
+
const msg2 = await (ctx.listenSetModel?.(model) ?? Promise.resolve(`Model set to ${model}.`));
|
|
10574
|
+
renderInfo(msg2);
|
|
10575
|
+
return "handled";
|
|
10576
|
+
}
|
|
10577
|
+
const msg = await ctx.listenToggle();
|
|
10578
|
+
renderInfo(msg);
|
|
10579
|
+
return "handled";
|
|
10580
|
+
}
|
|
9832
10581
|
case "bruteforce":
|
|
9833
10582
|
case "brute": {
|
|
9834
10583
|
const isOn = ctx.bruteForceToggle();
|
|
@@ -9837,9 +10586,19 @@ async function handleSlashCommand(input, ctx) {
|
|
|
9837
10586
|
renderInfo(`Brute-force mode: ${isOn ? "on" : "off"}${hasLocal ? " (project-local)" : ""}` + (isOn ? " \u2014 agent will auto re-engage when turn limit is hit, reassess and try creative strategies" : ""));
|
|
9838
10587
|
return "handled";
|
|
9839
10588
|
}
|
|
9840
|
-
default:
|
|
10589
|
+
default: {
|
|
10590
|
+
const skills = discoverSkills(ctx.repoRoot);
|
|
10591
|
+
const skill = skills.find((s) => s.name === cmd || s.name === cmd.replace(/_/g, "-"));
|
|
10592
|
+
if (skill) {
|
|
10593
|
+
const content = loadSkillContent(skill.filePath);
|
|
10594
|
+
if (content) {
|
|
10595
|
+
renderInfo(`Loading skill: ${c2.bold(skill.name)} (${skill.source})`);
|
|
10596
|
+
return { type: "skill", name: skill.name, content, args: arg };
|
|
10597
|
+
}
|
|
10598
|
+
}
|
|
9841
10599
|
renderWarning(`Unknown command: /${cmd}. Type /help for available commands.`);
|
|
9842
10600
|
return "handled";
|
|
10601
|
+
}
|
|
9843
10602
|
}
|
|
9844
10603
|
}
|
|
9845
10604
|
async function listModels(ctx) {
|
|
@@ -9971,17 +10730,17 @@ async function handleUpdate(subcommand, repoRoot, savePendingTaskState) {
|
|
|
9971
10730
|
try {
|
|
9972
10731
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
9973
10732
|
const { fileURLToPath: fileURLToPath3 } = await import("node:url");
|
|
9974
|
-
const { dirname: dirname5, join:
|
|
9975
|
-
const { existsSync:
|
|
10733
|
+
const { dirname: dirname5, join: join28 } = await import("node:path");
|
|
10734
|
+
const { existsSync: existsSync19 } = await import("node:fs");
|
|
9976
10735
|
const req = createRequire4(import.meta.url);
|
|
9977
10736
|
const thisDir = dirname5(fileURLToPath3(import.meta.url));
|
|
9978
10737
|
const candidates = [
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
10738
|
+
join28(thisDir, "..", "package.json"),
|
|
10739
|
+
join28(thisDir, "..", "..", "package.json"),
|
|
10740
|
+
join28(thisDir, "..", "..", "..", "package.json")
|
|
9982
10741
|
];
|
|
9983
10742
|
for (const pkgPath of candidates) {
|
|
9984
|
-
if (
|
|
10743
|
+
if (existsSync19(pkgPath)) {
|
|
9985
10744
|
const pkg = req(pkgPath);
|
|
9986
10745
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
9987
10746
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -10065,17 +10824,17 @@ var init_commands = __esm({
|
|
|
10065
10824
|
|
|
10066
10825
|
// packages/cli/dist/tui/setup.js
|
|
10067
10826
|
import * as readline from "node:readline";
|
|
10068
|
-
import { execSync as
|
|
10069
|
-
import { existsSync as
|
|
10070
|
-
import { join as
|
|
10071
|
-
import { homedir as
|
|
10827
|
+
import { execSync as execSync11 } from "node:child_process";
|
|
10828
|
+
import { existsSync as existsSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
10829
|
+
import { join as join18 } from "node:path";
|
|
10830
|
+
import { homedir as homedir8 } from "node:os";
|
|
10072
10831
|
function detectSystemSpecs() {
|
|
10073
10832
|
let totalRamGB = 0;
|
|
10074
10833
|
let availableRamGB = 0;
|
|
10075
10834
|
let gpuVramGB = 0;
|
|
10076
10835
|
let gpuName = "";
|
|
10077
10836
|
try {
|
|
10078
|
-
const memInfo =
|
|
10837
|
+
const memInfo = execSync11("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
|
|
10079
10838
|
encoding: "utf8",
|
|
10080
10839
|
timeout: 5e3
|
|
10081
10840
|
});
|
|
@@ -10095,7 +10854,7 @@ function detectSystemSpecs() {
|
|
|
10095
10854
|
} catch {
|
|
10096
10855
|
}
|
|
10097
10856
|
try {
|
|
10098
|
-
const nvidiaSmi =
|
|
10857
|
+
const nvidiaSmi = execSync11("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
|
|
10099
10858
|
const lines = nvidiaSmi.trim().split("\n");
|
|
10100
10859
|
if (lines.length > 0) {
|
|
10101
10860
|
for (const line of lines) {
|
|
@@ -10151,13 +10910,13 @@ function modelSupportsToolCalling(modelName) {
|
|
|
10151
10910
|
return false;
|
|
10152
10911
|
}
|
|
10153
10912
|
function ask(rl, question) {
|
|
10154
|
-
return new Promise((
|
|
10155
|
-
rl.question(question, (answer) =>
|
|
10913
|
+
return new Promise((resolve16) => {
|
|
10914
|
+
rl.question(question, (answer) => resolve16(answer.trim()));
|
|
10156
10915
|
});
|
|
10157
10916
|
}
|
|
10158
10917
|
function pullModelWithAutoUpdate(tag) {
|
|
10159
10918
|
try {
|
|
10160
|
-
|
|
10919
|
+
execSync11(`ollama pull ${tag}`, {
|
|
10161
10920
|
stdio: "inherit",
|
|
10162
10921
|
timeout: 36e5
|
|
10163
10922
|
// 1 hour max
|
|
@@ -10174,7 +10933,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
10174
10933
|
|
|
10175
10934
|
`);
|
|
10176
10935
|
try {
|
|
10177
|
-
|
|
10936
|
+
execSync11("curl -fsSL https://ollama.com/install.sh | sh", {
|
|
10178
10937
|
stdio: "inherit",
|
|
10179
10938
|
timeout: 3e5
|
|
10180
10939
|
// 5 min max for install
|
|
@@ -10185,7 +10944,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
10185
10944
|
process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
|
|
10186
10945
|
|
|
10187
10946
|
`);
|
|
10188
|
-
|
|
10947
|
+
execSync11(`ollama pull ${tag}`, {
|
|
10189
10948
|
stdio: "inherit",
|
|
10190
10949
|
timeout: 36e5
|
|
10191
10950
|
});
|
|
@@ -10363,12 +11122,12 @@ async function doSetup(config, rl) {
|
|
|
10363
11122
|
`PARAMETER num_predict 16384`,
|
|
10364
11123
|
`PARAMETER stop "<|endoftext|>"`
|
|
10365
11124
|
].join("\n");
|
|
10366
|
-
const modelDir2 =
|
|
10367
|
-
|
|
10368
|
-
const modelfilePath =
|
|
10369
|
-
|
|
11125
|
+
const modelDir2 = join18(homedir8(), ".open-agents", "models");
|
|
11126
|
+
mkdirSync7(modelDir2, { recursive: true });
|
|
11127
|
+
const modelfilePath = join18(modelDir2, `Modelfile.${customName}`);
|
|
11128
|
+
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
10370
11129
|
process.stdout.write(` ${c2.dim("Creating model...")} `);
|
|
10371
|
-
|
|
11130
|
+
execSync11(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
10372
11131
|
stdio: "pipe",
|
|
10373
11132
|
timeout: 12e4
|
|
10374
11133
|
});
|
|
@@ -10411,7 +11170,7 @@ async function isModelAvailable(config) {
|
|
|
10411
11170
|
}
|
|
10412
11171
|
function isFirstRun() {
|
|
10413
11172
|
try {
|
|
10414
|
-
return !
|
|
11173
|
+
return !existsSync13(join18(homedir8(), ".open-agents", "config.json"));
|
|
10415
11174
|
} catch {
|
|
10416
11175
|
return true;
|
|
10417
11176
|
}
|
|
@@ -10451,10 +11210,10 @@ var init_setup = __esm({
|
|
|
10451
11210
|
});
|
|
10452
11211
|
|
|
10453
11212
|
// packages/cli/dist/tui/project-context.js
|
|
10454
|
-
import { existsSync as
|
|
10455
|
-
import { join as
|
|
10456
|
-
import { execSync as
|
|
10457
|
-
import { homedir as
|
|
11213
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11, readdirSync as readdirSync7 } from "node:fs";
|
|
11214
|
+
import { join as join19, basename as basename5 } from "node:path";
|
|
11215
|
+
import { execSync as execSync12 } from "node:child_process";
|
|
11216
|
+
import { homedir as homedir9, platform, release } from "node:os";
|
|
10458
11217
|
function loadProjectFiles(repoRoot) {
|
|
10459
11218
|
const discovered = discoverContextFiles(repoRoot);
|
|
10460
11219
|
if (discovered.length === 0)
|
|
@@ -10472,10 +11231,10 @@ function loadProjectMap(repoRoot) {
|
|
|
10472
11231
|
if (!hasOaDirectory(repoRoot)) {
|
|
10473
11232
|
initOaDirectory(repoRoot);
|
|
10474
11233
|
}
|
|
10475
|
-
const mapPath =
|
|
10476
|
-
if (
|
|
11234
|
+
const mapPath = join19(repoRoot, OA_DIR, "context", "project-map.md");
|
|
11235
|
+
if (existsSync14(mapPath)) {
|
|
10477
11236
|
try {
|
|
10478
|
-
const content =
|
|
11237
|
+
const content = readFileSync11(mapPath, "utf-8");
|
|
10479
11238
|
return content;
|
|
10480
11239
|
} catch {
|
|
10481
11240
|
}
|
|
@@ -10484,19 +11243,19 @@ function loadProjectMap(repoRoot) {
|
|
|
10484
11243
|
}
|
|
10485
11244
|
function getGitInfo(repoRoot) {
|
|
10486
11245
|
try {
|
|
10487
|
-
|
|
11246
|
+
execSync12("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
|
|
10488
11247
|
} catch {
|
|
10489
11248
|
return "";
|
|
10490
11249
|
}
|
|
10491
11250
|
const lines = [];
|
|
10492
11251
|
try {
|
|
10493
|
-
const branch =
|
|
11252
|
+
const branch = execSync12("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
10494
11253
|
if (branch)
|
|
10495
11254
|
lines.push(`Branch: ${branch}`);
|
|
10496
11255
|
} catch {
|
|
10497
11256
|
}
|
|
10498
11257
|
try {
|
|
10499
|
-
const status =
|
|
11258
|
+
const status = execSync12("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
10500
11259
|
if (status) {
|
|
10501
11260
|
const changed = status.split("\n").length;
|
|
10502
11261
|
lines.push(`Working tree: ${changed} changed file(s)`);
|
|
@@ -10506,7 +11265,7 @@ function getGitInfo(repoRoot) {
|
|
|
10506
11265
|
} catch {
|
|
10507
11266
|
}
|
|
10508
11267
|
try {
|
|
10509
|
-
const log =
|
|
11268
|
+
const log = execSync12("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
10510
11269
|
if (log)
|
|
10511
11270
|
lines.push(`Recent commits:
|
|
10512
11271
|
${log}`);
|
|
@@ -10516,33 +11275,33 @@ ${log}`);
|
|
|
10516
11275
|
}
|
|
10517
11276
|
function loadMemoryContext(repoRoot) {
|
|
10518
11277
|
const sections = [];
|
|
10519
|
-
const oaMemDir =
|
|
11278
|
+
const oaMemDir = join19(repoRoot, OA_DIR, "memory");
|
|
10520
11279
|
const oaEntries = loadMemoryDir(oaMemDir, "project");
|
|
10521
11280
|
if (oaEntries)
|
|
10522
11281
|
sections.push(oaEntries);
|
|
10523
|
-
const legacyMemDir =
|
|
10524
|
-
if (legacyMemDir !== oaMemDir &&
|
|
11282
|
+
const legacyMemDir = join19(repoRoot, ".open-agents", "memory");
|
|
11283
|
+
if (legacyMemDir !== oaMemDir && existsSync14(legacyMemDir)) {
|
|
10525
11284
|
const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
|
|
10526
11285
|
if (legacyEntries)
|
|
10527
11286
|
sections.push(legacyEntries);
|
|
10528
11287
|
}
|
|
10529
|
-
const globalMemDir =
|
|
11288
|
+
const globalMemDir = join19(homedir9(), ".open-agents", "memory");
|
|
10530
11289
|
const globalEntries = loadMemoryDir(globalMemDir, "global");
|
|
10531
11290
|
if (globalEntries)
|
|
10532
11291
|
sections.push(globalEntries);
|
|
10533
11292
|
return sections.join("\n\n");
|
|
10534
11293
|
}
|
|
10535
11294
|
function loadMemoryDir(memDir, scope) {
|
|
10536
|
-
if (!
|
|
11295
|
+
if (!existsSync14(memDir))
|
|
10537
11296
|
return "";
|
|
10538
11297
|
const lines = [];
|
|
10539
11298
|
try {
|
|
10540
11299
|
const files = readdirSync7(memDir).filter((f) => f.endsWith(".json"));
|
|
10541
11300
|
for (const file of files.slice(0, 10)) {
|
|
10542
11301
|
try {
|
|
10543
|
-
const raw =
|
|
11302
|
+
const raw = readFileSync11(join19(memDir, file), "utf-8");
|
|
10544
11303
|
const entries = JSON.parse(raw);
|
|
10545
|
-
const topic =
|
|
11304
|
+
const topic = basename5(file, ".json");
|
|
10546
11305
|
const keys = Object.keys(entries);
|
|
10547
11306
|
if (keys.length === 0)
|
|
10548
11307
|
continue;
|
|
@@ -11551,25 +12310,25 @@ var init_carousel = __esm({
|
|
|
11551
12310
|
});
|
|
11552
12311
|
|
|
11553
12312
|
// packages/cli/dist/tui/voice.js
|
|
11554
|
-
import { existsSync as
|
|
11555
|
-
import { join as
|
|
11556
|
-
import { homedir as
|
|
11557
|
-
import { execSync as
|
|
12313
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readFileSync as readFileSync12, unlinkSync as unlinkSync3 } from "node:fs";
|
|
12314
|
+
import { join as join20 } from "node:path";
|
|
12315
|
+
import { homedir as homedir10, tmpdir as tmpdir2, platform as platform2 } from "node:os";
|
|
12316
|
+
import { execSync as execSync13, spawn as nodeSpawn } from "node:child_process";
|
|
11558
12317
|
import { createRequire } from "node:module";
|
|
11559
12318
|
function voiceDir() {
|
|
11560
|
-
return
|
|
12319
|
+
return join20(homedir10(), ".open-agents", "voice");
|
|
11561
12320
|
}
|
|
11562
12321
|
function modelsDir() {
|
|
11563
|
-
return
|
|
12322
|
+
return join20(voiceDir(), "models");
|
|
11564
12323
|
}
|
|
11565
12324
|
function modelDir(id) {
|
|
11566
|
-
return
|
|
12325
|
+
return join20(modelsDir(), id);
|
|
11567
12326
|
}
|
|
11568
12327
|
function modelOnnxPath(id) {
|
|
11569
|
-
return
|
|
12328
|
+
return join20(modelDir(id), "model.onnx");
|
|
11570
12329
|
}
|
|
11571
12330
|
function modelConfigPath(id) {
|
|
11572
|
-
return
|
|
12331
|
+
return join20(modelDir(id), "config.json");
|
|
11573
12332
|
}
|
|
11574
12333
|
function describeToolCall(toolName, args) {
|
|
11575
12334
|
const path = args["path"];
|
|
@@ -11842,11 +12601,11 @@ var init_voice = __esm({
|
|
|
11842
12601
|
const audioData = result["output"].data;
|
|
11843
12602
|
if (audioData.length === 0)
|
|
11844
12603
|
return;
|
|
11845
|
-
const wavPath =
|
|
12604
|
+
const wavPath = join20(tmpdir2(), `oa-voice-${Date.now()}.wav`);
|
|
11846
12605
|
this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
|
|
11847
12606
|
await this.playWav(wavPath);
|
|
11848
12607
|
try {
|
|
11849
|
-
|
|
12608
|
+
unlinkSync3(wavPath);
|
|
11850
12609
|
} catch {
|
|
11851
12610
|
}
|
|
11852
12611
|
}
|
|
@@ -11922,7 +12681,7 @@ var init_voice = __esm({
|
|
|
11922
12681
|
buffer.write("data", 36);
|
|
11923
12682
|
buffer.writeUInt32LE(dataSize, 40);
|
|
11924
12683
|
Buffer.from(int16.buffer, int16.byteOffset, int16.byteLength).copy(buffer, 44);
|
|
11925
|
-
|
|
12684
|
+
writeFileSync8(path, buffer);
|
|
11926
12685
|
}
|
|
11927
12686
|
// -------------------------------------------------------------------------
|
|
11928
12687
|
// Audio playback (system default speakers)
|
|
@@ -11931,7 +12690,7 @@ var init_voice = __esm({
|
|
|
11931
12690
|
const cmd = this.getPlayCommand(path);
|
|
11932
12691
|
if (!cmd)
|
|
11933
12692
|
return;
|
|
11934
|
-
return new Promise((
|
|
12693
|
+
return new Promise((resolve16) => {
|
|
11935
12694
|
const child = nodeSpawn(cmd[0], cmd.slice(1), {
|
|
11936
12695
|
stdio: "ignore",
|
|
11937
12696
|
detached: false
|
|
@@ -11940,12 +12699,12 @@ var init_voice = __esm({
|
|
|
11940
12699
|
child.on("close", () => {
|
|
11941
12700
|
if (this.currentPlayback === child)
|
|
11942
12701
|
this.currentPlayback = null;
|
|
11943
|
-
|
|
12702
|
+
resolve16();
|
|
11944
12703
|
});
|
|
11945
12704
|
child.on("error", () => {
|
|
11946
12705
|
if (this.currentPlayback === child)
|
|
11947
12706
|
this.currentPlayback = null;
|
|
11948
|
-
|
|
12707
|
+
resolve16();
|
|
11949
12708
|
});
|
|
11950
12709
|
setTimeout(() => {
|
|
11951
12710
|
if (this.currentPlayback === child) {
|
|
@@ -11955,7 +12714,7 @@ var init_voice = __esm({
|
|
|
11955
12714
|
}
|
|
11956
12715
|
this.currentPlayback = null;
|
|
11957
12716
|
}
|
|
11958
|
-
|
|
12717
|
+
resolve16();
|
|
11959
12718
|
}, 15e3);
|
|
11960
12719
|
});
|
|
11961
12720
|
}
|
|
@@ -11972,7 +12731,7 @@ var init_voice = __esm({
|
|
|
11972
12731
|
}
|
|
11973
12732
|
for (const player of ["paplay", "pw-play", "aplay"]) {
|
|
11974
12733
|
try {
|
|
11975
|
-
|
|
12734
|
+
execSync13(`which ${player}`, { stdio: "pipe" });
|
|
11976
12735
|
return [player, path];
|
|
11977
12736
|
} catch {
|
|
11978
12737
|
}
|
|
@@ -11994,36 +12753,36 @@ var init_voice = __esm({
|
|
|
11994
12753
|
async ensureRuntime() {
|
|
11995
12754
|
if (this.ort)
|
|
11996
12755
|
return;
|
|
11997
|
-
|
|
11998
|
-
const pkgPath =
|
|
12756
|
+
mkdirSync8(voiceDir(), { recursive: true });
|
|
12757
|
+
const pkgPath = join20(voiceDir(), "package.json");
|
|
11999
12758
|
const expectedDeps = {
|
|
12000
12759
|
"onnxruntime-node": "^1.21.0",
|
|
12001
12760
|
"phonemizer": "^1.2.1"
|
|
12002
12761
|
};
|
|
12003
|
-
if (
|
|
12762
|
+
if (existsSync15(pkgPath)) {
|
|
12004
12763
|
try {
|
|
12005
|
-
const existing = JSON.parse(
|
|
12764
|
+
const existing = JSON.parse(readFileSync12(pkgPath, "utf8"));
|
|
12006
12765
|
if (!existing.dependencies?.["phonemizer"]) {
|
|
12007
12766
|
existing.dependencies = { ...existing.dependencies, ...expectedDeps };
|
|
12008
|
-
|
|
12767
|
+
writeFileSync8(pkgPath, JSON.stringify(existing, null, 2));
|
|
12009
12768
|
}
|
|
12010
12769
|
} catch {
|
|
12011
12770
|
}
|
|
12012
12771
|
}
|
|
12013
|
-
if (!
|
|
12014
|
-
|
|
12772
|
+
if (!existsSync15(pkgPath)) {
|
|
12773
|
+
writeFileSync8(pkgPath, JSON.stringify({
|
|
12015
12774
|
name: "open-agents-voice",
|
|
12016
12775
|
private: true,
|
|
12017
12776
|
dependencies: expectedDeps
|
|
12018
12777
|
}, null, 2));
|
|
12019
12778
|
}
|
|
12020
|
-
const voiceRequire = createRequire(
|
|
12779
|
+
const voiceRequire = createRequire(join20(voiceDir(), "index.js"));
|
|
12021
12780
|
try {
|
|
12022
12781
|
this.ort = voiceRequire("onnxruntime-node");
|
|
12023
12782
|
} catch {
|
|
12024
12783
|
renderInfo("Installing ONNX runtime for voice synthesis...");
|
|
12025
12784
|
try {
|
|
12026
|
-
|
|
12785
|
+
execSync13("npm install --no-audit --no-fund", {
|
|
12027
12786
|
cwd: voiceDir(),
|
|
12028
12787
|
stdio: "pipe",
|
|
12029
12788
|
timeout: 12e4
|
|
@@ -12040,7 +12799,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
12040
12799
|
} catch {
|
|
12041
12800
|
renderInfo("Installing phonemizer for voice synthesis...");
|
|
12042
12801
|
try {
|
|
12043
|
-
|
|
12802
|
+
execSync13("npm install --no-audit --no-fund", {
|
|
12044
12803
|
cwd: voiceDir(),
|
|
12045
12804
|
stdio: "pipe",
|
|
12046
12805
|
timeout: 12e4
|
|
@@ -12063,18 +12822,18 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
12063
12822
|
const dir = modelDir(id);
|
|
12064
12823
|
const onnxPath = modelOnnxPath(id);
|
|
12065
12824
|
const configPath = modelConfigPath(id);
|
|
12066
|
-
if (
|
|
12825
|
+
if (existsSync15(onnxPath) && existsSync15(configPath))
|
|
12067
12826
|
return;
|
|
12068
|
-
|
|
12069
|
-
if (!
|
|
12827
|
+
mkdirSync8(dir, { recursive: true });
|
|
12828
|
+
if (!existsSync15(configPath)) {
|
|
12070
12829
|
renderInfo(`Downloading ${model.label} voice config...`);
|
|
12071
12830
|
const configResp = await fetch(model.configUrl);
|
|
12072
12831
|
if (!configResp.ok)
|
|
12073
12832
|
throw new Error(`Failed to download config: HTTP ${configResp.status}`);
|
|
12074
12833
|
const configText = await configResp.text();
|
|
12075
|
-
|
|
12834
|
+
writeFileSync8(configPath, configText);
|
|
12076
12835
|
}
|
|
12077
|
-
if (!
|
|
12836
|
+
if (!existsSync15(onnxPath)) {
|
|
12078
12837
|
renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
|
|
12079
12838
|
const onnxResp = await fetch(model.onnxUrl);
|
|
12080
12839
|
if (!onnxResp.ok)
|
|
@@ -12098,7 +12857,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
12098
12857
|
}
|
|
12099
12858
|
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
|
12100
12859
|
const fullBuffer = Buffer.concat(chunks);
|
|
12101
|
-
|
|
12860
|
+
writeFileSync8(onnxPath, fullBuffer);
|
|
12102
12861
|
renderInfo(`${model.label} model downloaded (${formatBytes2(fullBuffer.length)}).`);
|
|
12103
12862
|
}
|
|
12104
12863
|
}
|
|
@@ -12110,10 +12869,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
12110
12869
|
throw new Error("ONNX runtime not loaded");
|
|
12111
12870
|
const onnxPath = modelOnnxPath(this.modelId);
|
|
12112
12871
|
const configPath = modelConfigPath(this.modelId);
|
|
12113
|
-
if (!
|
|
12872
|
+
if (!existsSync15(onnxPath) || !existsSync15(configPath)) {
|
|
12114
12873
|
throw new Error(`Model files not found for ${this.modelId}`);
|
|
12115
12874
|
}
|
|
12116
|
-
this.config = JSON.parse(
|
|
12875
|
+
this.config = JSON.parse(readFileSync12(configPath, "utf8"));
|
|
12117
12876
|
renderInfo("Loading voice model...");
|
|
12118
12877
|
this.session = await this.ort.InferenceSession.create(onnxPath, {
|
|
12119
12878
|
executionProviders: ["cpu"],
|
|
@@ -12570,13 +13329,13 @@ var init_stream_renderer = __esm({
|
|
|
12570
13329
|
});
|
|
12571
13330
|
|
|
12572
13331
|
// packages/cli/dist/tui/edit-history.js
|
|
12573
|
-
import { appendFileSync, mkdirSync as
|
|
12574
|
-
import { join as
|
|
13332
|
+
import { appendFileSync, mkdirSync as mkdirSync9 } from "node:fs";
|
|
13333
|
+
import { join as join21 } from "node:path";
|
|
12575
13334
|
function createEditHistoryLogger(repoRoot, sessionId) {
|
|
12576
|
-
const historyDir =
|
|
12577
|
-
const logPath =
|
|
13335
|
+
const historyDir = join21(repoRoot, ".oa", "history");
|
|
13336
|
+
const logPath = join21(historyDir, "edits.jsonl");
|
|
12578
13337
|
try {
|
|
12579
|
-
|
|
13338
|
+
mkdirSync9(historyDir, { recursive: true });
|
|
12580
13339
|
} catch {
|
|
12581
13340
|
}
|
|
12582
13341
|
function logToolCall(toolName, toolArgs, success) {
|
|
@@ -12685,9 +13444,9 @@ var init_edit_history = __esm({
|
|
|
12685
13444
|
});
|
|
12686
13445
|
|
|
12687
13446
|
// packages/cli/dist/tui/dream-engine.js
|
|
12688
|
-
import { mkdirSync as
|
|
12689
|
-
import { join as
|
|
12690
|
-
import { execSync as
|
|
13447
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync13, existsSync as existsSync16, cpSync, rmSync, readdirSync as readdirSync8 } from "node:fs";
|
|
13448
|
+
import { join as join22, basename as basename6 } from "node:path";
|
|
13449
|
+
import { execSync as execSync14 } from "node:child_process";
|
|
12691
13450
|
function adaptTool(tool) {
|
|
12692
13451
|
return {
|
|
12693
13452
|
name: tool.name,
|
|
@@ -12861,14 +13620,14 @@ var init_dream_engine = __esm({
|
|
|
12861
13620
|
const content = String(args["content"] ?? "");
|
|
12862
13621
|
if (!rawPath)
|
|
12863
13622
|
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
12864
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
13623
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join22(this.dreamsDir, basename6(rawPath)) : join22(this.dreamsDir, rawPath);
|
|
12865
13624
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
12866
13625
|
return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
12867
13626
|
}
|
|
12868
13627
|
try {
|
|
12869
|
-
const dir =
|
|
12870
|
-
|
|
12871
|
-
|
|
13628
|
+
const dir = join22(targetPath, "..");
|
|
13629
|
+
mkdirSync10(dir, { recursive: true });
|
|
13630
|
+
writeFileSync9(targetPath, content, "utf-8");
|
|
12872
13631
|
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
12873
13632
|
} catch (err) {
|
|
12874
13633
|
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
@@ -12896,20 +13655,20 @@ var init_dream_engine = __esm({
|
|
|
12896
13655
|
const rawPath = String(args["path"] ?? "");
|
|
12897
13656
|
const oldStr = String(args["old_string"] ?? "");
|
|
12898
13657
|
const newStr = String(args["new_string"] ?? "");
|
|
12899
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
13658
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join22(this.dreamsDir, basename6(rawPath)) : join22(this.dreamsDir, rawPath);
|
|
12900
13659
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
12901
13660
|
return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
12902
13661
|
}
|
|
12903
13662
|
try {
|
|
12904
|
-
if (!
|
|
13663
|
+
if (!existsSync16(targetPath)) {
|
|
12905
13664
|
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
12906
13665
|
}
|
|
12907
|
-
let content =
|
|
13666
|
+
let content = readFileSync13(targetPath, "utf-8");
|
|
12908
13667
|
if (!content.includes(oldStr)) {
|
|
12909
13668
|
return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
|
|
12910
13669
|
}
|
|
12911
13670
|
content = content.replace(oldStr, newStr);
|
|
12912
|
-
|
|
13671
|
+
writeFileSync9(targetPath, content, "utf-8");
|
|
12913
13672
|
return { success: true, output: `Edited ${rawPath}`, durationMs: Date.now() - start };
|
|
12914
13673
|
} catch (err) {
|
|
12915
13674
|
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
@@ -12940,7 +13699,7 @@ var init_dream_engine = __esm({
|
|
|
12940
13699
|
}
|
|
12941
13700
|
}
|
|
12942
13701
|
try {
|
|
12943
|
-
const output =
|
|
13702
|
+
const output = execSync14(cmd, {
|
|
12944
13703
|
cwd: this.repoRoot,
|
|
12945
13704
|
timeout: 3e4,
|
|
12946
13705
|
encoding: "utf-8",
|
|
@@ -12963,7 +13722,7 @@ var init_dream_engine = __esm({
|
|
|
12963
13722
|
constructor(config, repoRoot) {
|
|
12964
13723
|
this.config = config;
|
|
12965
13724
|
this.repoRoot = repoRoot;
|
|
12966
|
-
this.dreamsDir =
|
|
13725
|
+
this.dreamsDir = join22(repoRoot, ".oa", "dreams");
|
|
12967
13726
|
this.state = {
|
|
12968
13727
|
mode: "default",
|
|
12969
13728
|
active: false,
|
|
@@ -12994,7 +13753,7 @@ var init_dream_engine = __esm({
|
|
|
12994
13753
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12995
13754
|
results: []
|
|
12996
13755
|
};
|
|
12997
|
-
|
|
13756
|
+
mkdirSync10(this.dreamsDir, { recursive: true });
|
|
12998
13757
|
this.saveDreamState();
|
|
12999
13758
|
try {
|
|
13000
13759
|
for (let cycle = 1; cycle <= totalCycles; cycle++) {
|
|
@@ -13035,8 +13794,8 @@ ${result.summary}`;
|
|
|
13035
13794
|
if (mode !== "default" || cycle === totalCycles) {
|
|
13036
13795
|
renderDreamContraction(cycle);
|
|
13037
13796
|
const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
|
|
13038
|
-
const summaryPath =
|
|
13039
|
-
|
|
13797
|
+
const summaryPath = join22(this.dreamsDir, `cycle-${cycle}-summary.md`);
|
|
13798
|
+
writeFileSync9(summaryPath, cycleSummary, "utf-8");
|
|
13040
13799
|
}
|
|
13041
13800
|
if (mode === "lucid" && !this.abortController.signal.aborted) {
|
|
13042
13801
|
this.saveVersionCheckpoint(cycle);
|
|
@@ -13156,29 +13915,29 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
13156
13915
|
}
|
|
13157
13916
|
/** Save workspace backup for lucid mode */
|
|
13158
13917
|
saveVersionCheckpoint(cycle) {
|
|
13159
|
-
const checkpointDir =
|
|
13918
|
+
const checkpointDir = join22(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
|
|
13160
13919
|
try {
|
|
13161
|
-
|
|
13920
|
+
mkdirSync10(checkpointDir, { recursive: true });
|
|
13162
13921
|
try {
|
|
13163
|
-
const gitStatus =
|
|
13922
|
+
const gitStatus = execSync14("git status --porcelain", {
|
|
13164
13923
|
cwd: this.repoRoot,
|
|
13165
13924
|
encoding: "utf-8",
|
|
13166
13925
|
timeout: 1e4
|
|
13167
13926
|
});
|
|
13168
|
-
const gitDiff =
|
|
13927
|
+
const gitDiff = execSync14("git diff", {
|
|
13169
13928
|
cwd: this.repoRoot,
|
|
13170
13929
|
encoding: "utf-8",
|
|
13171
13930
|
timeout: 1e4
|
|
13172
13931
|
});
|
|
13173
|
-
const gitHash =
|
|
13932
|
+
const gitHash = execSync14("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
|
|
13174
13933
|
cwd: this.repoRoot,
|
|
13175
13934
|
encoding: "utf-8",
|
|
13176
13935
|
timeout: 5e3
|
|
13177
13936
|
}).trim();
|
|
13178
|
-
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
|
|
13937
|
+
writeFileSync9(join22(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
|
|
13938
|
+
writeFileSync9(join22(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
|
|
13939
|
+
writeFileSync9(join22(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
|
|
13940
|
+
writeFileSync9(join22(checkpointDir, "checkpoint.json"), JSON.stringify({
|
|
13182
13941
|
cycle,
|
|
13183
13942
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13184
13943
|
gitHash,
|
|
@@ -13186,7 +13945,7 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
13186
13945
|
}, null, 2), "utf-8");
|
|
13187
13946
|
renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
|
|
13188
13947
|
} catch {
|
|
13189
|
-
|
|
13948
|
+
writeFileSync9(join22(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
|
|
13190
13949
|
renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
|
|
13191
13950
|
}
|
|
13192
13951
|
} catch (err) {
|
|
@@ -13244,14 +14003,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
|
|
|
13244
14003
|
---
|
|
13245
14004
|
*Auto-generated by open-agents dream engine*
|
|
13246
14005
|
`;
|
|
13247
|
-
|
|
14006
|
+
writeFileSync9(join22(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
|
|
13248
14007
|
} catch {
|
|
13249
14008
|
}
|
|
13250
14009
|
}
|
|
13251
14010
|
/** Save dream state for resume/inspection */
|
|
13252
14011
|
saveDreamState() {
|
|
13253
14012
|
try {
|
|
13254
|
-
|
|
14013
|
+
writeFileSync9(join22(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
|
|
13255
14014
|
} catch {
|
|
13256
14015
|
}
|
|
13257
14016
|
}
|
|
@@ -13297,6 +14056,10 @@ var init_status_bar = __esm({
|
|
|
13297
14056
|
* own output is suppressed.
|
|
13298
14057
|
*/
|
|
13299
14058
|
inputStateProvider = null;
|
|
14059
|
+
/** Whether microphone is recording (blinking indicator) */
|
|
14060
|
+
_recording = false;
|
|
14061
|
+
/** Countdown seconds for auto-mode silence timeout (0 = not counting down) */
|
|
14062
|
+
_countdown = 0;
|
|
13300
14063
|
/**
|
|
13301
14064
|
* Provide a callback that returns readline's current input state.
|
|
13302
14065
|
* StatusBar uses this to render typed text and position the cursor
|
|
@@ -13305,6 +14068,20 @@ var init_status_bar = __esm({
|
|
|
13305
14068
|
setInputStateProvider(provider) {
|
|
13306
14069
|
this.inputStateProvider = provider;
|
|
13307
14070
|
}
|
|
14071
|
+
/** Set recording indicator state (blinking red ●) */
|
|
14072
|
+
setRecording(active) {
|
|
14073
|
+
this._recording = active;
|
|
14074
|
+
if (!active)
|
|
14075
|
+
this._countdown = 0;
|
|
14076
|
+
if (this.active)
|
|
14077
|
+
this.renderFooterPreserveCursor();
|
|
14078
|
+
}
|
|
14079
|
+
/** Set countdown seconds for auto-mode silence timeout */
|
|
14080
|
+
setCountdown(seconds) {
|
|
14081
|
+
this._countdown = seconds;
|
|
14082
|
+
if (this.active)
|
|
14083
|
+
this.renderFooterPreserveCursor();
|
|
14084
|
+
}
|
|
13308
14085
|
/** Context window size to display. Can be updated if model changes. */
|
|
13309
14086
|
setContextWindowSize(size) {
|
|
13310
14087
|
this.metrics.contextWindowSize = size;
|
|
@@ -13453,7 +14230,13 @@ var init_status_bar = __esm({
|
|
|
13453
14230
|
const ctxPct = ctxTotal > 0 ? Math.max(0, Math.min(100, Math.round((1 - ctxUsed / ctxTotal) * 100))) : 100;
|
|
13454
14231
|
const ctxColor = ctxPct > 50 ? c2.green : ctxPct > 20 ? c2.yellow : c2.red;
|
|
13455
14232
|
const ctxLabel = c2.blue("Ctx: ") + c2.bold(`${ctxUsed.toLocaleString()}/${ctxTotal.toLocaleString()}`) + ` ${ctxColor(`${ctxPct}%`)}`;
|
|
13456
|
-
|
|
14233
|
+
let recordingLabel = "";
|
|
14234
|
+
if (this._recording) {
|
|
14235
|
+
const dot = c2.red("\u25CF");
|
|
14236
|
+
const countdown = this._countdown > 0 ? c2.dim(` ${this._countdown}s`) : "";
|
|
14237
|
+
recordingLabel = pipe + dot + c2.red(" REC") + countdown;
|
|
14238
|
+
}
|
|
14239
|
+
return ` ${tokInLabel}${pipe}${tokOutLabel}${pipe}${ctxLabel}${recordingLabel}`;
|
|
13457
14240
|
}
|
|
13458
14241
|
// -------------------------------------------------------------------------
|
|
13459
14242
|
// Private
|
|
@@ -13580,23 +14363,22 @@ var init_status_bar = __esm({
|
|
|
13580
14363
|
import * as readline2 from "node:readline";
|
|
13581
14364
|
import { Writable } from "node:stream";
|
|
13582
14365
|
import { cwd } from "node:process";
|
|
13583
|
-
import { resolve as
|
|
14366
|
+
import { resolve as resolve13, join as join23, dirname as dirname3, extname as extname6 } from "node:path";
|
|
13584
14367
|
import { createRequire as createRequire2 } from "node:module";
|
|
13585
14368
|
import { fileURLToPath } from "node:url";
|
|
13586
|
-
import { readFileSync as
|
|
13587
|
-
import { existsSync as
|
|
13588
|
-
import { extname as extname5 } from "node:path";
|
|
14369
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
14370
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
13589
14371
|
function getVersion() {
|
|
13590
14372
|
try {
|
|
13591
14373
|
const require2 = createRequire2(import.meta.url);
|
|
13592
14374
|
const thisDir = dirname3(fileURLToPath(import.meta.url));
|
|
13593
14375
|
const candidates = [
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
14376
|
+
join23(thisDir, "..", "package.json"),
|
|
14377
|
+
join23(thisDir, "..", "..", "package.json"),
|
|
14378
|
+
join23(thisDir, "..", "..", "..", "package.json")
|
|
13597
14379
|
];
|
|
13598
14380
|
for (const pkgPath of candidates) {
|
|
13599
|
-
if (
|
|
14381
|
+
if (existsSync17(pkgPath)) {
|
|
13600
14382
|
const pkg = require2(pkgPath);
|
|
13601
14383
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
13602
14384
|
return pkg.version ?? "0.0.0";
|
|
@@ -13673,7 +14455,10 @@ function buildTools(repoRoot, config) {
|
|
|
13673
14455
|
...buildCustomTools(repoRoot),
|
|
13674
14456
|
// Skill system (AIWG skills — discovery and execution)
|
|
13675
14457
|
new SkillListTool(repoRoot),
|
|
13676
|
-
new SkillExecuteTool(repoRoot)
|
|
14458
|
+
new SkillExecuteTool(repoRoot),
|
|
14459
|
+
// Transcription tools (transcribe-cli / faster-whisper)
|
|
14460
|
+
new TranscribeFileTool(repoRoot),
|
|
14461
|
+
new TranscribeUrlTool(repoRoot)
|
|
13677
14462
|
];
|
|
13678
14463
|
return [
|
|
13679
14464
|
...executionTools.map(adaptTool2),
|
|
@@ -13926,7 +14711,7 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
13926
14711
|
} };
|
|
13927
14712
|
}
|
|
13928
14713
|
async function startInteractive(config, repoPath) {
|
|
13929
|
-
const repoRoot =
|
|
14714
|
+
const repoRoot = resolve13(repoPath ?? cwd());
|
|
13930
14715
|
const isResumed = !!process.env.__OA_RESUMED;
|
|
13931
14716
|
if (isResumed) {
|
|
13932
14717
|
delete process.env.__OA_RESUMED;
|
|
@@ -14195,6 +14980,56 @@ async function startInteractive(config, repoPath) {
|
|
|
14195
14980
|
},
|
|
14196
14981
|
isDreaming() {
|
|
14197
14982
|
return dreamEngine?.isActive ?? false;
|
|
14983
|
+
},
|
|
14984
|
+
// Listen mode (transcribe-cli integration)
|
|
14985
|
+
async listenToggle() {
|
|
14986
|
+
const engine = getListenEngine();
|
|
14987
|
+
if (engine.isActive) {
|
|
14988
|
+
const text = await engine.stop();
|
|
14989
|
+
statusBar.setRecording(false);
|
|
14990
|
+
return text ? `Stopped. Last transcript: "${text}"` : "Stopped listening.";
|
|
14991
|
+
}
|
|
14992
|
+
const available = await engine.isAvailable();
|
|
14993
|
+
if (!available) {
|
|
14994
|
+
return "transcribe-cli not installed. Run: npm i -g transcribe-cli";
|
|
14995
|
+
}
|
|
14996
|
+
engine.on("transcript", (text, isFinal) => {
|
|
14997
|
+
if (engine.currentMode === "confirm") {
|
|
14998
|
+
writeContent(() => renderInfo(`Heard: "${text}" ${c2.dim("(press Enter to submit)")}`));
|
|
14999
|
+
} else if (isFinal) {
|
|
15000
|
+
writeContent(() => renderInfo(`Auto-submitting: "${text}"`));
|
|
15001
|
+
rl.write(text + "\n");
|
|
15002
|
+
} else {
|
|
15003
|
+
writeContent(() => renderInfo(`Hearing: "${text}"`));
|
|
15004
|
+
}
|
|
15005
|
+
});
|
|
15006
|
+
engine.on("recording", (active) => {
|
|
15007
|
+
statusBar.setRecording(active);
|
|
15008
|
+
});
|
|
15009
|
+
engine.on("countdown", (seconds) => {
|
|
15010
|
+
statusBar.setCountdown(seconds);
|
|
15011
|
+
});
|
|
15012
|
+
engine.on("error", (err) => {
|
|
15013
|
+
writeContent(() => renderWarning(`Listen error: ${err.message}`));
|
|
15014
|
+
});
|
|
15015
|
+
const msg = await engine.start();
|
|
15016
|
+
return msg;
|
|
15017
|
+
},
|
|
15018
|
+
async listenSetModel(model) {
|
|
15019
|
+
const engine = getListenEngine();
|
|
15020
|
+
engine.setModel(model);
|
|
15021
|
+
return `Whisper model set to: ${model}`;
|
|
15022
|
+
},
|
|
15023
|
+
listenSetMode(mode) {
|
|
15024
|
+
const engine = getListenEngine();
|
|
15025
|
+
engine.setMode(mode);
|
|
15026
|
+
return mode === "auto" ? "Auto mode: transcriptions auto-submit after 3s silence" : "Confirm mode: press Enter to submit transcriptions";
|
|
15027
|
+
},
|
|
15028
|
+
async listenStop() {
|
|
15029
|
+
const engine = getListenEngine();
|
|
15030
|
+
const text = await engine.stop();
|
|
15031
|
+
statusBar.setRecording(false);
|
|
15032
|
+
return text ? `Stopped. Last transcript: "${text}"` : "Stopped listening.";
|
|
14198
15033
|
}
|
|
14199
15034
|
};
|
|
14200
15035
|
showPrompt();
|
|
@@ -14242,16 +15077,56 @@ ${c2.dim("Goodbye!")}
|
|
|
14242
15077
|
showPrompt();
|
|
14243
15078
|
return;
|
|
14244
15079
|
}
|
|
15080
|
+
if (typeof cmdResult === "object" && cmdResult.type === "skill") {
|
|
15081
|
+
const skillPrompt = cmdResult.args ? `<skill-context name="${cmdResult.name}">
|
|
15082
|
+
${cmdResult.content}
|
|
15083
|
+
</skill-context>
|
|
15084
|
+
|
|
15085
|
+
ARGUMENTS: ${cmdResult.args}` : `<skill-context name="${cmdResult.name}">
|
|
15086
|
+
${cmdResult.content}
|
|
15087
|
+
</skill-context>
|
|
15088
|
+
|
|
15089
|
+
Execute this skill now. Follow the behavioral guidance above.`;
|
|
15090
|
+
if (!carouselRetired && carousel.isRunning) {
|
|
15091
|
+
carousel.stop();
|
|
15092
|
+
carouselRetired = true;
|
|
15093
|
+
if (statusBar.isActive)
|
|
15094
|
+
statusBar.setScrollRegionTop(1);
|
|
15095
|
+
}
|
|
15096
|
+
writeContent(() => renderUserMessage(`/${cmdResult.name}${cmdResult.args ? " " + cmdResult.args : ""}`));
|
|
15097
|
+
lastSubmittedPrompt = skillPrompt;
|
|
15098
|
+
try {
|
|
15099
|
+
const task = startTask(skillPrompt, currentConfig, repoRoot, voiceEngine, {
|
|
15100
|
+
enabled: streamEnabled,
|
|
15101
|
+
renderer: streamRenderer
|
|
15102
|
+
}, {
|
|
15103
|
+
contextStores,
|
|
15104
|
+
taskMemoryStore: taskMemoryStore ?? void 0,
|
|
15105
|
+
failureStore: failureStore ?? void 0,
|
|
15106
|
+
toolPatternStore: toolPatternStore ?? void 0
|
|
15107
|
+
}, bruteForceEnabled, statusBar);
|
|
15108
|
+
activeTask = task;
|
|
15109
|
+
showPrompt();
|
|
15110
|
+
await task.promise;
|
|
15111
|
+
} catch (err) {
|
|
15112
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
15113
|
+
writeContent(() => renderError(errMsg));
|
|
15114
|
+
}
|
|
15115
|
+
activeTask = null;
|
|
15116
|
+
showPrompt();
|
|
15117
|
+
return;
|
|
15118
|
+
}
|
|
14245
15119
|
}
|
|
14246
15120
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
14247
|
-
const isImage = isImagePath(cleanPath) &&
|
|
15121
|
+
const isImage = isImagePath(cleanPath) && existsSync17(resolve13(repoRoot, cleanPath));
|
|
15122
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync17(resolve13(repoRoot, cleanPath));
|
|
14248
15123
|
if (activeTask) {
|
|
14249
15124
|
if (isImage) {
|
|
14250
15125
|
try {
|
|
14251
|
-
const imgPath =
|
|
14252
|
-
const imgBuffer =
|
|
15126
|
+
const imgPath = resolve13(repoRoot, cleanPath);
|
|
15127
|
+
const imgBuffer = readFileSync14(imgPath);
|
|
14253
15128
|
const base64 = imgBuffer.toString("base64");
|
|
14254
|
-
const ext =
|
|
15129
|
+
const ext = extname6(cleanPath).toLowerCase();
|
|
14255
15130
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
14256
15131
|
activeTask.runner.injectImage(base64, mime, `User shared image: ${cleanPath}`);
|
|
14257
15132
|
writeContent(() => renderUserInterrupt(`[Image: ${cleanPath}]`));
|
|
@@ -14259,6 +15134,19 @@ ${c2.dim("Goodbye!")}
|
|
|
14259
15134
|
activeTask.runner.injectUserMessage(input);
|
|
14260
15135
|
writeContent(() => renderUserInterrupt(input));
|
|
14261
15136
|
}
|
|
15137
|
+
} else if (isMedia) {
|
|
15138
|
+
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
15139
|
+
const engine = getListenEngine();
|
|
15140
|
+
const result = await engine.transcribeFile(resolve13(repoRoot, cleanPath), repoRoot);
|
|
15141
|
+
if (result) {
|
|
15142
|
+
const transcript = `[Transcription of ${cleanPath}]
|
|
15143
|
+
${result.text}`;
|
|
15144
|
+
activeTask.runner.injectUserMessage(transcript);
|
|
15145
|
+
writeContent(() => renderUserInterrupt(`[Audio: ${cleanPath}] (${result.text.split(" ").length} words)`));
|
|
15146
|
+
} else {
|
|
15147
|
+
activeTask.runner.injectUserMessage(`User dropped audio/video file: ${cleanPath}. Use transcribe_file tool to transcribe it.`);
|
|
15148
|
+
writeContent(() => renderUserInterrupt(`[Media: ${cleanPath}]`));
|
|
15149
|
+
}
|
|
14262
15150
|
} else {
|
|
14263
15151
|
activeTask.runner.injectUserMessage(input);
|
|
14264
15152
|
writeContent(() => renderUserInterrupt(input));
|
|
@@ -14274,6 +15162,22 @@ ${c2.dim("Goodbye!")}
|
|
|
14274
15162
|
if (isImage && fullInput === input) {
|
|
14275
15163
|
fullInput = `The user has provided an image file: ${cleanPath}. Read it with image_read and describe what you see. Extract any text with OCR if relevant.`;
|
|
14276
15164
|
}
|
|
15165
|
+
if (isMedia && fullInput === input) {
|
|
15166
|
+
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
15167
|
+
const engine = getListenEngine();
|
|
15168
|
+
const result = await engine.transcribeFile(resolve13(repoRoot, cleanPath), repoRoot);
|
|
15169
|
+
if (result) {
|
|
15170
|
+
fullInput = `The user has provided an audio/video file: ${cleanPath}.
|
|
15171
|
+
|
|
15172
|
+
Transcription (${result.text.split(" ").length} words, ${result.duration ? result.duration.toFixed(1) + "s" : "unknown duration"}):
|
|
15173
|
+
|
|
15174
|
+
${result.text}
|
|
15175
|
+
|
|
15176
|
+
Summarize or analyze this transcription as appropriate.`;
|
|
15177
|
+
} else {
|
|
15178
|
+
fullInput = `The user has provided an audio/video file: ${cleanPath}. Use the transcribe_file tool to transcribe it and then summarize the content.`;
|
|
15179
|
+
}
|
|
15180
|
+
}
|
|
14277
15181
|
if (!carouselRetired && carousel.isRunning) {
|
|
14278
15182
|
carousel.stop();
|
|
14279
15183
|
carouselRetired = true;
|
|
@@ -14384,7 +15288,7 @@ ${c2.dim("(Use /quit to exit)")}
|
|
|
14384
15288
|
});
|
|
14385
15289
|
}
|
|
14386
15290
|
async function runWithTUI(task, config, repoPath) {
|
|
14387
|
-
const repoRoot =
|
|
15291
|
+
const repoRoot = resolve13(repoPath ?? cwd());
|
|
14388
15292
|
const needsSetup = isFirstRun() || !await isModelAvailable(config);
|
|
14389
15293
|
if (needsSetup && config.backendType === "ollama") {
|
|
14390
15294
|
const setupModel = await runSetupWizard(config);
|
|
@@ -14421,6 +15325,7 @@ var init_interactive = __esm({
|
|
|
14421
15325
|
"use strict";
|
|
14422
15326
|
init_dist5();
|
|
14423
15327
|
init_dist2();
|
|
15328
|
+
init_listen();
|
|
14424
15329
|
init_updater();
|
|
14425
15330
|
init_commands();
|
|
14426
15331
|
init_setup();
|
|
@@ -14469,7 +15374,7 @@ import { glob } from "glob";
|
|
|
14469
15374
|
import ignore from "ignore";
|
|
14470
15375
|
import { readFile as readFile9, stat as stat2 } from "node:fs/promises";
|
|
14471
15376
|
import { createHash } from "node:crypto";
|
|
14472
|
-
import { join as
|
|
15377
|
+
import { join as join24, relative as relative3, extname as extname7, basename as basename7 } from "node:path";
|
|
14473
15378
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
14474
15379
|
var init_codebase_indexer = __esm({
|
|
14475
15380
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -14513,7 +15418,7 @@ var init_codebase_indexer = __esm({
|
|
|
14513
15418
|
const ig = ignore.default();
|
|
14514
15419
|
if (this.config.respectGitignore) {
|
|
14515
15420
|
try {
|
|
14516
|
-
const gitignoreContent = await readFile9(
|
|
15421
|
+
const gitignoreContent = await readFile9(join24(this.config.rootDir, ".gitignore"), "utf-8");
|
|
14517
15422
|
ig.add(gitignoreContent);
|
|
14518
15423
|
} catch {
|
|
14519
15424
|
}
|
|
@@ -14528,14 +15433,14 @@ var init_codebase_indexer = __esm({
|
|
|
14528
15433
|
for (const relativePath of files) {
|
|
14529
15434
|
if (ig.ignores(relativePath))
|
|
14530
15435
|
continue;
|
|
14531
|
-
const fullPath =
|
|
15436
|
+
const fullPath = join24(this.config.rootDir, relativePath);
|
|
14532
15437
|
try {
|
|
14533
15438
|
const fileStat = await stat2(fullPath);
|
|
14534
15439
|
if (fileStat.size > this.config.maxFileSize)
|
|
14535
15440
|
continue;
|
|
14536
15441
|
const content = await readFile9(fullPath);
|
|
14537
15442
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
14538
|
-
const ext =
|
|
15443
|
+
const ext = extname7(relativePath);
|
|
14539
15444
|
indexed.push({
|
|
14540
15445
|
path: fullPath,
|
|
14541
15446
|
relativePath,
|
|
@@ -14551,7 +15456,7 @@ var init_codebase_indexer = __esm({
|
|
|
14551
15456
|
}
|
|
14552
15457
|
buildTree(files) {
|
|
14553
15458
|
const root = {
|
|
14554
|
-
name:
|
|
15459
|
+
name: basename7(this.config.rootDir),
|
|
14555
15460
|
path: this.config.rootDir,
|
|
14556
15461
|
type: "directory",
|
|
14557
15462
|
children: []
|
|
@@ -14574,7 +15479,7 @@ var init_codebase_indexer = __esm({
|
|
|
14574
15479
|
if (!child) {
|
|
14575
15480
|
child = {
|
|
14576
15481
|
name: part,
|
|
14577
|
-
path:
|
|
15482
|
+
path: join24(current.path, part),
|
|
14578
15483
|
type: "directory",
|
|
14579
15484
|
children: []
|
|
14580
15485
|
};
|
|
@@ -14648,14 +15553,14 @@ var index_repo_exports = {};
|
|
|
14648
15553
|
__export(index_repo_exports, {
|
|
14649
15554
|
indexRepoCommand: () => indexRepoCommand
|
|
14650
15555
|
});
|
|
14651
|
-
import { resolve as
|
|
14652
|
-
import { existsSync as
|
|
15556
|
+
import { resolve as resolve14 } from "node:path";
|
|
15557
|
+
import { existsSync as existsSync18, statSync as statSync6 } from "node:fs";
|
|
14653
15558
|
import { cwd as cwd2 } from "node:process";
|
|
14654
15559
|
async function indexRepoCommand(opts, _config) {
|
|
14655
|
-
const repoRoot =
|
|
15560
|
+
const repoRoot = resolve14(opts.repoPath ?? cwd2());
|
|
14656
15561
|
printHeader("Index Repository");
|
|
14657
15562
|
printInfo(`Indexing: ${repoRoot}`);
|
|
14658
|
-
if (!
|
|
15563
|
+
if (!existsSync18(repoRoot)) {
|
|
14659
15564
|
printError(`Path does not exist: ${repoRoot}`);
|
|
14660
15565
|
process.exit(1);
|
|
14661
15566
|
}
|
|
@@ -14901,8 +15806,8 @@ var config_exports = {};
|
|
|
14901
15806
|
__export(config_exports, {
|
|
14902
15807
|
configCommand: () => configCommand
|
|
14903
15808
|
});
|
|
14904
|
-
import { join as
|
|
14905
|
-
import { homedir as
|
|
15809
|
+
import { join as join25, resolve as resolve15 } from "node:path";
|
|
15810
|
+
import { homedir as homedir11 } from "node:os";
|
|
14906
15811
|
import { cwd as cwd3 } from "node:process";
|
|
14907
15812
|
function coerceForSettings(key, value) {
|
|
14908
15813
|
if (INT_KEYS.has(key))
|
|
@@ -14922,7 +15827,7 @@ async function configCommand(opts, config) {
|
|
|
14922
15827
|
return handleShow(opts, config);
|
|
14923
15828
|
}
|
|
14924
15829
|
function handleShow(opts, config) {
|
|
14925
|
-
const repoRoot =
|
|
15830
|
+
const repoRoot = resolve15(opts.repoPath ?? cwd3());
|
|
14926
15831
|
printHeader("Configuration");
|
|
14927
15832
|
printSection("Active Settings (merged)");
|
|
14928
15833
|
printKeyValue("backendUrl", config.backendUrl, 2);
|
|
@@ -14954,7 +15859,7 @@ function handleShow(opts, config) {
|
|
|
14954
15859
|
}
|
|
14955
15860
|
}
|
|
14956
15861
|
printSection("Config File");
|
|
14957
|
-
printInfo(`~/.open-agents/config.json (${
|
|
15862
|
+
printInfo(`~/.open-agents/config.json (${join25(homedir11(), ".open-agents", "config.json")})`);
|
|
14958
15863
|
printSection("Priority Chain");
|
|
14959
15864
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
14960
15865
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -14987,13 +15892,13 @@ function handleSet(opts, _config) {
|
|
|
14987
15892
|
process.exit(1);
|
|
14988
15893
|
}
|
|
14989
15894
|
if (opts.local) {
|
|
14990
|
-
const repoRoot =
|
|
15895
|
+
const repoRoot = resolve15(opts.repoPath ?? cwd3());
|
|
14991
15896
|
try {
|
|
14992
15897
|
initOaDirectory(repoRoot);
|
|
14993
15898
|
const coerced = coerceForSettings(key, value);
|
|
14994
15899
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
14995
15900
|
printSuccess(`Project override set: ${key} = ${value}`);
|
|
14996
|
-
printInfo(`Saved to ${
|
|
15901
|
+
printInfo(`Saved to ${join25(repoRoot, ".oa", "settings.json")}`);
|
|
14997
15902
|
printInfo("This override applies only when running in this workspace.");
|
|
14998
15903
|
} catch (err) {
|
|
14999
15904
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -15053,7 +15958,7 @@ var serve_exports = {};
|
|
|
15053
15958
|
__export(serve_exports, {
|
|
15054
15959
|
serveCommand: () => serveCommand
|
|
15055
15960
|
});
|
|
15056
|
-
import { spawn as
|
|
15961
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
15057
15962
|
async function serveCommand(opts, config) {
|
|
15058
15963
|
const backendType = config.backendType;
|
|
15059
15964
|
if (backendType === "ollama") {
|
|
@@ -15145,8 +16050,8 @@ async function serveVllm(opts, config) {
|
|
|
15145
16050
|
await runVllmServer(args, opts.verbose ?? false);
|
|
15146
16051
|
}
|
|
15147
16052
|
async function runVllmServer(args, verbose) {
|
|
15148
|
-
return new Promise((
|
|
15149
|
-
const child =
|
|
16053
|
+
return new Promise((resolve16, reject) => {
|
|
16054
|
+
const child = spawn6("python", args, {
|
|
15150
16055
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
15151
16056
|
env: { ...process.env }
|
|
15152
16057
|
});
|
|
@@ -15180,10 +16085,10 @@ async function runVllmServer(args, verbose) {
|
|
|
15180
16085
|
child.once("exit", (code, signal) => {
|
|
15181
16086
|
if (signal) {
|
|
15182
16087
|
printInfo(`vLLM server stopped by signal ${signal}`);
|
|
15183
|
-
|
|
16088
|
+
resolve16();
|
|
15184
16089
|
} else if (code === 0) {
|
|
15185
16090
|
printSuccess("vLLM server exited cleanly");
|
|
15186
|
-
|
|
16091
|
+
resolve16();
|
|
15187
16092
|
} else {
|
|
15188
16093
|
printError(`vLLM server exited with code ${code}`);
|
|
15189
16094
|
reject(new Error(`vLLM exited with code ${code}`));
|
|
@@ -15211,8 +16116,8 @@ __export(eval_exports, {
|
|
|
15211
16116
|
evalCommand: () => evalCommand
|
|
15212
16117
|
});
|
|
15213
16118
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
15214
|
-
import { mkdirSync as
|
|
15215
|
-
import { join as
|
|
16119
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
|
|
16120
|
+
import { join as join26 } from "node:path";
|
|
15216
16121
|
async function evalCommand(opts, config) {
|
|
15217
16122
|
const suiteName = opts.suite ?? "basic";
|
|
15218
16123
|
const suite = SUITES[suiteName];
|
|
@@ -15333,9 +16238,9 @@ async function evalCommand(opts, config) {
|
|
|
15333
16238
|
process.exit(failed > 0 ? 1 : 0);
|
|
15334
16239
|
}
|
|
15335
16240
|
function createTempEvalRepo() {
|
|
15336
|
-
const dir =
|
|
15337
|
-
|
|
15338
|
-
|
|
16241
|
+
const dir = join26(tmpdir3(), `open-agents-eval-${Date.now()}`);
|
|
16242
|
+
mkdirSync11(dir, { recursive: true });
|
|
16243
|
+
writeFileSync10(join26(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
|
|
15339
16244
|
return dir;
|
|
15340
16245
|
}
|
|
15341
16246
|
var BASIC_SUITE, FULL_SUITE, SUITES;
|
|
@@ -15395,7 +16300,7 @@ init_updater();
|
|
|
15395
16300
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
15396
16301
|
import { createRequire as createRequire3 } from "node:module";
|
|
15397
16302
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15398
|
-
import { dirname as dirname4, join as
|
|
16303
|
+
import { dirname as dirname4, join as join27 } from "node:path";
|
|
15399
16304
|
|
|
15400
16305
|
// packages/cli/dist/cli.js
|
|
15401
16306
|
import { createInterface } from "node:readline";
|
|
@@ -15502,7 +16407,7 @@ init_output();
|
|
|
15502
16407
|
function getVersion2() {
|
|
15503
16408
|
try {
|
|
15504
16409
|
const require2 = createRequire3(import.meta.url);
|
|
15505
|
-
const pkgPath =
|
|
16410
|
+
const pkgPath = join27(dirname4(fileURLToPath2(import.meta.url)), "..", "package.json");
|
|
15506
16411
|
const pkg = require2(pkgPath);
|
|
15507
16412
|
return pkg.version;
|
|
15508
16413
|
} catch {
|