open-agents-ai 0.103.98 → 0.104.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 +286 -172
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33610,6 +33610,45 @@ var init_setup = __esm({
|
|
|
33610
33610
|
}
|
|
33611
33611
|
});
|
|
33612
33612
|
|
|
33613
|
+
// packages/cli/dist/tui/overlay-lock.js
|
|
33614
|
+
function isOverlayActive() {
|
|
33615
|
+
return _overlayActive;
|
|
33616
|
+
}
|
|
33617
|
+
function bufferIfOverlay(stream, data) {
|
|
33618
|
+
if (!_overlayActive)
|
|
33619
|
+
return false;
|
|
33620
|
+
_buffer.push({ stream, data });
|
|
33621
|
+
return true;
|
|
33622
|
+
}
|
|
33623
|
+
function enterOverlay() {
|
|
33624
|
+
_depth++;
|
|
33625
|
+
_overlayActive = true;
|
|
33626
|
+
}
|
|
33627
|
+
function leaveOverlay() {
|
|
33628
|
+
_depth = Math.max(0, _depth - 1);
|
|
33629
|
+
if (_depth === 0) {
|
|
33630
|
+
_overlayActive = false;
|
|
33631
|
+
const pending = _buffer;
|
|
33632
|
+
_buffer = [];
|
|
33633
|
+
for (const { stream, data } of pending) {
|
|
33634
|
+
if (stream === "stdout") {
|
|
33635
|
+
process.stdout.write(data);
|
|
33636
|
+
} else {
|
|
33637
|
+
process.stderr.write(data);
|
|
33638
|
+
}
|
|
33639
|
+
}
|
|
33640
|
+
}
|
|
33641
|
+
}
|
|
33642
|
+
var _overlayActive, _depth, _buffer;
|
|
33643
|
+
var init_overlay_lock = __esm({
|
|
33644
|
+
"packages/cli/dist/tui/overlay-lock.js"() {
|
|
33645
|
+
"use strict";
|
|
33646
|
+
_overlayActive = false;
|
|
33647
|
+
_depth = 0;
|
|
33648
|
+
_buffer = [];
|
|
33649
|
+
}
|
|
33650
|
+
});
|
|
33651
|
+
|
|
33613
33652
|
// packages/cli/dist/tui/tui-select.js
|
|
33614
33653
|
function ansi3(code, text) {
|
|
33615
33654
|
return isTTY3 ? `\x1B[${code}m${text}\x1B[0m` : text;
|
|
@@ -33704,6 +33743,7 @@ function tuiSelect(opts) {
|
|
|
33704
33743
|
}
|
|
33705
33744
|
stdin.resume();
|
|
33706
33745
|
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l");
|
|
33746
|
+
enterOverlay();
|
|
33707
33747
|
function clampScroll(displayList) {
|
|
33708
33748
|
const cursorPos = displayList.indexOf(cursor);
|
|
33709
33749
|
if (cursorPos < 0)
|
|
@@ -33797,6 +33837,7 @@ function tuiSelect(opts) {
|
|
|
33797
33837
|
function cleanup() {
|
|
33798
33838
|
stdin.removeListener("data", onData);
|
|
33799
33839
|
process.stdout.removeListener("resize", onResize);
|
|
33840
|
+
leaveOverlay();
|
|
33800
33841
|
process.stdout.write("\x1B[?1049l\x1B[?25h");
|
|
33801
33842
|
if (typeof stdin.setRawMode === "function") {
|
|
33802
33843
|
stdin.setRawMode(hadRawMode ?? false);
|
|
@@ -34052,6 +34093,7 @@ var isTTY3, selectColors;
|
|
|
34052
34093
|
var init_tui_select = __esm({
|
|
34053
34094
|
"packages/cli/dist/tui/tui-select.js"() {
|
|
34054
34095
|
"use strict";
|
|
34096
|
+
init_overlay_lock();
|
|
34055
34097
|
isTTY3 = process.stdout.isTTY ?? false;
|
|
34056
34098
|
selectColors = {
|
|
34057
34099
|
orange: (t) => fg2562(208, t),
|
|
@@ -34094,6 +34136,7 @@ function showDropPanel(opts) {
|
|
|
34094
34136
|
}
|
|
34095
34137
|
stdin.resume();
|
|
34096
34138
|
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H\x1B[?25h");
|
|
34139
|
+
enterOverlay();
|
|
34097
34140
|
let inputBuf = "";
|
|
34098
34141
|
let errorMsg = "";
|
|
34099
34142
|
function render() {
|
|
@@ -34137,6 +34180,7 @@ function showDropPanel(opts) {
|
|
|
34137
34180
|
}
|
|
34138
34181
|
function cleanup() {
|
|
34139
34182
|
stdin.removeListener("data", onData);
|
|
34183
|
+
leaveOverlay();
|
|
34140
34184
|
process.stdout.write("\x1B[?1049l\x1B[?25h");
|
|
34141
34185
|
if (typeof stdin.setRawMode === "function") {
|
|
34142
34186
|
stdin.setRawMode(hadRawMode ?? false);
|
|
@@ -34212,6 +34256,7 @@ var isTTY4, dc;
|
|
|
34212
34256
|
var init_drop_panel = __esm({
|
|
34213
34257
|
"packages/cli/dist/tui/drop-panel.js"() {
|
|
34214
34258
|
"use strict";
|
|
34259
|
+
init_overlay_lock();
|
|
34215
34260
|
isTTY4 = process.stdout.isTTY ?? false;
|
|
34216
34261
|
dc = {
|
|
34217
34262
|
bold: (t) => ansi4("1", t),
|
|
@@ -35165,6 +35210,8 @@ var init_voice = __esm({
|
|
|
35165
35210
|
* Accepts a path to a WAV/MP3/OGG/FLAC file (min 3 seconds).
|
|
35166
35211
|
* Returns status message.
|
|
35167
35212
|
*/
|
|
35213
|
+
/** Filename of the last cloned voice (set by setCloneVoice for UI to locate new entry) */
|
|
35214
|
+
lastClonedFilename = null;
|
|
35168
35215
|
async setCloneVoice(audioPath) {
|
|
35169
35216
|
let p = audioPath.trim();
|
|
35170
35217
|
if (p.startsWith("'") && p.endsWith("'") || p.startsWith('"') && p.endsWith('"')) {
|
|
@@ -35183,16 +35230,22 @@ var init_voice = __esm({
|
|
|
35183
35230
|
if (!existsSync33(refsDir))
|
|
35184
35231
|
mkdirSync13(refsDir, { recursive: true });
|
|
35185
35232
|
const ext = audioPath.split(".").pop() || "wav";
|
|
35186
|
-
const
|
|
35233
|
+
const srcName = (audioPath.split("/").pop() ?? "clone").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
35234
|
+
const ts = Date.now().toString(36);
|
|
35235
|
+
const destFilename = `clone-${srcName}-${ts}.${ext}`;
|
|
35236
|
+
const destPath = join41(refsDir, destFilename);
|
|
35187
35237
|
try {
|
|
35188
35238
|
const data = readFileSync23(audioPath);
|
|
35189
35239
|
writeFileSync13(destPath, data);
|
|
35190
35240
|
} catch (err) {
|
|
35191
35241
|
return `Failed to copy audio file: ${err instanceof Error ? err.message : String(err)}`;
|
|
35192
35242
|
}
|
|
35243
|
+
const meta = this.loadCloneMeta();
|
|
35244
|
+
meta[destFilename] = srcName.replace(/[-_]/g, " ");
|
|
35245
|
+
this.saveCloneMeta(meta);
|
|
35193
35246
|
this.luxttsCloneRef = destPath;
|
|
35194
|
-
|
|
35195
|
-
return `Voice clone reference set: ${
|
|
35247
|
+
this.lastClonedFilename = destFilename;
|
|
35248
|
+
return `Voice clone reference set: ${destFilename}. LuxTTS will use this voice.`;
|
|
35196
35249
|
}
|
|
35197
35250
|
/**
|
|
35198
35251
|
* Generate a synthetic voice clone reference from an existing ONNX voice model.
|
|
@@ -38238,185 +38291,177 @@ function formatFileSize(bytes) {
|
|
|
38238
38291
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
38239
38292
|
}
|
|
38240
38293
|
async function handleVoiceMenu(ctx, save, hasLocal) {
|
|
38241
|
-
const currentMode = ctx.voiceGetMode?.() ?? "action";
|
|
38242
38294
|
const modeLabels = {
|
|
38243
38295
|
chat: "Chat \u2014 speaks model responses",
|
|
38244
38296
|
action: "Action \u2014 speaks tool narrations",
|
|
38245
38297
|
verbose: "Verbose \u2014 speaks both"
|
|
38246
38298
|
};
|
|
38247
|
-
|
|
38248
|
-
|
|
38249
|
-
|
|
38250
|
-
|
|
38251
|
-
|
|
38252
|
-
|
|
38253
|
-
|
|
38254
|
-
|
|
38255
|
-
|
|
38256
|
-
|
|
38257
|
-
|
|
38258
|
-
|
|
38259
|
-
|
|
38260
|
-
|
|
38261
|
-
|
|
38262
|
-
|
|
38263
|
-
|
|
38264
|
-
|
|
38265
|
-
|
|
38266
|
-
|
|
38267
|
-
|
|
38268
|
-
|
|
38269
|
-
|
|
38270
|
-
|
|
38271
|
-
|
|
38272
|
-
|
|
38273
|
-
|
|
38274
|
-
|
|
38275
|
-
|
|
38276
|
-
|
|
38277
|
-
{ key: "action", label: "Action", detail: "speaks tool call narrations with emotion pitch" },
|
|
38278
|
-
{ key: "verbose", label: "Verbose", detail: "speaks both chat and actions" }
|
|
38279
|
-
];
|
|
38280
|
-
const modeResult = await tuiSelect({
|
|
38281
|
-
items: modeItems,
|
|
38282
|
-
activeKey: currentMode,
|
|
38283
|
-
title: "Voice Mode",
|
|
38284
|
-
rl: ctx.rl,
|
|
38285
|
-
availableRows: ctx.availableContentRows?.()
|
|
38286
|
-
});
|
|
38287
|
-
if (modeResult.confirmed && modeResult.key) {
|
|
38288
|
-
const mode = modeResult.key;
|
|
38289
|
-
ctx.voiceSetMode?.(mode);
|
|
38290
|
-
save({ voiceMode: mode });
|
|
38291
|
-
renderInfo(`Voice mode: ${modeLabels[mode]}${hasLocal ? " (project-local)" : ""}`);
|
|
38299
|
+
while (true) {
|
|
38300
|
+
const isEnabled = ctx.voiceIsEnabled?.() ?? false;
|
|
38301
|
+
const currentMode = ctx.voiceGetMode?.() ?? "action";
|
|
38302
|
+
const currentModel = ctx.voiceGetModel?.() ?? "unknown";
|
|
38303
|
+
const enabledLabel = isEnabled ? selectColors.green("\u25CF Voice: Enabled") : selectColors.dim("\u25CB Voice: Disabled");
|
|
38304
|
+
const items = [
|
|
38305
|
+
{ key: "header-status", label: selectColors.dim("\u2500\u2500\u2500 Voice Status \u2500\u2500\u2500") },
|
|
38306
|
+
{ key: "toggle", label: isEnabled ? "Disable Voice" : "Enable Voice", detail: enabledLabel },
|
|
38307
|
+
{ key: "header-config", label: selectColors.dim("\u2500\u2500\u2500 Configuration \u2500\u2500\u2500") },
|
|
38308
|
+
{ key: "mode", label: "Voice Mode", detail: `${selectColors.green(currentMode)} \u2014 ${modeLabels[currentMode]}` },
|
|
38309
|
+
{ key: "voice", label: "Change TTS Voice", detail: `current: ${selectColors.green(currentModel)}` },
|
|
38310
|
+
{ key: "system", label: "Change TTS System", detail: "onnx / mlx / luxtts" },
|
|
38311
|
+
{ key: "clone", label: "Clone Voice", detail: "drag & drop audio file" },
|
|
38312
|
+
{ key: "list", label: "Manage Clone Voices", detail: "rename, play, delete" }
|
|
38313
|
+
];
|
|
38314
|
+
const result = await tuiSelect({
|
|
38315
|
+
items,
|
|
38316
|
+
title: "Voice Configuration",
|
|
38317
|
+
rl: ctx.rl,
|
|
38318
|
+
availableRows: ctx.availableContentRows?.(),
|
|
38319
|
+
skipKeys: ["header-status", "header-config"]
|
|
38320
|
+
});
|
|
38321
|
+
if (!result.confirmed || !result.key)
|
|
38322
|
+
return;
|
|
38323
|
+
switch (result.key) {
|
|
38324
|
+
case "toggle": {
|
|
38325
|
+
const msg = await ctx.voiceToggle();
|
|
38326
|
+
const isOn = msg.toLowerCase().includes("enabled") || msg.toLowerCase().includes("on");
|
|
38327
|
+
save({ voice: isOn });
|
|
38328
|
+
continue;
|
|
38292
38329
|
}
|
|
38293
|
-
|
|
38294
|
-
|
|
38295
|
-
|
|
38296
|
-
|
|
38297
|
-
|
|
38298
|
-
|
|
38299
|
-
|
|
38300
|
-
|
|
38301
|
-
|
|
38302
|
-
|
|
38303
|
-
|
|
38304
|
-
|
|
38305
|
-
|
|
38306
|
-
|
|
38307
|
-
|
|
38308
|
-
|
|
38309
|
-
|
|
38310
|
-
|
|
38311
|
-
|
|
38312
|
-
availableRows: ctx.availableContentRows?.(),
|
|
38313
|
-
skipKeys: ["header-onnx", "header-mlx", "header-clone"]
|
|
38314
|
-
});
|
|
38315
|
-
if (voiceResult.confirmed && voiceResult.key) {
|
|
38316
|
-
const msg = await ctx.voiceSetModel(voiceResult.key);
|
|
38317
|
-
save({ voice: true, voiceModel: voiceResult.key });
|
|
38318
|
-
renderInfo(msg + (hasLocal ? " (project-local)" : ""));
|
|
38330
|
+
case "mode": {
|
|
38331
|
+
const modeItems = [
|
|
38332
|
+
{ key: "chat", label: "Chat", detail: "speaks streamed model text at normal pitch" },
|
|
38333
|
+
{ key: "action", label: "Action", detail: "speaks tool call narrations with emotion pitch" },
|
|
38334
|
+
{ key: "verbose", label: "Verbose", detail: "speaks both chat and actions" }
|
|
38335
|
+
];
|
|
38336
|
+
const modeResult = await tuiSelect({
|
|
38337
|
+
items: modeItems,
|
|
38338
|
+
activeKey: currentMode,
|
|
38339
|
+
title: "Voice Mode",
|
|
38340
|
+
rl: ctx.rl,
|
|
38341
|
+
availableRows: ctx.availableContentRows?.()
|
|
38342
|
+
});
|
|
38343
|
+
if (modeResult.confirmed && modeResult.key) {
|
|
38344
|
+
const mode = modeResult.key;
|
|
38345
|
+
ctx.voiceSetMode?.(mode);
|
|
38346
|
+
save({ voiceMode: mode });
|
|
38347
|
+
}
|
|
38348
|
+
continue;
|
|
38319
38349
|
}
|
|
38320
|
-
|
|
38321
|
-
|
|
38322
|
-
|
|
38323
|
-
|
|
38324
|
-
|
|
38325
|
-
|
|
38326
|
-
|
|
38327
|
-
|
|
38328
|
-
|
|
38329
|
-
|
|
38330
|
-
|
|
38350
|
+
case "voice": {
|
|
38351
|
+
const voiceItems = [
|
|
38352
|
+
{ key: "header-onnx", label: selectColors.dim("\u2500\u2500\u2500 ONNX Voices \u2500\u2500\u2500") },
|
|
38353
|
+
{ key: "glados", label: "GLaDOS", detail: "Portal AI voice (ONNX)" },
|
|
38354
|
+
{ key: "overwatch", label: "Overwatch", detail: "Overwatch announcer (ONNX)" },
|
|
38355
|
+
{ key: "header-mlx", label: selectColors.dim("\u2500\u2500\u2500 MLX Voices (macOS) \u2500\u2500\u2500") },
|
|
38356
|
+
{ key: "kokoro:af_heart", label: "Kokoro Heart", detail: "warm female (MLX)" },
|
|
38357
|
+
{ key: "kokoro:af_bella", label: "Kokoro Bella", detail: "expressive female (MLX)" },
|
|
38358
|
+
{ key: "kokoro:am_adam", label: "Kokoro Adam", detail: "male (MLX)" },
|
|
38359
|
+
{ key: "kokoro:bf_emma", label: "Kokoro Emma", detail: "British female (MLX)" },
|
|
38360
|
+
{ key: "header-clone", label: selectColors.dim("\u2500\u2500\u2500 Voice Clone \u2500\u2500\u2500") },
|
|
38361
|
+
{ key: "luxtts", label: "LuxTTS", detail: "voice cloning engine" }
|
|
38362
|
+
];
|
|
38363
|
+
const voiceResult = await tuiSelect({
|
|
38364
|
+
items: voiceItems,
|
|
38365
|
+
activeKey: currentModel,
|
|
38366
|
+
title: "Select TTS Voice",
|
|
38367
|
+
rl: ctx.rl,
|
|
38368
|
+
availableRows: ctx.availableContentRows?.(),
|
|
38369
|
+
skipKeys: ["header-onnx", "header-mlx", "header-clone"]
|
|
38370
|
+
});
|
|
38371
|
+
if (voiceResult.confirmed && voiceResult.key) {
|
|
38372
|
+
await ctx.voiceSetModel(voiceResult.key);
|
|
38373
|
+
save({ voice: true, voiceModel: voiceResult.key });
|
|
38374
|
+
}
|
|
38375
|
+
continue;
|
|
38331
38376
|
}
|
|
38332
|
-
|
|
38333
|
-
|
|
38334
|
-
|
|
38335
|
-
|
|
38336
|
-
|
|
38337
|
-
|
|
38338
|
-
|
|
38339
|
-
|
|
38340
|
-
|
|
38341
|
-
|
|
38342
|
-
|
|
38343
|
-
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38347
|
-
|
|
38348
|
-
|
|
38349
|
-
|
|
38350
|
-
|
|
38351
|
-
|
|
38352
|
-
|
|
38353
|
-
|
|
38354
|
-
|
|
38355
|
-
|
|
38356
|
-
|
|
38357
|
-
|
|
38358
|
-
|
|
38359
|
-
|
|
38360
|
-
|
|
38361
|
-
|
|
38362
|
-
|
|
38363
|
-
|
|
38377
|
+
case "system": {
|
|
38378
|
+
const sysItems = [
|
|
38379
|
+
{ key: "onnx", label: "Piper ONNX", detail: "cross-platform, fast, offline" },
|
|
38380
|
+
{ key: "luxtts", label: "LuxTTS", detail: "voice cloning, Python venv" },
|
|
38381
|
+
{ key: "header-import", label: selectColors.dim("\u2500\u2500\u2500 Import \u2500\u2500\u2500") },
|
|
38382
|
+
{ key: "import-onnx", label: "Import Piper Model", detail: "drag & drop .onnx + .onnx.json" }
|
|
38383
|
+
];
|
|
38384
|
+
if (process.platform === "darwin") {
|
|
38385
|
+
sysItems.splice(1, 0, { key: "mlx", label: "MLX Audio", detail: "Apple Silicon, Kokoro voices" });
|
|
38386
|
+
}
|
|
38387
|
+
const sysResult = await tuiSelect({
|
|
38388
|
+
items: sysItems,
|
|
38389
|
+
title: "Select TTS System",
|
|
38390
|
+
rl: ctx.rl,
|
|
38391
|
+
availableRows: ctx.availableContentRows?.(),
|
|
38392
|
+
skipKeys: ["header-import"]
|
|
38393
|
+
});
|
|
38394
|
+
if (sysResult.confirmed && sysResult.key) {
|
|
38395
|
+
if (sysResult.key === "import-onnx") {
|
|
38396
|
+
const onnxDrop = await showDropPanel({
|
|
38397
|
+
title: "Import Piper Voice \u2014 Drop .onnx File",
|
|
38398
|
+
instruction: "Drag and drop the .onnx model file",
|
|
38399
|
+
allowedExtensions: [".onnx"],
|
|
38400
|
+
typeLabel: "ONNX model",
|
|
38401
|
+
rl: ctx.rl
|
|
38402
|
+
});
|
|
38403
|
+
if (!onnxDrop.confirmed || !onnxDrop.path) {
|
|
38404
|
+
continue;
|
|
38405
|
+
}
|
|
38406
|
+
const jsonDrop = await showDropPanel({
|
|
38407
|
+
title: "Import Piper Voice \u2014 Drop .onnx.json Config",
|
|
38408
|
+
instruction: "Drag and drop the .onnx.json config file for the model",
|
|
38409
|
+
allowedExtensions: [".json"],
|
|
38410
|
+
typeLabel: "JSON config",
|
|
38411
|
+
rl: ctx.rl
|
|
38412
|
+
});
|
|
38413
|
+
if (!jsonDrop.confirmed || !jsonDrop.path) {
|
|
38414
|
+
continue;
|
|
38415
|
+
}
|
|
38416
|
+
const { basename: basename16, join: pathJoin } = await import("node:path");
|
|
38417
|
+
const { copyFileSync: copyFileSync2, mkdirSync: mkdirSync21, existsSync: exists } = await import("node:fs");
|
|
38418
|
+
const { homedir: homedir15 } = await import("node:os");
|
|
38419
|
+
const modelName = basename16(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
38420
|
+
const destDir = pathJoin(homedir15(), ".open-agents", "voice", "models", modelName);
|
|
38421
|
+
if (!exists(destDir))
|
|
38422
|
+
mkdirSync21(destDir, { recursive: true });
|
|
38423
|
+
copyFileSync2(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
38424
|
+
copyFileSync2(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
38425
|
+
const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
|
|
38426
|
+
registerCustomOnnxModel2(modelName, modelName);
|
|
38427
|
+
await ctx.voiceSetModel(modelName);
|
|
38428
|
+
save({ voice: true, voiceModel: modelName });
|
|
38429
|
+
} else {
|
|
38430
|
+
const systemModelMap = {
|
|
38431
|
+
onnx: "glados",
|
|
38432
|
+
mlx: "kokoro:af_heart",
|
|
38433
|
+
luxtts: "luxtts"
|
|
38434
|
+
};
|
|
38435
|
+
const modelId = systemModelMap[sysResult.key] ?? "glados";
|
|
38436
|
+
await ctx.voiceSetModel(modelId);
|
|
38437
|
+
save({ voice: true, voiceModel: modelId });
|
|
38364
38438
|
}
|
|
38365
|
-
const { basename: basename16, join: pathJoin } = await import("node:path");
|
|
38366
|
-
const { copyFileSync: copyFileSync2, mkdirSync: mkdirSync21, existsSync: exists } = await import("node:fs");
|
|
38367
|
-
const { homedir: homedir15 } = await import("node:os");
|
|
38368
|
-
const modelName = basename16(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
38369
|
-
const destDir = pathJoin(homedir15(), ".open-agents", "voice", "models", modelName);
|
|
38370
|
-
if (!exists(destDir))
|
|
38371
|
-
mkdirSync21(destDir, { recursive: true });
|
|
38372
|
-
copyFileSync2(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
38373
|
-
copyFileSync2(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
38374
|
-
const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
|
|
38375
|
-
registerCustomOnnxModel2(modelName, modelName);
|
|
38376
|
-
const msg = await ctx.voiceSetModel(modelName);
|
|
38377
|
-
save({ voice: true, voiceModel: modelName });
|
|
38378
|
-
renderInfo(`Imported Piper model "${modelName}". ${msg}`);
|
|
38379
|
-
} else {
|
|
38380
|
-
const systemModelMap = {
|
|
38381
|
-
onnx: "glados",
|
|
38382
|
-
mlx: "kokoro:af_heart",
|
|
38383
|
-
luxtts: "luxtts"
|
|
38384
|
-
};
|
|
38385
|
-
const modelId = systemModelMap[sysResult.key] ?? "glados";
|
|
38386
|
-
const msg = await ctx.voiceSetModel(modelId);
|
|
38387
|
-
save({ voice: true, voiceModel: modelId });
|
|
38388
|
-
renderInfo(msg + (hasLocal ? " (project-local)" : ""));
|
|
38389
38439
|
}
|
|
38440
|
+
continue;
|
|
38390
38441
|
}
|
|
38391
|
-
|
|
38392
|
-
|
|
38393
|
-
|
|
38394
|
-
|
|
38395
|
-
|
|
38396
|
-
|
|
38397
|
-
|
|
38398
|
-
|
|
38399
|
-
|
|
38400
|
-
|
|
38401
|
-
|
|
38402
|
-
|
|
38403
|
-
renderWarning("Voice cloning not available in this context.");
|
|
38404
|
-
break;
|
|
38442
|
+
case "clone": {
|
|
38443
|
+
const dropResult = await showDropPanel({
|
|
38444
|
+
title: "Voice Clone \u2014 Drop Audio File",
|
|
38445
|
+
instruction: "Drag and drop an audio file to use as voice clone reference",
|
|
38446
|
+
allowedExtensions: [".wav", ".mp3", ".ogg", ".flac", ".m4a", ".opus", ".aac"],
|
|
38447
|
+
typeLabel: "Audio files",
|
|
38448
|
+
rl: ctx.rl
|
|
38449
|
+
});
|
|
38450
|
+
if (dropResult.confirmed && dropResult.path && ctx.voiceClone) {
|
|
38451
|
+
await ctx.voiceClone(dropResult.path);
|
|
38452
|
+
const newFilename = ctx.voiceGetLastClonedFilename?.();
|
|
38453
|
+
await handleVoiceList(ctx, newFilename ?? void 0);
|
|
38405
38454
|
}
|
|
38406
|
-
|
|
38407
|
-
|
|
38408
|
-
|
|
38409
|
-
|
|
38455
|
+
continue;
|
|
38456
|
+
}
|
|
38457
|
+
case "list": {
|
|
38458
|
+
await handleVoiceList(ctx);
|
|
38459
|
+
continue;
|
|
38410
38460
|
}
|
|
38411
|
-
break;
|
|
38412
|
-
}
|
|
38413
|
-
case "list": {
|
|
38414
|
-
await handleVoiceList(ctx);
|
|
38415
|
-
break;
|
|
38416
38461
|
}
|
|
38417
38462
|
}
|
|
38418
38463
|
}
|
|
38419
|
-
async function handleVoiceList(ctx) {
|
|
38464
|
+
async function handleVoiceList(ctx, focusFilename) {
|
|
38420
38465
|
if (!ctx.voiceListClones) {
|
|
38421
38466
|
renderWarning("Voice clone management not available in this context.");
|
|
38422
38467
|
return;
|
|
@@ -38433,11 +38478,12 @@ async function handleVoiceList(ctx) {
|
|
|
38433
38478
|
label: cl.name,
|
|
38434
38479
|
detail: `${cl.filename} ${formatFileSize(cl.size)}`
|
|
38435
38480
|
}));
|
|
38436
|
-
const activeFilename = clones.find((cl) => cl.isActive)?.filename;
|
|
38481
|
+
const activeFilename = focusFilename ?? clones.find((cl) => cl.isActive)?.filename;
|
|
38482
|
+
let pendingAutoRename = focusFilename ?? null;
|
|
38437
38483
|
const result = await tuiSelect({
|
|
38438
38484
|
items,
|
|
38439
38485
|
activeKey: activeFilename,
|
|
38440
|
-
title: "Voice Clone References",
|
|
38486
|
+
title: focusFilename ? "Voice Clone References \u2014 Press any key to name your new voice" : "Voice Clone References",
|
|
38441
38487
|
rl: ctx.rl,
|
|
38442
38488
|
availableRows: ctx.availableContentRows?.(),
|
|
38443
38489
|
customKeyHint: " e rename p play",
|
|
@@ -38449,6 +38495,22 @@ async function handleVoiceList(ctx) {
|
|
|
38449
38495
|
}
|
|
38450
38496
|
},
|
|
38451
38497
|
onCustomKey: (item, key, helpers) => {
|
|
38498
|
+
if (pendingAutoRename && item.key === pendingAutoRename) {
|
|
38499
|
+
pendingAutoRename = null;
|
|
38500
|
+
const currentName = item.label;
|
|
38501
|
+
helpers.getInput("Name this voice:", currentName).then((newName) => {
|
|
38502
|
+
if (newName !== null && newName.trim() && newName.trim() !== currentName) {
|
|
38503
|
+
ctx.voiceRenameClone?.(item.key, newName.trim());
|
|
38504
|
+
const idx = items.findIndex((i) => i.key === item.key);
|
|
38505
|
+
if (idx >= 0) {
|
|
38506
|
+
helpers.updateItem(idx, { label: newName.trim() });
|
|
38507
|
+
}
|
|
38508
|
+
} else {
|
|
38509
|
+
helpers.render();
|
|
38510
|
+
}
|
|
38511
|
+
});
|
|
38512
|
+
return true;
|
|
38513
|
+
}
|
|
38452
38514
|
if (key === "e" || key === "E") {
|
|
38453
38515
|
const currentName = item.label;
|
|
38454
38516
|
helpers.getInput("New name:", currentName).then((newName) => {
|
|
@@ -48373,14 +48435,18 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
48373
48435
|
}
|
|
48374
48436
|
backend = new CascadeBackend(config.model, [primaryEndpoint, ...fallbackEndpoints], {
|
|
48375
48437
|
onSwitch: (_from, to, reason) => {
|
|
48376
|
-
|
|
48438
|
+
const msg = `
|
|
48377
48439
|
[cascade] Failover \u2192 ${to.label ?? to.url}: ${reason}
|
|
48378
|
-
|
|
48440
|
+
`;
|
|
48441
|
+
if (!bufferIfOverlay("stderr", msg))
|
|
48442
|
+
process.stderr.write(msg);
|
|
48379
48443
|
},
|
|
48380
48444
|
onProbeResult: (ep, success) => {
|
|
48381
48445
|
if (success) {
|
|
48382
|
-
|
|
48383
|
-
|
|
48446
|
+
const msg = `[cascade] Primary recovered: ${ep.label ?? ep.url}
|
|
48447
|
+
`;
|
|
48448
|
+
if (!bufferIfOverlay("stderr", msg))
|
|
48449
|
+
process.stderr.write(msg);
|
|
48384
48450
|
}
|
|
48385
48451
|
}
|
|
48386
48452
|
});
|
|
@@ -48620,6 +48686,22 @@ ${entry.fullContent}`
|
|
|
48620
48686
|
let streamStartMs = 0;
|
|
48621
48687
|
let streamTextBuffer = "";
|
|
48622
48688
|
const contentWrite = (fn) => {
|
|
48689
|
+
if (isOverlayActive()) {
|
|
48690
|
+
const origWrite = process.stdout.write;
|
|
48691
|
+
const chunks = [];
|
|
48692
|
+
process.stdout.write = ((chunk) => {
|
|
48693
|
+
chunks.push(chunk);
|
|
48694
|
+
return true;
|
|
48695
|
+
});
|
|
48696
|
+
try {
|
|
48697
|
+
fn();
|
|
48698
|
+
} finally {
|
|
48699
|
+
process.stdout.write = origWrite;
|
|
48700
|
+
}
|
|
48701
|
+
for (const chunk of chunks)
|
|
48702
|
+
bufferIfOverlay("stdout", chunk);
|
|
48703
|
+
return;
|
|
48704
|
+
}
|
|
48623
48705
|
if (statusBar?.isActive) {
|
|
48624
48706
|
statusBar.beginContentWrite();
|
|
48625
48707
|
fn();
|
|
@@ -49371,6 +49453,22 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
49371
49453
|
}
|
|
49372
49454
|
}
|
|
49373
49455
|
function writeContent(fn) {
|
|
49456
|
+
if (isOverlayActive()) {
|
|
49457
|
+
const origWrite = process.stdout.write;
|
|
49458
|
+
const chunks = [];
|
|
49459
|
+
process.stdout.write = ((chunk) => {
|
|
49460
|
+
chunks.push(chunk);
|
|
49461
|
+
return true;
|
|
49462
|
+
});
|
|
49463
|
+
try {
|
|
49464
|
+
fn();
|
|
49465
|
+
} finally {
|
|
49466
|
+
process.stdout.write = origWrite;
|
|
49467
|
+
}
|
|
49468
|
+
for (const chunk of chunks)
|
|
49469
|
+
bufferIfOverlay("stdout", chunk);
|
|
49470
|
+
return;
|
|
49471
|
+
}
|
|
49374
49472
|
if (statusBar.isActive) {
|
|
49375
49473
|
statusBar.beginContentWrite();
|
|
49376
49474
|
try {
|
|
@@ -49698,6 +49796,21 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
49698
49796
|
voiceSetMode(mode) {
|
|
49699
49797
|
voiceEngine.voiceMode = mode;
|
|
49700
49798
|
},
|
|
49799
|
+
voiceIsEnabled() {
|
|
49800
|
+
return voiceEngine.enabled;
|
|
49801
|
+
},
|
|
49802
|
+
voiceGetModel() {
|
|
49803
|
+
return voiceEngine.modelId ?? "unknown";
|
|
49804
|
+
},
|
|
49805
|
+
voiceGetLastClonedFilename() {
|
|
49806
|
+
return voiceEngine.lastClonedFilename;
|
|
49807
|
+
},
|
|
49808
|
+
setOverlayActive(active) {
|
|
49809
|
+
if (active)
|
|
49810
|
+
enterOverlay();
|
|
49811
|
+
else
|
|
49812
|
+
leaveOverlay();
|
|
49813
|
+
},
|
|
49701
49814
|
streamToggle() {
|
|
49702
49815
|
streamEnabled = !streamEnabled;
|
|
49703
49816
|
return streamEnabled;
|
|
@@ -51422,6 +51535,7 @@ var init_interactive = __esm({
|
|
|
51422
51535
|
init_telegram_bridge();
|
|
51423
51536
|
init_status_bar();
|
|
51424
51537
|
init_dist6();
|
|
51538
|
+
init_overlay_lock();
|
|
51425
51539
|
taskManager = new BackgroundTaskManager();
|
|
51426
51540
|
}
|
|
51427
51541
|
});
|
package/package.json
CHANGED