open-agents-ai 0.185.23 → 0.185.26
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 +1661 -721
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11914,8 +11914,8 @@ async function loadTranscribeCli() {
|
|
|
11914
11914
|
const nvmBase = join19(homedir7(), ".nvm", "versions", "node");
|
|
11915
11915
|
if (existsSync16(nvmBase)) {
|
|
11916
11916
|
try {
|
|
11917
|
-
const { readdirSync:
|
|
11918
|
-
for (const ver of
|
|
11917
|
+
const { readdirSync: readdirSync24 } = await import("node:fs");
|
|
11918
|
+
for (const ver of readdirSync24(nvmBase)) {
|
|
11919
11919
|
const tcPath = join19(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
11920
11920
|
if (existsSync16(join19(tcPath, "dist", "index.js"))) {
|
|
11921
11921
|
const { createRequire: createRequire6 } = await import("node:module");
|
|
@@ -13741,9 +13741,9 @@ print("${sentinel}")
|
|
|
13741
13741
|
if (!this.proc || this.proc.killed) {
|
|
13742
13742
|
return { success: false, path: "" };
|
|
13743
13743
|
}
|
|
13744
|
-
const { mkdirSync:
|
|
13744
|
+
const { mkdirSync: mkdirSync31, writeFileSync: writeFileSync30 } = await import("node:fs");
|
|
13745
13745
|
const sessionDir = join22(this.cwd, ".oa", "rlm");
|
|
13746
|
-
|
|
13746
|
+
mkdirSync31(sessionDir, { recursive: true });
|
|
13747
13747
|
const sessionPath = join22(sessionDir, "session.json");
|
|
13748
13748
|
try {
|
|
13749
13749
|
const inspectCode = `
|
|
@@ -13767,7 +13767,7 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
13767
13767
|
trajectoryCount: this.trajectory.length,
|
|
13768
13768
|
subCallCount: this.subCallCount
|
|
13769
13769
|
};
|
|
13770
|
-
|
|
13770
|
+
writeFileSync30(sessionPath, JSON.stringify(sessionData, null, 2), "utf8");
|
|
13771
13771
|
return { success: true, path: sessionPath };
|
|
13772
13772
|
}
|
|
13773
13773
|
} catch {
|
|
@@ -13779,11 +13779,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
13779
13779
|
* what was previously computed. */
|
|
13780
13780
|
async loadSessionInfo() {
|
|
13781
13781
|
try {
|
|
13782
|
-
const { readFileSync:
|
|
13782
|
+
const { readFileSync: readFileSync45, existsSync: existsSync57 } = await import("node:fs");
|
|
13783
13783
|
const sessionPath = join22(this.cwd, ".oa", "rlm", "session.json");
|
|
13784
|
-
if (!
|
|
13784
|
+
if (!existsSync57(sessionPath))
|
|
13785
13785
|
return null;
|
|
13786
|
-
return JSON.parse(
|
|
13786
|
+
return JSON.parse(readFileSync45(sessionPath, "utf8"));
|
|
13787
13787
|
} catch {
|
|
13788
13788
|
return null;
|
|
13789
13789
|
}
|
|
@@ -13960,10 +13960,10 @@ var init_memory_metabolism = __esm({
|
|
|
13960
13960
|
const trajDir = join23(this.cwd, ".oa", "rlm-trajectories");
|
|
13961
13961
|
let lessons = [];
|
|
13962
13962
|
try {
|
|
13963
|
-
const { readdirSync:
|
|
13964
|
-
const files =
|
|
13963
|
+
const { readdirSync: readdirSync24, readFileSync: readFileSync45 } = await import("node:fs");
|
|
13964
|
+
const files = readdirSync24(trajDir).filter((f) => f.endsWith(".jsonl")).sort().reverse().slice(0, 3);
|
|
13965
13965
|
for (const file of files) {
|
|
13966
|
-
const lines =
|
|
13966
|
+
const lines = readFileSync45(join23(trajDir, file), "utf8").split("\n").filter((l) => l.trim());
|
|
13967
13967
|
for (const line of lines) {
|
|
13968
13968
|
try {
|
|
13969
13969
|
const entry = JSON.parse(line);
|
|
@@ -14347,14 +14347,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
|
|
|
14347
14347
|
* Optionally filter by task type for phase-aware context (FSM paper insight).
|
|
14348
14348
|
*/
|
|
14349
14349
|
getTopMemoriesSync(k = 5, taskType) {
|
|
14350
|
-
const { readFileSync:
|
|
14350
|
+
const { readFileSync: readFileSync45, existsSync: existsSync57 } = __require("node:fs");
|
|
14351
14351
|
const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
|
|
14352
14352
|
const storeFile = join23(metaDir, "store.json");
|
|
14353
|
-
if (!
|
|
14353
|
+
if (!existsSync57(storeFile))
|
|
14354
14354
|
return "";
|
|
14355
14355
|
let store = [];
|
|
14356
14356
|
try {
|
|
14357
|
-
store = JSON.parse(
|
|
14357
|
+
store = JSON.parse(readFileSync45(storeFile, "utf8"));
|
|
14358
14358
|
} catch {
|
|
14359
14359
|
return "";
|
|
14360
14360
|
}
|
|
@@ -14376,14 +14376,14 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
|
|
|
14376
14376
|
/** Update memory scores based on task outcome. Called after task completion.
|
|
14377
14377
|
* Memories used in successful tasks get boosted. Memories present during failures get decayed. */
|
|
14378
14378
|
updateFromOutcomeSync(surfacedMemoryText, succeeded) {
|
|
14379
|
-
const { readFileSync:
|
|
14379
|
+
const { readFileSync: readFileSync45, writeFileSync: writeFileSync30, existsSync: existsSync57, mkdirSync: mkdirSync31 } = __require("node:fs");
|
|
14380
14380
|
const metaDir = join23(this.cwd, ".oa", "memory", "metabolism");
|
|
14381
14381
|
const storeFile = join23(metaDir, "store.json");
|
|
14382
|
-
if (!
|
|
14382
|
+
if (!existsSync57(storeFile))
|
|
14383
14383
|
return;
|
|
14384
14384
|
let store = [];
|
|
14385
14385
|
try {
|
|
14386
|
-
store = JSON.parse(
|
|
14386
|
+
store = JSON.parse(readFileSync45(storeFile, "utf8"));
|
|
14387
14387
|
} catch {
|
|
14388
14388
|
return;
|
|
14389
14389
|
}
|
|
@@ -14407,8 +14407,8 @@ ${issues.map((i) => ` - ${i}`).join("\n")}` : " No issues found."),
|
|
|
14407
14407
|
updated = true;
|
|
14408
14408
|
}
|
|
14409
14409
|
if (updated) {
|
|
14410
|
-
|
|
14411
|
-
|
|
14410
|
+
mkdirSync31(metaDir, { recursive: true });
|
|
14411
|
+
writeFileSync30(storeFile, JSON.stringify(store, null, 2));
|
|
14412
14412
|
}
|
|
14413
14413
|
}
|
|
14414
14414
|
// ── Storage ──────────────────────────────────────────────────────────
|
|
@@ -14830,13 +14830,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
14830
14830
|
// Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
|
|
14831
14831
|
/** Retrieve top-K strategies for context injection. Returns "" if none. */
|
|
14832
14832
|
getRelevantStrategiesSync(k = 3, taskType) {
|
|
14833
|
-
const { readFileSync:
|
|
14833
|
+
const { readFileSync: readFileSync45, existsSync: existsSync57 } = __require("node:fs");
|
|
14834
14834
|
const archiveFile = join25(this.cwd, ".oa", "arche", "variants.json");
|
|
14835
|
-
if (!
|
|
14835
|
+
if (!existsSync57(archiveFile))
|
|
14836
14836
|
return "";
|
|
14837
14837
|
let variants = [];
|
|
14838
14838
|
try {
|
|
14839
|
-
variants = JSON.parse(
|
|
14839
|
+
variants = JSON.parse(readFileSync45(archiveFile, "utf8"));
|
|
14840
14840
|
} catch {
|
|
14841
14841
|
return "";
|
|
14842
14842
|
}
|
|
@@ -14854,13 +14854,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
14854
14854
|
}
|
|
14855
14855
|
/** Archive a strategy variant synchronously (for task completion path) */
|
|
14856
14856
|
archiveVariantSync(strategy, outcome, tags = []) {
|
|
14857
|
-
const { readFileSync:
|
|
14857
|
+
const { readFileSync: readFileSync45, writeFileSync: writeFileSync30, existsSync: existsSync57, mkdirSync: mkdirSync31 } = __require("node:fs");
|
|
14858
14858
|
const dir = join25(this.cwd, ".oa", "arche");
|
|
14859
14859
|
const archiveFile = join25(dir, "variants.json");
|
|
14860
14860
|
let variants = [];
|
|
14861
14861
|
try {
|
|
14862
|
-
if (
|
|
14863
|
-
variants = JSON.parse(
|
|
14862
|
+
if (existsSync57(archiveFile))
|
|
14863
|
+
variants = JSON.parse(readFileSync45(archiveFile, "utf8"));
|
|
14864
14864
|
} catch {
|
|
14865
14865
|
}
|
|
14866
14866
|
variants.push({
|
|
@@ -14875,8 +14875,8 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
14875
14875
|
});
|
|
14876
14876
|
if (variants.length > 50)
|
|
14877
14877
|
variants = variants.slice(-50);
|
|
14878
|
-
|
|
14879
|
-
|
|
14878
|
+
mkdirSync31(dir, { recursive: true });
|
|
14879
|
+
writeFileSync30(archiveFile, JSON.stringify(variants, null, 2));
|
|
14880
14880
|
}
|
|
14881
14881
|
async saveArchive(variants) {
|
|
14882
14882
|
const dir = join25(this.cwd, ".oa", "arche");
|
|
@@ -15840,9 +15840,9 @@ var init_vision = __esm({
|
|
|
15840
15840
|
if (ollamaResult)
|
|
15841
15841
|
return ollamaResult;
|
|
15842
15842
|
try {
|
|
15843
|
-
const { execSync:
|
|
15843
|
+
const { execSync: execSync35 } = await import("node:child_process");
|
|
15844
15844
|
try {
|
|
15845
|
-
|
|
15845
|
+
execSync35("pip3 install --user moondream 2>/dev/null || pip install --user moondream 2>/dev/null", {
|
|
15846
15846
|
timeout: 12e4,
|
|
15847
15847
|
stdio: "pipe"
|
|
15848
15848
|
});
|
|
@@ -15855,7 +15855,7 @@ var init_vision = __esm({
|
|
|
15855
15855
|
} catch {
|
|
15856
15856
|
}
|
|
15857
15857
|
try {
|
|
15858
|
-
|
|
15858
|
+
execSync35("ollama pull moondream", { timeout: 3e5, stdio: "pipe" });
|
|
15859
15859
|
const retryOllama = await this.tryOllamaVision(buffer, filename, action, prompt, length, start);
|
|
15860
15860
|
if (retryOllama)
|
|
15861
15861
|
return retryOllama;
|
|
@@ -15963,8 +15963,8 @@ Coordinates are normalized (0-1). Multiply by image width/height for pixel value
|
|
|
15963
15963
|
const errText = await res.text().catch(() => "");
|
|
15964
15964
|
if (res.status === 404 || /not found|does not exist/i.test(errText)) {
|
|
15965
15965
|
try {
|
|
15966
|
-
const { execSync:
|
|
15967
|
-
|
|
15966
|
+
const { execSync: execSync35 } = await import("node:child_process");
|
|
15967
|
+
execSync35("ollama pull moondream", { timeout: 3e5, stdio: "pipe" });
|
|
15968
15968
|
res = await fetch(`${ollamaHost}/api/generate`, {
|
|
15969
15969
|
method: "POST",
|
|
15970
15970
|
headers: { "Content-Type": "application/json" },
|
|
@@ -27351,10 +27351,10 @@ ${marker}` : marker);
|
|
|
27351
27351
|
if (!this._workingDirectory)
|
|
27352
27352
|
return;
|
|
27353
27353
|
try {
|
|
27354
|
-
const { mkdirSync:
|
|
27355
|
-
const { join:
|
|
27356
|
-
const sessionDir =
|
|
27357
|
-
|
|
27354
|
+
const { mkdirSync: mkdirSync31, writeFileSync: writeFileSync30 } = __require("node:fs");
|
|
27355
|
+
const { join: join77 } = __require("node:path");
|
|
27356
|
+
const sessionDir = join77(this._workingDirectory, ".oa", "session", this._sessionId);
|
|
27357
|
+
mkdirSync31(sessionDir, { recursive: true });
|
|
27358
27358
|
const checkpoint = {
|
|
27359
27359
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27360
27360
|
sessionId: this._sessionId,
|
|
@@ -27366,7 +27366,7 @@ ${marker}` : marker);
|
|
|
27366
27366
|
memexEntryCount: this._memexArchive.size,
|
|
27367
27367
|
fileRegistrySize: this._fileRegistry.size
|
|
27368
27368
|
};
|
|
27369
|
-
|
|
27369
|
+
writeFileSync30(join77(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
|
|
27370
27370
|
} catch {
|
|
27371
27371
|
}
|
|
27372
27372
|
}
|
|
@@ -30460,8 +30460,8 @@ var init_listen = __esm({
|
|
|
30460
30460
|
const nvmBase = join48(homedir11(), ".nvm", "versions", "node");
|
|
30461
30461
|
if (existsSync32(nvmBase)) {
|
|
30462
30462
|
try {
|
|
30463
|
-
const { readdirSync:
|
|
30464
|
-
for (const ver of
|
|
30463
|
+
const { readdirSync: readdirSync24 } = await import("node:fs");
|
|
30464
|
+
for (const ver of readdirSync24(nvmBase)) {
|
|
30465
30465
|
const tcPath = join48(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
30466
30466
|
if (existsSync32(join48(tcPath, "dist", "index.js"))) {
|
|
30467
30467
|
const { createRequire: createRequire6 } = await import("node:module");
|
|
@@ -35595,6 +35595,351 @@ connect();
|
|
|
35595
35595
|
</body>
|
|
35596
35596
|
</html>`;
|
|
35597
35597
|
}
|
|
35598
|
+
function generatePersonaPlexHTML(ppWsUrl, textPrompt, voicePrompt) {
|
|
35599
|
+
return `<!DOCTYPE html>
|
|
35600
|
+
<html lang="en">
|
|
35601
|
+
<head>
|
|
35602
|
+
<meta charset="UTF-8">
|
|
35603
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
35604
|
+
<title>OA \u2014 PersonaPlex Voice</title>
|
|
35605
|
+
<style>
|
|
35606
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
35607
|
+
body {
|
|
35608
|
+
background: #1a1a1e;
|
|
35609
|
+
color: #b0b0b0;
|
|
35610
|
+
font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
|
|
35611
|
+
display: flex;
|
|
35612
|
+
flex-direction: column;
|
|
35613
|
+
min-height: 100vh;
|
|
35614
|
+
}
|
|
35615
|
+
#header {
|
|
35616
|
+
background: #1e1e22;
|
|
35617
|
+
padding: 8px 16px;
|
|
35618
|
+
display: flex;
|
|
35619
|
+
align-items: center;
|
|
35620
|
+
gap: 12px;
|
|
35621
|
+
border-bottom: 1px solid #2a2a30;
|
|
35622
|
+
}
|
|
35623
|
+
#header .accent { color: #b2920a; font-weight: bold; font-size: 0.8rem; }
|
|
35624
|
+
#header .badge { font-size: 0.6rem; color: #555; background: #2a2a30; padding: 2px 6px; border-radius: 2px; }
|
|
35625
|
+
#header .status { font-size: 0.7rem; color: #555; }
|
|
35626
|
+
#header .status.live { color: #b2920a; }
|
|
35627
|
+
#waveform {
|
|
35628
|
+
height: 48px;
|
|
35629
|
+
display: flex;
|
|
35630
|
+
align-items: center;
|
|
35631
|
+
justify-content: center;
|
|
35632
|
+
font-size: 1.6rem;
|
|
35633
|
+
line-height: 1;
|
|
35634
|
+
letter-spacing: 0.04em;
|
|
35635
|
+
white-space: nowrap;
|
|
35636
|
+
overflow: hidden;
|
|
35637
|
+
user-select: none;
|
|
35638
|
+
background: #1e1e22;
|
|
35639
|
+
border-bottom: 1px solid #2a2a30;
|
|
35640
|
+
}
|
|
35641
|
+
#conversation {
|
|
35642
|
+
flex: 1;
|
|
35643
|
+
overflow-y: auto;
|
|
35644
|
+
padding: 12px 16px;
|
|
35645
|
+
}
|
|
35646
|
+
.msg {
|
|
35647
|
+
padding: 6px 0;
|
|
35648
|
+
font-size: 0.82rem;
|
|
35649
|
+
line-height: 1.4;
|
|
35650
|
+
}
|
|
35651
|
+
.msg.user { color: #888; }
|
|
35652
|
+
.msg.user::before { content: '\\25B8 '; color: #555; }
|
|
35653
|
+
.msg.agent { color: #b2920a; }
|
|
35654
|
+
.msg.agent::before { content: '\\25B9 '; color: #b2920a; }
|
|
35655
|
+
#footer {
|
|
35656
|
+
background: #1e1e22;
|
|
35657
|
+
padding: 8px 16px;
|
|
35658
|
+
display: flex;
|
|
35659
|
+
align-items: center;
|
|
35660
|
+
gap: 10px;
|
|
35661
|
+
border-top: 1px solid #2a2a30;
|
|
35662
|
+
}
|
|
35663
|
+
button {
|
|
35664
|
+
background: #2a2a30;
|
|
35665
|
+
border: 1px solid #3a3a42;
|
|
35666
|
+
color: #b2920a;
|
|
35667
|
+
padding: 6px 16px;
|
|
35668
|
+
border-radius: 3px;
|
|
35669
|
+
font-family: inherit;
|
|
35670
|
+
font-size: 0.75rem;
|
|
35671
|
+
cursor: pointer;
|
|
35672
|
+
transition: background 0.15s;
|
|
35673
|
+
}
|
|
35674
|
+
button:hover { background: #3a3a42; }
|
|
35675
|
+
button.active { background: #3a2a10; border-color: #b2920a; }
|
|
35676
|
+
#footer .hint { font-size: 0.65rem; color: #444; }
|
|
35677
|
+
</style>
|
|
35678
|
+
</head>
|
|
35679
|
+
<body>
|
|
35680
|
+
<div id="header">
|
|
35681
|
+
<span class="accent">OA</span>
|
|
35682
|
+
<span class="badge">PersonaPlex 7B</span>
|
|
35683
|
+
<span id="status" class="status">connecting</span>
|
|
35684
|
+
</div>
|
|
35685
|
+
<div id="waveform"></div>
|
|
35686
|
+
<div id="conversation"></div>
|
|
35687
|
+
<div id="footer">
|
|
35688
|
+
<button id="micBtn" onclick="toggleMic()">mic</button>
|
|
35689
|
+
<span class="hint" id="hint">tap to start full-duplex voice</span>
|
|
35690
|
+
</div>
|
|
35691
|
+
|
|
35692
|
+
<script>
|
|
35693
|
+
const waveEl = document.getElementById('waveform');
|
|
35694
|
+
const statusEl = document.getElementById('status');
|
|
35695
|
+
const convoEl = document.getElementById('conversation');
|
|
35696
|
+
const micBtn = document.getElementById('micBtn');
|
|
35697
|
+
const hintEl = document.getElementById('hint');
|
|
35698
|
+
|
|
35699
|
+
// PersonaPlex WebSocket URL (moshi.server)
|
|
35700
|
+
const PP_WS_URL = ${JSON.stringify(ppWsUrl)};
|
|
35701
|
+
const TEXT_PROMPT = ${JSON.stringify(textPrompt)};
|
|
35702
|
+
const VOICE_PROMPT = ${JSON.stringify(voicePrompt)};
|
|
35703
|
+
|
|
35704
|
+
// Braille waveform
|
|
35705
|
+
const DENSITY = ['\\u2800','\\u2840','\\u28C0','\\u28C4','\\u28E4','\\u28E6','\\u28F6','\\u28F7','\\u28FF'];
|
|
35706
|
+
const WAVE = [...DENSITY, ...DENSITY.slice(1,-1).reverse()];
|
|
35707
|
+
const THEME_IDLE = ['#1e1e22','#2a2a30','#333338','#3e3e44','#4a4a52','#555560','#666670','#777780','#888890'];
|
|
35708
|
+
const THEME_SPEAKING = ['#1e1e22','#2a2510','#3a3518','#4a4520','#5a5528','#6a6530','#8a7a20','#a89010','#b2920a'];
|
|
35709
|
+
const THEME_LISTENING = ['#1e1e22','#2a2818','#3a3820','#4a4828','#5a5830','#6a6838','#8a8830','#a8a020','#b2920a'];
|
|
35710
|
+
function buildColorRamp(r) { return [...r, ...r.slice(1,-1).reverse()]; }
|
|
35711
|
+
|
|
35712
|
+
let waveFrame = 0, waveState = 'idle', micLevel = 0;
|
|
35713
|
+
function renderWave() {
|
|
35714
|
+
const cols = Math.min(40, Math.floor(waveEl.offsetWidth / 20)) || 30;
|
|
35715
|
+
const cl = WAVE.length;
|
|
35716
|
+
const theme = waveState==='speaking'?THEME_SPEAKING:waveState==='listening'?THEME_LISTENING:THEME_IDLE;
|
|
35717
|
+
const cr = buildColorRamp(theme);
|
|
35718
|
+
const bp = Math.sin(waveFrame*0.06);
|
|
35719
|
+
const speed = waveState==='speaking'?2.5+bp*0.5:waveState==='listening'?2.0+micLevel*3.0+bp*0.3:1.2+bp*0.8;
|
|
35720
|
+
const ds = waveState==='idle'?0.35+bp*0.15:waveState==='listening'?0.3+micLevel*0.7:0.6+bp*0.2;
|
|
35721
|
+
const sa = 1.5+ds*2.0;
|
|
35722
|
+
let html='';
|
|
35723
|
+
for(let c=0;c<cols;c++){
|
|
35724
|
+
const so=Math.sin(c*0.1+waveFrame*0.02)*sa;
|
|
35725
|
+
const rp=c*speed+waveFrame+so;
|
|
35726
|
+
const np=((rp%cl)+cl)%cl;
|
|
35727
|
+
let wi=Math.round(np)%cl;
|
|
35728
|
+
let amp=wi<=8?wi:16-wi;
|
|
35729
|
+
const sc=Math.round(amp*ds);
|
|
35730
|
+
let si=wi<=8?sc:16-sc;
|
|
35731
|
+
si=Math.max(0,Math.min(cl-1,si));
|
|
35732
|
+
html+='<span style="color:'+cr[si]+'">'+WAVE[si]+'</span>';
|
|
35733
|
+
}
|
|
35734
|
+
waveEl.innerHTML=html;
|
|
35735
|
+
}
|
|
35736
|
+
setInterval(()=>{waveFrame++;renderWave();},80);
|
|
35737
|
+
|
|
35738
|
+
// \u2500\u2500 PersonaPlex connection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
35739
|
+
let ppWs = null;
|
|
35740
|
+
let micCtx = null, micStream = null, micActive = false;
|
|
35741
|
+
let playbackCtx = null;
|
|
35742
|
+
let handshakeReceived = false;
|
|
35743
|
+
let opusEncoder = null, opusDecoder = null;
|
|
35744
|
+
let agentText = '';
|
|
35745
|
+
|
|
35746
|
+
function connectPP() {
|
|
35747
|
+
const url = PP_WS_URL + '/api/chat?text_prompt=' + encodeURIComponent(TEXT_PROMPT) +
|
|
35748
|
+
'&voice_prompt=' + encodeURIComponent(VOICE_PROMPT) + '&seed=-1';
|
|
35749
|
+
statusEl.textContent = 'connecting to PersonaPlex...';
|
|
35750
|
+
ppWs = new WebSocket(url);
|
|
35751
|
+
ppWs.binaryType = 'arraybuffer';
|
|
35752
|
+
|
|
35753
|
+
ppWs.onopen = () => {
|
|
35754
|
+
statusEl.textContent = 'loading persona...';
|
|
35755
|
+
statusEl.className = 'status';
|
|
35756
|
+
};
|
|
35757
|
+
|
|
35758
|
+
ppWs.onmessage = (evt) => {
|
|
35759
|
+
if (!(evt.data instanceof ArrayBuffer)) return;
|
|
35760
|
+
const bytes = new Uint8Array(evt.data);
|
|
35761
|
+
if (bytes.length === 0) return;
|
|
35762
|
+
|
|
35763
|
+
const kind = bytes[0];
|
|
35764
|
+
if (kind === 0x00) {
|
|
35765
|
+
// Handshake \u2014 server is ready
|
|
35766
|
+
handshakeReceived = true;
|
|
35767
|
+
statusEl.textContent = 'ready \u2014 full duplex';
|
|
35768
|
+
statusEl.className = 'status live';
|
|
35769
|
+
hintEl.textContent = 'tap mic to start talking';
|
|
35770
|
+
} else if (kind === 0x01) {
|
|
35771
|
+
// Audio (Opus) from PersonaPlex
|
|
35772
|
+
const opusData = bytes.slice(1);
|
|
35773
|
+
playOpus(opusData);
|
|
35774
|
+
waveState = 'speaking';
|
|
35775
|
+
} else if (kind === 0x02) {
|
|
35776
|
+
// Text token from PersonaPlex
|
|
35777
|
+
const text = new TextDecoder().decode(bytes.slice(1));
|
|
35778
|
+
agentText += text;
|
|
35779
|
+
// Flush on sentence boundary
|
|
35780
|
+
if (/[.!?]\\s*$/.test(agentText) || agentText.length > 200) {
|
|
35781
|
+
addTranscript('agent', agentText.trim());
|
|
35782
|
+
agentText = '';
|
|
35783
|
+
}
|
|
35784
|
+
}
|
|
35785
|
+
};
|
|
35786
|
+
|
|
35787
|
+
ppWs.onclose = () => {
|
|
35788
|
+
handshakeReceived = false;
|
|
35789
|
+
statusEl.textContent = 'disconnected';
|
|
35790
|
+
statusEl.className = 'status';
|
|
35791
|
+
if (agentText.trim()) { addTranscript('agent', agentText.trim()); agentText=''; }
|
|
35792
|
+
setTimeout(connectPP, 3000);
|
|
35793
|
+
};
|
|
35794
|
+
|
|
35795
|
+
ppWs.onerror = () => {};
|
|
35796
|
+
}
|
|
35797
|
+
|
|
35798
|
+
function addTranscript(speaker, text) {
|
|
35799
|
+
const div = document.createElement('div');
|
|
35800
|
+
div.className = 'msg ' + speaker;
|
|
35801
|
+
div.textContent = text;
|
|
35802
|
+
convoEl.appendChild(div);
|
|
35803
|
+
convoEl.scrollTop = convoEl.scrollHeight;
|
|
35804
|
+
}
|
|
35805
|
+
|
|
35806
|
+
// \u2500\u2500 Opus playback via WebAudio \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
35807
|
+
// PersonaPlex sends Opus-encoded audio via sphn. We decode via AudioDecoder or fallback.
|
|
35808
|
+
|
|
35809
|
+
async function playOpus(opusData) {
|
|
35810
|
+
// Use raw PCM fallback \u2014 decode Opus in a worker or use AudioContext.decodeAudioData
|
|
35811
|
+
// For simplicity, we'll use the AudioDecoder API if available
|
|
35812
|
+
if (!playbackCtx) playbackCtx = new AudioContext({ sampleRate: 24000 });
|
|
35813
|
+
|
|
35814
|
+
try {
|
|
35815
|
+
// Wrap opus in a minimal ogg-like container isn't practical,
|
|
35816
|
+
// so we attempt raw decode via AudioDecoder (Chrome 94+)
|
|
35817
|
+
if (typeof AudioDecoder !== 'undefined' && !opusDecoder) {
|
|
35818
|
+
opusDecoder = new AudioDecoder({
|
|
35819
|
+
output: (frame) => {
|
|
35820
|
+
const buf = playbackCtx.createBuffer(1, frame.numberOfFrames, frame.sampleRate);
|
|
35821
|
+
frame.copyTo(buf.getChannelData(0), { planeIndex: 0 });
|
|
35822
|
+
const src = playbackCtx.createBufferSource();
|
|
35823
|
+
src.buffer = buf;
|
|
35824
|
+
src.connect(playbackCtx.destination);
|
|
35825
|
+
src.start();
|
|
35826
|
+
frame.close();
|
|
35827
|
+
},
|
|
35828
|
+
error: (e) => { console.warn('opus decode err:', e); }
|
|
35829
|
+
});
|
|
35830
|
+
opusDecoder.configure({
|
|
35831
|
+
codec: 'opus',
|
|
35832
|
+
sampleRate: 24000,
|
|
35833
|
+
numberOfChannels: 1,
|
|
35834
|
+
});
|
|
35835
|
+
}
|
|
35836
|
+
if (opusDecoder && opusDecoder.state === 'configured') {
|
|
35837
|
+
opusDecoder.decode(new EncodedAudioChunk({
|
|
35838
|
+
type: 'key',
|
|
35839
|
+
timestamp: 0,
|
|
35840
|
+
data: opusData,
|
|
35841
|
+
}));
|
|
35842
|
+
}
|
|
35843
|
+
} catch (e) {
|
|
35844
|
+
// Fallback: skip frame
|
|
35845
|
+
console.warn('Opus playback unavailable:', e);
|
|
35846
|
+
}
|
|
35847
|
+
}
|
|
35848
|
+
|
|
35849
|
+
// \u2500\u2500 Microphone \u2192 Opus \u2192 PersonaPlex \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
35850
|
+
|
|
35851
|
+
let scriptProcessor = null;
|
|
35852
|
+
|
|
35853
|
+
async function toggleMic() {
|
|
35854
|
+
if (micActive) { stopMic(); return; }
|
|
35855
|
+
if (!handshakeReceived) {
|
|
35856
|
+
hintEl.textContent = 'waiting for PersonaPlex...';
|
|
35857
|
+
return;
|
|
35858
|
+
}
|
|
35859
|
+
try {
|
|
35860
|
+
if (!micCtx) micCtx = new AudioContext({ sampleRate: 24000 });
|
|
35861
|
+
micStream = await navigator.mediaDevices.getUserMedia({
|
|
35862
|
+
audio: { sampleRate: 24000, channelCount: 1, echoCancellation: true, noiseSuppression: true }
|
|
35863
|
+
});
|
|
35864
|
+
const source = micCtx.createMediaStreamSource(micStream);
|
|
35865
|
+
scriptProcessor = micCtx.createScriptProcessor(1920, 1, 1); // 80ms at 24kHz
|
|
35866
|
+
|
|
35867
|
+
// Use AudioEncoder to send Opus to PersonaPlex
|
|
35868
|
+
let audioEncoder = null;
|
|
35869
|
+
if (typeof AudioEncoder !== 'undefined') {
|
|
35870
|
+
audioEncoder = new AudioEncoder({
|
|
35871
|
+
output: (chunk) => {
|
|
35872
|
+
if (!ppWs || ppWs.readyState !== 1) return;
|
|
35873
|
+
const buf = new ArrayBuffer(chunk.byteLength + 1);
|
|
35874
|
+
const view = new Uint8Array(buf);
|
|
35875
|
+
view[0] = 0x01; // audio kind byte
|
|
35876
|
+
chunk.copyTo(view.subarray(1));
|
|
35877
|
+
ppWs.send(buf);
|
|
35878
|
+
},
|
|
35879
|
+
error: (e) => { console.warn('encode err:', e); }
|
|
35880
|
+
});
|
|
35881
|
+
audioEncoder.configure({
|
|
35882
|
+
codec: 'opus',
|
|
35883
|
+
sampleRate: 24000,
|
|
35884
|
+
numberOfChannels: 1,
|
|
35885
|
+
bitrate: 24000,
|
|
35886
|
+
});
|
|
35887
|
+
}
|
|
35888
|
+
|
|
35889
|
+
let frameCounter = 0;
|
|
35890
|
+
scriptProcessor.onaudioprocess = (e) => {
|
|
35891
|
+
if (!micActive || !ppWs || ppWs.readyState !== 1) return;
|
|
35892
|
+
const input = e.inputBuffer.getChannelData(0);
|
|
35893
|
+
micLevel = Math.min(1, rms(input) * 5);
|
|
35894
|
+
|
|
35895
|
+
if (audioEncoder && audioEncoder.state === 'configured') {
|
|
35896
|
+
const data = new AudioData({
|
|
35897
|
+
format: 'f32',
|
|
35898
|
+
sampleRate: 24000,
|
|
35899
|
+
numberOfFrames: input.length,
|
|
35900
|
+
numberOfChannels: 1,
|
|
35901
|
+
timestamp: frameCounter * (input.length / 24000) * 1e6,
|
|
35902
|
+
data: input,
|
|
35903
|
+
});
|
|
35904
|
+
audioEncoder.encode(data);
|
|
35905
|
+
data.close();
|
|
35906
|
+
frameCounter++;
|
|
35907
|
+
}
|
|
35908
|
+
};
|
|
35909
|
+
source.connect(scriptProcessor);
|
|
35910
|
+
scriptProcessor.connect(micCtx.destination);
|
|
35911
|
+
micActive = true;
|
|
35912
|
+
waveState = 'listening';
|
|
35913
|
+
micBtn.textContent = 'stop';
|
|
35914
|
+
micBtn.classList.add('active');
|
|
35915
|
+
hintEl.textContent = 'full-duplex active \u2014 speak freely';
|
|
35916
|
+
} catch (err) {
|
|
35917
|
+
hintEl.textContent = 'mic error: ' + err.message;
|
|
35918
|
+
}
|
|
35919
|
+
}
|
|
35920
|
+
|
|
35921
|
+
function stopMic() {
|
|
35922
|
+
micActive = false;
|
|
35923
|
+
micLevel = 0;
|
|
35924
|
+
waveState = 'idle';
|
|
35925
|
+
if (scriptProcessor) { scriptProcessor.disconnect(); scriptProcessor = null; }
|
|
35926
|
+
if (micStream) { micStream.getTracks().forEach(t => t.stop()); micStream = null; }
|
|
35927
|
+
micBtn.textContent = 'mic';
|
|
35928
|
+
micBtn.classList.remove('active');
|
|
35929
|
+
hintEl.textContent = 'tap mic to start talking';
|
|
35930
|
+
}
|
|
35931
|
+
|
|
35932
|
+
function rms(arr) {
|
|
35933
|
+
let sum = 0;
|
|
35934
|
+
for (let i = 0; i < arr.length; i++) sum += arr[i] * arr[i];
|
|
35935
|
+
return Math.sqrt(sum / arr.length);
|
|
35936
|
+
}
|
|
35937
|
+
|
|
35938
|
+
connectPP();
|
|
35939
|
+
</script>
|
|
35940
|
+
</body>
|
|
35941
|
+
</html>`;
|
|
35942
|
+
}
|
|
35598
35943
|
function renderVoiceSessionStart(tunnelUrl) {
|
|
35599
35944
|
process.stdout.write(`
|
|
35600
35945
|
${c2.cyan("\u2601")} ${c2.bold("Live Voice Session")}
|
|
@@ -35641,6 +35986,10 @@ var init_voice_session = __esm({
|
|
|
35641
35986
|
runtimeTimer = null;
|
|
35642
35987
|
idleTimer = null;
|
|
35643
35988
|
ttsSpeaking = false;
|
|
35989
|
+
/** When set, serve PersonaPlex frontend that connects directly to this moshi.server WS URL */
|
|
35990
|
+
personaPlexWsUrl = null;
|
|
35991
|
+
personaPlexTextPrompt = "You enjoy having a good conversation.";
|
|
35992
|
+
personaPlexVoicePrompt = "NATF2.pt";
|
|
35644
35993
|
/** Idle timeout before auto-closing (ms). Default 60s — no users connected → session ends. */
|
|
35645
35994
|
idleTimeoutMs = 6e4;
|
|
35646
35995
|
/** Callback invoked when user audio chunk arrives (PCM 16kHz 16-bit mono) */
|
|
@@ -35829,7 +36178,11 @@ var init_voice_session = __esm({
|
|
|
35829
36178
|
handleHTTP(req, res) {
|
|
35830
36179
|
if (req.url === "/" || req.url === "/index.html") {
|
|
35831
36180
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
35832
|
-
|
|
36181
|
+
if (this.personaPlexWsUrl) {
|
|
36182
|
+
res.end(generatePersonaPlexHTML(this.personaPlexWsUrl, this.personaPlexTextPrompt, this.personaPlexVoicePrompt));
|
|
36183
|
+
} else {
|
|
36184
|
+
res.end(generateFrontendHTML());
|
|
36185
|
+
}
|
|
35833
36186
|
} else if (req.url === "/health") {
|
|
35834
36187
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
35835
36188
|
res.end(JSON.stringify({
|
|
@@ -38906,26 +39259,26 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
|
38906
39259
|
async function fetchPeerModels(peerId, authKey) {
|
|
38907
39260
|
try {
|
|
38908
39261
|
const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
|
|
38909
|
-
const { existsSync:
|
|
38910
|
-
const { join:
|
|
39262
|
+
const { existsSync: existsSync57, readFileSync: readFileSync45 } = await import("node:fs");
|
|
39263
|
+
const { join: join77 } = await import("node:path");
|
|
38911
39264
|
const cwd4 = process.cwd();
|
|
38912
39265
|
const nexusTool = new NexusTool2(cwd4);
|
|
38913
39266
|
const nexusDir = nexusTool.getNexusDir();
|
|
38914
39267
|
let isLocalPeer = false;
|
|
38915
39268
|
try {
|
|
38916
|
-
const statusPath =
|
|
38917
|
-
if (
|
|
38918
|
-
const status = JSON.parse(
|
|
39269
|
+
const statusPath = join77(nexusDir, "status.json");
|
|
39270
|
+
if (existsSync57(statusPath)) {
|
|
39271
|
+
const status = JSON.parse(readFileSync45(statusPath, "utf8"));
|
|
38919
39272
|
if (status.peerId === peerId)
|
|
38920
39273
|
isLocalPeer = true;
|
|
38921
39274
|
}
|
|
38922
39275
|
} catch {
|
|
38923
39276
|
}
|
|
38924
39277
|
if (isLocalPeer) {
|
|
38925
|
-
const pricingPath =
|
|
38926
|
-
if (
|
|
39278
|
+
const pricingPath = join77(nexusDir, "pricing.json");
|
|
39279
|
+
if (existsSync57(pricingPath)) {
|
|
38927
39280
|
try {
|
|
38928
|
-
const pricing = JSON.parse(
|
|
39281
|
+
const pricing = JSON.parse(readFileSync45(pricingPath, "utf8"));
|
|
38929
39282
|
const localModels = (pricing.models || []).map((m) => ({
|
|
38930
39283
|
name: m.model || "unknown",
|
|
38931
39284
|
size: m.parameterSize || "",
|
|
@@ -38939,10 +39292,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
38939
39292
|
}
|
|
38940
39293
|
}
|
|
38941
39294
|
}
|
|
38942
|
-
const cachePath =
|
|
38943
|
-
if (
|
|
39295
|
+
const cachePath = join77(nexusDir, "peer-models-cache.json");
|
|
39296
|
+
if (existsSync57(cachePath)) {
|
|
38944
39297
|
try {
|
|
38945
|
-
const cache4 = JSON.parse(
|
|
39298
|
+
const cache4 = JSON.parse(readFileSync45(cachePath, "utf8"));
|
|
38946
39299
|
if (cache4.peerId === peerId && cache4.models?.length > 0) {
|
|
38947
39300
|
const age = Date.now() - new Date(cache4.cachedAt).getTime();
|
|
38948
39301
|
if (age < 5 * 60 * 1e3) {
|
|
@@ -39057,10 +39410,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
39057
39410
|
} catch {
|
|
39058
39411
|
}
|
|
39059
39412
|
if (isLocalPeer) {
|
|
39060
|
-
const pricingPath =
|
|
39061
|
-
if (
|
|
39413
|
+
const pricingPath = join77(nexusDir, "pricing.json");
|
|
39414
|
+
if (existsSync57(pricingPath)) {
|
|
39062
39415
|
try {
|
|
39063
|
-
const pricing = JSON.parse(
|
|
39416
|
+
const pricing = JSON.parse(readFileSync45(pricingPath, "utf8"));
|
|
39064
39417
|
return (pricing.models || []).map((m) => ({
|
|
39065
39418
|
name: m.model || "unknown",
|
|
39066
39419
|
size: m.parameterSize || "",
|
|
@@ -40724,13 +41077,505 @@ var init_tui_select = __esm({
|
|
|
40724
41077
|
}
|
|
40725
41078
|
});
|
|
40726
41079
|
|
|
41080
|
+
// packages/cli/dist/tui/personaplex.js
|
|
41081
|
+
var personaplex_exports = {};
|
|
41082
|
+
__export(personaplex_exports, {
|
|
41083
|
+
autoSetupPersonaPlex: () => autoSetupPersonaPlex,
|
|
41084
|
+
clonePersonaPlexVoice: () => clonePersonaPlexVoice,
|
|
41085
|
+
detectPersonaPlexCapability: () => detectPersonaPlexCapability,
|
|
41086
|
+
getPersonaPlexWSUrl: () => getPersonaPlexWSUrl,
|
|
41087
|
+
installPersonaPlex: () => installPersonaPlex,
|
|
41088
|
+
isPersonaPlexInstalled: () => isPersonaPlexInstalled,
|
|
41089
|
+
isPersonaPlexRunning: () => isPersonaPlexRunning,
|
|
41090
|
+
listPersonaPlexVoices: () => listPersonaPlexVoices,
|
|
41091
|
+
patchFrontendVoiceList: () => patchFrontendVoiceList,
|
|
41092
|
+
provisionShippedVoices: () => provisionShippedVoices,
|
|
41093
|
+
startPersonaPlexDaemon: () => startPersonaPlexDaemon,
|
|
41094
|
+
stopPersonaPlex: () => stopPersonaPlex
|
|
41095
|
+
});
|
|
41096
|
+
import { existsSync as existsSync37, writeFileSync as writeFileSync16, readFileSync as readFileSync28, mkdirSync as mkdirSync15, copyFileSync as copyFileSync2, readdirSync as readdirSync11 } from "node:fs";
|
|
41097
|
+
import { join as join54, dirname as dirname18 } from "node:path";
|
|
41098
|
+
import { homedir as homedir13 } from "node:os";
|
|
41099
|
+
import { execSync as execSync27, spawn as spawn19 } from "node:child_process";
|
|
41100
|
+
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
41101
|
+
function detectPersonaPlexCapability() {
|
|
41102
|
+
try {
|
|
41103
|
+
const nvsmi = execSync27("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits", {
|
|
41104
|
+
encoding: "utf8",
|
|
41105
|
+
timeout: 5e3,
|
|
41106
|
+
stdio: "pipe"
|
|
41107
|
+
}).trim();
|
|
41108
|
+
if (!nvsmi) {
|
|
41109
|
+
return { supported: false, reason: "No NVIDIA GPU detected", gpuName: "", vramGB: 0 };
|
|
41110
|
+
}
|
|
41111
|
+
const [gpuName, vramMB] = nvsmi.split("\n")[0].split(", ");
|
|
41112
|
+
const vramGB = parseInt(vramMB ?? "0", 10) / 1024;
|
|
41113
|
+
if (vramGB < 16) {
|
|
41114
|
+
return { supported: false, reason: `GPU has ${vramGB.toFixed(1)}GB VRAM (need \u226516GB)`, gpuName: gpuName ?? "", vramGB };
|
|
41115
|
+
}
|
|
41116
|
+
try {
|
|
41117
|
+
execSync27('python3 -c "import torch; assert torch.cuda.is_available()"', {
|
|
41118
|
+
timeout: 1e4,
|
|
41119
|
+
stdio: "pipe"
|
|
41120
|
+
});
|
|
41121
|
+
} catch {
|
|
41122
|
+
return { supported: false, reason: "PyTorch CUDA not available", gpuName: gpuName ?? "", vramGB };
|
|
41123
|
+
}
|
|
41124
|
+
return { supported: true, reason: "OK", gpuName: gpuName ?? "", vramGB };
|
|
41125
|
+
} catch {
|
|
41126
|
+
return { supported: false, reason: "nvidia-smi not found", gpuName: "", vramGB: 0 };
|
|
41127
|
+
}
|
|
41128
|
+
}
|
|
41129
|
+
function isPersonaPlexRunning() {
|
|
41130
|
+
if (!existsSync37(PID_FILE))
|
|
41131
|
+
return false;
|
|
41132
|
+
const pid = parseInt(readFileSync28(PID_FILE, "utf8").trim(), 10);
|
|
41133
|
+
if (isNaN(pid) || pid <= 0)
|
|
41134
|
+
return false;
|
|
41135
|
+
try {
|
|
41136
|
+
process.kill(pid, 0);
|
|
41137
|
+
return true;
|
|
41138
|
+
} catch {
|
|
41139
|
+
return false;
|
|
41140
|
+
}
|
|
41141
|
+
}
|
|
41142
|
+
function getPersonaPlexWSUrl() {
|
|
41143
|
+
if (!isPersonaPlexRunning())
|
|
41144
|
+
return null;
|
|
41145
|
+
if (!existsSync37(PORT_FILE))
|
|
41146
|
+
return null;
|
|
41147
|
+
const port = parseInt(readFileSync28(PORT_FILE, "utf8").trim(), 10);
|
|
41148
|
+
return isNaN(port) ? null : `wss://127.0.0.1:${port}`;
|
|
41149
|
+
}
|
|
41150
|
+
function isPersonaPlexInstalled() {
|
|
41151
|
+
return existsSync37(join54(PERSONAPLEX_DIR, "model_ready"));
|
|
41152
|
+
}
|
|
41153
|
+
async function installPersonaPlex(onInfo) {
|
|
41154
|
+
const log = onInfo ?? (() => {
|
|
41155
|
+
});
|
|
41156
|
+
mkdirSync15(PERSONAPLEX_DIR, { recursive: true });
|
|
41157
|
+
const venvDir = join54(PERSONAPLEX_DIR, "venv");
|
|
41158
|
+
if (!existsSync37(venvDir)) {
|
|
41159
|
+
log("Creating Python virtual environment...");
|
|
41160
|
+
try {
|
|
41161
|
+
execSync27(`python3 -m venv "${venvDir}"`, { timeout: 6e4, stdio: "pipe" });
|
|
41162
|
+
} catch (err) {
|
|
41163
|
+
log(`Failed to create venv: ${err instanceof Error ? err.message : String(err)}`);
|
|
41164
|
+
return false;
|
|
41165
|
+
}
|
|
41166
|
+
}
|
|
41167
|
+
const pip = process.platform === "win32" ? join54(venvDir, "Scripts", "pip.exe") : join54(venvDir, "bin", "pip");
|
|
41168
|
+
const python = process.platform === "win32" ? join54(venvDir, "Scripts", "python.exe") : join54(venvDir, "bin", "python3");
|
|
41169
|
+
log("Checking system dependencies (libopus)...");
|
|
41170
|
+
try {
|
|
41171
|
+
if (process.platform === "linux") {
|
|
41172
|
+
execSync27("dpkg -l libopus-dev 2>/dev/null || sudo apt-get install -y libopus-dev", { timeout: 3e4, stdio: "pipe" });
|
|
41173
|
+
} else if (process.platform === "darwin") {
|
|
41174
|
+
execSync27("brew list opus 2>/dev/null || brew install opus", { timeout: 6e4, stdio: "pipe" });
|
|
41175
|
+
}
|
|
41176
|
+
} catch {
|
|
41177
|
+
}
|
|
41178
|
+
log("Installing PersonaPlex (moshi package)...");
|
|
41179
|
+
const repoDir = join54(PERSONAPLEX_DIR, "personaplex-repo");
|
|
41180
|
+
try {
|
|
41181
|
+
if (!existsSync37(repoDir)) {
|
|
41182
|
+
execSync27(`git clone https://github.com/NVIDIA/personaplex.git "${repoDir}"`, { timeout: 12e4, stdio: "pipe" });
|
|
41183
|
+
}
|
|
41184
|
+
execSync27(`"${pip}" install --quiet "${join54(repoDir, "moshi")}/."`, { timeout: 3e5, stdio: "pipe" });
|
|
41185
|
+
} catch (err) {
|
|
41186
|
+
log(`Moshi install failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
41187
|
+
try {
|
|
41188
|
+
execSync27(`"${pip}" install --quiet torch torchaudio websockets soundfile huggingface_hub`, { timeout: 3e5, stdio: "pipe" });
|
|
41189
|
+
} catch {
|
|
41190
|
+
}
|
|
41191
|
+
return false;
|
|
41192
|
+
}
|
|
41193
|
+
const serverPy = join54(venvDir, "lib", `python3.${process.versions.node ? "12" : "10"}`, "site-packages", "moshi", "server.py");
|
|
41194
|
+
try {
|
|
41195
|
+
const sitePackages = execSync27(`"${python}" -c "import moshi, os; print(os.path.dirname(moshi.__file__))"`, {
|
|
41196
|
+
encoding: "utf8",
|
|
41197
|
+
timeout: 5e3,
|
|
41198
|
+
stdio: "pipe"
|
|
41199
|
+
}).trim();
|
|
41200
|
+
const serverFile = join54(sitePackages, "server.py");
|
|
41201
|
+
if (existsSync37(serverFile)) {
|
|
41202
|
+
let src = readFileSync28(serverFile, "utf8");
|
|
41203
|
+
if (src.includes('int(request["seed"])')) {
|
|
41204
|
+
src = src.replace('int(request["seed"])', 'int(request.query["seed"])');
|
|
41205
|
+
writeFileSync16(serverFile, src);
|
|
41206
|
+
log("Applied seed parameter bug fix to moshi server.");
|
|
41207
|
+
}
|
|
41208
|
+
}
|
|
41209
|
+
} catch {
|
|
41210
|
+
}
|
|
41211
|
+
log("PersonaPlex installed. Model will download on first launch (~14GB).");
|
|
41212
|
+
writeFileSync16(join54(PERSONAPLEX_DIR, "model_ready"), (/* @__PURE__ */ new Date()).toISOString());
|
|
41213
|
+
log("PersonaPlex installed successfully.");
|
|
41214
|
+
return true;
|
|
41215
|
+
}
|
|
41216
|
+
async function startPersonaPlexDaemon(onInfo) {
|
|
41217
|
+
const log = onInfo ?? (() => {
|
|
41218
|
+
});
|
|
41219
|
+
const PORT = 8998;
|
|
41220
|
+
if (isPersonaPlexRunning()) {
|
|
41221
|
+
const url = getPersonaPlexWSUrl();
|
|
41222
|
+
if (url) {
|
|
41223
|
+
log(`PersonaPlex already running at ${url}`);
|
|
41224
|
+
return url;
|
|
41225
|
+
}
|
|
41226
|
+
}
|
|
41227
|
+
if (!isPersonaPlexInstalled()) {
|
|
41228
|
+
log("PersonaPlex not installed. Run /voice personaplex to set up.");
|
|
41229
|
+
return null;
|
|
41230
|
+
}
|
|
41231
|
+
mkdirSync15(PERSONAPLEX_DIR, { recursive: true });
|
|
41232
|
+
const venvPython2 = process.platform === "win32" ? join54(PERSONAPLEX_DIR, "venv", "Scripts", "python.exe") : join54(PERSONAPLEX_DIR, "venv", "bin", "python3");
|
|
41233
|
+
const sslDir = join54(PERSONAPLEX_DIR, "ssl");
|
|
41234
|
+
mkdirSync15(sslDir, { recursive: true });
|
|
41235
|
+
log("Starting PersonaPlex daemon (loading ~7B model)...");
|
|
41236
|
+
const child = spawn19(venvPython2, [
|
|
41237
|
+
"-m",
|
|
41238
|
+
"moshi.server",
|
|
41239
|
+
"--host",
|
|
41240
|
+
"0.0.0.0",
|
|
41241
|
+
"--port",
|
|
41242
|
+
String(PORT),
|
|
41243
|
+
"--ssl",
|
|
41244
|
+
sslDir,
|
|
41245
|
+
"--device",
|
|
41246
|
+
"cuda"
|
|
41247
|
+
], {
|
|
41248
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
41249
|
+
detached: true,
|
|
41250
|
+
env: { ...process.env },
|
|
41251
|
+
cwd: PERSONAPLEX_DIR
|
|
41252
|
+
});
|
|
41253
|
+
if (child.pid) {
|
|
41254
|
+
writeFileSync16(PID_FILE, String(child.pid));
|
|
41255
|
+
writeFileSync16(PORT_FILE, String(PORT));
|
|
41256
|
+
}
|
|
41257
|
+
child.unref();
|
|
41258
|
+
const { createWriteStream } = await import("node:fs");
|
|
41259
|
+
const logStream = createWriteStream(LOG_FILE, { flags: "w" });
|
|
41260
|
+
child.stdout?.pipe(logStream);
|
|
41261
|
+
child.stderr?.pipe(logStream);
|
|
41262
|
+
const startTime = Date.now();
|
|
41263
|
+
const timeout = 12e4;
|
|
41264
|
+
while (Date.now() - startTime < timeout) {
|
|
41265
|
+
try {
|
|
41266
|
+
if (child.pid)
|
|
41267
|
+
process.kill(child.pid, 0);
|
|
41268
|
+
} catch {
|
|
41269
|
+
log("PersonaPlex daemon exited unexpectedly. Check daemon.log.");
|
|
41270
|
+
return null;
|
|
41271
|
+
}
|
|
41272
|
+
try {
|
|
41273
|
+
execSync27(`curl -sk -o /dev/null -w "%{http_code}" https://127.0.0.1:${PORT}/`, {
|
|
41274
|
+
timeout: 3e3,
|
|
41275
|
+
stdio: "pipe",
|
|
41276
|
+
encoding: "utf8"
|
|
41277
|
+
});
|
|
41278
|
+
const url = `wss://127.0.0.1:${PORT}`;
|
|
41279
|
+
log(`PersonaPlex ready at ${url}`);
|
|
41280
|
+
return url;
|
|
41281
|
+
} catch {
|
|
41282
|
+
}
|
|
41283
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
41284
|
+
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
41285
|
+
if (elapsed % 10 === 0)
|
|
41286
|
+
log(`Still loading... (${elapsed}s)`);
|
|
41287
|
+
}
|
|
41288
|
+
log("PersonaPlex daemon failed to start within 120s. Check daemon.log.");
|
|
41289
|
+
return null;
|
|
41290
|
+
}
|
|
41291
|
+
function stopPersonaPlex() {
|
|
41292
|
+
if (!existsSync37(PID_FILE))
|
|
41293
|
+
return;
|
|
41294
|
+
const pid = parseInt(readFileSync28(PID_FILE, "utf8").trim(), 10);
|
|
41295
|
+
if (isNaN(pid) || pid <= 0)
|
|
41296
|
+
return;
|
|
41297
|
+
try {
|
|
41298
|
+
if (process.platform === "win32") {
|
|
41299
|
+
execSync27(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
41300
|
+
} else {
|
|
41301
|
+
process.kill(pid, "SIGTERM");
|
|
41302
|
+
}
|
|
41303
|
+
} catch {
|
|
41304
|
+
}
|
|
41305
|
+
}
|
|
41306
|
+
function listPersonaPlexVoices() {
|
|
41307
|
+
const voices = [];
|
|
41308
|
+
const builtins = [
|
|
41309
|
+
"NATF0",
|
|
41310
|
+
"NATF1",
|
|
41311
|
+
"NATF2",
|
|
41312
|
+
"NATF3",
|
|
41313
|
+
"NATM0",
|
|
41314
|
+
"NATM1",
|
|
41315
|
+
"NATM2",
|
|
41316
|
+
"NATM3",
|
|
41317
|
+
"VARF0",
|
|
41318
|
+
"VARF1",
|
|
41319
|
+
"VARF2",
|
|
41320
|
+
"VARF3",
|
|
41321
|
+
"VARF4",
|
|
41322
|
+
"VARM0",
|
|
41323
|
+
"VARM1",
|
|
41324
|
+
"VARM2",
|
|
41325
|
+
"VARM3",
|
|
41326
|
+
"VARM4"
|
|
41327
|
+
];
|
|
41328
|
+
for (const name of builtins) {
|
|
41329
|
+
voices.push({ name, type: "builtin", path: `${name}.pt` });
|
|
41330
|
+
}
|
|
41331
|
+
if (existsSync37(CUSTOM_VOICES_DIR)) {
|
|
41332
|
+
try {
|
|
41333
|
+
const { readdirSync: readdirSync24 } = __require("node:fs");
|
|
41334
|
+
for (const f of readdirSync24(CUSTOM_VOICES_DIR)) {
|
|
41335
|
+
if (f.endsWith(".pt")) {
|
|
41336
|
+
const name = f.replace(/\.pt$/, "");
|
|
41337
|
+
voices.push({ name, type: "custom", path: join54(CUSTOM_VOICES_DIR, f) });
|
|
41338
|
+
}
|
|
41339
|
+
}
|
|
41340
|
+
} catch {
|
|
41341
|
+
}
|
|
41342
|
+
}
|
|
41343
|
+
return voices;
|
|
41344
|
+
}
|
|
41345
|
+
async function clonePersonaPlexVoice(inputWav, voiceName, onInfo) {
|
|
41346
|
+
const log = onInfo ?? (() => {
|
|
41347
|
+
});
|
|
41348
|
+
if (!isPersonaPlexInstalled()) {
|
|
41349
|
+
log("PersonaPlex not installed. Run /voice personaplex first.");
|
|
41350
|
+
return null;
|
|
41351
|
+
}
|
|
41352
|
+
if (!existsSync37(inputWav)) {
|
|
41353
|
+
log(`Input WAV not found: ${inputWav}`);
|
|
41354
|
+
return null;
|
|
41355
|
+
}
|
|
41356
|
+
mkdirSync15(CUSTOM_VOICES_DIR, { recursive: true });
|
|
41357
|
+
const outputPt = join54(CUSTOM_VOICES_DIR, `${voiceName}.pt`);
|
|
41358
|
+
if (existsSync37(outputPt)) {
|
|
41359
|
+
log(`Voice "${voiceName}" already exists. Delete ${outputPt} to re-clone.`);
|
|
41360
|
+
return outputPt;
|
|
41361
|
+
}
|
|
41362
|
+
const venvPython2 = process.platform === "win32" ? join54(PERSONAPLEX_DIR, "venv", "Scripts", "python.exe") : join54(PERSONAPLEX_DIR, "venv", "bin", "python3");
|
|
41363
|
+
const cloneScript = join54(PERSONAPLEX_DIR, "clone-voice.py");
|
|
41364
|
+
if (!existsSync37(cloneScript)) {
|
|
41365
|
+
log("clone-voice.py not found. Reinstall PersonaPlex.");
|
|
41366
|
+
return null;
|
|
41367
|
+
}
|
|
41368
|
+
log(`Cloning voice "${voiceName}" from ${inputWav}...`);
|
|
41369
|
+
log("This requires loading the full 7B model \u2014 may take 30-60s...");
|
|
41370
|
+
return new Promise((resolve36) => {
|
|
41371
|
+
const child = spawn19(venvPython2, [
|
|
41372
|
+
cloneScript,
|
|
41373
|
+
"--input",
|
|
41374
|
+
inputWav,
|
|
41375
|
+
"--name",
|
|
41376
|
+
voiceName,
|
|
41377
|
+
"--device",
|
|
41378
|
+
"cuda"
|
|
41379
|
+
], {
|
|
41380
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
41381
|
+
env: { ...process.env },
|
|
41382
|
+
cwd: PERSONAPLEX_DIR
|
|
41383
|
+
});
|
|
41384
|
+
let output = "";
|
|
41385
|
+
child.stdout?.on("data", (d) => {
|
|
41386
|
+
const line = d.toString();
|
|
41387
|
+
output += line;
|
|
41388
|
+
for (const l of line.split("\n").filter((s) => s.trim())) {
|
|
41389
|
+
log(l.trim());
|
|
41390
|
+
}
|
|
41391
|
+
});
|
|
41392
|
+
child.stderr?.on("data", (d) => {
|
|
41393
|
+
output += d.toString();
|
|
41394
|
+
});
|
|
41395
|
+
child.on("close", (code) => {
|
|
41396
|
+
if (code === 0 && existsSync37(outputPt)) {
|
|
41397
|
+
log(`Voice "${voiceName}" cloned successfully.`);
|
|
41398
|
+
resolve36(outputPt);
|
|
41399
|
+
} else {
|
|
41400
|
+
log(`Voice cloning failed (exit ${code}).`);
|
|
41401
|
+
resolve36(null);
|
|
41402
|
+
}
|
|
41403
|
+
});
|
|
41404
|
+
});
|
|
41405
|
+
}
|
|
41406
|
+
function getShippedVoicesDir() {
|
|
41407
|
+
const candidates = [
|
|
41408
|
+
join54(PERSONAPLEX_DIR, "shipped_voices"),
|
|
41409
|
+
// cached copy
|
|
41410
|
+
join54(process.cwd(), "voices", "personaplex")
|
|
41411
|
+
// repo root
|
|
41412
|
+
];
|
|
41413
|
+
try {
|
|
41414
|
+
const modDir = dirname18(fileURLToPath11(import.meta.url));
|
|
41415
|
+
candidates.push(join54(modDir, "..", "..", "..", "voices", "personaplex"));
|
|
41416
|
+
candidates.push(join54(modDir, "..", "..", "..", "..", "voices", "personaplex"));
|
|
41417
|
+
} catch {
|
|
41418
|
+
}
|
|
41419
|
+
for (const dir of candidates) {
|
|
41420
|
+
if (existsSync37(dir)) {
|
|
41421
|
+
try {
|
|
41422
|
+
const files = readdirSync11(dir);
|
|
41423
|
+
if (files.some((f) => f.endsWith(".pt")))
|
|
41424
|
+
return dir;
|
|
41425
|
+
} catch {
|
|
41426
|
+
}
|
|
41427
|
+
}
|
|
41428
|
+
}
|
|
41429
|
+
return null;
|
|
41430
|
+
}
|
|
41431
|
+
function provisionShippedVoices(onInfo) {
|
|
41432
|
+
const log = onInfo ?? (() => {
|
|
41433
|
+
});
|
|
41434
|
+
const shippedDir = getShippedVoicesDir();
|
|
41435
|
+
if (!shippedDir)
|
|
41436
|
+
return 0;
|
|
41437
|
+
const hfVoicesDir = getHFVoicesDir();
|
|
41438
|
+
mkdirSync15(CUSTOM_VOICES_DIR, { recursive: true });
|
|
41439
|
+
let deployed = 0;
|
|
41440
|
+
try {
|
|
41441
|
+
for (const f of readdirSync11(shippedDir)) {
|
|
41442
|
+
if (!f.endsWith(".pt"))
|
|
41443
|
+
continue;
|
|
41444
|
+
const customDst = join54(CUSTOM_VOICES_DIR, f);
|
|
41445
|
+
if (!existsSync37(customDst)) {
|
|
41446
|
+
copyFileSync2(join54(shippedDir, f), customDst);
|
|
41447
|
+
}
|
|
41448
|
+
if (hfVoicesDir) {
|
|
41449
|
+
const hfDst = join54(hfVoicesDir, f);
|
|
41450
|
+
if (!existsSync37(hfDst)) {
|
|
41451
|
+
copyFileSync2(join54(shippedDir, f), hfDst);
|
|
41452
|
+
log(`Deployed voice: ${f.replace(".pt", "")}`);
|
|
41453
|
+
deployed++;
|
|
41454
|
+
}
|
|
41455
|
+
}
|
|
41456
|
+
}
|
|
41457
|
+
} catch {
|
|
41458
|
+
}
|
|
41459
|
+
const shippedScript = join54(shippedDir, "clone-voice.py");
|
|
41460
|
+
const targetScript = join54(PERSONAPLEX_DIR, "clone-voice.py");
|
|
41461
|
+
if (existsSync37(shippedScript) && !existsSync37(targetScript)) {
|
|
41462
|
+
try {
|
|
41463
|
+
copyFileSync2(shippedScript, targetScript);
|
|
41464
|
+
} catch {
|
|
41465
|
+
}
|
|
41466
|
+
}
|
|
41467
|
+
return deployed;
|
|
41468
|
+
}
|
|
41469
|
+
function getHFVoicesDir() {
|
|
41470
|
+
const hfBase = join54(homedir13(), ".cache", "huggingface", "hub", "models--nvidia--personaplex-7b-v1");
|
|
41471
|
+
if (!existsSync37(hfBase))
|
|
41472
|
+
return null;
|
|
41473
|
+
try {
|
|
41474
|
+
const snapshots = join54(hfBase, "snapshots");
|
|
41475
|
+
if (!existsSync37(snapshots))
|
|
41476
|
+
return null;
|
|
41477
|
+
for (const snap of readdirSync11(snapshots)) {
|
|
41478
|
+
const voicesDir = join54(snapshots, snap, "voices");
|
|
41479
|
+
if (existsSync37(voicesDir))
|
|
41480
|
+
return voicesDir;
|
|
41481
|
+
}
|
|
41482
|
+
} catch {
|
|
41483
|
+
}
|
|
41484
|
+
return null;
|
|
41485
|
+
}
|
|
41486
|
+
function patchFrontendVoiceList(onInfo) {
|
|
41487
|
+
const log = onInfo ?? (() => {
|
|
41488
|
+
});
|
|
41489
|
+
const hfBase = join54(homedir13(), ".cache", "huggingface", "hub", "models--nvidia--personaplex-7b-v1");
|
|
41490
|
+
if (!existsSync37(hfBase))
|
|
41491
|
+
return;
|
|
41492
|
+
try {
|
|
41493
|
+
const snapshots = join54(hfBase, "snapshots");
|
|
41494
|
+
for (const snap of readdirSync11(snapshots)) {
|
|
41495
|
+
const distDir = join54(snapshots, snap, "dist", "assets");
|
|
41496
|
+
if (!existsSync37(distDir))
|
|
41497
|
+
continue;
|
|
41498
|
+
for (const f of readdirSync11(distDir)) {
|
|
41499
|
+
if (!f.startsWith("index-") || !f.endsWith(".js"))
|
|
41500
|
+
continue;
|
|
41501
|
+
const jsPath = join54(distDir, f);
|
|
41502
|
+
let js = readFileSync28(jsPath, "utf8");
|
|
41503
|
+
const customVoices = [];
|
|
41504
|
+
if (existsSync37(CUSTOM_VOICES_DIR)) {
|
|
41505
|
+
for (const vf of readdirSync11(CUSTOM_VOICES_DIR)) {
|
|
41506
|
+
if (vf.endsWith(".pt")) {
|
|
41507
|
+
const name = vf.replace(".pt", "");
|
|
41508
|
+
if (!js.includes(`"${vf}"`)) {
|
|
41509
|
+
customVoices.push(vf);
|
|
41510
|
+
}
|
|
41511
|
+
}
|
|
41512
|
+
}
|
|
41513
|
+
}
|
|
41514
|
+
if (customVoices.length === 0)
|
|
41515
|
+
continue;
|
|
41516
|
+
const needle = '"VARM4.pt"]';
|
|
41517
|
+
if (js.includes(needle)) {
|
|
41518
|
+
const additions = customVoices.map((v) => `"${v}"`).join(", ");
|
|
41519
|
+
js = js.replace(needle, `"VARM4.pt", ${additions}]`);
|
|
41520
|
+
writeFileSync16(jsPath, js);
|
|
41521
|
+
log(`Added ${customVoices.length} custom voice(s) to frontend: ${customVoices.map((v) => v.replace(".pt", "")).join(", ")}`);
|
|
41522
|
+
}
|
|
41523
|
+
}
|
|
41524
|
+
}
|
|
41525
|
+
} catch {
|
|
41526
|
+
}
|
|
41527
|
+
}
|
|
41528
|
+
async function autoSetupPersonaPlex(onInfo) {
|
|
41529
|
+
const log = onInfo ?? (() => {
|
|
41530
|
+
});
|
|
41531
|
+
const caps = detectPersonaPlexCapability();
|
|
41532
|
+
if (!caps.supported) {
|
|
41533
|
+
log(`PersonaPlex not available: ${caps.reason}`);
|
|
41534
|
+
return null;
|
|
41535
|
+
}
|
|
41536
|
+
log(`GPU: ${caps.gpuName} (${caps.vramGB.toFixed(0)}GB) \u2014 PersonaPlex compatible`);
|
|
41537
|
+
if (!isPersonaPlexInstalled()) {
|
|
41538
|
+
log("Installing PersonaPlex (first time setup)...");
|
|
41539
|
+
const ok = await installPersonaPlex(log);
|
|
41540
|
+
if (!ok) {
|
|
41541
|
+
log("PersonaPlex installation failed.");
|
|
41542
|
+
return null;
|
|
41543
|
+
}
|
|
41544
|
+
}
|
|
41545
|
+
const deployed = provisionShippedVoices(log);
|
|
41546
|
+
if (deployed > 0) {
|
|
41547
|
+
log(`Provisioned ${deployed} shipped voice(s)`);
|
|
41548
|
+
}
|
|
41549
|
+
patchFrontendVoiceList(log);
|
|
41550
|
+
if (isPersonaPlexRunning()) {
|
|
41551
|
+
const url = getPersonaPlexWSUrl();
|
|
41552
|
+
if (url) {
|
|
41553
|
+
log(`PersonaPlex already running at ${url}`);
|
|
41554
|
+
return url;
|
|
41555
|
+
}
|
|
41556
|
+
}
|
|
41557
|
+
return await startPersonaPlexDaemon(log);
|
|
41558
|
+
}
|
|
41559
|
+
var PERSONAPLEX_DIR, PID_FILE, PORT_FILE, LOG_FILE, CUSTOM_VOICES_DIR;
|
|
41560
|
+
var init_personaplex = __esm({
|
|
41561
|
+
"packages/cli/dist/tui/personaplex.js"() {
|
|
41562
|
+
"use strict";
|
|
41563
|
+
init_render();
|
|
41564
|
+
PERSONAPLEX_DIR = join54(homedir13(), ".open-agents", "voice", "personaplex");
|
|
41565
|
+
PID_FILE = join54(PERSONAPLEX_DIR, "daemon.pid");
|
|
41566
|
+
PORT_FILE = join54(PERSONAPLEX_DIR, "daemon.port");
|
|
41567
|
+
LOG_FILE = join54(PERSONAPLEX_DIR, "daemon.log");
|
|
41568
|
+
CUSTOM_VOICES_DIR = join54(PERSONAPLEX_DIR, "custom_voices");
|
|
41569
|
+
}
|
|
41570
|
+
});
|
|
41571
|
+
|
|
40727
41572
|
// packages/cli/dist/tui/setup.js
|
|
40728
41573
|
import * as readline from "node:readline";
|
|
40729
|
-
import { execSync as
|
|
41574
|
+
import { execSync as execSync28, spawn as spawn20, exec as exec2 } from "node:child_process";
|
|
40730
41575
|
import { promisify as promisify6 } from "node:util";
|
|
40731
|
-
import { existsSync as
|
|
40732
|
-
import { join as
|
|
40733
|
-
import { homedir as
|
|
41576
|
+
import { existsSync as existsSync38, writeFileSync as writeFileSync17, readFileSync as readFileSync29, appendFileSync as appendFileSync2, mkdirSync as mkdirSync16 } from "node:fs";
|
|
41577
|
+
import { join as join55 } from "node:path";
|
|
41578
|
+
import { homedir as homedir14, platform as platform2 } from "node:os";
|
|
40734
41579
|
async function checkToolSupport(modelName, backendUrl = "http://localhost:11434") {
|
|
40735
41580
|
if (_toolSupportCache.has(modelName))
|
|
40736
41581
|
return _toolSupportCache.get(modelName);
|
|
@@ -40761,7 +41606,7 @@ function detectSystemSpecs() {
|
|
|
40761
41606
|
let gpuVramGB = 0;
|
|
40762
41607
|
let gpuName = "";
|
|
40763
41608
|
try {
|
|
40764
|
-
const memInfo =
|
|
41609
|
+
const memInfo = execSync28("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
|
|
40765
41610
|
encoding: "utf8",
|
|
40766
41611
|
timeout: 5e3
|
|
40767
41612
|
});
|
|
@@ -40781,7 +41626,7 @@ function detectSystemSpecs() {
|
|
|
40781
41626
|
} catch {
|
|
40782
41627
|
}
|
|
40783
41628
|
try {
|
|
40784
|
-
const nvidiaSmi =
|
|
41629
|
+
const nvidiaSmi = execSync28("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
|
|
40785
41630
|
const lines = nvidiaSmi.trim().split("\n");
|
|
40786
41631
|
if (lines.length > 0) {
|
|
40787
41632
|
for (const line of lines) {
|
|
@@ -40952,7 +41797,7 @@ function ensureCurl() {
|
|
|
40952
41797
|
for (const s of strategies) {
|
|
40953
41798
|
if (hasCmd(s.check)) {
|
|
40954
41799
|
try {
|
|
40955
|
-
|
|
41800
|
+
execSync28(s.install, { stdio: "inherit", timeout: 12e4 });
|
|
40956
41801
|
if (hasCmd("curl")) {
|
|
40957
41802
|
process.stdout.write(` ${c2.green("\u2714")} curl installed via ${s.label}.
|
|
40958
41803
|
`);
|
|
@@ -40966,7 +41811,7 @@ function ensureCurl() {
|
|
|
40966
41811
|
}
|
|
40967
41812
|
if (plat === "darwin") {
|
|
40968
41813
|
try {
|
|
40969
|
-
|
|
41814
|
+
execSync28("xcode-select --install", { stdio: "inherit", timeout: 3e5 });
|
|
40970
41815
|
if (hasCmd("curl"))
|
|
40971
41816
|
return true;
|
|
40972
41817
|
} catch {
|
|
@@ -41001,7 +41846,7 @@ function installOllamaLinux() {
|
|
|
41001
41846
|
|
|
41002
41847
|
`);
|
|
41003
41848
|
try {
|
|
41004
|
-
|
|
41849
|
+
execSync28("curl -fsSL https://ollama.com/install.sh | sh", {
|
|
41005
41850
|
stdio: "inherit",
|
|
41006
41851
|
timeout: 3e5
|
|
41007
41852
|
});
|
|
@@ -41029,10 +41874,10 @@ async function installOllamaMac(_rl) {
|
|
|
41029
41874
|
|
|
41030
41875
|
`);
|
|
41031
41876
|
try {
|
|
41032
|
-
|
|
41877
|
+
execSync28('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
|
|
41033
41878
|
if (!hasCmd("brew")) {
|
|
41034
41879
|
try {
|
|
41035
|
-
const brewPrefix =
|
|
41880
|
+
const brewPrefix = existsSync38("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
|
|
41036
41881
|
process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
|
|
41037
41882
|
} catch {
|
|
41038
41883
|
}
|
|
@@ -41062,7 +41907,7 @@ async function installOllamaMac(_rl) {
|
|
|
41062
41907
|
|
|
41063
41908
|
`);
|
|
41064
41909
|
try {
|
|
41065
|
-
|
|
41910
|
+
execSync28("brew install ollama", {
|
|
41066
41911
|
stdio: "inherit",
|
|
41067
41912
|
timeout: 3e5
|
|
41068
41913
|
});
|
|
@@ -41089,7 +41934,7 @@ function installOllamaWindows() {
|
|
|
41089
41934
|
|
|
41090
41935
|
`);
|
|
41091
41936
|
try {
|
|
41092
|
-
|
|
41937
|
+
execSync28('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
|
|
41093
41938
|
stdio: "inherit",
|
|
41094
41939
|
timeout: 3e5
|
|
41095
41940
|
});
|
|
@@ -41140,7 +41985,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
|
|
|
41140
41985
|
process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
|
|
41141
41986
|
`);
|
|
41142
41987
|
try {
|
|
41143
|
-
const child =
|
|
41988
|
+
const child = spawn20("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
41144
41989
|
child.unref();
|
|
41145
41990
|
} catch {
|
|
41146
41991
|
process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
|
|
@@ -41170,7 +42015,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
|
|
|
41170
42015
|
}
|
|
41171
42016
|
function pullModelWithAutoUpdate(tag) {
|
|
41172
42017
|
try {
|
|
41173
|
-
|
|
42018
|
+
execSync28(`ollama pull ${tag}`, {
|
|
41174
42019
|
stdio: "inherit",
|
|
41175
42020
|
timeout: 36e5
|
|
41176
42021
|
// 1 hour max
|
|
@@ -41190,7 +42035,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
41190
42035
|
|
|
41191
42036
|
`);
|
|
41192
42037
|
try {
|
|
41193
|
-
|
|
42038
|
+
execSync28("curl -fsSL https://ollama.com/install.sh | sh", {
|
|
41194
42039
|
stdio: "inherit",
|
|
41195
42040
|
timeout: 3e5
|
|
41196
42041
|
// 5 min max for install
|
|
@@ -41201,7 +42046,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
41201
42046
|
process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
|
|
41202
42047
|
|
|
41203
42048
|
`);
|
|
41204
|
-
|
|
42049
|
+
execSync28(`ollama pull ${tag}`, {
|
|
41205
42050
|
stdio: "inherit",
|
|
41206
42051
|
timeout: 36e5
|
|
41207
42052
|
});
|
|
@@ -41303,7 +42148,7 @@ function ensurePython3() {
|
|
|
41303
42148
|
if (plat === "darwin") {
|
|
41304
42149
|
if (hasCmd("brew")) {
|
|
41305
42150
|
try {
|
|
41306
|
-
|
|
42151
|
+
execSync28("brew install python3", { stdio: "inherit", timeout: 3e5 });
|
|
41307
42152
|
if (hasCmd("python3")) {
|
|
41308
42153
|
process.stdout.write(` ${c2.green("\u2714")} Python3 installed via Homebrew.
|
|
41309
42154
|
`);
|
|
@@ -41316,7 +42161,7 @@ function ensurePython3() {
|
|
|
41316
42161
|
for (const s of strategies) {
|
|
41317
42162
|
if (hasCmd(s.check)) {
|
|
41318
42163
|
try {
|
|
41319
|
-
|
|
42164
|
+
execSync28(s.install, { stdio: "inherit", timeout: 12e4 });
|
|
41320
42165
|
if (hasCmd("python3") || hasCmd("python")) {
|
|
41321
42166
|
process.stdout.write(` ${c2.green("\u2714")} Python3 installed via ${s.label}.
|
|
41322
42167
|
`);
|
|
@@ -41332,11 +42177,11 @@ function ensurePython3() {
|
|
|
41332
42177
|
}
|
|
41333
42178
|
function checkPythonVenv() {
|
|
41334
42179
|
try {
|
|
41335
|
-
|
|
42180
|
+
execSync28("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
|
|
41336
42181
|
return true;
|
|
41337
42182
|
} catch {
|
|
41338
42183
|
try {
|
|
41339
|
-
|
|
42184
|
+
execSync28("python -m venv --help", { stdio: "pipe", timeout: 5e3 });
|
|
41340
42185
|
return true;
|
|
41341
42186
|
} catch {
|
|
41342
42187
|
return false;
|
|
@@ -41355,7 +42200,7 @@ function ensurePythonVenv() {
|
|
|
41355
42200
|
for (const s of strategies) {
|
|
41356
42201
|
if (hasCmd(s.check)) {
|
|
41357
42202
|
try {
|
|
41358
|
-
|
|
42203
|
+
execSync28(s.install, { stdio: "inherit", timeout: 12e4 });
|
|
41359
42204
|
if (checkPythonVenv()) {
|
|
41360
42205
|
process.stdout.write(` ${c2.green("\u2714")} python3-venv installed via ${s.label}.
|
|
41361
42206
|
`);
|
|
@@ -41513,6 +42358,20 @@ async function doSetup(config, rl) {
|
|
|
41513
42358
|
} else {
|
|
41514
42359
|
process.stdout.write(` ${c2.dim(" GPU:")} No NVIDIA GPU detected (CPU inference)
|
|
41515
42360
|
`);
|
|
42361
|
+
}
|
|
42362
|
+
let personaPlexCapable = false;
|
|
42363
|
+
try {
|
|
42364
|
+
const { detectPersonaPlexCapability: detectPersonaPlexCapability2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
42365
|
+
const ppCaps = detectPersonaPlexCapability2();
|
|
42366
|
+
personaPlexCapable = ppCaps.supported;
|
|
42367
|
+
if (ppCaps.supported) {
|
|
42368
|
+
process.stdout.write(` ${c2.green("\u2714")} PersonaPlex full-duplex voice: ${c2.bold("compatible")} (${ppCaps.gpuName}, ${ppCaps.vramGB.toFixed(0)}GB VRAM)
|
|
42369
|
+
`);
|
|
42370
|
+
process.stdout.write(` ${c2.dim("Enable with: /voice personaplex")}
|
|
42371
|
+
|
|
42372
|
+
`);
|
|
42373
|
+
}
|
|
42374
|
+
} catch {
|
|
41516
42375
|
}
|
|
41517
42376
|
const score = computeInferenceScore(specs);
|
|
41518
42377
|
const bw = 30;
|
|
@@ -41602,7 +42461,7 @@ async function doSetup(config, rl) {
|
|
|
41602
42461
|
${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
|
|
41603
42462
|
`);
|
|
41604
42463
|
try {
|
|
41605
|
-
const child =
|
|
42464
|
+
const child = spawn20("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
41606
42465
|
child.unref();
|
|
41607
42466
|
await new Promise((resolve36) => setTimeout(resolve36, 3e3));
|
|
41608
42467
|
try {
|
|
@@ -41630,7 +42489,7 @@ async function doSetup(config, rl) {
|
|
|
41630
42489
|
${c2.cyan("\u25CF")} Starting ollama serve...
|
|
41631
42490
|
`);
|
|
41632
42491
|
try {
|
|
41633
|
-
const child =
|
|
42492
|
+
const child = spawn20("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
41634
42493
|
child.unref();
|
|
41635
42494
|
await new Promise((resolve36) => setTimeout(resolve36, 3e3));
|
|
41636
42495
|
try {
|
|
@@ -41763,12 +42622,12 @@ async function doSetup(config, rl) {
|
|
|
41763
42622
|
`PARAMETER num_predict ${numPredict}`,
|
|
41764
42623
|
`PARAMETER stop "<|endoftext|>"`
|
|
41765
42624
|
].join("\n");
|
|
41766
|
-
const modelDir2 =
|
|
41767
|
-
|
|
41768
|
-
const modelfilePath =
|
|
41769
|
-
|
|
42625
|
+
const modelDir2 = join55(homedir14(), ".open-agents", "models");
|
|
42626
|
+
mkdirSync16(modelDir2, { recursive: true });
|
|
42627
|
+
const modelfilePath = join55(modelDir2, `Modelfile.${customName}`);
|
|
42628
|
+
writeFileSync17(modelfilePath, modelfileContent + "\n", "utf8");
|
|
41770
42629
|
process.stdout.write(` ${c2.dim("Creating model...")} `);
|
|
41771
|
-
|
|
42630
|
+
execSync28(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
41772
42631
|
stdio: "pipe",
|
|
41773
42632
|
timeout: 12e4
|
|
41774
42633
|
});
|
|
@@ -41811,7 +42670,7 @@ async function isModelAvailable(config) {
|
|
|
41811
42670
|
}
|
|
41812
42671
|
function isFirstRun() {
|
|
41813
42672
|
try {
|
|
41814
|
-
return !
|
|
42673
|
+
return !existsSync38(join55(homedir14(), ".open-agents", "config.json"));
|
|
41815
42674
|
} catch {
|
|
41816
42675
|
return true;
|
|
41817
42676
|
}
|
|
@@ -41819,7 +42678,7 @@ function isFirstRun() {
|
|
|
41819
42678
|
function hasCmd(cmd) {
|
|
41820
42679
|
try {
|
|
41821
42680
|
const whichCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
|
|
41822
|
-
|
|
42681
|
+
execSync28(whichCmd, { stdio: "pipe", timeout: 3e3 });
|
|
41823
42682
|
return true;
|
|
41824
42683
|
} catch {
|
|
41825
42684
|
return false;
|
|
@@ -41848,11 +42707,11 @@ function detectPkgManager() {
|
|
|
41848
42707
|
return null;
|
|
41849
42708
|
}
|
|
41850
42709
|
function getVenvDir() {
|
|
41851
|
-
return
|
|
42710
|
+
return join55(homedir14(), ".open-agents", "venv");
|
|
41852
42711
|
}
|
|
41853
42712
|
function hasVenvModule() {
|
|
41854
42713
|
try {
|
|
41855
|
-
|
|
42714
|
+
execSync28("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
|
|
41856
42715
|
return true;
|
|
41857
42716
|
} catch {
|
|
41858
42717
|
return false;
|
|
@@ -41861,9 +42720,9 @@ function hasVenvModule() {
|
|
|
41861
42720
|
function ensureVenv(log) {
|
|
41862
42721
|
const venvDir = getVenvDir();
|
|
41863
42722
|
const isWin2 = process.platform === "win32";
|
|
41864
|
-
const pipPath = isWin2 ?
|
|
42723
|
+
const pipPath = isWin2 ? join55(venvDir, "Scripts", "pip.exe") : join55(venvDir, "bin", "pip");
|
|
41865
42724
|
const pythonCmd = isWin2 ? "python" : "python3";
|
|
41866
|
-
if (
|
|
42725
|
+
if (existsSync38(pipPath))
|
|
41867
42726
|
return venvDir;
|
|
41868
42727
|
log("Creating Python venv for vision deps...");
|
|
41869
42728
|
if (!hasCmd(pythonCmd) && !hasCmd("python3")) {
|
|
@@ -41875,10 +42734,10 @@ function ensureVenv(log) {
|
|
|
41875
42734
|
return null;
|
|
41876
42735
|
}
|
|
41877
42736
|
try {
|
|
41878
|
-
|
|
42737
|
+
mkdirSync16(join55(homedir14(), ".open-agents"), { recursive: true });
|
|
41879
42738
|
const pyCmd = hasCmd(pythonCmd) ? pythonCmd : "python3";
|
|
41880
|
-
|
|
41881
|
-
|
|
42739
|
+
execSync28(`${pyCmd} -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
|
|
42740
|
+
execSync28(`"${pipPath}" install --upgrade pip`, {
|
|
41882
42741
|
stdio: "pipe",
|
|
41883
42742
|
timeout: 6e4
|
|
41884
42743
|
});
|
|
@@ -41891,7 +42750,7 @@ function ensureVenv(log) {
|
|
|
41891
42750
|
}
|
|
41892
42751
|
function trySudoPasswordless(cmd, timeoutMs = 12e4) {
|
|
41893
42752
|
try {
|
|
41894
|
-
|
|
42753
|
+
execSync28(`sudo -n ${cmd}`, {
|
|
41895
42754
|
stdio: "pipe",
|
|
41896
42755
|
timeout: timeoutMs,
|
|
41897
42756
|
env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
|
|
@@ -41904,7 +42763,7 @@ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
|
|
|
41904
42763
|
function runWithSudo(cmd, password, timeoutMs = 12e4) {
|
|
41905
42764
|
try {
|
|
41906
42765
|
const escaped = cmd.replace(/'/g, "'\\''");
|
|
41907
|
-
|
|
42766
|
+
execSync28(`sudo -S bash -c '${escaped}'`, {
|
|
41908
42767
|
input: password + "\n",
|
|
41909
42768
|
stdio: ["pipe", "pipe", "pipe"],
|
|
41910
42769
|
timeout: timeoutMs,
|
|
@@ -42021,7 +42880,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
42021
42880
|
ok = await sudoInstall(batchCmd, getPassword, log, cachedPasswordRef, 18e4);
|
|
42022
42881
|
} else {
|
|
42023
42882
|
try {
|
|
42024
|
-
|
|
42883
|
+
execSync28(batchCmd, { stdio: "pipe", timeout: 18e4 });
|
|
42025
42884
|
ok = true;
|
|
42026
42885
|
} catch {
|
|
42027
42886
|
ok = false;
|
|
@@ -42058,7 +42917,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
42058
42917
|
const venvCmds = {
|
|
42059
42918
|
apt: () => {
|
|
42060
42919
|
try {
|
|
42061
|
-
const pyVer =
|
|
42920
|
+
const pyVer = execSync28(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
|
|
42062
42921
|
return `apt-get install -y python3-venv python${pyVer}-venv`;
|
|
42063
42922
|
} catch {
|
|
42064
42923
|
return "apt-get install -y python3-venv";
|
|
@@ -42079,19 +42938,19 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
42079
42938
|
}
|
|
42080
42939
|
}
|
|
42081
42940
|
const venvDir = getVenvDir();
|
|
42082
|
-
const venvBin =
|
|
42083
|
-
const venvMoondream =
|
|
42941
|
+
const venvBin = join55(venvDir, "bin");
|
|
42942
|
+
const venvMoondream = join55(venvBin, "moondream-station");
|
|
42084
42943
|
const venv = ensureVenv(log);
|
|
42085
|
-
if (venv && !hasCmd("moondream-station") && !
|
|
42086
|
-
const venvPip2 =
|
|
42944
|
+
if (venv && !hasCmd("moondream-station") && !existsSync38(venvMoondream)) {
|
|
42945
|
+
const venvPip2 = join55(venvBin, "pip");
|
|
42087
42946
|
log("Installing moondream-station in ~/.open-agents/venv...");
|
|
42088
42947
|
try {
|
|
42089
|
-
|
|
42090
|
-
if (
|
|
42948
|
+
execSync28(`"${venvPip2}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
|
|
42949
|
+
if (existsSync38(venvMoondream)) {
|
|
42091
42950
|
log("moondream-station installed successfully.");
|
|
42092
42951
|
} else {
|
|
42093
42952
|
try {
|
|
42094
|
-
const check =
|
|
42953
|
+
const check = execSync28(`"${venvPip2}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
|
|
42095
42954
|
if (check.includes("moondream")) {
|
|
42096
42955
|
log("moondream-station package installed.");
|
|
42097
42956
|
}
|
|
@@ -42104,11 +42963,11 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
42104
42963
|
}
|
|
42105
42964
|
}
|
|
42106
42965
|
if (venv) {
|
|
42107
|
-
const venvPython2 =
|
|
42108
|
-
const venvPip2 =
|
|
42966
|
+
const venvPython2 = join55(venvBin, "python");
|
|
42967
|
+
const venvPip2 = join55(venvBin, "pip");
|
|
42109
42968
|
let ocrStackInstalled = false;
|
|
42110
42969
|
try {
|
|
42111
|
-
|
|
42970
|
+
execSync28(`"${venvPython2}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
|
|
42112
42971
|
ocrStackInstalled = true;
|
|
42113
42972
|
} catch {
|
|
42114
42973
|
}
|
|
@@ -42116,9 +42975,9 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
|
|
|
42116
42975
|
const ocrPackages = "pytesseract Pillow opencv-python-headless numpy";
|
|
42117
42976
|
log("Installing OCR Python stack (pytesseract, OpenCV, Pillow, numpy)...");
|
|
42118
42977
|
try {
|
|
42119
|
-
|
|
42978
|
+
execSync28(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
|
|
42120
42979
|
try {
|
|
42121
|
-
|
|
42980
|
+
execSync28(`"${venvPython2}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
|
|
42122
42981
|
log("OCR Python stack installed successfully.");
|
|
42123
42982
|
} catch {
|
|
42124
42983
|
log("OCR Python stack install completed but import verification failed.");
|
|
@@ -42152,9 +43011,9 @@ function ensureCloudflaredBackground(onInfo) {
|
|
|
42152
43011
|
const archMap = { x64: "amd64", arm64: "arm64", arm: "arm" };
|
|
42153
43012
|
const cfArch = archMap[arch2] ?? "amd64";
|
|
42154
43013
|
try {
|
|
42155
|
-
|
|
42156
|
-
if (!process.env.PATH?.includes(`${
|
|
42157
|
-
process.env.PATH = `${
|
|
43014
|
+
execSync28(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir14()}/.local/bin" && mv /tmp/cloudflared "${homedir14()}/.local/bin/cloudflared"`, { stdio: "pipe", timeout: 6e4 });
|
|
43015
|
+
if (!process.env.PATH?.includes(`${homedir14()}/.local/bin`)) {
|
|
43016
|
+
process.env.PATH = `${homedir14()}/.local/bin:${process.env.PATH}`;
|
|
42158
43017
|
}
|
|
42159
43018
|
if (hasCmd("cloudflared")) {
|
|
42160
43019
|
log("cloudflared installed.");
|
|
@@ -42163,7 +43022,7 @@ function ensureCloudflaredBackground(onInfo) {
|
|
|
42163
43022
|
} catch {
|
|
42164
43023
|
}
|
|
42165
43024
|
try {
|
|
42166
|
-
|
|
43025
|
+
execSync28(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared 2>/dev/null`, { stdio: "pipe", timeout: 6e4 });
|
|
42167
43026
|
if (hasCmd("cloudflared")) {
|
|
42168
43027
|
log("cloudflared installed.");
|
|
42169
43028
|
return true;
|
|
@@ -42172,7 +43031,7 @@ function ensureCloudflaredBackground(onInfo) {
|
|
|
42172
43031
|
}
|
|
42173
43032
|
} else if (os === "darwin") {
|
|
42174
43033
|
try {
|
|
42175
|
-
|
|
43034
|
+
execSync28("brew install cloudflared", { stdio: "pipe", timeout: 12e4 });
|
|
42176
43035
|
if (hasCmd("cloudflared")) {
|
|
42177
43036
|
log("cloudflared installed via Homebrew.");
|
|
42178
43037
|
return true;
|
|
@@ -42249,10 +43108,10 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
|
|
|
42249
43108
|
`PARAMETER num_predict ${numPredict}`,
|
|
42250
43109
|
`PARAMETER stop "<|endoftext|>"`
|
|
42251
43110
|
].join("\n");
|
|
42252
|
-
const modelDir2 =
|
|
42253
|
-
|
|
42254
|
-
const modelfilePath =
|
|
42255
|
-
|
|
43111
|
+
const modelDir2 = join55(homedir14(), ".open-agents", "models");
|
|
43112
|
+
mkdirSync16(modelDir2, { recursive: true });
|
|
43113
|
+
const modelfilePath = join55(modelDir2, `Modelfile.${customName}`);
|
|
43114
|
+
writeFileSync17(modelfilePath, modelfileContent + "\n", "utf8");
|
|
42256
43115
|
await execAsync(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
42257
43116
|
timeout: 12e4
|
|
42258
43117
|
});
|
|
@@ -42314,7 +43173,7 @@ async function ensureExpandedContext(modelName, backendUrl) {
|
|
|
42314
43173
|
}
|
|
42315
43174
|
async function ensureNeovim() {
|
|
42316
43175
|
try {
|
|
42317
|
-
const nvimPath =
|
|
43176
|
+
const nvimPath = execSync28("which nvim 2>/dev/null || where nvim 2>nul", {
|
|
42318
43177
|
encoding: "utf8",
|
|
42319
43178
|
stdio: "pipe",
|
|
42320
43179
|
timeout: 5e3
|
|
@@ -42326,24 +43185,24 @@ async function ensureNeovim() {
|
|
|
42326
43185
|
const platform6 = process.platform;
|
|
42327
43186
|
const arch2 = process.arch;
|
|
42328
43187
|
if (platform6 === "linux") {
|
|
42329
|
-
const binDir =
|
|
42330
|
-
const nvimDest =
|
|
43188
|
+
const binDir = join55(homedir14(), ".local", "bin");
|
|
43189
|
+
const nvimDest = join55(binDir, "nvim");
|
|
42331
43190
|
try {
|
|
42332
|
-
|
|
43191
|
+
mkdirSync16(binDir, { recursive: true });
|
|
42333
43192
|
} catch {
|
|
42334
43193
|
}
|
|
42335
43194
|
const appImageName = arch2 === "arm64" ? "nvim-linux-arm64.appimage" : "nvim-linux-x86_64.appimage";
|
|
42336
43195
|
const url = `https://github.com/neovim/neovim/releases/latest/download/${appImageName}`;
|
|
42337
43196
|
console.log(` Downloading Neovim (${appImageName})...`);
|
|
42338
43197
|
try {
|
|
42339
|
-
|
|
42340
|
-
|
|
43198
|
+
execSync28(`curl -fsSL "${url}" -o "${nvimDest}"`, { stdio: "pipe", timeout: 6e4 });
|
|
43199
|
+
execSync28(`chmod +x "${nvimDest}"`, { stdio: "pipe", timeout: 3e3 });
|
|
42341
43200
|
} catch (err) {
|
|
42342
43201
|
console.log(` Failed to download Neovim: ${err instanceof Error ? err.message : String(err)}`);
|
|
42343
43202
|
return null;
|
|
42344
43203
|
}
|
|
42345
43204
|
try {
|
|
42346
|
-
const ver =
|
|
43205
|
+
const ver = execSync28(`"${nvimDest}" --version`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).split("\n")[0];
|
|
42347
43206
|
console.log(` Installed: ${ver}`);
|
|
42348
43207
|
} catch {
|
|
42349
43208
|
console.log(" Warning: nvim binary downloaded but may not work (missing FUSE? Try: nvim --appimage-extract)");
|
|
@@ -42358,8 +43217,8 @@ async function ensureNeovim() {
|
|
|
42358
43217
|
if (hasCmd("brew")) {
|
|
42359
43218
|
console.log(" Installing Neovim via Homebrew...");
|
|
42360
43219
|
try {
|
|
42361
|
-
|
|
42362
|
-
const nvimPath =
|
|
43220
|
+
execSync28("brew install neovim", { stdio: "inherit", timeout: 12e4 });
|
|
43221
|
+
const nvimPath = execSync28("which nvim", { encoding: "utf8", stdio: "pipe", timeout: 3e3 }).trim();
|
|
42363
43222
|
return nvimPath || null;
|
|
42364
43223
|
} catch {
|
|
42365
43224
|
console.log(" brew install neovim failed.");
|
|
@@ -42373,7 +43232,7 @@ async function ensureNeovim() {
|
|
|
42373
43232
|
if (hasCmd("choco")) {
|
|
42374
43233
|
console.log(" Installing Neovim via Chocolatey...");
|
|
42375
43234
|
try {
|
|
42376
|
-
|
|
43235
|
+
execSync28("choco install neovim -y", { stdio: "inherit", timeout: 12e4 });
|
|
42377
43236
|
return "nvim";
|
|
42378
43237
|
} catch {
|
|
42379
43238
|
console.log(" choco install neovim failed.");
|
|
@@ -42382,7 +43241,7 @@ async function ensureNeovim() {
|
|
|
42382
43241
|
if (hasCmd("winget")) {
|
|
42383
43242
|
console.log(" Installing Neovim via winget...");
|
|
42384
43243
|
try {
|
|
42385
|
-
|
|
43244
|
+
execSync28("winget install Neovim.Neovim --accept-source-agreements --accept-package-agreements", {
|
|
42386
43245
|
stdio: "inherit",
|
|
42387
43246
|
timeout: 12e4
|
|
42388
43247
|
});
|
|
@@ -42398,9 +43257,9 @@ async function ensureNeovim() {
|
|
|
42398
43257
|
}
|
|
42399
43258
|
function ensurePathInShellRc(binDir) {
|
|
42400
43259
|
const shell = process.env.SHELL ?? "";
|
|
42401
|
-
const rcFile = shell.includes("zsh") ?
|
|
43260
|
+
const rcFile = shell.includes("zsh") ? join55(homedir14(), ".zshrc") : join55(homedir14(), ".bashrc");
|
|
42402
43261
|
try {
|
|
42403
|
-
const rcContent =
|
|
43262
|
+
const rcContent = existsSync38(rcFile) ? readFileSync29(rcFile, "utf8") : "";
|
|
42404
43263
|
if (rcContent.includes(binDir))
|
|
42405
43264
|
return;
|
|
42406
43265
|
const exportLine = `
|
|
@@ -42438,7 +43297,7 @@ var init_setup = __esm({
|
|
|
42438
43297
|
});
|
|
42439
43298
|
|
|
42440
43299
|
// packages/cli/dist/tui/drop-panel.js
|
|
42441
|
-
import { existsSync as
|
|
43300
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
42442
43301
|
import { extname as extname10, resolve as resolve29 } from "node:path";
|
|
42443
43302
|
function ansi4(code, text) {
|
|
42444
43303
|
return isTTY4 ? `\x1B[${code}m${text}\x1B[0m` : text;
|
|
@@ -42553,7 +43412,7 @@ function showDropPanel(opts) {
|
|
|
42553
43412
|
filePath = decodeURIComponent(filePath.slice(7));
|
|
42554
43413
|
}
|
|
42555
43414
|
filePath = resolve29(filePath);
|
|
42556
|
-
if (!
|
|
43415
|
+
if (!existsSync39(filePath)) {
|
|
42557
43416
|
errorMsg = `File not found: ${filePath}`;
|
|
42558
43417
|
render();
|
|
42559
43418
|
return;
|
|
@@ -42624,10 +43483,10 @@ var init_drop_panel = __esm({
|
|
|
42624
43483
|
});
|
|
42625
43484
|
|
|
42626
43485
|
// packages/cli/dist/tui/neovim-mode.js
|
|
42627
|
-
import { existsSync as
|
|
43486
|
+
import { existsSync as existsSync40, unlinkSync as unlinkSync8 } from "node:fs";
|
|
42628
43487
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
42629
|
-
import { join as
|
|
42630
|
-
import { execSync as
|
|
43488
|
+
import { join as join56 } from "node:path";
|
|
43489
|
+
import { execSync as execSync29 } from "node:child_process";
|
|
42631
43490
|
function isNeovimActive() {
|
|
42632
43491
|
return _state !== null && !_state.cleanedUp;
|
|
42633
43492
|
}
|
|
@@ -42645,7 +43504,7 @@ async function startNeovimMode(opts) {
|
|
|
42645
43504
|
}
|
|
42646
43505
|
let nvimPath;
|
|
42647
43506
|
try {
|
|
42648
|
-
nvimPath =
|
|
43507
|
+
nvimPath = execSync29("which nvim 2>/dev/null", { encoding: "utf8" }).trim();
|
|
42649
43508
|
if (!nvimPath)
|
|
42650
43509
|
throw new Error();
|
|
42651
43510
|
} catch {
|
|
@@ -42674,9 +43533,9 @@ async function startNeovimMode(opts) {
|
|
|
42674
43533
|
);
|
|
42675
43534
|
} catch {
|
|
42676
43535
|
}
|
|
42677
|
-
const socketPath =
|
|
43536
|
+
const socketPath = join56(tmpdir8(), `oa-nvim-${process.pid}-${Date.now()}.sock`);
|
|
42678
43537
|
try {
|
|
42679
|
-
if (
|
|
43538
|
+
if (existsSync40(socketPath))
|
|
42680
43539
|
unlinkSync8(socketPath);
|
|
42681
43540
|
} catch {
|
|
42682
43541
|
}
|
|
@@ -42903,13 +43762,13 @@ function resizeNeovim(cols, contentRows) {
|
|
|
42903
43762
|
}
|
|
42904
43763
|
async function connectRPC(state, neovimPkg, cols) {
|
|
42905
43764
|
let attempts = 0;
|
|
42906
|
-
while (!
|
|
43765
|
+
while (!existsSync40(state.socketPath) && attempts < 30) {
|
|
42907
43766
|
await new Promise((r) => setTimeout(r, 200));
|
|
42908
43767
|
attempts++;
|
|
42909
43768
|
if (state.cleanedUp)
|
|
42910
43769
|
return;
|
|
42911
43770
|
}
|
|
42912
|
-
if (!
|
|
43771
|
+
if (!existsSync40(state.socketPath))
|
|
42913
43772
|
return;
|
|
42914
43773
|
const nvim = neovimPkg.attach({ socket: state.socketPath });
|
|
42915
43774
|
state.nvim = nvim;
|
|
@@ -43046,7 +43905,7 @@ function doCleanup(state) {
|
|
|
43046
43905
|
state.pty = null;
|
|
43047
43906
|
}
|
|
43048
43907
|
try {
|
|
43049
|
-
if (
|
|
43908
|
+
if (existsSync40(state.socketPath))
|
|
43050
43909
|
unlinkSync8(state.socketPath);
|
|
43051
43910
|
} catch {
|
|
43052
43911
|
}
|
|
@@ -43481,8 +44340,8 @@ __export(sponsor_wizard_exports, {
|
|
|
43481
44340
|
saveSponsorConfig: () => saveSponsorConfig,
|
|
43482
44341
|
showSponsorDashboard: () => showSponsorDashboard
|
|
43483
44342
|
});
|
|
43484
|
-
import { existsSync as
|
|
43485
|
-
import { join as
|
|
44343
|
+
import { existsSync as existsSync41, readFileSync as readFileSync30, writeFileSync as writeFileSync18, mkdirSync as mkdirSync17 } from "node:fs";
|
|
44344
|
+
import { join as join57 } from "node:path";
|
|
43486
44345
|
function colorPreview(code) {
|
|
43487
44346
|
return `\x1B[38;5;${code}m\u2588\u2588\u2588\u2588\x1B[0m (${code})`;
|
|
43488
44347
|
}
|
|
@@ -43495,26 +44354,26 @@ function gradientPreview(start, end) {
|
|
|
43495
44354
|
return s;
|
|
43496
44355
|
}
|
|
43497
44356
|
function sponsorDir(projectDir) {
|
|
43498
|
-
return
|
|
44357
|
+
return join57(projectDir, ".oa", "sponsor");
|
|
43499
44358
|
}
|
|
43500
44359
|
function configPath(projectDir) {
|
|
43501
|
-
return
|
|
44360
|
+
return join57(sponsorDir(projectDir), "config.json");
|
|
43502
44361
|
}
|
|
43503
44362
|
function loadSponsorConfig(projectDir) {
|
|
43504
44363
|
const p = configPath(projectDir);
|
|
43505
|
-
if (!
|
|
44364
|
+
if (!existsSync41(p))
|
|
43506
44365
|
return null;
|
|
43507
44366
|
try {
|
|
43508
|
-
return JSON.parse(
|
|
44367
|
+
return JSON.parse(readFileSync30(p, "utf8"));
|
|
43509
44368
|
} catch {
|
|
43510
44369
|
return null;
|
|
43511
44370
|
}
|
|
43512
44371
|
}
|
|
43513
44372
|
function saveSponsorConfig(projectDir, config) {
|
|
43514
44373
|
const dir = sponsorDir(projectDir);
|
|
43515
|
-
|
|
44374
|
+
mkdirSync17(dir, { recursive: true });
|
|
43516
44375
|
config.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43517
|
-
|
|
44376
|
+
writeFileSync18(configPath(projectDir), JSON.stringify(config, null, 2), "utf8");
|
|
43518
44377
|
}
|
|
43519
44378
|
function defaultConfig() {
|
|
43520
44379
|
return {
|
|
@@ -44217,10 +45076,10 @@ __export(voice_exports, {
|
|
|
44217
45076
|
registerCustomOnnxModel: () => registerCustomOnnxModel,
|
|
44218
45077
|
resetNarrationContext: () => resetNarrationContext
|
|
44219
45078
|
});
|
|
44220
|
-
import { existsSync as
|
|
44221
|
-
import { join as
|
|
44222
|
-
import { homedir as
|
|
44223
|
-
import { execSync as
|
|
45079
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync18, writeFileSync as writeFileSync19, readFileSync as readFileSync31, unlinkSync as unlinkSync9, readdirSync as readdirSync12, renameSync, statSync as statSync13 } from "node:fs";
|
|
45080
|
+
import { join as join58, dirname as dirname19 } from "node:path";
|
|
45081
|
+
import { homedir as homedir15, tmpdir as tmpdir9, platform as platform3 } from "node:os";
|
|
45082
|
+
import { execSync as execSync30, spawn as nodeSpawn } from "node:child_process";
|
|
44224
45083
|
import { createRequire } from "node:module";
|
|
44225
45084
|
function sanitizeForTTS(text) {
|
|
44226
45085
|
return text.replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/```[\s\S]*?```/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/^[\s]*[-*+]\s+/gm, "").replace(/^[\s]*\d+\.\s+/gm, "").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}$/gm, "").replace(/\[[ xX]\]\s*/g, "").replace(/[\u{1F600}-\u{1F64F}]/gu, "").replace(/[\u{1F300}-\u{1F5FF}]/gu, "").replace(/[\u{1F680}-\u{1F6FF}]/gu, "").replace(/[\u{1F1E0}-\u{1F1FF}]/gu, "").replace(/[\u{2600}-\u{26FF}]/gu, "").replace(/[\u{2700}-\u{27BF}]/gu, "").replace(/[\u{FE00}-\u{FE0F}]/gu, "").replace(/[\u{1F900}-\u{1F9FF}]/gu, "").replace(/[\u{1FA00}-\u{1FA6F}]/gu, "").replace(/[\u{1FA70}-\u{1FAFF}]/gu, "").replace(/[\u{200D}]/gu, "").replace(/[\u{20E3}]/gu, "").replace(/[✓✔✗✘✕✖⚠️⏸⏹⏵●○◆◇■□▪▫►▼▲◀⬆⬇⬅➡↑↓←→⇐⇒⇑⇓]/g, "").replace(/[─━│┃┌┐└┘├┤┬┴┼╔╗╚╝╠╣╦╩╬⎿⎾▕▏⏐░▒▓█⠀-⣿]/g, "").replace(/\s{2,}/g, " ").trim();
|
|
@@ -44243,40 +45102,40 @@ function listVoiceModels() {
|
|
|
44243
45102
|
}));
|
|
44244
45103
|
}
|
|
44245
45104
|
function voiceDir() {
|
|
44246
|
-
return
|
|
45105
|
+
return join58(homedir15(), ".open-agents", "voice");
|
|
44247
45106
|
}
|
|
44248
45107
|
function modelsDir() {
|
|
44249
|
-
return
|
|
45108
|
+
return join58(voiceDir(), "models");
|
|
44250
45109
|
}
|
|
44251
45110
|
function modelDir(id) {
|
|
44252
|
-
return
|
|
45111
|
+
return join58(modelsDir(), id);
|
|
44253
45112
|
}
|
|
44254
45113
|
function modelOnnxPath(id) {
|
|
44255
|
-
return
|
|
45114
|
+
return join58(modelDir(id), "model.onnx");
|
|
44256
45115
|
}
|
|
44257
45116
|
function modelConfigPath(id) {
|
|
44258
|
-
return
|
|
45117
|
+
return join58(modelDir(id), "config.json");
|
|
44259
45118
|
}
|
|
44260
45119
|
function luxttsVenvDir() {
|
|
44261
|
-
return
|
|
45120
|
+
return join58(voiceDir(), "luxtts-venv");
|
|
44262
45121
|
}
|
|
44263
45122
|
function luxttsVenvPy() {
|
|
44264
|
-
return platform3() === "win32" ?
|
|
45123
|
+
return platform3() === "win32" ? join58(luxttsVenvDir(), "Scripts", "python.exe") : join58(luxttsVenvDir(), "bin", "python3");
|
|
44265
45124
|
}
|
|
44266
45125
|
function luxttsRepoDir() {
|
|
44267
|
-
return
|
|
45126
|
+
return join58(voiceDir(), "LuxTTS");
|
|
44268
45127
|
}
|
|
44269
45128
|
function luxttsCloneRefsDir() {
|
|
44270
|
-
return
|
|
45129
|
+
return join58(voiceDir(), "clone-refs");
|
|
44271
45130
|
}
|
|
44272
45131
|
function luxttsInferScript() {
|
|
44273
|
-
return
|
|
45132
|
+
return join58(voiceDir(), "luxtts-infer.py");
|
|
44274
45133
|
}
|
|
44275
45134
|
function writeDetectTorchScript(targetPath) {
|
|
44276
|
-
if (
|
|
45135
|
+
if (existsSync42(targetPath))
|
|
44277
45136
|
return;
|
|
44278
45137
|
try {
|
|
44279
|
-
|
|
45138
|
+
mkdirSync18(dirname19(targetPath), { recursive: true });
|
|
44280
45139
|
} catch {
|
|
44281
45140
|
}
|
|
44282
45141
|
const script = `#!/usr/bin/env python3
|
|
@@ -44349,7 +45208,7 @@ def main():
|
|
|
44349
45208
|
if __name__ == "__main__": main()
|
|
44350
45209
|
`;
|
|
44351
45210
|
try {
|
|
44352
|
-
|
|
45211
|
+
writeFileSync19(targetPath, script, { mode: 493 });
|
|
44353
45212
|
} catch {
|
|
44354
45213
|
}
|
|
44355
45214
|
}
|
|
@@ -45159,8 +46018,8 @@ var init_voice = __esm({
|
|
|
45159
46018
|
const refsDir = luxttsCloneRefsDir();
|
|
45160
46019
|
const targets = ["glados", "overwatch"];
|
|
45161
46020
|
for (const modelId of targets) {
|
|
45162
|
-
const refFile =
|
|
45163
|
-
if (
|
|
46021
|
+
const refFile = join58(refsDir, `${modelId}-ref.wav`);
|
|
46022
|
+
if (existsSync42(refFile))
|
|
45164
46023
|
continue;
|
|
45165
46024
|
try {
|
|
45166
46025
|
await this.generateCloneRef(modelId);
|
|
@@ -45239,24 +46098,24 @@ var init_voice = __esm({
|
|
|
45239
46098
|
}
|
|
45240
46099
|
p = p.replace(/\\ /g, " ");
|
|
45241
46100
|
if (p.startsWith("~/") || p === "~") {
|
|
45242
|
-
p =
|
|
46101
|
+
p = join58(homedir15(), p.slice(1));
|
|
45243
46102
|
}
|
|
45244
|
-
if (!
|
|
46103
|
+
if (!existsSync42(p)) {
|
|
45245
46104
|
return `File not found: ${p}
|
|
45246
46105
|
(original input: ${audioPath})`;
|
|
45247
46106
|
}
|
|
45248
46107
|
audioPath = p;
|
|
45249
46108
|
const refsDir = luxttsCloneRefsDir();
|
|
45250
|
-
if (!
|
|
45251
|
-
|
|
46109
|
+
if (!existsSync42(refsDir))
|
|
46110
|
+
mkdirSync18(refsDir, { recursive: true });
|
|
45252
46111
|
const ext = audioPath.split(".").pop() || "wav";
|
|
45253
46112
|
const srcName = (audioPath.split("/").pop() ?? "clone").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
45254
46113
|
const ts = Date.now().toString(36);
|
|
45255
46114
|
const destFilename = `clone-${srcName}-${ts}.${ext}`;
|
|
45256
|
-
const destPath =
|
|
46115
|
+
const destPath = join58(refsDir, destFilename);
|
|
45257
46116
|
try {
|
|
45258
|
-
const data =
|
|
45259
|
-
|
|
46117
|
+
const data = readFileSync31(audioPath);
|
|
46118
|
+
writeFileSync19(destPath, data);
|
|
45260
46119
|
} catch (err) {
|
|
45261
46120
|
return `Failed to copy audio file: ${err instanceof Error ? err.message : String(err)}`;
|
|
45262
46121
|
}
|
|
@@ -45296,9 +46155,9 @@ var init_voice = __esm({
|
|
|
45296
46155
|
return `Failed to synthesize reference audio from ${source.label}.`;
|
|
45297
46156
|
}
|
|
45298
46157
|
const refsDir = luxttsCloneRefsDir();
|
|
45299
|
-
if (!
|
|
45300
|
-
|
|
45301
|
-
const destPath =
|
|
46158
|
+
if (!existsSync42(refsDir))
|
|
46159
|
+
mkdirSync18(refsDir, { recursive: true });
|
|
46160
|
+
const destPath = join58(refsDir, `${sourceModelId}-ref.wav`);
|
|
45302
46161
|
const sampleRate = this.config?.audio?.sample_rate ?? 22050;
|
|
45303
46162
|
this.writeWav(audioData, sampleRate, destPath);
|
|
45304
46163
|
this.luxttsCloneRef = destPath;
|
|
@@ -45314,23 +46173,23 @@ var init_voice = __esm({
|
|
|
45314
46173
|
// -------------------------------------------------------------------------
|
|
45315
46174
|
/** Metadata file for friendly names of clone refs */
|
|
45316
46175
|
static cloneMetaFile() {
|
|
45317
|
-
return
|
|
46176
|
+
return join58(luxttsCloneRefsDir(), "meta.json");
|
|
45318
46177
|
}
|
|
45319
46178
|
loadCloneMeta() {
|
|
45320
46179
|
const p = _VoiceEngine.cloneMetaFile();
|
|
45321
|
-
if (!
|
|
46180
|
+
if (!existsSync42(p))
|
|
45322
46181
|
return {};
|
|
45323
46182
|
try {
|
|
45324
|
-
return JSON.parse(
|
|
46183
|
+
return JSON.parse(readFileSync31(p, "utf8"));
|
|
45325
46184
|
} catch {
|
|
45326
46185
|
return {};
|
|
45327
46186
|
}
|
|
45328
46187
|
}
|
|
45329
46188
|
saveCloneMeta(meta) {
|
|
45330
46189
|
const dir = luxttsCloneRefsDir();
|
|
45331
|
-
if (!
|
|
45332
|
-
|
|
45333
|
-
|
|
46190
|
+
if (!existsSync42(dir))
|
|
46191
|
+
mkdirSync18(dir, { recursive: true });
|
|
46192
|
+
writeFileSync19(_VoiceEngine.cloneMetaFile(), JSON.stringify(meta, null, 2));
|
|
45334
46193
|
}
|
|
45335
46194
|
/** Audio file extensions recognized as clone references */
|
|
45336
46195
|
static AUDIO_EXTS = /* @__PURE__ */ new Set(["wav", "mp3", "ogg", "flac", "m4a", "opus", "aac"]);
|
|
@@ -45340,15 +46199,15 @@ var init_voice = __esm({
|
|
|
45340
46199
|
*/
|
|
45341
46200
|
listCloneRefs() {
|
|
45342
46201
|
const dir = luxttsCloneRefsDir();
|
|
45343
|
-
if (!
|
|
46202
|
+
if (!existsSync42(dir))
|
|
45344
46203
|
return [];
|
|
45345
46204
|
const meta = this.loadCloneMeta();
|
|
45346
|
-
const files =
|
|
46205
|
+
const files = readdirSync12(dir).filter((f) => {
|
|
45347
46206
|
const ext = f.split(".").pop()?.toLowerCase() ?? "";
|
|
45348
46207
|
return _VoiceEngine.AUDIO_EXTS.has(ext);
|
|
45349
46208
|
});
|
|
45350
46209
|
return files.map((f) => {
|
|
45351
|
-
const p =
|
|
46210
|
+
const p = join58(dir, f);
|
|
45352
46211
|
let size = 0;
|
|
45353
46212
|
try {
|
|
45354
46213
|
size = statSync13(p).size;
|
|
@@ -45365,8 +46224,8 @@ var init_voice = __esm({
|
|
|
45365
46224
|
}
|
|
45366
46225
|
/** Delete a clone reference file by filename. Returns true if deleted. */
|
|
45367
46226
|
deleteCloneRef(filename) {
|
|
45368
|
-
const p =
|
|
45369
|
-
if (!
|
|
46227
|
+
const p = join58(luxttsCloneRefsDir(), filename);
|
|
46228
|
+
if (!existsSync42(p))
|
|
45370
46229
|
return false;
|
|
45371
46230
|
try {
|
|
45372
46231
|
unlinkSync9(p);
|
|
@@ -45390,8 +46249,8 @@ var init_voice = __esm({
|
|
|
45390
46249
|
}
|
|
45391
46250
|
/** Set the active clone reference by filename. */
|
|
45392
46251
|
setActiveCloneRef(filename) {
|
|
45393
|
-
const p =
|
|
45394
|
-
if (!
|
|
46252
|
+
const p = join58(luxttsCloneRefsDir(), filename);
|
|
46253
|
+
if (!existsSync42(p))
|
|
45395
46254
|
return `File not found: ${filename}`;
|
|
45396
46255
|
this.luxttsCloneRef = p;
|
|
45397
46256
|
return `Active clone voice set to: ${filename}`;
|
|
@@ -45716,7 +46575,7 @@ var init_voice = __esm({
|
|
|
45716
46575
|
}
|
|
45717
46576
|
this.onPCMOutput(Buffer.from(int16.buffer), sampleRate);
|
|
45718
46577
|
}
|
|
45719
|
-
const wavPath =
|
|
46578
|
+
const wavPath = join58(tmpdir9(), `oa-voice-${Date.now()}.wav`);
|
|
45720
46579
|
this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
|
|
45721
46580
|
await this.playWav(wavPath);
|
|
45722
46581
|
try {
|
|
@@ -45833,7 +46692,7 @@ var init_voice = __esm({
|
|
|
45833
46692
|
buffer.writeInt16LE(rSample < 0 ? rSample * 32768 : rSample * 32767, pos);
|
|
45834
46693
|
pos += 2;
|
|
45835
46694
|
}
|
|
45836
|
-
|
|
46695
|
+
writeFileSync19(path, buffer);
|
|
45837
46696
|
}
|
|
45838
46697
|
// -------------------------------------------------------------------------
|
|
45839
46698
|
// Phonemization
|
|
@@ -45911,7 +46770,7 @@ var init_voice = __esm({
|
|
|
45911
46770
|
return buffer;
|
|
45912
46771
|
}
|
|
45913
46772
|
writeWav(samples, sampleRate, path) {
|
|
45914
|
-
|
|
46773
|
+
writeFileSync19(path, this.buildWavBuffer(samples, sampleRate));
|
|
45915
46774
|
}
|
|
45916
46775
|
// -------------------------------------------------------------------------
|
|
45917
46776
|
// Audio playback (system default speakers)
|
|
@@ -45961,7 +46820,7 @@ var init_voice = __esm({
|
|
|
45961
46820
|
}
|
|
45962
46821
|
for (const player of ["paplay", "pw-play", "aplay"]) {
|
|
45963
46822
|
try {
|
|
45964
|
-
|
|
46823
|
+
execSync30(`which ${player}`, { stdio: "pipe" });
|
|
45965
46824
|
return [player, path];
|
|
45966
46825
|
} catch {
|
|
45967
46826
|
}
|
|
@@ -45990,7 +46849,7 @@ var init_voice = __esm({
|
|
|
45990
46849
|
return this.python3Path;
|
|
45991
46850
|
for (const bin of ["python3", "python"]) {
|
|
45992
46851
|
try {
|
|
45993
|
-
const path =
|
|
46852
|
+
const path = execSync30(`which ${bin}`, { stdio: "pipe", timeout: 5e3 }).toString().trim();
|
|
45994
46853
|
if (path) {
|
|
45995
46854
|
this.python3Path = path;
|
|
45996
46855
|
return path;
|
|
@@ -46056,7 +46915,7 @@ var init_voice = __esm({
|
|
|
46056
46915
|
return false;
|
|
46057
46916
|
}
|
|
46058
46917
|
try {
|
|
46059
|
-
|
|
46918
|
+
execSync30(`${py} -c "import mlx_audio"`, { stdio: "pipe", timeout: 1e4 });
|
|
46060
46919
|
this.mlxInstalled = true;
|
|
46061
46920
|
return true;
|
|
46062
46921
|
} catch {
|
|
@@ -46109,7 +46968,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46109
46968
|
const mlxModelId = model.mlxModelId ?? "mlx-community/Kokoro-82M-bf16";
|
|
46110
46969
|
const mlxVoice = model.mlxVoice ?? "af_heart";
|
|
46111
46970
|
const mlxLangCode = model.mlxLangCode ?? "a";
|
|
46112
|
-
const wavPath =
|
|
46971
|
+
const wavPath = join58(tmpdir9(), `oa-mlx-${Date.now()}.wav`);
|
|
46113
46972
|
const pyScript = [
|
|
46114
46973
|
"import sys, json",
|
|
46115
46974
|
"from mlx_audio.tts import generate as tts_gen",
|
|
@@ -46117,20 +46976,20 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46117
46976
|
`tts_gen.main(["--model", ${JSON.stringify(mlxModelId)}, "--text", text, "--voice", ${JSON.stringify(mlxVoice)}, "--lang_code", ${JSON.stringify(mlxLangCode)}, "--audio_path", ${JSON.stringify(wavPath)}])`
|
|
46118
46977
|
].join("; ");
|
|
46119
46978
|
try {
|
|
46120
|
-
|
|
46979
|
+
execSync30(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
|
|
46121
46980
|
} catch (err) {
|
|
46122
46981
|
try {
|
|
46123
46982
|
const safeText = cleaned.replace(/'/g, "'\\''");
|
|
46124
|
-
|
|
46983
|
+
execSync30(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
|
|
46125
46984
|
} catch (err2) {
|
|
46126
46985
|
return;
|
|
46127
46986
|
}
|
|
46128
46987
|
}
|
|
46129
|
-
if (!
|
|
46988
|
+
if (!existsSync42(wavPath))
|
|
46130
46989
|
return;
|
|
46131
46990
|
if (volume !== 1) {
|
|
46132
46991
|
try {
|
|
46133
|
-
const wavData =
|
|
46992
|
+
const wavData = readFileSync31(wavPath);
|
|
46134
46993
|
if (wavData.length > 44) {
|
|
46135
46994
|
const header = wavData.subarray(0, 44);
|
|
46136
46995
|
const samples = new Int16Array(wavData.buffer, wavData.byteOffset + 44, (wavData.length - 44) / 2);
|
|
@@ -46138,14 +46997,14 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46138
46997
|
samples[i] = Math.round(samples[i] * volume);
|
|
46139
46998
|
}
|
|
46140
46999
|
const scaled = Buffer.concat([header, Buffer.from(samples.buffer, samples.byteOffset, samples.byteLength)]);
|
|
46141
|
-
|
|
47000
|
+
writeFileSync19(wavPath, scaled);
|
|
46142
47001
|
}
|
|
46143
47002
|
} catch {
|
|
46144
47003
|
}
|
|
46145
47004
|
}
|
|
46146
47005
|
if (this.onPCMOutput) {
|
|
46147
47006
|
try {
|
|
46148
|
-
const wavData =
|
|
47007
|
+
const wavData = readFileSync31(wavPath);
|
|
46149
47008
|
if (wavData.length > 44) {
|
|
46150
47009
|
const pcm = Buffer.from(wavData.buffer, wavData.byteOffset + 44, wavData.length - 44);
|
|
46151
47010
|
const sampleRate = wavData.readUInt32LE(24);
|
|
@@ -46177,7 +47036,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46177
47036
|
const mlxModelId = model.mlxModelId ?? "mlx-community/Kokoro-82M-bf16";
|
|
46178
47037
|
const mlxVoice = model.mlxVoice ?? "af_heart";
|
|
46179
47038
|
const mlxLangCode = model.mlxLangCode ?? "a";
|
|
46180
|
-
const wavPath =
|
|
47039
|
+
const wavPath = join58(tmpdir9(), `oa-mlx-buf-${Date.now()}.wav`);
|
|
46181
47040
|
const pyScript = [
|
|
46182
47041
|
"import sys, json",
|
|
46183
47042
|
"from mlx_audio.tts import generate as tts_gen",
|
|
@@ -46185,19 +47044,19 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46185
47044
|
`tts_gen.main(["--model", ${JSON.stringify(mlxModelId)}, "--text", text, "--voice", ${JSON.stringify(mlxVoice)}, "--lang_code", ${JSON.stringify(mlxLangCode)}, "--audio_path", ${JSON.stringify(wavPath)}])`
|
|
46186
47045
|
].join("; ");
|
|
46187
47046
|
try {
|
|
46188
|
-
|
|
47047
|
+
execSync30(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
|
|
46189
47048
|
} catch {
|
|
46190
47049
|
try {
|
|
46191
47050
|
const safeText = cleaned.replace(/'/g, "'\\''");
|
|
46192
|
-
|
|
47051
|
+
execSync30(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
|
|
46193
47052
|
} catch {
|
|
46194
47053
|
return null;
|
|
46195
47054
|
}
|
|
46196
47055
|
}
|
|
46197
|
-
if (!
|
|
47056
|
+
if (!existsSync42(wavPath))
|
|
46198
47057
|
return null;
|
|
46199
47058
|
try {
|
|
46200
|
-
const data =
|
|
47059
|
+
const data = readFileSync31(wavPath);
|
|
46201
47060
|
unlinkSync9(wavPath);
|
|
46202
47061
|
return data;
|
|
46203
47062
|
} catch {
|
|
@@ -46220,7 +47079,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46220
47079
|
}
|
|
46221
47080
|
const venvDir = luxttsVenvDir();
|
|
46222
47081
|
const venvPy = luxttsVenvPy();
|
|
46223
|
-
if (
|
|
47082
|
+
if (existsSync42(venvPy)) {
|
|
46224
47083
|
try {
|
|
46225
47084
|
await this.asyncShell(`${venvPy} -c "import sys; sys.path.insert(0, '${luxttsRepoDir()}'); from zipvoice.luxvoice import LuxTTS; print('ok')"`, 3e4);
|
|
46226
47085
|
let hasCudaSys = false;
|
|
@@ -46234,7 +47093,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46234
47093
|
if (torchCheck === "cpu") {
|
|
46235
47094
|
renderWarning("GPU detected but PyTorch is CPU-only. Reinstalling with CUDA support in background...");
|
|
46236
47095
|
try {
|
|
46237
|
-
const detectScript =
|
|
47096
|
+
const detectScript = join58(voiceDir(), "detect-torch.py");
|
|
46238
47097
|
writeDetectTorchScript(detectScript);
|
|
46239
47098
|
let pipArgs = `torch torchaudio --index-url https://download.pytorch.org/whl/cu124`;
|
|
46240
47099
|
try {
|
|
@@ -46259,7 +47118,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46259
47118
|
}
|
|
46260
47119
|
}
|
|
46261
47120
|
renderInfo("Setting up LuxTTS voice cloning (first-time setup, this takes several minutes)...");
|
|
46262
|
-
if (!
|
|
47121
|
+
if (!existsSync42(venvDir)) {
|
|
46263
47122
|
renderInfo(" Creating Python virtual environment...");
|
|
46264
47123
|
try {
|
|
46265
47124
|
await this.asyncShell(`${py} -m venv ${JSON.stringify(venvDir)}`, 6e4);
|
|
@@ -46268,7 +47127,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46268
47127
|
}
|
|
46269
47128
|
}
|
|
46270
47129
|
{
|
|
46271
|
-
const detectScript =
|
|
47130
|
+
const detectScript = join58(voiceDir(), "detect-torch.py");
|
|
46272
47131
|
writeDetectTorchScript(detectScript);
|
|
46273
47132
|
let pipArgsStr = "torch torchaudio";
|
|
46274
47133
|
let torchDesc = "unknown platform";
|
|
@@ -46305,10 +47164,10 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46305
47164
|
}
|
|
46306
47165
|
}
|
|
46307
47166
|
const repoDir = luxttsRepoDir();
|
|
46308
|
-
if (!
|
|
47167
|
+
if (!existsSync42(join58(repoDir, "zipvoice", "luxvoice.py"))) {
|
|
46309
47168
|
renderInfo(" Cloning LuxTTS repository...");
|
|
46310
47169
|
try {
|
|
46311
|
-
if (
|
|
47170
|
+
if (existsSync42(repoDir)) {
|
|
46312
47171
|
const rmCmd = process.platform === "win32" ? `rmdir /s /q ${JSON.stringify(repoDir)}` : `rm -rf ${JSON.stringify(repoDir)}`;
|
|
46313
47172
|
await this.asyncShell(rmCmd, 3e4);
|
|
46314
47173
|
}
|
|
@@ -46387,7 +47246,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46387
47246
|
renderWarning(` Could not install system build deps: ${err instanceof Error ? err.message : String(err)}`);
|
|
46388
47247
|
}
|
|
46389
47248
|
}
|
|
46390
|
-
const isJetson = isArm && (
|
|
47249
|
+
const isJetson = isArm && (existsSync42("/etc/nv_tegra_release") || existsSync42("/usr/local/cuda/targets/aarch64-linux") || (process.env.JETSON_L4T_VERSION ?? "") !== "");
|
|
46391
47250
|
const installSteps = isArm ? [
|
|
46392
47251
|
// ARM: install individually so we get clear error messages per package.
|
|
46393
47252
|
// ALL are fatal because LuxTTS hard-imports them (no lazy/optional imports).
|
|
@@ -46457,14 +47316,14 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
|
46457
47316
|
}
|
|
46458
47317
|
/** Auto-detect an existing clone reference in the refs directory */
|
|
46459
47318
|
autoDetectCloneRef() {
|
|
46460
|
-
if (this.luxttsCloneRef &&
|
|
47319
|
+
if (this.luxttsCloneRef && existsSync42(this.luxttsCloneRef))
|
|
46461
47320
|
return;
|
|
46462
47321
|
const refsDir = luxttsCloneRefsDir();
|
|
46463
|
-
if (!
|
|
47322
|
+
if (!existsSync42(refsDir))
|
|
46464
47323
|
return;
|
|
46465
47324
|
for (const name of ["custom-clone.wav", "custom-clone.mp3", "glados-ref.wav", "overwatch-ref.wav"]) {
|
|
46466
|
-
const p =
|
|
46467
|
-
if (
|
|
47325
|
+
const p = join58(refsDir, name);
|
|
47326
|
+
if (existsSync42(p)) {
|
|
46468
47327
|
this.luxttsCloneRef = p;
|
|
46469
47328
|
return;
|
|
46470
47329
|
}
|
|
@@ -46564,15 +47423,15 @@ if __name__ == '__main__':
|
|
|
46564
47423
|
main()
|
|
46565
47424
|
`;
|
|
46566
47425
|
const scriptPath2 = luxttsInferScript();
|
|
46567
|
-
|
|
46568
|
-
|
|
47426
|
+
mkdirSync18(voiceDir(), { recursive: true });
|
|
47427
|
+
writeFileSync19(scriptPath2, script);
|
|
46569
47428
|
}
|
|
46570
47429
|
/** Ensure the LuxTTS daemon is running, spawn if needed */
|
|
46571
47430
|
async ensureLuxttsDaemon() {
|
|
46572
47431
|
if (this._luxttsDaemon && !this._luxttsDaemon.killed)
|
|
46573
47432
|
return true;
|
|
46574
47433
|
const venvPy = luxttsVenvPy();
|
|
46575
|
-
if (!
|
|
47434
|
+
if (!existsSync42(venvPy))
|
|
46576
47435
|
return false;
|
|
46577
47436
|
return new Promise((resolve36) => {
|
|
46578
47437
|
const env = { ...process.env, LUXTTS_REPO_PATH: luxttsRepoDir() };
|
|
@@ -46656,7 +47515,7 @@ if __name__ == '__main__':
|
|
|
46656
47515
|
* Used by drainQueue's pre-fetch pipeline for gapless back-to-back playback.
|
|
46657
47516
|
*/
|
|
46658
47517
|
async synthesizeLuxttsWav(text, speedFactor = 1) {
|
|
46659
|
-
if (!this.luxttsCloneRef || !
|
|
47518
|
+
if (!this.luxttsCloneRef || !existsSync42(this.luxttsCloneRef))
|
|
46660
47519
|
return null;
|
|
46661
47520
|
const cleaned = text.replace(/\*/g, "").trim();
|
|
46662
47521
|
if (!cleaned)
|
|
@@ -46664,7 +47523,7 @@ if __name__ == '__main__':
|
|
|
46664
47523
|
const ready = await this.ensureLuxttsDaemon();
|
|
46665
47524
|
if (!ready)
|
|
46666
47525
|
return null;
|
|
46667
|
-
const wavPath =
|
|
47526
|
+
const wavPath = join58(tmpdir9(), `oa-luxtts-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.wav`);
|
|
46668
47527
|
try {
|
|
46669
47528
|
await this.luxttsRequest({
|
|
46670
47529
|
action: "synthesize",
|
|
@@ -46676,17 +47535,17 @@ if __name__ == '__main__':
|
|
|
46676
47535
|
} catch {
|
|
46677
47536
|
return null;
|
|
46678
47537
|
}
|
|
46679
|
-
return
|
|
47538
|
+
return existsSync42(wavPath) ? wavPath : null;
|
|
46680
47539
|
}
|
|
46681
47540
|
/**
|
|
46682
47541
|
* Post-process (fade-in, volume, pitch, stereo) and play a LuxTTS WAV file.
|
|
46683
47542
|
* Cleans up the WAV file after playback.
|
|
46684
47543
|
*/
|
|
46685
47544
|
async postProcessAndPlayLuxtts(wavPath, volume = 1, pitchFactor = 1, stereoDelayMs = 0.6) {
|
|
46686
|
-
if (!
|
|
47545
|
+
if (!existsSync42(wavPath))
|
|
46687
47546
|
return;
|
|
46688
47547
|
try {
|
|
46689
|
-
const wavData =
|
|
47548
|
+
const wavData = readFileSync31(wavPath);
|
|
46690
47549
|
if (wavData.length > 44) {
|
|
46691
47550
|
const sampleRate = wavData.readUInt32LE(24);
|
|
46692
47551
|
const samples = new Int16Array(wavData.buffer, wavData.byteOffset + 44, (wavData.length - 44) / 2);
|
|
@@ -46701,13 +47560,13 @@ if __name__ == '__main__':
|
|
|
46701
47560
|
}
|
|
46702
47561
|
const header = wavData.subarray(0, 44);
|
|
46703
47562
|
const scaled = Buffer.concat([header, Buffer.from(samples.buffer, samples.byteOffset, samples.byteLength)]);
|
|
46704
|
-
|
|
47563
|
+
writeFileSync19(wavPath, scaled);
|
|
46705
47564
|
}
|
|
46706
47565
|
} catch {
|
|
46707
47566
|
}
|
|
46708
47567
|
if (pitchFactor !== 1) {
|
|
46709
47568
|
try {
|
|
46710
|
-
const wavData =
|
|
47569
|
+
const wavData = readFileSync31(wavPath);
|
|
46711
47570
|
if (wavData.length > 44) {
|
|
46712
47571
|
const int16 = new Int16Array(wavData.buffer, wavData.byteOffset + 44, (wavData.length - 44) / 2);
|
|
46713
47572
|
const float32 = new Float32Array(int16.length);
|
|
@@ -46722,7 +47581,7 @@ if __name__ == '__main__':
|
|
|
46722
47581
|
}
|
|
46723
47582
|
if (this.onPCMOutput) {
|
|
46724
47583
|
try {
|
|
46725
|
-
const wavData =
|
|
47584
|
+
const wavData = readFileSync31(wavPath);
|
|
46726
47585
|
if (wavData.length > 44) {
|
|
46727
47586
|
const pcm = Buffer.from(wavData.buffer, wavData.byteOffset + 44, wavData.length - 44);
|
|
46728
47587
|
const sampleRate = wavData.readUInt32LE(24);
|
|
@@ -46733,7 +47592,7 @@ if __name__ == '__main__':
|
|
|
46733
47592
|
}
|
|
46734
47593
|
if (stereoDelayMs > 0) {
|
|
46735
47594
|
try {
|
|
46736
|
-
const wavData =
|
|
47595
|
+
const wavData = readFileSync31(wavPath);
|
|
46737
47596
|
if (wavData.length > 44) {
|
|
46738
47597
|
const sampleRate = wavData.readUInt32LE(24);
|
|
46739
47598
|
const numChannels = wavData.readUInt16LE(22);
|
|
@@ -46769,7 +47628,7 @@ if __name__ == '__main__':
|
|
|
46769
47628
|
* Used for Telegram voice messages and WebSocket streaming.
|
|
46770
47629
|
*/
|
|
46771
47630
|
async synthesizeLuxttsToBuffer(text) {
|
|
46772
|
-
if (!this.luxttsCloneRef || !
|
|
47631
|
+
if (!this.luxttsCloneRef || !existsSync42(this.luxttsCloneRef))
|
|
46773
47632
|
return null;
|
|
46774
47633
|
const cleaned = text.replace(/\*/g, "").trim();
|
|
46775
47634
|
if (!cleaned)
|
|
@@ -46777,7 +47636,7 @@ if __name__ == '__main__':
|
|
|
46777
47636
|
const ready = await this.ensureLuxttsDaemon();
|
|
46778
47637
|
if (!ready)
|
|
46779
47638
|
return null;
|
|
46780
|
-
const wavPath =
|
|
47639
|
+
const wavPath = join58(tmpdir9(), `oa-luxtts-buf-${Date.now()}.wav`);
|
|
46781
47640
|
try {
|
|
46782
47641
|
await this.luxttsRequest({
|
|
46783
47642
|
action: "synthesize",
|
|
@@ -46789,10 +47648,10 @@ if __name__ == '__main__':
|
|
|
46789
47648
|
} catch {
|
|
46790
47649
|
return null;
|
|
46791
47650
|
}
|
|
46792
|
-
if (!
|
|
47651
|
+
if (!existsSync42(wavPath))
|
|
46793
47652
|
return null;
|
|
46794
47653
|
try {
|
|
46795
|
-
const data =
|
|
47654
|
+
const data = readFileSync31(wavPath);
|
|
46796
47655
|
unlinkSync9(wavPath);
|
|
46797
47656
|
return data;
|
|
46798
47657
|
} catch {
|
|
@@ -46806,40 +47665,40 @@ if __name__ == '__main__':
|
|
|
46806
47665
|
if (this.ort)
|
|
46807
47666
|
return;
|
|
46808
47667
|
const arch2 = process.arch;
|
|
46809
|
-
|
|
46810
|
-
const pkgPath =
|
|
47668
|
+
mkdirSync18(voiceDir(), { recursive: true });
|
|
47669
|
+
const pkgPath = join58(voiceDir(), "package.json");
|
|
46811
47670
|
const expectedDeps = {
|
|
46812
47671
|
"onnxruntime-node": "^1.21.0",
|
|
46813
47672
|
"phonemizer": "^1.2.1"
|
|
46814
47673
|
};
|
|
46815
|
-
if (
|
|
47674
|
+
if (existsSync42(pkgPath)) {
|
|
46816
47675
|
try {
|
|
46817
|
-
const existing = JSON.parse(
|
|
47676
|
+
const existing = JSON.parse(readFileSync31(pkgPath, "utf8"));
|
|
46818
47677
|
if (!existing.dependencies?.["phonemizer"]) {
|
|
46819
47678
|
existing.dependencies = { ...existing.dependencies, ...expectedDeps };
|
|
46820
|
-
|
|
47679
|
+
writeFileSync19(pkgPath, JSON.stringify(existing, null, 2));
|
|
46821
47680
|
}
|
|
46822
47681
|
} catch {
|
|
46823
47682
|
}
|
|
46824
47683
|
}
|
|
46825
|
-
if (!
|
|
46826
|
-
|
|
47684
|
+
if (!existsSync42(pkgPath)) {
|
|
47685
|
+
writeFileSync19(pkgPath, JSON.stringify({
|
|
46827
47686
|
name: "open-agents-voice",
|
|
46828
47687
|
private: true,
|
|
46829
47688
|
dependencies: expectedDeps
|
|
46830
47689
|
}, null, 2));
|
|
46831
47690
|
}
|
|
46832
|
-
const voiceRequire = createRequire(
|
|
47691
|
+
const voiceRequire = createRequire(join58(voiceDir(), "index.js"));
|
|
46833
47692
|
const probeOnnx = async () => {
|
|
46834
47693
|
try {
|
|
46835
|
-
const output = await this.asyncShell(`NODE_PATH="${
|
|
47694
|
+
const output = await this.asyncShell(`NODE_PATH="${join58(voiceDir(), "node_modules")}" node -e "try { require('onnxruntime-node'); console.log('OK'); } catch(e) { console.log('FAIL:' + e.message); }"`, 15e3);
|
|
46836
47695
|
return output.trim() === "OK";
|
|
46837
47696
|
} catch {
|
|
46838
47697
|
return false;
|
|
46839
47698
|
}
|
|
46840
47699
|
};
|
|
46841
|
-
const onnxNodeModules =
|
|
46842
|
-
const onnxInstalled =
|
|
47700
|
+
const onnxNodeModules = join58(voiceDir(), "node_modules", "onnxruntime-node");
|
|
47701
|
+
const onnxInstalled = existsSync42(onnxNodeModules);
|
|
46843
47702
|
if (onnxInstalled && !await probeOnnx()) {
|
|
46844
47703
|
throw new Error(`Voice synthesis unavailable: ONNX runtime crashes on this CPU (${process.platform}-${arch2}). This is a known issue with some ARM SoCs where the CPU vendor is not recognized. Voice feedback will be disabled but all other features work normally.`);
|
|
46845
47704
|
}
|
|
@@ -46889,18 +47748,18 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
46889
47748
|
const dir = modelDir(id);
|
|
46890
47749
|
const onnxPath = modelOnnxPath(id);
|
|
46891
47750
|
const configPath2 = modelConfigPath(id);
|
|
46892
|
-
if (
|
|
47751
|
+
if (existsSync42(onnxPath) && existsSync42(configPath2))
|
|
46893
47752
|
return;
|
|
46894
|
-
|
|
46895
|
-
if (!
|
|
47753
|
+
mkdirSync18(dir, { recursive: true });
|
|
47754
|
+
if (!existsSync42(configPath2)) {
|
|
46896
47755
|
renderInfo(`Downloading ${model.label} voice config...`);
|
|
46897
47756
|
const configResp = await fetch(model.configUrl);
|
|
46898
47757
|
if (!configResp.ok)
|
|
46899
47758
|
throw new Error(`Failed to download config: HTTP ${configResp.status}`);
|
|
46900
47759
|
const configText = await configResp.text();
|
|
46901
|
-
|
|
47760
|
+
writeFileSync19(configPath2, configText);
|
|
46902
47761
|
}
|
|
46903
|
-
if (!
|
|
47762
|
+
if (!existsSync42(onnxPath)) {
|
|
46904
47763
|
renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
|
|
46905
47764
|
const onnxResp = await fetch(model.onnxUrl);
|
|
46906
47765
|
if (!onnxResp.ok)
|
|
@@ -46925,7 +47784,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
46925
47784
|
}
|
|
46926
47785
|
}
|
|
46927
47786
|
const fullBuffer = Buffer.concat(chunks);
|
|
46928
|
-
|
|
47787
|
+
writeFileSync19(onnxPath, fullBuffer);
|
|
46929
47788
|
renderInfo(`${model.label} model downloaded (${formatBytes2(fullBuffer.length)}).`);
|
|
46930
47789
|
}
|
|
46931
47790
|
}
|
|
@@ -46937,10 +47796,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
46937
47796
|
throw new Error("ONNX runtime not loaded");
|
|
46938
47797
|
const onnxPath = modelOnnxPath(this.modelId);
|
|
46939
47798
|
const configPath2 = modelConfigPath(this.modelId);
|
|
46940
|
-
if (!
|
|
47799
|
+
if (!existsSync42(onnxPath) || !existsSync42(configPath2)) {
|
|
46941
47800
|
throw new Error(`Model files not found for ${this.modelId}`);
|
|
46942
47801
|
}
|
|
46943
|
-
this.config = JSON.parse(
|
|
47802
|
+
this.config = JSON.parse(readFileSync31(configPath2, "utf8"));
|
|
46944
47803
|
this.session = await this.ort.InferenceSession.create(onnxPath, {
|
|
46945
47804
|
executionProviders: ["cpu"],
|
|
46946
47805
|
graphOptimizationLevel: "all"
|
|
@@ -46967,8 +47826,8 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
46967
47826
|
// packages/cli/dist/tui/commands.js
|
|
46968
47827
|
import * as nodeOs from "node:os";
|
|
46969
47828
|
import { execSync as nodeExecSync } from "node:child_process";
|
|
46970
|
-
import { existsSync as
|
|
46971
|
-
import { join as
|
|
47829
|
+
import { existsSync as existsSync43, readFileSync as readFileSync32, writeFileSync as writeFileSync20, mkdirSync as mkdirSync19, readdirSync as readdirSync13, statSync as statSync14, rmSync } from "node:fs";
|
|
47830
|
+
import { join as join59 } from "node:path";
|
|
46972
47831
|
function safeLog(text) {
|
|
46973
47832
|
if (isNeovimActive()) {
|
|
46974
47833
|
writeToNeovimOutput(text + "\n");
|
|
@@ -47387,9 +48246,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47387
48246
|
renderInfo("No wallet configured. Ask the agent to create one via the nexus tool.");
|
|
47388
48247
|
}
|
|
47389
48248
|
} else if (sub === "name") {
|
|
47390
|
-
const { homedir:
|
|
48249
|
+
const { homedir: homedir21 } = __require("node:os");
|
|
47391
48250
|
const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
|
|
47392
|
-
const namePath = __require("node:path").join(
|
|
48251
|
+
const namePath = __require("node:path").join(homedir21(), ".open-agents", "agent-name");
|
|
47393
48252
|
if (rest2) {
|
|
47394
48253
|
const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
|
|
47395
48254
|
if (!customName) {
|
|
@@ -47662,22 +48521,22 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47662
48521
|
let content = "";
|
|
47663
48522
|
let metadata = {};
|
|
47664
48523
|
if (shareType === "tool") {
|
|
47665
|
-
const toolDir =
|
|
47666
|
-
const toolFile =
|
|
47667
|
-
if (!
|
|
48524
|
+
const toolDir = join59(ctx.repoRoot, ".oa", "tools");
|
|
48525
|
+
const toolFile = join59(toolDir, shareName.endsWith(".json") ? shareName : `${shareName}.json`);
|
|
48526
|
+
if (!existsSync43(toolFile)) {
|
|
47668
48527
|
renderWarning(`Tool not found: ${toolFile}`);
|
|
47669
48528
|
return "handled";
|
|
47670
48529
|
}
|
|
47671
|
-
content =
|
|
48530
|
+
content = readFileSync32(toolFile, "utf8");
|
|
47672
48531
|
metadata = { type: "tool", name: shareName };
|
|
47673
48532
|
} else if (shareType === "skill") {
|
|
47674
|
-
const skillDir =
|
|
47675
|
-
const skillFile =
|
|
47676
|
-
if (!
|
|
48533
|
+
const skillDir = join59(ctx.repoRoot, ".oa", "skills", shareName);
|
|
48534
|
+
const skillFile = join59(skillDir, "SKILL.md");
|
|
48535
|
+
if (!existsSync43(skillFile)) {
|
|
47677
48536
|
renderWarning(`Skill not found: ${skillFile}`);
|
|
47678
48537
|
return "handled";
|
|
47679
48538
|
}
|
|
47680
|
-
content =
|
|
48539
|
+
content = readFileSync32(skillFile, "utf8");
|
|
47681
48540
|
metadata = { type: "skill", name: shareName };
|
|
47682
48541
|
} else {
|
|
47683
48542
|
renderWarning(`Unknown share type: ${shareType}. Use 'tool' or 'skill'.`);
|
|
@@ -47714,9 +48573,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47714
48573
|
try {
|
|
47715
48574
|
const nexus = new NexusTool(ctx.repoRoot);
|
|
47716
48575
|
await nexus.execute({ action: "ipfs_pin", cid: importCid, source: "import" });
|
|
47717
|
-
const regFile =
|
|
47718
|
-
if (
|
|
47719
|
-
const reg = JSON.parse(
|
|
48576
|
+
const regFile = join59(ctx.repoRoot, ".oa", "nexus", "ipfs", "cid-registry", "learning-cids.json");
|
|
48577
|
+
if (existsSync43(regFile)) {
|
|
48578
|
+
const reg = JSON.parse(readFileSync32(regFile, "utf8"));
|
|
47720
48579
|
const pinned = Object.values(reg).some((e) => e.cid === importCid && e.pinned);
|
|
47721
48580
|
if (pinned) {
|
|
47722
48581
|
renderInfo(`CID ${importCid.slice(0, 20)}... pinned successfully.`);
|
|
@@ -47768,33 +48627,33 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47768
48627
|
lines.push(`
|
|
47769
48628
|
${c2.bold("IPFS / Helia Status")}
|
|
47770
48629
|
`);
|
|
47771
|
-
const ipfsDir =
|
|
47772
|
-
const ipfsLocalDir =
|
|
48630
|
+
const ipfsDir = join59(ctx.repoRoot, ".oa", "ipfs");
|
|
48631
|
+
const ipfsLocalDir = join59(ipfsDir, "local");
|
|
47773
48632
|
let ipfsFiles = 0;
|
|
47774
48633
|
let ipfsBytes = 0;
|
|
47775
48634
|
let heliaBlocks = 0;
|
|
47776
48635
|
let heliaBytes = 0;
|
|
47777
48636
|
try {
|
|
47778
|
-
if (
|
|
47779
|
-
const files =
|
|
48637
|
+
if (existsSync43(ipfsLocalDir)) {
|
|
48638
|
+
const files = readdirSync13(ipfsLocalDir).filter((f) => f.endsWith(".json"));
|
|
47780
48639
|
ipfsFiles = files.length;
|
|
47781
48640
|
for (const f of files) {
|
|
47782
48641
|
try {
|
|
47783
|
-
ipfsBytes += statSync14(
|
|
48642
|
+
ipfsBytes += statSync14(join59(ipfsLocalDir, f)).size;
|
|
47784
48643
|
} catch {
|
|
47785
48644
|
}
|
|
47786
48645
|
}
|
|
47787
48646
|
}
|
|
47788
|
-
const heliaBlockDir =
|
|
47789
|
-
if (
|
|
48647
|
+
const heliaBlockDir = join59(ipfsDir, "blocks");
|
|
48648
|
+
if (existsSync43(heliaBlockDir)) {
|
|
47790
48649
|
const walkDir = (dir) => {
|
|
47791
|
-
for (const entry of
|
|
48650
|
+
for (const entry of readdirSync13(dir, { withFileTypes: true })) {
|
|
47792
48651
|
if (entry.isDirectory())
|
|
47793
|
-
walkDir(
|
|
48652
|
+
walkDir(join59(dir, entry.name));
|
|
47794
48653
|
else {
|
|
47795
48654
|
heliaBlocks++;
|
|
47796
48655
|
try {
|
|
47797
|
-
heliaBytes += statSync14(
|
|
48656
|
+
heliaBytes += statSync14(join59(dir, entry.name)).size;
|
|
47798
48657
|
} catch {
|
|
47799
48658
|
}
|
|
47800
48659
|
}
|
|
@@ -47810,9 +48669,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47810
48669
|
lines.push(` Blocks: ${c2.bold(String(heliaBlocks))} Size: ${c2.bold(formatFileSize(heliaBytes))}`);
|
|
47811
48670
|
lines.push(` Backend: ${heliaBlocks > 0 ? c2.green("helia-ipfs") : c2.yellow("sha256-local (Helia not initialized)")}`);
|
|
47812
48671
|
try {
|
|
47813
|
-
const statusFile =
|
|
47814
|
-
if (
|
|
47815
|
-
const status = JSON.parse(
|
|
48672
|
+
const statusFile = join59(ctx.repoRoot, ".oa", "nexus", "status.json");
|
|
48673
|
+
if (existsSync43(statusFile)) {
|
|
48674
|
+
const status = JSON.parse(readFileSync32(statusFile, "utf8"));
|
|
47816
48675
|
if (status.peerId) {
|
|
47817
48676
|
lines.push(`
|
|
47818
48677
|
${c2.bold("Peer Info")}`);
|
|
@@ -47831,11 +48690,11 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47831
48690
|
${c2.dim("Commands: /ipfs pin <CID> /ipfs publish /ipfs cids")}`);
|
|
47832
48691
|
lines.push(`
|
|
47833
48692
|
${c2.bold("Identity Kernel")}`);
|
|
47834
|
-
const idDir =
|
|
48693
|
+
const idDir = join59(ctx.repoRoot, ".oa", "identity");
|
|
47835
48694
|
try {
|
|
47836
|
-
const stateFile =
|
|
47837
|
-
if (
|
|
47838
|
-
const state = JSON.parse(
|
|
48695
|
+
const stateFile = join59(idDir, "self-state.json");
|
|
48696
|
+
if (existsSync43(stateFile)) {
|
|
48697
|
+
const state = JSON.parse(readFileSync32(stateFile, "utf8"));
|
|
47839
48698
|
lines.push(` Version: ${c2.bold("v" + (state.version ?? "?"))} Sessions: ${c2.bold(String(state.session_count ?? 0))}`);
|
|
47840
48699
|
if (state.narrative_summary) {
|
|
47841
48700
|
lines.push(` Narrative: ${c2.dim(state.narrative_summary.slice(0, 60))}${state.narrative_summary.length > 60 ? "..." : ""}`);
|
|
@@ -47844,9 +48703,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47844
48703
|
const traits = typeof state.personality_traits === "object" ? Object.entries(state.personality_traits).map(([k, v]) => `${k}:${v}`).join(", ") : String(state.personality_traits);
|
|
47845
48704
|
lines.push(` Traits: ${c2.dim(traits.slice(0, 60))}`);
|
|
47846
48705
|
}
|
|
47847
|
-
const cidFile =
|
|
47848
|
-
if (
|
|
47849
|
-
const cids = JSON.parse(
|
|
48706
|
+
const cidFile = join59(idDir, "cids.json");
|
|
48707
|
+
if (existsSync43(cidFile)) {
|
|
48708
|
+
const cids = JSON.parse(readFileSync32(cidFile, "utf8"));
|
|
47850
48709
|
const lastCid = Array.isArray(cids) ? cids[cids.length - 1] : cids.latest;
|
|
47851
48710
|
if (lastCid)
|
|
47852
48711
|
lines.push(` Last CID: ${c2.dim(String(lastCid).slice(0, 50))}`);
|
|
@@ -47859,9 +48718,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47859
48718
|
lines.push(`
|
|
47860
48719
|
${c2.bold("Memory Sentiment")}`);
|
|
47861
48720
|
try {
|
|
47862
|
-
const metaFile =
|
|
47863
|
-
if (
|
|
47864
|
-
const store = JSON.parse(
|
|
48721
|
+
const metaFile = join59(ctx.repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
48722
|
+
if (existsSync43(metaFile)) {
|
|
48723
|
+
const store = JSON.parse(readFileSync32(metaFile, "utf8"));
|
|
47865
48724
|
const active = store.filter((m) => m.type !== "quarantine");
|
|
47866
48725
|
const recoveries = active.filter((m) => m.content?.startsWith("[recovery]")).length;
|
|
47867
48726
|
const strategies = active.filter((m) => m.content?.startsWith("[strategy]")).length;
|
|
@@ -47879,8 +48738,8 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47879
48738
|
} catch {
|
|
47880
48739
|
}
|
|
47881
48740
|
try {
|
|
47882
|
-
const dbPath =
|
|
47883
|
-
if (
|
|
48741
|
+
const dbPath = join59(ctx.repoRoot, ".oa", "memory", "structured.db");
|
|
48742
|
+
if (existsSync43(dbPath)) {
|
|
47884
48743
|
const { initDb: initDb2, closeDb: cDb, ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
47885
48744
|
const db = initDb2(dbPath);
|
|
47886
48745
|
const memStore = new ProceduralMemoryStore2(db);
|
|
@@ -47901,8 +48760,8 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47901
48760
|
lines.push(`
|
|
47902
48761
|
${c2.bold("Storage Overview")}
|
|
47903
48762
|
`);
|
|
47904
|
-
const oaDir =
|
|
47905
|
-
if (!
|
|
48763
|
+
const oaDir = join59(ctx.repoRoot, ".oa");
|
|
48764
|
+
if (!existsSync43(oaDir)) {
|
|
47906
48765
|
lines.push(` ${c2.dim("No .oa/ directory found.")}`);
|
|
47907
48766
|
safeLog(lines.join("\n") + "\n");
|
|
47908
48767
|
return "handled";
|
|
@@ -47911,8 +48770,8 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47911
48770
|
const categories = {};
|
|
47912
48771
|
const walkStorage = (dir, category) => {
|
|
47913
48772
|
try {
|
|
47914
|
-
for (const entry of
|
|
47915
|
-
const full =
|
|
48773
|
+
for (const entry of readdirSync13(dir, { withFileTypes: true })) {
|
|
48774
|
+
const full = join59(dir, entry.name);
|
|
47916
48775
|
if (entry.isDirectory()) {
|
|
47917
48776
|
const subCat = category || entry.name;
|
|
47918
48777
|
walkStorage(full, subCat);
|
|
@@ -47945,13 +48804,13 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47945
48804
|
const sensitiveFound = [];
|
|
47946
48805
|
const checkSensitive = (dir) => {
|
|
47947
48806
|
try {
|
|
47948
|
-
for (const entry of
|
|
48807
|
+
for (const entry of readdirSync13(dir, { withFileTypes: true })) {
|
|
47949
48808
|
const name = entry.name.toLowerCase();
|
|
47950
48809
|
if (sensitivePatterns.some((p) => name.includes(p))) {
|
|
47951
|
-
sensitiveFound.push(
|
|
48810
|
+
sensitiveFound.push(join59(dir, entry.name).replace(oaDir + "/", ""));
|
|
47952
48811
|
}
|
|
47953
48812
|
if (entry.isDirectory())
|
|
47954
|
-
checkSensitive(
|
|
48813
|
+
checkSensitive(join59(dir, entry.name));
|
|
47955
48814
|
}
|
|
47956
48815
|
} catch {
|
|
47957
48816
|
}
|
|
@@ -47979,8 +48838,8 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47979
48838
|
renderInfo("Supported: .wav .mp3 .flac .ogg (audio\u2192transcribe) | .pdf .txt .md (text\u2192chunk)");
|
|
47980
48839
|
return "handled";
|
|
47981
48840
|
}
|
|
47982
|
-
const resolvedPath =
|
|
47983
|
-
if (!
|
|
48841
|
+
const resolvedPath = join59(ctx.repoRoot, filePath);
|
|
48842
|
+
if (!existsSync43(resolvedPath)) {
|
|
47984
48843
|
renderWarning(`File not found: ${resolvedPath}`);
|
|
47985
48844
|
return "handled";
|
|
47986
48845
|
}
|
|
@@ -47996,9 +48855,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
47996
48855
|
}
|
|
47997
48856
|
try {
|
|
47998
48857
|
const { initDb: initDb2, closeDb: cDb, ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
47999
|
-
const dbDir =
|
|
48000
|
-
|
|
48001
|
-
const db = initDb2(
|
|
48858
|
+
const dbDir = join59(ctx.repoRoot, ".oa", "memory");
|
|
48859
|
+
mkdirSync19(dbDir, { recursive: true });
|
|
48860
|
+
const db = initDb2(join59(dbDir, "structured.db"));
|
|
48002
48861
|
const memStore = new ProceduralMemoryStore2(db);
|
|
48003
48862
|
if (isAudio) {
|
|
48004
48863
|
renderInfo(`Transcribing: ${filePath}...`);
|
|
@@ -48039,7 +48898,7 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48039
48898
|
return "handled";
|
|
48040
48899
|
}
|
|
48041
48900
|
} else {
|
|
48042
|
-
content =
|
|
48901
|
+
content = readFileSync32(resolvedPath, "utf8");
|
|
48043
48902
|
}
|
|
48044
48903
|
if (!content.trim()) {
|
|
48045
48904
|
renderWarning("No content extracted.");
|
|
@@ -48078,9 +48937,9 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48078
48937
|
}
|
|
48079
48938
|
case "fortemi": {
|
|
48080
48939
|
const fortemiSubCmd = (arg || "").trim().toLowerCase();
|
|
48081
|
-
const fortemiDir =
|
|
48082
|
-
const altFortemiDir =
|
|
48083
|
-
const fDir =
|
|
48940
|
+
const fortemiDir = join59(ctx.repoRoot, "..", "fortemi-react");
|
|
48941
|
+
const altFortemiDir = join59(nodeOs.homedir(), "fortemi-react");
|
|
48942
|
+
const fDir = existsSync43(fortemiDir) ? fortemiDir : existsSync43(altFortemiDir) ? altFortemiDir : null;
|
|
48084
48943
|
if (fortemiSubCmd === "start" || fortemiSubCmd === "") {
|
|
48085
48944
|
if (!fDir) {
|
|
48086
48945
|
renderWarning("fortemi-react not found adjacent or in home directory.");
|
|
@@ -48095,14 +48954,14 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48095
48954
|
// 24h
|
|
48096
48955
|
nonce: Math.random().toString(36).slice(2, 10)
|
|
48097
48956
|
};
|
|
48098
|
-
const jwtFile =
|
|
48099
|
-
|
|
48100
|
-
|
|
48957
|
+
const jwtFile = join59(ctx.repoRoot, ".oa", "fortemi-jwt.json");
|
|
48958
|
+
mkdirSync19(join59(ctx.repoRoot, ".oa"), { recursive: true });
|
|
48959
|
+
writeFileSync20(jwtFile, JSON.stringify(jwtPayload, null, 2));
|
|
48101
48960
|
renderInfo(`Launching fortemi-react from ${fDir}...`);
|
|
48102
48961
|
try {
|
|
48103
|
-
const { spawn:
|
|
48104
|
-
const child =
|
|
48105
|
-
cwd:
|
|
48962
|
+
const { spawn: spawn23 } = __require("node:child_process");
|
|
48963
|
+
const child = spawn23("npx", ["vite", "dev", "--host", "0.0.0.0", "--port", "3000"], {
|
|
48964
|
+
cwd: join59(fDir, "apps", "standalone"),
|
|
48106
48965
|
stdio: "ignore",
|
|
48107
48966
|
detached: true,
|
|
48108
48967
|
env: { ...process.env, OA_JWT: JSON.stringify(jwtPayload) }
|
|
@@ -48111,8 +48970,8 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48111
48970
|
renderInfo("Fortemi-React starting on http://localhost:3000");
|
|
48112
48971
|
renderInfo(`JWT saved to ${jwtFile}`);
|
|
48113
48972
|
renderInfo("Memory operations will proxy to fortemi when available.");
|
|
48114
|
-
const bridgeFile =
|
|
48115
|
-
|
|
48973
|
+
const bridgeFile = join59(ctx.repoRoot, ".oa", "fortemi-bridge.json");
|
|
48974
|
+
writeFileSync20(bridgeFile, JSON.stringify({
|
|
48116
48975
|
url: "http://localhost:3000",
|
|
48117
48976
|
pid: child.pid,
|
|
48118
48977
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -48124,12 +48983,12 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48124
48983
|
return "handled";
|
|
48125
48984
|
}
|
|
48126
48985
|
if (fortemiSubCmd === "status") {
|
|
48127
|
-
const bridgeFile =
|
|
48128
|
-
if (!
|
|
48986
|
+
const bridgeFile = join59(ctx.repoRoot, ".oa", "fortemi-bridge.json");
|
|
48987
|
+
if (!existsSync43(bridgeFile)) {
|
|
48129
48988
|
renderInfo("Fortemi bridge: not connected. Run /fortemi start");
|
|
48130
48989
|
return "handled";
|
|
48131
48990
|
}
|
|
48132
|
-
const bridge = JSON.parse(
|
|
48991
|
+
const bridge = JSON.parse(readFileSync32(bridgeFile, "utf8"));
|
|
48133
48992
|
let alive = false;
|
|
48134
48993
|
try {
|
|
48135
48994
|
process.kill(bridge.pid, 0);
|
|
@@ -48149,15 +49008,15 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48149
49008
|
lines.push(` Process: ${alive ? c2.green("running") : c2.yellow("not running")} (PID ${bridge.pid})`);
|
|
48150
49009
|
lines.push(` HTTP: ${httpOk ? c2.green("connected") : c2.yellow("unreachable")}`);
|
|
48151
49010
|
lines.push(` Started: ${bridge.startedAt}`);
|
|
48152
|
-
lines.push(` JWT: ${
|
|
49011
|
+
lines.push(` JWT: ${existsSync43(bridge.jwtFile) ? c2.green("valid") : c2.yellow("missing")}`);
|
|
48153
49012
|
lines.push("");
|
|
48154
49013
|
safeLog(lines.join("\n"));
|
|
48155
49014
|
return "handled";
|
|
48156
49015
|
}
|
|
48157
49016
|
if (fortemiSubCmd === "stop") {
|
|
48158
|
-
const bridgeFile =
|
|
48159
|
-
if (
|
|
48160
|
-
const bridge = JSON.parse(
|
|
49017
|
+
const bridgeFile = join59(ctx.repoRoot, ".oa", "fortemi-bridge.json");
|
|
49018
|
+
if (existsSync43(bridgeFile)) {
|
|
49019
|
+
const bridge = JSON.parse(readFileSync32(bridgeFile, "utf8"));
|
|
48161
49020
|
try {
|
|
48162
49021
|
process.kill(bridge.pid, "SIGTERM");
|
|
48163
49022
|
} catch {
|
|
@@ -48214,6 +49073,76 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48214
49073
|
ctx.saveSettings(settings);
|
|
48215
49074
|
};
|
|
48216
49075
|
if (arg) {
|
|
49076
|
+
if (arg === "personaplex" || arg === "pp") {
|
|
49077
|
+
const { detectPersonaPlexCapability: detectPersonaPlexCapability2, isPersonaPlexInstalled: isPersonaPlexInstalled2, installPersonaPlex: installPersonaPlex2, startPersonaPlexDaemon: startPersonaPlexDaemon2, stopPersonaPlex: stopPersonaPlex2, isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49078
|
+
const caps = detectPersonaPlexCapability2();
|
|
49079
|
+
if (!caps.supported) {
|
|
49080
|
+
renderWarning(`PersonaPlex not available: ${caps.reason}`);
|
|
49081
|
+
renderInfo("Requirements: NVIDIA GPU with \u226516GB VRAM (RTX 3090/4090/A100+), CUDA 12.1+, PyTorch");
|
|
49082
|
+
return "handled";
|
|
49083
|
+
}
|
|
49084
|
+
renderInfo(`GPU: ${caps.gpuName} (${caps.vramGB.toFixed(0)}GB VRAM) \u2014 PersonaPlex compatible \u2713`);
|
|
49085
|
+
if (!isPersonaPlexInstalled2()) {
|
|
49086
|
+
renderInfo("Installing PersonaPlex-7B (~14GB download)...");
|
|
49087
|
+
const ok = await installPersonaPlex2((msg2) => renderInfo(msg2));
|
|
49088
|
+
if (!ok) {
|
|
49089
|
+
renderError("PersonaPlex installation failed.");
|
|
49090
|
+
return "handled";
|
|
49091
|
+
}
|
|
49092
|
+
}
|
|
49093
|
+
if (isPersonaPlexRunning2()) {
|
|
49094
|
+
renderInfo("PersonaPlex daemon is running.");
|
|
49095
|
+
renderInfo("Use /call to start a full-duplex voice session.");
|
|
49096
|
+
} else {
|
|
49097
|
+
const url = await startPersonaPlexDaemon2((msg2) => renderInfo(msg2));
|
|
49098
|
+
if (url) {
|
|
49099
|
+
renderInfo(`PersonaPlex ready at ${url}`);
|
|
49100
|
+
renderInfo("Use /call to start a full-duplex voice session with PersonaPlex.");
|
|
49101
|
+
} else {
|
|
49102
|
+
renderError("PersonaPlex daemon failed to start.");
|
|
49103
|
+
}
|
|
49104
|
+
}
|
|
49105
|
+
return "handled";
|
|
49106
|
+
}
|
|
49107
|
+
if (arg.startsWith("clone")) {
|
|
49108
|
+
const parts = arg.slice(5).trim().split(/\s+/);
|
|
49109
|
+
if (parts.length < 2) {
|
|
49110
|
+
renderInfo("Usage: /voice clone <wav-file> <voice-name>");
|
|
49111
|
+
renderInfo("Example: /voice clone ~/my_voice.wav MyVoice");
|
|
49112
|
+
renderInfo("");
|
|
49113
|
+
renderInfo("Record 4-10 seconds of clean speech (24kHz mono WAV recommended).");
|
|
49114
|
+
renderInfo("The voice embedding will be extracted and saved for PersonaPlex.");
|
|
49115
|
+
return "handled";
|
|
49116
|
+
}
|
|
49117
|
+
const [wavPath, voiceName] = parts;
|
|
49118
|
+
const { clonePersonaPlexVoice: clonePersonaPlexVoice2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49119
|
+
const result = await clonePersonaPlexVoice2(wavPath, voiceName, (msg2) => renderInfo(msg2));
|
|
49120
|
+
if (result) {
|
|
49121
|
+
renderInfo(`Use with /call by setting voice_prompt to "${voiceName}.pt"`);
|
|
49122
|
+
}
|
|
49123
|
+
return "handled";
|
|
49124
|
+
}
|
|
49125
|
+
if (arg === "list" || arg === "voices") {
|
|
49126
|
+
const { listPersonaPlexVoices: listPersonaPlexVoices2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
49127
|
+
const voices = listPersonaPlexVoices2();
|
|
49128
|
+
const builtins = voices.filter((v) => v.type === "builtin");
|
|
49129
|
+
const customs = voices.filter((v) => v.type === "custom");
|
|
49130
|
+
renderInfo("Natural voices:");
|
|
49131
|
+
renderInfo(" Female: " + builtins.filter((v) => v.name.startsWith("NATF")).map((v) => v.name).join(", "));
|
|
49132
|
+
renderInfo(" Male: " + builtins.filter((v) => v.name.startsWith("NATM")).map((v) => v.name).join(", "));
|
|
49133
|
+
renderInfo("Variety voices:");
|
|
49134
|
+
renderInfo(" Female: " + builtins.filter((v) => v.name.startsWith("VARF")).map((v) => v.name).join(", "));
|
|
49135
|
+
renderInfo(" Male: " + builtins.filter((v) => v.name.startsWith("VARM")).map((v) => v.name).join(", "));
|
|
49136
|
+
if (customs.length > 0) {
|
|
49137
|
+
renderInfo("Custom cloned voices:");
|
|
49138
|
+
for (const v of customs) {
|
|
49139
|
+
renderInfo(` ${v.name} (${v.path})`);
|
|
49140
|
+
}
|
|
49141
|
+
} else {
|
|
49142
|
+
renderInfo("No custom voices. Use /voice clone <wav> <name> to create one.");
|
|
49143
|
+
}
|
|
49144
|
+
return "handled";
|
|
49145
|
+
}
|
|
48217
49146
|
if (arg === "enable" || arg === "on") {
|
|
48218
49147
|
const msg2 = await ctx.voiceToggle();
|
|
48219
49148
|
const isOn = msg2.toLowerCase().includes("enabled") || msg2.toLowerCase().includes("on");
|
|
@@ -48738,10 +49667,10 @@ async function handleSlashCommand(input, ctx) {
|
|
|
48738
49667
|
let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
|
|
48739
49668
|
if (!sponsorName || sponsorName.length < 2) {
|
|
48740
49669
|
try {
|
|
48741
|
-
const { homedir:
|
|
48742
|
-
const namePath = __require("path").join(
|
|
48743
|
-
if (
|
|
48744
|
-
sponsorName =
|
|
49670
|
+
const { homedir: homedir21 } = __require("os");
|
|
49671
|
+
const namePath = __require("path").join(homedir21(), ".open-agents", "agent-name");
|
|
49672
|
+
if (existsSync43(namePath))
|
|
49673
|
+
sponsorName = readFileSync32(namePath, "utf8").trim();
|
|
48745
49674
|
} catch {
|
|
48746
49675
|
}
|
|
48747
49676
|
if (!sponsorName)
|
|
@@ -49812,13 +50741,13 @@ async function showCohereDashboard(ctx) {
|
|
|
49812
50741
|
} else if (idResult.key === "view") {
|
|
49813
50742
|
await ik.execute({ operation: "hydrate" });
|
|
49814
50743
|
} else if (idResult.key === "history") {
|
|
49815
|
-
const snapDir =
|
|
49816
|
-
if (
|
|
49817
|
-
const snaps =
|
|
50744
|
+
const snapDir = join59(ctx.repoRoot, ".oa", "identity", "snapshots");
|
|
50745
|
+
if (existsSync43(snapDir)) {
|
|
50746
|
+
const snaps = readdirSync13(snapDir).filter((f) => f.endsWith(".json")).sort().reverse();
|
|
49818
50747
|
const snapItems = snaps.slice(0, 20).map((f) => ({
|
|
49819
50748
|
key: f,
|
|
49820
50749
|
label: f.replace(".json", ""),
|
|
49821
|
-
detail: `${formatFileSize(statSync14(
|
|
50750
|
+
detail: `${formatFileSize(statSync14(join59(snapDir, f)).size)}`
|
|
49822
50751
|
}));
|
|
49823
50752
|
if (snapItems.length > 0) {
|
|
49824
50753
|
await tuiSelect({
|
|
@@ -50139,14 +51068,14 @@ async function handleVoiceMenu(ctx, save, hasLocal) {
|
|
|
50139
51068
|
continue;
|
|
50140
51069
|
}
|
|
50141
51070
|
const { basename: basename18, join: pathJoin } = await import("node:path");
|
|
50142
|
-
const { copyFileSync:
|
|
50143
|
-
const { homedir:
|
|
51071
|
+
const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync31, existsSync: exists } = await import("node:fs");
|
|
51072
|
+
const { homedir: homedir21 } = await import("node:os");
|
|
50144
51073
|
const modelName = basename18(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
50145
|
-
const destDir = pathJoin(
|
|
51074
|
+
const destDir = pathJoin(homedir21(), ".open-agents", "voice", "models", modelName);
|
|
50146
51075
|
if (!exists(destDir))
|
|
50147
|
-
|
|
50148
|
-
|
|
50149
|
-
|
|
51076
|
+
mkdirSync31(destDir, { recursive: true });
|
|
51077
|
+
copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
51078
|
+
copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
50150
51079
|
const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
|
|
50151
51080
|
registerCustomOnnxModel2(modelName, modelName);
|
|
50152
51081
|
await ctx.voiceSetModel(modelName);
|
|
@@ -50272,8 +51201,8 @@ async function handleVoiceList(ctx, focusFilename) {
|
|
|
50272
51201
|
helpers.getInput("Export to:", defaultPath).then((destPath) => {
|
|
50273
51202
|
if (destPath !== null && destPath.trim()) {
|
|
50274
51203
|
try {
|
|
50275
|
-
const { copyFileSync:
|
|
50276
|
-
|
|
51204
|
+
const { copyFileSync: copyFileSync3 } = __require("node:fs");
|
|
51205
|
+
copyFileSync3(clone.path, destPath.trim());
|
|
50277
51206
|
renderInfo(`Exported "${clone.name}" \u2192 ${destPath.trim()}`);
|
|
50278
51207
|
} catch (err) {
|
|
50279
51208
|
renderError(`Export failed: ${err.message}`);
|
|
@@ -50771,11 +51700,11 @@ async function handleSponsoredEndpoint(ctx, local) {
|
|
|
50771
51700
|
}
|
|
50772
51701
|
} catch {
|
|
50773
51702
|
}
|
|
50774
|
-
const sponsorDir2 =
|
|
50775
|
-
const knownFile =
|
|
51703
|
+
const sponsorDir2 = join59(ctx.repoRoot ?? process.cwd(), ".oa", "sponsor");
|
|
51704
|
+
const knownFile = join59(sponsorDir2, "known-sponsors.json");
|
|
50776
51705
|
try {
|
|
50777
|
-
if (
|
|
50778
|
-
const saved = JSON.parse(
|
|
51706
|
+
if (existsSync43(knownFile)) {
|
|
51707
|
+
const saved = JSON.parse(readFileSync32(knownFile, "utf8"));
|
|
50779
51708
|
for (const s of saved) {
|
|
50780
51709
|
if (!sponsors.some((sp) => sp.url === s.url)) {
|
|
50781
51710
|
sponsors.push({ ...s, source: "saved" });
|
|
@@ -50910,11 +51839,11 @@ async function handleSponsoredEndpoint(ctx, local) {
|
|
|
50910
51839
|
}
|
|
50911
51840
|
const saveKey = selected.url || selected.peerId || selected.name;
|
|
50912
51841
|
try {
|
|
50913
|
-
|
|
50914
|
-
const existing =
|
|
51842
|
+
mkdirSync19(sponsorDir2, { recursive: true });
|
|
51843
|
+
const existing = existsSync43(knownFile) ? JSON.parse(readFileSync32(knownFile, "utf8")) : [];
|
|
50915
51844
|
const updated = existing.filter((s) => (s.url || s.peerId || s.name) !== saveKey);
|
|
50916
51845
|
updated.push(selected);
|
|
50917
|
-
|
|
51846
|
+
writeFileSync20(knownFile, JSON.stringify(updated, null, 2), "utf8");
|
|
50918
51847
|
} catch {
|
|
50919
51848
|
}
|
|
50920
51849
|
renderInfo(`Connected to sponsored endpoint: ${selected.name}`);
|
|
@@ -50983,11 +51912,11 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
|
|
|
50983
51912
|
const models = await fetchModels(peerUrl, authKey);
|
|
50984
51913
|
if (models.length > 0) {
|
|
50985
51914
|
try {
|
|
50986
|
-
const { writeFileSync:
|
|
50987
|
-
const { join:
|
|
50988
|
-
const cachePath =
|
|
50989
|
-
|
|
50990
|
-
|
|
51915
|
+
const { writeFileSync: writeFileSync30, mkdirSync: mkdirSync31 } = await import("node:fs");
|
|
51916
|
+
const { join: join77, dirname: dirname24 } = await import("node:path");
|
|
51917
|
+
const cachePath = join77(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
|
|
51918
|
+
mkdirSync31(dirname24(cachePath), { recursive: true });
|
|
51919
|
+
writeFileSync30(cachePath, JSON.stringify({
|
|
50991
51920
|
peerId,
|
|
50992
51921
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
50993
51922
|
models: models.map((m) => ({ name: m.name, size: m.size, parameterSize: m.parameterSize }))
|
|
@@ -51036,7 +51965,7 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
|
|
|
51036
51965
|
}
|
|
51037
51966
|
}
|
|
51038
51967
|
async function handleParallel(arg, ctx) {
|
|
51039
|
-
const { execSync:
|
|
51968
|
+
const { execSync: execSync35 } = await import("node:child_process");
|
|
51040
51969
|
const baseUrl = ctx.config.backendUrl || "http://localhost:11434";
|
|
51041
51970
|
const isRemote = ctx.config.backendType === "nexus";
|
|
51042
51971
|
if (isRemote) {
|
|
@@ -51060,7 +51989,7 @@ async function handleParallel(arg, ctx) {
|
|
|
51060
51989
|
}
|
|
51061
51990
|
let systemdVal = "";
|
|
51062
51991
|
try {
|
|
51063
|
-
const out =
|
|
51992
|
+
const out = execSync35("systemctl show ollama.service -p Environment 2>/dev/null || true", { encoding: "utf8" });
|
|
51064
51993
|
const match = out.match(/OLLAMA_NUM_PARALLEL=(\d+)/);
|
|
51065
51994
|
if (match)
|
|
51066
51995
|
systemdVal = match[1];
|
|
@@ -51089,7 +52018,7 @@ async function handleParallel(arg, ctx) {
|
|
|
51089
52018
|
}
|
|
51090
52019
|
const isSystemd = (() => {
|
|
51091
52020
|
try {
|
|
51092
|
-
const out =
|
|
52021
|
+
const out = execSync35("systemctl is-active ollama.service 2>/dev/null", { encoding: "utf8" }).trim();
|
|
51093
52022
|
return out === "active" || out === "inactive";
|
|
51094
52023
|
} catch {
|
|
51095
52024
|
return false;
|
|
@@ -51103,10 +52032,10 @@ async function handleParallel(arg, ctx) {
|
|
|
51103
52032
|
const overrideContent = `[Service]
|
|
51104
52033
|
Environment="OLLAMA_NUM_PARALLEL=${n}"
|
|
51105
52034
|
`;
|
|
51106
|
-
|
|
51107
|
-
|
|
51108
|
-
|
|
51109
|
-
|
|
52035
|
+
execSync35(`sudo mkdir -p ${overrideDir}`, { stdio: "pipe" });
|
|
52036
|
+
execSync35(`echo '${overrideContent}' | sudo tee ${overrideFile} > /dev/null`, { stdio: "pipe" });
|
|
52037
|
+
execSync35("sudo systemctl daemon-reload", { stdio: "pipe" });
|
|
52038
|
+
execSync35("sudo systemctl restart ollama.service", { stdio: "pipe" });
|
|
51110
52039
|
let ready = false;
|
|
51111
52040
|
for (let i = 0; i < 30 && !ready; i++) {
|
|
51112
52041
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -51133,13 +52062,13 @@ Environment="OLLAMA_NUM_PARALLEL=${n}"
|
|
|
51133
52062
|
renderInfo(`Setting OLLAMA_NUM_PARALLEL=${n}...`);
|
|
51134
52063
|
try {
|
|
51135
52064
|
try {
|
|
51136
|
-
|
|
52065
|
+
execSync35("pkill -f 'ollama serve' 2>/dev/null || true", { stdio: "pipe" });
|
|
51137
52066
|
} catch {
|
|
51138
52067
|
}
|
|
51139
52068
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
51140
52069
|
process.env.OLLAMA_NUM_PARALLEL = String(n);
|
|
51141
|
-
const { spawn:
|
|
51142
|
-
const child =
|
|
52070
|
+
const { spawn: spawn23 } = await import("node:child_process");
|
|
52071
|
+
const child = spawn23("ollama", ["serve"], {
|
|
51143
52072
|
stdio: "ignore",
|
|
51144
52073
|
detached: true,
|
|
51145
52074
|
env: { ...process.env, OLLAMA_NUM_PARALLEL: String(n) }
|
|
@@ -51185,18 +52114,18 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
51185
52114
|
let currentVersion = "0.0.0";
|
|
51186
52115
|
try {
|
|
51187
52116
|
const { createRequire: createRequire6 } = await import("node:module");
|
|
51188
|
-
const { fileURLToPath:
|
|
51189
|
-
const { dirname:
|
|
51190
|
-
const { existsSync:
|
|
52117
|
+
const { fileURLToPath: fileURLToPath16 } = await import("node:url");
|
|
52118
|
+
const { dirname: dirname24, join: join77 } = await import("node:path");
|
|
52119
|
+
const { existsSync: existsSync57 } = await import("node:fs");
|
|
51191
52120
|
const req = createRequire6(import.meta.url);
|
|
51192
|
-
const thisDir =
|
|
52121
|
+
const thisDir = dirname24(fileURLToPath16(import.meta.url));
|
|
51193
52122
|
const candidates = [
|
|
51194
|
-
|
|
51195
|
-
|
|
51196
|
-
|
|
52123
|
+
join77(thisDir, "..", "package.json"),
|
|
52124
|
+
join77(thisDir, "..", "..", "package.json"),
|
|
52125
|
+
join77(thisDir, "..", "..", "..", "package.json")
|
|
51197
52126
|
];
|
|
51198
52127
|
for (const pkgPath of candidates) {
|
|
51199
|
-
if (
|
|
52128
|
+
if (existsSync57(pkgPath)) {
|
|
51200
52129
|
const pkg = req(pkgPath);
|
|
51201
52130
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
51202
52131
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -51952,18 +52881,18 @@ async function showExposeDashboard(gateway, rl, ctx) {
|
|
|
51952
52881
|
const cmd = `/endpoint ${id} --auth ${gateway.authKey ?? ""}`;
|
|
51953
52882
|
let copied = false;
|
|
51954
52883
|
try {
|
|
51955
|
-
const { execSync:
|
|
52884
|
+
const { execSync: execSync35 } = __require("node:child_process");
|
|
51956
52885
|
const platform6 = process.platform;
|
|
51957
52886
|
if (platform6 === "darwin") {
|
|
51958
|
-
|
|
52887
|
+
execSync35("pbcopy", { input: cmd, timeout: 3e3 });
|
|
51959
52888
|
copied = true;
|
|
51960
52889
|
} else if (platform6 === "win32") {
|
|
51961
|
-
|
|
52890
|
+
execSync35("clip", { input: cmd, timeout: 3e3 });
|
|
51962
52891
|
copied = true;
|
|
51963
52892
|
} else {
|
|
51964
52893
|
for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
|
|
51965
52894
|
try {
|
|
51966
|
-
|
|
52895
|
+
execSync35(tool, { input: cmd, timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] });
|
|
51967
52896
|
copied = true;
|
|
51968
52897
|
break;
|
|
51969
52898
|
} catch {
|
|
@@ -52050,10 +52979,10 @@ var init_commands = __esm({
|
|
|
52050
52979
|
});
|
|
52051
52980
|
|
|
52052
52981
|
// packages/cli/dist/tui/project-context.js
|
|
52053
|
-
import { existsSync as
|
|
52054
|
-
import { join as
|
|
52055
|
-
import { execSync as
|
|
52056
|
-
import { homedir as
|
|
52982
|
+
import { existsSync as existsSync44, readFileSync as readFileSync33, readdirSync as readdirSync14 } from "node:fs";
|
|
52983
|
+
import { join as join60, basename as basename12 } from "node:path";
|
|
52984
|
+
import { execSync as execSync31 } from "node:child_process";
|
|
52985
|
+
import { homedir as homedir17, platform as platform4, release } from "node:os";
|
|
52057
52986
|
function getModelTier(modelName) {
|
|
52058
52987
|
const m = modelName.toLowerCase();
|
|
52059
52988
|
const sizeMatch = m.match(/\b(\d+)b\b/);
|
|
@@ -52086,10 +53015,10 @@ function loadProjectMap(repoRoot) {
|
|
|
52086
53015
|
if (!hasOaDirectory(repoRoot)) {
|
|
52087
53016
|
initOaDirectory(repoRoot);
|
|
52088
53017
|
}
|
|
52089
|
-
const mapPath2 =
|
|
52090
|
-
if (
|
|
53018
|
+
const mapPath2 = join60(repoRoot, OA_DIR, "context", "project-map.md");
|
|
53019
|
+
if (existsSync44(mapPath2)) {
|
|
52091
53020
|
try {
|
|
52092
|
-
const content =
|
|
53021
|
+
const content = readFileSync33(mapPath2, "utf-8");
|
|
52093
53022
|
return content;
|
|
52094
53023
|
} catch {
|
|
52095
53024
|
}
|
|
@@ -52098,19 +53027,19 @@ function loadProjectMap(repoRoot) {
|
|
|
52098
53027
|
}
|
|
52099
53028
|
function getGitInfo(repoRoot) {
|
|
52100
53029
|
try {
|
|
52101
|
-
|
|
53030
|
+
execSync31("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
|
|
52102
53031
|
} catch {
|
|
52103
53032
|
return "";
|
|
52104
53033
|
}
|
|
52105
53034
|
const lines = [];
|
|
52106
53035
|
try {
|
|
52107
|
-
const branch =
|
|
53036
|
+
const branch = execSync31("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
52108
53037
|
if (branch)
|
|
52109
53038
|
lines.push(`Branch: ${branch}`);
|
|
52110
53039
|
} catch {
|
|
52111
53040
|
}
|
|
52112
53041
|
try {
|
|
52113
|
-
const status =
|
|
53042
|
+
const status = execSync31("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
52114
53043
|
if (status) {
|
|
52115
53044
|
const changed = status.split("\n").length;
|
|
52116
53045
|
lines.push(`Working tree: ${changed} changed file(s)`);
|
|
@@ -52120,7 +53049,7 @@ function getGitInfo(repoRoot) {
|
|
|
52120
53049
|
} catch {
|
|
52121
53050
|
}
|
|
52122
53051
|
try {
|
|
52123
|
-
const log =
|
|
53052
|
+
const log = execSync31("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
52124
53053
|
if (log)
|
|
52125
53054
|
lines.push(`Recent commits:
|
|
52126
53055
|
${log}`);
|
|
@@ -52130,31 +53059,31 @@ ${log}`);
|
|
|
52130
53059
|
}
|
|
52131
53060
|
function loadMemoryContext(repoRoot) {
|
|
52132
53061
|
const sections = [];
|
|
52133
|
-
const oaMemDir =
|
|
53062
|
+
const oaMemDir = join60(repoRoot, OA_DIR, "memory");
|
|
52134
53063
|
const oaEntries = loadMemoryDir(oaMemDir, "project");
|
|
52135
53064
|
if (oaEntries)
|
|
52136
53065
|
sections.push(oaEntries);
|
|
52137
|
-
const legacyMemDir =
|
|
52138
|
-
if (legacyMemDir !== oaMemDir &&
|
|
53066
|
+
const legacyMemDir = join60(repoRoot, ".open-agents", "memory");
|
|
53067
|
+
if (legacyMemDir !== oaMemDir && existsSync44(legacyMemDir)) {
|
|
52139
53068
|
const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
|
|
52140
53069
|
if (legacyEntries)
|
|
52141
53070
|
sections.push(legacyEntries);
|
|
52142
53071
|
}
|
|
52143
|
-
const globalMemDir =
|
|
53072
|
+
const globalMemDir = join60(homedir17(), ".open-agents", "memory");
|
|
52144
53073
|
const globalEntries = loadMemoryDir(globalMemDir, "global");
|
|
52145
53074
|
if (globalEntries)
|
|
52146
53075
|
sections.push(globalEntries);
|
|
52147
53076
|
return sections.join("\n\n");
|
|
52148
53077
|
}
|
|
52149
53078
|
function loadMemoryDir(memDir, scope) {
|
|
52150
|
-
if (!
|
|
53079
|
+
if (!existsSync44(memDir))
|
|
52151
53080
|
return "";
|
|
52152
53081
|
const lines = [];
|
|
52153
53082
|
try {
|
|
52154
|
-
const files =
|
|
53083
|
+
const files = readdirSync14(memDir).filter((f) => f.endsWith(".json"));
|
|
52155
53084
|
for (const file of files.slice(0, 10)) {
|
|
52156
53085
|
try {
|
|
52157
|
-
const raw =
|
|
53086
|
+
const raw = readFileSync33(join60(memDir, file), "utf-8");
|
|
52158
53087
|
const entries = JSON.parse(raw);
|
|
52159
53088
|
const topic = basename12(file, ".json");
|
|
52160
53089
|
const keys = Object.keys(entries);
|
|
@@ -53294,8 +54223,8 @@ __export(banner_exports, {
|
|
|
53294
54223
|
saveBannerDesign: () => saveBannerDesign,
|
|
53295
54224
|
setGridText: () => setGridText
|
|
53296
54225
|
});
|
|
53297
|
-
import { existsSync as
|
|
53298
|
-
import { join as
|
|
54226
|
+
import { existsSync as existsSync45, readFileSync as readFileSync34, writeFileSync as writeFileSync21, mkdirSync as mkdirSync20 } from "node:fs";
|
|
54227
|
+
import { join as join61 } from "node:path";
|
|
53299
54228
|
function generateMnemonic(seed) {
|
|
53300
54229
|
let h = 2166136261;
|
|
53301
54230
|
for (let i = 0; i < seed.length; i++) {
|
|
@@ -53490,27 +54419,27 @@ function createSponsorBanner(sponsorName, tagline, primaryColor = 214, bgColor =
|
|
|
53490
54419
|
};
|
|
53491
54420
|
}
|
|
53492
54421
|
function saveBannerDesign(workDir, design) {
|
|
53493
|
-
const dir =
|
|
53494
|
-
|
|
53495
|
-
|
|
54422
|
+
const dir = join61(workDir, ".oa", "banners");
|
|
54423
|
+
mkdirSync20(dir, { recursive: true });
|
|
54424
|
+
writeFileSync21(join61(dir, `${design.id}.json`), JSON.stringify(design, null, 2), "utf8");
|
|
53496
54425
|
}
|
|
53497
54426
|
function loadBannerDesign(workDir, id) {
|
|
53498
|
-
const file =
|
|
53499
|
-
if (!
|
|
54427
|
+
const file = join61(workDir, ".oa", "banners", `${id}.json`);
|
|
54428
|
+
if (!existsSync45(file))
|
|
53500
54429
|
return null;
|
|
53501
54430
|
try {
|
|
53502
|
-
return JSON.parse(
|
|
54431
|
+
return JSON.parse(readFileSync34(file, "utf8"));
|
|
53503
54432
|
} catch {
|
|
53504
54433
|
return null;
|
|
53505
54434
|
}
|
|
53506
54435
|
}
|
|
53507
54436
|
function listBannerDesigns(workDir) {
|
|
53508
|
-
const dir =
|
|
53509
|
-
if (!
|
|
54437
|
+
const dir = join61(workDir, ".oa", "banners");
|
|
54438
|
+
if (!existsSync45(dir))
|
|
53510
54439
|
return [];
|
|
53511
54440
|
try {
|
|
53512
|
-
const { readdirSync:
|
|
53513
|
-
return
|
|
54441
|
+
const { readdirSync: readdirSync24 } = __require("node:fs");
|
|
54442
|
+
return readdirSync24(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
|
|
53514
54443
|
} catch {
|
|
53515
54444
|
return [];
|
|
53516
54445
|
}
|
|
@@ -53864,22 +54793,22 @@ var init_banner = __esm({
|
|
|
53864
54793
|
});
|
|
53865
54794
|
|
|
53866
54795
|
// packages/cli/dist/tui/carousel-descriptors.js
|
|
53867
|
-
import { existsSync as
|
|
53868
|
-
import { join as
|
|
54796
|
+
import { existsSync as existsSync46, readFileSync as readFileSync35, writeFileSync as writeFileSync22, mkdirSync as mkdirSync21, readdirSync as readdirSync15 } from "node:fs";
|
|
54797
|
+
import { join as join62, basename as basename13 } from "node:path";
|
|
53869
54798
|
function loadToolProfile(repoRoot) {
|
|
53870
|
-
const filePath =
|
|
54799
|
+
const filePath = join62(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
|
|
53871
54800
|
try {
|
|
53872
|
-
if (!
|
|
54801
|
+
if (!existsSync46(filePath))
|
|
53873
54802
|
return null;
|
|
53874
|
-
return JSON.parse(
|
|
54803
|
+
return JSON.parse(readFileSync35(filePath, "utf-8"));
|
|
53875
54804
|
} catch {
|
|
53876
54805
|
return null;
|
|
53877
54806
|
}
|
|
53878
54807
|
}
|
|
53879
54808
|
function saveToolProfile(repoRoot, profile) {
|
|
53880
|
-
const contextDir =
|
|
53881
|
-
|
|
53882
|
-
|
|
54809
|
+
const contextDir = join62(repoRoot, OA_DIR, "context");
|
|
54810
|
+
mkdirSync21(contextDir, { recursive: true });
|
|
54811
|
+
writeFileSync22(join62(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
|
|
53883
54812
|
}
|
|
53884
54813
|
function categorizeToolCall(toolName) {
|
|
53885
54814
|
for (const cat of TOOL_CATEGORIES) {
|
|
@@ -53937,25 +54866,25 @@ function weightedColor(profile) {
|
|
|
53937
54866
|
return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
|
|
53938
54867
|
}
|
|
53939
54868
|
function loadCachedDescriptors(repoRoot) {
|
|
53940
|
-
const filePath =
|
|
54869
|
+
const filePath = join62(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
|
|
53941
54870
|
try {
|
|
53942
|
-
if (!
|
|
54871
|
+
if (!existsSync46(filePath))
|
|
53943
54872
|
return null;
|
|
53944
|
-
const cached = JSON.parse(
|
|
54873
|
+
const cached = JSON.parse(readFileSync35(filePath, "utf-8"));
|
|
53945
54874
|
return cached.phrases.length > 0 ? cached.phrases : null;
|
|
53946
54875
|
} catch {
|
|
53947
54876
|
return null;
|
|
53948
54877
|
}
|
|
53949
54878
|
}
|
|
53950
54879
|
function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
|
|
53951
|
-
const contextDir =
|
|
53952
|
-
|
|
54880
|
+
const contextDir = join62(repoRoot, OA_DIR, "context");
|
|
54881
|
+
mkdirSync21(contextDir, { recursive: true });
|
|
53953
54882
|
const cached = {
|
|
53954
54883
|
phrases,
|
|
53955
54884
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
53956
54885
|
sourceHash
|
|
53957
54886
|
};
|
|
53958
|
-
|
|
54887
|
+
writeFileSync22(join62(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
|
|
53959
54888
|
}
|
|
53960
54889
|
function generateDescriptors(repoRoot) {
|
|
53961
54890
|
const profile = loadToolProfile(repoRoot);
|
|
@@ -54003,11 +54932,11 @@ function generateDescriptors(repoRoot) {
|
|
|
54003
54932
|
return phrases;
|
|
54004
54933
|
}
|
|
54005
54934
|
function extractFromPackageJson(repoRoot, tags) {
|
|
54006
|
-
const pkgPath =
|
|
54935
|
+
const pkgPath = join62(repoRoot, "package.json");
|
|
54007
54936
|
try {
|
|
54008
|
-
if (!
|
|
54937
|
+
if (!existsSync46(pkgPath))
|
|
54009
54938
|
return;
|
|
54010
|
-
const pkg = JSON.parse(
|
|
54939
|
+
const pkg = JSON.parse(readFileSync35(pkgPath, "utf-8"));
|
|
54011
54940
|
if (pkg.name && typeof pkg.name === "string") {
|
|
54012
54941
|
const parts = pkg.name.replace(/^@/, "").split("/");
|
|
54013
54942
|
for (const p of parts)
|
|
@@ -54051,7 +54980,7 @@ function extractFromManifests(repoRoot, tags) {
|
|
|
54051
54980
|
{ file: ".github/workflows", tag: "ci/cd" }
|
|
54052
54981
|
];
|
|
54053
54982
|
for (const check of manifestChecks) {
|
|
54054
|
-
if (
|
|
54983
|
+
if (existsSync46(join62(repoRoot, check.file))) {
|
|
54055
54984
|
tags.push(check.tag);
|
|
54056
54985
|
}
|
|
54057
54986
|
}
|
|
@@ -54073,16 +55002,16 @@ function extractFromSessions(repoRoot, tags) {
|
|
|
54073
55002
|
}
|
|
54074
55003
|
}
|
|
54075
55004
|
function extractFromMemory(repoRoot, tags) {
|
|
54076
|
-
const memoryDir =
|
|
55005
|
+
const memoryDir = join62(repoRoot, OA_DIR, "memory");
|
|
54077
55006
|
try {
|
|
54078
|
-
if (!
|
|
55007
|
+
if (!existsSync46(memoryDir))
|
|
54079
55008
|
return;
|
|
54080
|
-
const files =
|
|
55009
|
+
const files = readdirSync15(memoryDir).filter((f) => f.endsWith(".json"));
|
|
54081
55010
|
for (const file of files) {
|
|
54082
55011
|
const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
|
|
54083
55012
|
tags.push(topic);
|
|
54084
55013
|
try {
|
|
54085
|
-
const data = JSON.parse(
|
|
55014
|
+
const data = JSON.parse(readFileSync35(join62(memoryDir, file), "utf-8"));
|
|
54086
55015
|
if (data && typeof data === "object") {
|
|
54087
55016
|
const keys = Object.keys(data).slice(0, 3);
|
|
54088
55017
|
for (const key of keys) {
|
|
@@ -54753,13 +55682,13 @@ var init_stream_renderer = __esm({
|
|
|
54753
55682
|
});
|
|
54754
55683
|
|
|
54755
55684
|
// packages/cli/dist/tui/edit-history.js
|
|
54756
|
-
import { appendFileSync as appendFileSync3, mkdirSync as
|
|
54757
|
-
import { join as
|
|
55685
|
+
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync22 } from "node:fs";
|
|
55686
|
+
import { join as join63 } from "node:path";
|
|
54758
55687
|
function createEditHistoryLogger(repoRoot, sessionId) {
|
|
54759
|
-
const historyDir =
|
|
54760
|
-
const logPath2 =
|
|
55688
|
+
const historyDir = join63(repoRoot, ".oa", "history");
|
|
55689
|
+
const logPath2 = join63(historyDir, "edits.jsonl");
|
|
54761
55690
|
try {
|
|
54762
|
-
|
|
55691
|
+
mkdirSync22(historyDir, { recursive: true });
|
|
54763
55692
|
} catch {
|
|
54764
55693
|
}
|
|
54765
55694
|
function logToolCall(toolName, toolArgs, success) {
|
|
@@ -54868,17 +55797,17 @@ var init_edit_history = __esm({
|
|
|
54868
55797
|
});
|
|
54869
55798
|
|
|
54870
55799
|
// packages/cli/dist/tui/promptLoader.js
|
|
54871
|
-
import { readFileSync as
|
|
54872
|
-
import { join as
|
|
54873
|
-
import { fileURLToPath as
|
|
55800
|
+
import { readFileSync as readFileSync36, existsSync as existsSync47 } from "node:fs";
|
|
55801
|
+
import { join as join64, dirname as dirname20 } from "node:path";
|
|
55802
|
+
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
54874
55803
|
function loadPrompt3(promptPath, vars) {
|
|
54875
55804
|
let content = cache3.get(promptPath);
|
|
54876
55805
|
if (content === void 0) {
|
|
54877
|
-
const fullPath =
|
|
54878
|
-
if (!
|
|
55806
|
+
const fullPath = join64(PROMPTS_DIR3, promptPath);
|
|
55807
|
+
if (!existsSync47(fullPath)) {
|
|
54879
55808
|
throw new Error(`Prompt file not found: ${fullPath}`);
|
|
54880
55809
|
}
|
|
54881
|
-
content =
|
|
55810
|
+
content = readFileSync36(fullPath, "utf-8");
|
|
54882
55811
|
cache3.set(promptPath, content);
|
|
54883
55812
|
}
|
|
54884
55813
|
if (!vars)
|
|
@@ -54889,25 +55818,25 @@ var __filename3, __dirname6, devPath2, publishedPath2, PROMPTS_DIR3, cache3;
|
|
|
54889
55818
|
var init_promptLoader3 = __esm({
|
|
54890
55819
|
"packages/cli/dist/tui/promptLoader.js"() {
|
|
54891
55820
|
"use strict";
|
|
54892
|
-
__filename3 =
|
|
54893
|
-
__dirname6 =
|
|
54894
|
-
devPath2 =
|
|
54895
|
-
publishedPath2 =
|
|
54896
|
-
PROMPTS_DIR3 =
|
|
55821
|
+
__filename3 = fileURLToPath12(import.meta.url);
|
|
55822
|
+
__dirname6 = dirname20(__filename3);
|
|
55823
|
+
devPath2 = join64(__dirname6, "..", "..", "prompts");
|
|
55824
|
+
publishedPath2 = join64(__dirname6, "..", "prompts");
|
|
55825
|
+
PROMPTS_DIR3 = existsSync47(devPath2) ? devPath2 : publishedPath2;
|
|
54897
55826
|
cache3 = /* @__PURE__ */ new Map();
|
|
54898
55827
|
}
|
|
54899
55828
|
});
|
|
54900
55829
|
|
|
54901
55830
|
// packages/cli/dist/tui/dream-engine.js
|
|
54902
|
-
import { mkdirSync as
|
|
54903
|
-
import { join as
|
|
54904
|
-
import { execSync as
|
|
55831
|
+
import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync23, readFileSync as readFileSync37, existsSync as existsSync48, cpSync, rmSync as rmSync2, readdirSync as readdirSync16 } from "node:fs";
|
|
55832
|
+
import { join as join65, basename as basename14 } from "node:path";
|
|
55833
|
+
import { execSync as execSync32 } from "node:child_process";
|
|
54905
55834
|
function loadAutoresearchMemory(repoRoot) {
|
|
54906
|
-
const memoryPath =
|
|
54907
|
-
if (!
|
|
55835
|
+
const memoryPath = join65(repoRoot, ".oa", "memory", "autoresearch.json");
|
|
55836
|
+
if (!existsSync48(memoryPath))
|
|
54908
55837
|
return "";
|
|
54909
55838
|
try {
|
|
54910
|
-
const raw =
|
|
55839
|
+
const raw = readFileSync37(memoryPath, "utf-8");
|
|
54911
55840
|
const data = JSON.parse(raw);
|
|
54912
55841
|
const sections = [];
|
|
54913
55842
|
for (const key of AUTORESEARCH_MEMORY_KEYS) {
|
|
@@ -55097,14 +56026,14 @@ var init_dream_engine = __esm({
|
|
|
55097
56026
|
const content = String(args["content"] ?? "");
|
|
55098
56027
|
if (!rawPath)
|
|
55099
56028
|
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
55100
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ?
|
|
56029
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join65(this.autoresearchDir, basename14(rawPath)) : join65(this.autoresearchDir, rawPath);
|
|
55101
56030
|
if (!targetPath.startsWith(this.autoresearchDir)) {
|
|
55102
56031
|
return { success: false, output: "", error: "Autoresearch mode: writes are confined to .oa/autoresearch/", durationMs: Date.now() - start };
|
|
55103
56032
|
}
|
|
55104
56033
|
try {
|
|
55105
|
-
const dir =
|
|
55106
|
-
|
|
55107
|
-
|
|
56034
|
+
const dir = join65(targetPath, "..");
|
|
56035
|
+
mkdirSync23(dir, { recursive: true });
|
|
56036
|
+
writeFileSync23(targetPath, content, "utf-8");
|
|
55108
56037
|
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
55109
56038
|
} catch (err) {
|
|
55110
56039
|
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
@@ -55132,20 +56061,20 @@ var init_dream_engine = __esm({
|
|
|
55132
56061
|
const rawPath = String(args["path"] ?? "");
|
|
55133
56062
|
const oldStr = String(args["old_string"] ?? "");
|
|
55134
56063
|
const newStr = String(args["new_string"] ?? "");
|
|
55135
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ?
|
|
56064
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join65(this.autoresearchDir, basename14(rawPath)) : join65(this.autoresearchDir, rawPath);
|
|
55136
56065
|
if (!targetPath.startsWith(this.autoresearchDir)) {
|
|
55137
56066
|
return { success: false, output: "", error: "Autoresearch mode: edits are confined to .oa/autoresearch/", durationMs: Date.now() - start };
|
|
55138
56067
|
}
|
|
55139
56068
|
try {
|
|
55140
|
-
if (!
|
|
56069
|
+
if (!existsSync48(targetPath)) {
|
|
55141
56070
|
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
55142
56071
|
}
|
|
55143
|
-
let content =
|
|
56072
|
+
let content = readFileSync37(targetPath, "utf-8");
|
|
55144
56073
|
if (!content.includes(oldStr)) {
|
|
55145
56074
|
return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
|
|
55146
56075
|
}
|
|
55147
56076
|
content = content.replace(oldStr, newStr);
|
|
55148
|
-
|
|
56077
|
+
writeFileSync23(targetPath, content, "utf-8");
|
|
55149
56078
|
return { success: true, output: `Edited ${rawPath}`, durationMs: Date.now() - start };
|
|
55150
56079
|
} catch (err) {
|
|
55151
56080
|
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
@@ -55186,14 +56115,14 @@ var init_dream_engine = __esm({
|
|
|
55186
56115
|
const content = String(args["content"] ?? "");
|
|
55187
56116
|
if (!rawPath)
|
|
55188
56117
|
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
55189
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
56118
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join65(this.dreamsDir, basename14(rawPath)) : join65(this.dreamsDir, rawPath);
|
|
55190
56119
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
55191
56120
|
return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
55192
56121
|
}
|
|
55193
56122
|
try {
|
|
55194
|
-
const dir =
|
|
55195
|
-
|
|
55196
|
-
|
|
56123
|
+
const dir = join65(targetPath, "..");
|
|
56124
|
+
mkdirSync23(dir, { recursive: true });
|
|
56125
|
+
writeFileSync23(targetPath, content, "utf-8");
|
|
55197
56126
|
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
55198
56127
|
} catch (err) {
|
|
55199
56128
|
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
@@ -55221,20 +56150,20 @@ var init_dream_engine = __esm({
|
|
|
55221
56150
|
const rawPath = String(args["path"] ?? "");
|
|
55222
56151
|
const oldStr = String(args["old_string"] ?? "");
|
|
55223
56152
|
const newStr = String(args["new_string"] ?? "");
|
|
55224
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
56153
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join65(this.dreamsDir, basename14(rawPath)) : join65(this.dreamsDir, rawPath);
|
|
55225
56154
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
55226
56155
|
return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
55227
56156
|
}
|
|
55228
56157
|
try {
|
|
55229
|
-
if (!
|
|
56158
|
+
if (!existsSync48(targetPath)) {
|
|
55230
56159
|
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
55231
56160
|
}
|
|
55232
|
-
let content =
|
|
56161
|
+
let content = readFileSync37(targetPath, "utf-8");
|
|
55233
56162
|
if (!content.includes(oldStr)) {
|
|
55234
56163
|
return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start };
|
|
55235
56164
|
}
|
|
55236
56165
|
content = content.replace(oldStr, newStr);
|
|
55237
|
-
|
|
56166
|
+
writeFileSync23(targetPath, content, "utf-8");
|
|
55238
56167
|
return { success: true, output: `Edited ${rawPath}`, durationMs: Date.now() - start };
|
|
55239
56168
|
} catch (err) {
|
|
55240
56169
|
return { success: false, output: "", error: String(err), durationMs: Date.now() - start };
|
|
@@ -55265,7 +56194,7 @@ var init_dream_engine = __esm({
|
|
|
55265
56194
|
}
|
|
55266
56195
|
}
|
|
55267
56196
|
try {
|
|
55268
|
-
const output =
|
|
56197
|
+
const output = execSync32(cmd, {
|
|
55269
56198
|
cwd: this.repoRoot,
|
|
55270
56199
|
timeout: 3e4,
|
|
55271
56200
|
encoding: "utf-8",
|
|
@@ -55288,7 +56217,7 @@ var init_dream_engine = __esm({
|
|
|
55288
56217
|
constructor(config, repoRoot) {
|
|
55289
56218
|
this.config = config;
|
|
55290
56219
|
this.repoRoot = repoRoot;
|
|
55291
|
-
this.dreamsDir =
|
|
56220
|
+
this.dreamsDir = join65(repoRoot, ".oa", "dreams");
|
|
55292
56221
|
this.state = {
|
|
55293
56222
|
mode: "default",
|
|
55294
56223
|
active: false,
|
|
@@ -55319,7 +56248,7 @@ var init_dream_engine = __esm({
|
|
|
55319
56248
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
55320
56249
|
results: []
|
|
55321
56250
|
};
|
|
55322
|
-
|
|
56251
|
+
mkdirSync23(this.dreamsDir, { recursive: true });
|
|
55323
56252
|
this.saveDreamState();
|
|
55324
56253
|
try {
|
|
55325
56254
|
for (let cycle = 1; cycle <= totalCycles; cycle++) {
|
|
@@ -55372,8 +56301,8 @@ ${result.summary}`;
|
|
|
55372
56301
|
if (mode !== "default" || cycle === totalCycles) {
|
|
55373
56302
|
renderDreamContraction(cycle);
|
|
55374
56303
|
const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
|
|
55375
|
-
const summaryPath =
|
|
55376
|
-
|
|
56304
|
+
const summaryPath = join65(this.dreamsDir, `cycle-${cycle}-summary.md`);
|
|
56305
|
+
writeFileSync23(summaryPath, cycleSummary, "utf-8");
|
|
55377
56306
|
}
|
|
55378
56307
|
if (mode === "lucid" && !this.abortController.signal.aborted) {
|
|
55379
56308
|
this.saveVersionCheckpoint(cycle);
|
|
@@ -55585,7 +56514,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
|
|
|
55585
56514
|
}
|
|
55586
56515
|
/** Build role-specific tool sets for swarm agents */
|
|
55587
56516
|
buildSwarmTools(role, _workspace) {
|
|
55588
|
-
const autoresearchDir =
|
|
56517
|
+
const autoresearchDir = join65(this.repoRoot, ".oa", "autoresearch");
|
|
55589
56518
|
const taskComplete = this.createSwarmTaskCompleteTool(role);
|
|
55590
56519
|
switch (role) {
|
|
55591
56520
|
case "researcher": {
|
|
@@ -55949,7 +56878,7 @@ INSTRUCTIONS:
|
|
|
55949
56878
|
2. Summarize the key learnings and next steps
|
|
55950
56879
|
|
|
55951
56880
|
Call task_complete with a human-readable summary of the autoresearch session.`, workspace, onEvent);
|
|
55952
|
-
const reportPath =
|
|
56881
|
+
const reportPath = join65(this.dreamsDir, `cycle-${cycleNum}-autoresearch-report.md`);
|
|
55953
56882
|
const report = `# Autoresearch Swarm Report \u2014 Cycle ${cycleNum}
|
|
55954
56883
|
|
|
55955
56884
|
**Date**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
@@ -55971,8 +56900,8 @@ ${summaryResult}
|
|
|
55971
56900
|
*Generated by open-agents autoresearch swarm*
|
|
55972
56901
|
`;
|
|
55973
56902
|
try {
|
|
55974
|
-
|
|
55975
|
-
|
|
56903
|
+
mkdirSync23(this.dreamsDir, { recursive: true });
|
|
56904
|
+
writeFileSync23(reportPath, report, "utf-8");
|
|
55976
56905
|
} catch {
|
|
55977
56906
|
}
|
|
55978
56907
|
renderSwarmComplete(workspace);
|
|
@@ -56038,29 +56967,29 @@ ${summaryResult}
|
|
|
56038
56967
|
}
|
|
56039
56968
|
/** Save workspace backup for lucid mode */
|
|
56040
56969
|
saveVersionCheckpoint(cycle) {
|
|
56041
|
-
const checkpointDir =
|
|
56970
|
+
const checkpointDir = join65(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
|
|
56042
56971
|
try {
|
|
56043
|
-
|
|
56972
|
+
mkdirSync23(checkpointDir, { recursive: true });
|
|
56044
56973
|
try {
|
|
56045
|
-
const gitStatus =
|
|
56974
|
+
const gitStatus = execSync32("git status --porcelain", {
|
|
56046
56975
|
cwd: this.repoRoot,
|
|
56047
56976
|
encoding: "utf-8",
|
|
56048
56977
|
timeout: 1e4
|
|
56049
56978
|
});
|
|
56050
|
-
const gitDiff =
|
|
56979
|
+
const gitDiff = execSync32("git diff", {
|
|
56051
56980
|
cwd: this.repoRoot,
|
|
56052
56981
|
encoding: "utf-8",
|
|
56053
56982
|
timeout: 1e4
|
|
56054
56983
|
});
|
|
56055
|
-
const gitHash =
|
|
56984
|
+
const gitHash = execSync32("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
|
|
56056
56985
|
cwd: this.repoRoot,
|
|
56057
56986
|
encoding: "utf-8",
|
|
56058
56987
|
timeout: 5e3
|
|
56059
56988
|
}).trim();
|
|
56060
|
-
|
|
56061
|
-
|
|
56062
|
-
|
|
56063
|
-
|
|
56989
|
+
writeFileSync23(join65(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
|
|
56990
|
+
writeFileSync23(join65(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
|
|
56991
|
+
writeFileSync23(join65(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
|
|
56992
|
+
writeFileSync23(join65(checkpointDir, "checkpoint.json"), JSON.stringify({
|
|
56064
56993
|
cycle,
|
|
56065
56994
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
56066
56995
|
gitHash,
|
|
@@ -56068,7 +56997,7 @@ ${summaryResult}
|
|
|
56068
56997
|
}, null, 2), "utf-8");
|
|
56069
56998
|
renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
|
|
56070
56999
|
} catch {
|
|
56071
|
-
|
|
57000
|
+
writeFileSync23(join65(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
|
|
56072
57001
|
renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
|
|
56073
57002
|
}
|
|
56074
57003
|
} catch (err) {
|
|
@@ -56105,7 +57034,7 @@ Each proposal includes implementation entrypoints and estimated effort.
|
|
|
56105
57034
|
/** Update the master proposal index */
|
|
56106
57035
|
updateProposalIndex() {
|
|
56107
57036
|
try {
|
|
56108
|
-
const files =
|
|
57037
|
+
const files = readdirSync16(this.dreamsDir).filter((f) => f.endsWith(".md") && f !== "PROPOSAL-INDEX.md" && f !== "dream-state.json").sort();
|
|
56109
57038
|
const index = `# Dream Proposals Index
|
|
56110
57039
|
|
|
56111
57040
|
**Last updated**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
@@ -56126,14 +57055,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
|
|
|
56126
57055
|
---
|
|
56127
57056
|
*Auto-generated by open-agents dream engine*
|
|
56128
57057
|
`;
|
|
56129
|
-
|
|
57058
|
+
writeFileSync23(join65(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
|
|
56130
57059
|
} catch {
|
|
56131
57060
|
}
|
|
56132
57061
|
}
|
|
56133
57062
|
/** Save dream state for resume/inspection */
|
|
56134
57063
|
saveDreamState() {
|
|
56135
57064
|
try {
|
|
56136
|
-
|
|
57065
|
+
writeFileSync23(join65(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
|
|
56137
57066
|
} catch {
|
|
56138
57067
|
}
|
|
56139
57068
|
}
|
|
@@ -56507,8 +57436,8 @@ var init_bless_engine = __esm({
|
|
|
56507
57436
|
});
|
|
56508
57437
|
|
|
56509
57438
|
// packages/cli/dist/tui/dmn-engine.js
|
|
56510
|
-
import { existsSync as
|
|
56511
|
-
import { join as
|
|
57439
|
+
import { existsSync as existsSync49, readFileSync as readFileSync38, writeFileSync as writeFileSync24, mkdirSync as mkdirSync24, readdirSync as readdirSync17, unlinkSync as unlinkSync10 } from "node:fs";
|
|
57440
|
+
import { join as join66, basename as basename15 } from "node:path";
|
|
56512
57441
|
function buildDMNGatherPrompt(recentTaskSummaries, dueReminders, attentionItems, memoryTopics, capabilities, competence, reflectionBuffer) {
|
|
56513
57442
|
const competenceReport = competence.length > 0 ? competence.map((c3) => {
|
|
56514
57443
|
const rate = c3.attempts > 0 ? Math.round(c3.successes / c3.attempts * 100) : 0;
|
|
@@ -56628,9 +57557,9 @@ var init_dmn_engine = __esm({
|
|
|
56628
57557
|
constructor(config, repoRoot) {
|
|
56629
57558
|
this.config = config;
|
|
56630
57559
|
this.repoRoot = repoRoot;
|
|
56631
|
-
this.stateDir =
|
|
56632
|
-
this.historyDir =
|
|
56633
|
-
|
|
57560
|
+
this.stateDir = join66(repoRoot, ".oa", "dmn");
|
|
57561
|
+
this.historyDir = join66(repoRoot, ".oa", "dmn", "cycles");
|
|
57562
|
+
mkdirSync24(this.historyDir, { recursive: true });
|
|
56634
57563
|
this.loadState();
|
|
56635
57564
|
}
|
|
56636
57565
|
get stats() {
|
|
@@ -57219,14 +58148,14 @@ OUTPUT: Call task_complete with JSON:
|
|
|
57219
58148
|
async gatherMemoryTopics() {
|
|
57220
58149
|
const topics = [];
|
|
57221
58150
|
const dirs = [
|
|
57222
|
-
|
|
57223
|
-
|
|
58151
|
+
join66(this.repoRoot, ".oa", "memory"),
|
|
58152
|
+
join66(this.repoRoot, ".open-agents", "memory")
|
|
57224
58153
|
];
|
|
57225
58154
|
for (const dir of dirs) {
|
|
57226
|
-
if (!
|
|
58155
|
+
if (!existsSync49(dir))
|
|
57227
58156
|
continue;
|
|
57228
58157
|
try {
|
|
57229
|
-
const files =
|
|
58158
|
+
const files = readdirSync17(dir).filter((f) => f.endsWith(".json"));
|
|
57230
58159
|
for (const f of files) {
|
|
57231
58160
|
const topic = basename15(f, ".json");
|
|
57232
58161
|
if (!topics.includes(topic))
|
|
@@ -57239,29 +58168,29 @@ OUTPUT: Call task_complete with JSON:
|
|
|
57239
58168
|
}
|
|
57240
58169
|
// ── State persistence ─────────────────────────────────────────────────
|
|
57241
58170
|
loadState() {
|
|
57242
|
-
const path =
|
|
57243
|
-
if (
|
|
58171
|
+
const path = join66(this.stateDir, "state.json");
|
|
58172
|
+
if (existsSync49(path)) {
|
|
57244
58173
|
try {
|
|
57245
|
-
this.state = JSON.parse(
|
|
58174
|
+
this.state = JSON.parse(readFileSync38(path, "utf-8"));
|
|
57246
58175
|
} catch {
|
|
57247
58176
|
}
|
|
57248
58177
|
}
|
|
57249
58178
|
}
|
|
57250
58179
|
saveState() {
|
|
57251
58180
|
try {
|
|
57252
|
-
|
|
58181
|
+
writeFileSync24(join66(this.stateDir, "state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
|
|
57253
58182
|
} catch {
|
|
57254
58183
|
}
|
|
57255
58184
|
}
|
|
57256
58185
|
saveCycleResult(result) {
|
|
57257
58186
|
try {
|
|
57258
58187
|
const filename = `cycle-${result.cycleNumber}-${Date.now()}.json`;
|
|
57259
|
-
|
|
57260
|
-
const files =
|
|
58188
|
+
writeFileSync24(join66(this.historyDir, filename), JSON.stringify(result, null, 2) + "\n", "utf-8");
|
|
58189
|
+
const files = readdirSync17(this.historyDir).filter((f) => f.startsWith("cycle-") && f.endsWith(".json")).sort();
|
|
57261
58190
|
if (files.length > 50) {
|
|
57262
58191
|
for (const old of files.slice(0, files.length - 50)) {
|
|
57263
58192
|
try {
|
|
57264
|
-
unlinkSync10(
|
|
58193
|
+
unlinkSync10(join66(this.historyDir, old));
|
|
57265
58194
|
} catch {
|
|
57266
58195
|
}
|
|
57267
58196
|
}
|
|
@@ -57274,8 +58203,8 @@ OUTPUT: Call task_complete with JSON:
|
|
|
57274
58203
|
});
|
|
57275
58204
|
|
|
57276
58205
|
// packages/cli/dist/tui/snr-engine.js
|
|
57277
|
-
import { existsSync as
|
|
57278
|
-
import { join as
|
|
58206
|
+
import { existsSync as existsSync50, readdirSync as readdirSync18, readFileSync as readFileSync39 } from "node:fs";
|
|
58207
|
+
import { join as join67, basename as basename16 } from "node:path";
|
|
57279
58208
|
function computeDPrime(signalScores, noiseScores) {
|
|
57280
58209
|
if (signalScores.length === 0 || noiseScores.length === 0)
|
|
57281
58210
|
return 0;
|
|
@@ -57515,20 +58444,20 @@ Call task_complete with the JSON array when done.`, onEvent)
|
|
|
57515
58444
|
loadMemoryEntries(topics) {
|
|
57516
58445
|
const entries = [];
|
|
57517
58446
|
const dirs = [
|
|
57518
|
-
|
|
57519
|
-
|
|
58447
|
+
join67(this.repoRoot, ".oa", "memory"),
|
|
58448
|
+
join67(this.repoRoot, ".open-agents", "memory")
|
|
57520
58449
|
];
|
|
57521
58450
|
for (const dir of dirs) {
|
|
57522
|
-
if (!
|
|
58451
|
+
if (!existsSync50(dir))
|
|
57523
58452
|
continue;
|
|
57524
58453
|
try {
|
|
57525
|
-
const files =
|
|
58454
|
+
const files = readdirSync18(dir).filter((f) => f.endsWith(".json"));
|
|
57526
58455
|
for (const f of files) {
|
|
57527
58456
|
const topic = basename16(f, ".json");
|
|
57528
58457
|
if (topics.length > 0 && !topics.includes(topic))
|
|
57529
58458
|
continue;
|
|
57530
58459
|
try {
|
|
57531
|
-
const data = JSON.parse(
|
|
58460
|
+
const data = JSON.parse(readFileSync39(join67(dir, f), "utf-8"));
|
|
57532
58461
|
for (const [key, val] of Object.entries(data)) {
|
|
57533
58462
|
const value = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
57534
58463
|
entries.push({ topic, key, value });
|
|
@@ -58095,8 +59024,8 @@ var init_tool_policy = __esm({
|
|
|
58095
59024
|
});
|
|
58096
59025
|
|
|
58097
59026
|
// packages/cli/dist/tui/telegram-bridge.js
|
|
58098
|
-
import { mkdirSync as
|
|
58099
|
-
import { join as
|
|
59027
|
+
import { mkdirSync as mkdirSync25, existsSync as existsSync51, unlinkSync as unlinkSync11, readdirSync as readdirSync19, statSync as statSync15 } from "node:fs";
|
|
59028
|
+
import { join as join68, resolve as resolve30 } from "node:path";
|
|
58100
59029
|
import { writeFile as writeFileAsync } from "node:fs/promises";
|
|
58101
59030
|
function convertMarkdownToTelegramHTML(md) {
|
|
58102
59031
|
let html = md;
|
|
@@ -58424,7 +59353,7 @@ with summary "no_reply" to silently skip without responding.
|
|
|
58424
59353
|
this.polling = true;
|
|
58425
59354
|
this.abortController = new AbortController();
|
|
58426
59355
|
try {
|
|
58427
|
-
|
|
59356
|
+
mkdirSync25(this.mediaCacheDir, { recursive: true });
|
|
58428
59357
|
} catch {
|
|
58429
59358
|
}
|
|
58430
59359
|
this.mediaCacheCleanupTimer = setInterval(() => this.cleanupMediaCache(), 5 * 60 * 1e3);
|
|
@@ -58861,7 +59790,7 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
|
|
|
58861
59790
|
return null;
|
|
58862
59791
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
58863
59792
|
const fileName = `${Date.now()}-${fileId.slice(0, 8)}${extension}`;
|
|
58864
|
-
const localPath =
|
|
59793
|
+
const localPath = join68(this.mediaCacheDir, fileName);
|
|
58865
59794
|
await writeFileAsync(localPath, buffer);
|
|
58866
59795
|
return localPath;
|
|
58867
59796
|
} catch {
|
|
@@ -59877,7 +60806,7 @@ __export(text_selection_exports, {
|
|
|
59877
60806
|
stripAnsi: () => stripAnsi3,
|
|
59878
60807
|
visibleLength: () => visibleLength
|
|
59879
60808
|
});
|
|
59880
|
-
import { execSync as
|
|
60809
|
+
import { execSync as execSync33 } from "node:child_process";
|
|
59881
60810
|
function stripAnsi3(s) {
|
|
59882
60811
|
return s.replace(/\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\)/g, "");
|
|
59883
60812
|
}
|
|
@@ -59888,16 +60817,16 @@ function copyText(text) {
|
|
|
59888
60817
|
try {
|
|
59889
60818
|
const platform6 = process.platform;
|
|
59890
60819
|
if (platform6 === "darwin") {
|
|
59891
|
-
|
|
60820
|
+
execSync33("pbcopy", { input: text, timeout: 3e3 });
|
|
59892
60821
|
return true;
|
|
59893
60822
|
}
|
|
59894
60823
|
if (platform6 === "win32") {
|
|
59895
|
-
|
|
60824
|
+
execSync33("clip", { input: text, timeout: 3e3 });
|
|
59896
60825
|
return true;
|
|
59897
60826
|
}
|
|
59898
60827
|
for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
|
|
59899
60828
|
try {
|
|
59900
|
-
|
|
60829
|
+
execSync33(tool, { input: text, timeout: 3e3 });
|
|
59901
60830
|
return true;
|
|
59902
60831
|
} catch {
|
|
59903
60832
|
continue;
|
|
@@ -59906,10 +60835,10 @@ function copyText(text) {
|
|
|
59906
60835
|
if (!_clipboardAutoInstallAttempted) {
|
|
59907
60836
|
_clipboardAutoInstallAttempted = true;
|
|
59908
60837
|
try {
|
|
59909
|
-
|
|
60838
|
+
execSync33("which apt-get", { timeout: 2e3, stdio: "pipe" });
|
|
59910
60839
|
try {
|
|
59911
|
-
|
|
59912
|
-
|
|
60840
|
+
execSync33("sudo -n apt-get install -y xclip 2>/dev/null", { timeout: 15e3, stdio: "pipe" });
|
|
60841
|
+
execSync33("xclip -selection clipboard", { input: text, timeout: 3e3 });
|
|
59913
60842
|
return true;
|
|
59914
60843
|
} catch {
|
|
59915
60844
|
}
|
|
@@ -60217,7 +61146,7 @@ var init_text_selection = __esm({
|
|
|
60217
61146
|
});
|
|
60218
61147
|
|
|
60219
61148
|
// packages/cli/dist/tui/status-bar.js
|
|
60220
|
-
import { readFileSync as
|
|
61149
|
+
import { readFileSync as readFileSync40 } from "node:fs";
|
|
60221
61150
|
function setTerminalTitle(task, version) {
|
|
60222
61151
|
if (!process.stdout.isTTY)
|
|
60223
61152
|
return;
|
|
@@ -60914,7 +61843,7 @@ var init_status_bar = __esm({
|
|
|
60914
61843
|
if (nexusDir) {
|
|
60915
61844
|
try {
|
|
60916
61845
|
const metricsPath = nexusDir + "/remote-metrics.json";
|
|
60917
|
-
const raw =
|
|
61846
|
+
const raw = readFileSync40(metricsPath, "utf8");
|
|
60918
61847
|
const cached = JSON.parse(raw);
|
|
60919
61848
|
if (cached && cached.ts && Date.now() - cached.ts < 6e4) {
|
|
60920
61849
|
const m = cached.data;
|
|
@@ -63207,24 +64136,24 @@ var init_direct_input = __esm({
|
|
|
63207
64136
|
});
|
|
63208
64137
|
|
|
63209
64138
|
// packages/cli/dist/api/profiles.js
|
|
63210
|
-
import { existsSync as
|
|
63211
|
-
import { join as
|
|
63212
|
-
import { homedir as
|
|
64139
|
+
import { existsSync as existsSync52, readFileSync as readFileSync41, writeFileSync as writeFileSync25, mkdirSync as mkdirSync26, readdirSync as readdirSync20, unlinkSync as unlinkSync12 } from "node:fs";
|
|
64140
|
+
import { join as join69 } from "node:path";
|
|
64141
|
+
import { homedir as homedir18 } from "node:os";
|
|
63213
64142
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes15, scryptSync as scryptSync3, createHash as createHash5 } from "node:crypto";
|
|
63214
64143
|
function globalProfileDir() {
|
|
63215
|
-
return
|
|
64144
|
+
return join69(homedir18(), ".open-agents", "profiles");
|
|
63216
64145
|
}
|
|
63217
64146
|
function projectProfileDir(projectDir) {
|
|
63218
|
-
return
|
|
64147
|
+
return join69(projectDir || process.cwd(), ".oa", "profiles");
|
|
63219
64148
|
}
|
|
63220
64149
|
function listProfiles(projectDir) {
|
|
63221
64150
|
const result = [];
|
|
63222
64151
|
const seen = /* @__PURE__ */ new Set();
|
|
63223
64152
|
const projDir = projectProfileDir(projectDir);
|
|
63224
|
-
if (
|
|
63225
|
-
for (const f of
|
|
64153
|
+
if (existsSync52(projDir)) {
|
|
64154
|
+
for (const f of readdirSync20(projDir).filter((f2) => f2.endsWith(".json"))) {
|
|
63226
64155
|
try {
|
|
63227
|
-
const raw = JSON.parse(
|
|
64156
|
+
const raw = JSON.parse(readFileSync41(join69(projDir, f), "utf8"));
|
|
63228
64157
|
const name = f.replace(".json", "");
|
|
63229
64158
|
seen.add(name);
|
|
63230
64159
|
result.push({
|
|
@@ -63238,13 +64167,13 @@ function listProfiles(projectDir) {
|
|
|
63238
64167
|
}
|
|
63239
64168
|
}
|
|
63240
64169
|
const globDir = globalProfileDir();
|
|
63241
|
-
if (
|
|
63242
|
-
for (const f of
|
|
64170
|
+
if (existsSync52(globDir)) {
|
|
64171
|
+
for (const f of readdirSync20(globDir).filter((f2) => f2.endsWith(".json"))) {
|
|
63243
64172
|
const name = f.replace(".json", "");
|
|
63244
64173
|
if (seen.has(name))
|
|
63245
64174
|
continue;
|
|
63246
64175
|
try {
|
|
63247
|
-
const raw = JSON.parse(
|
|
64176
|
+
const raw = JSON.parse(readFileSync41(join69(globDir, f), "utf8"));
|
|
63248
64177
|
result.push({
|
|
63249
64178
|
name,
|
|
63250
64179
|
description: raw.description || "",
|
|
@@ -63259,12 +64188,12 @@ function listProfiles(projectDir) {
|
|
|
63259
64188
|
}
|
|
63260
64189
|
function loadProfile(name, password, projectDir) {
|
|
63261
64190
|
const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
63262
|
-
const projPath =
|
|
63263
|
-
const globPath =
|
|
63264
|
-
const filePath =
|
|
64191
|
+
const projPath = join69(projectProfileDir(projectDir), `${sanitized}.json`);
|
|
64192
|
+
const globPath = join69(globalProfileDir(), `${sanitized}.json`);
|
|
64193
|
+
const filePath = existsSync52(projPath) ? projPath : existsSync52(globPath) ? globPath : null;
|
|
63265
64194
|
if (!filePath)
|
|
63266
64195
|
return null;
|
|
63267
|
-
const raw = JSON.parse(
|
|
64196
|
+
const raw = JSON.parse(readFileSync41(filePath, "utf8"));
|
|
63268
64197
|
if (raw.encrypted === true) {
|
|
63269
64198
|
if (!password)
|
|
63270
64199
|
return null;
|
|
@@ -63274,23 +64203,23 @@ function loadProfile(name, password, projectDir) {
|
|
|
63274
64203
|
}
|
|
63275
64204
|
function saveProfile(profile, password, scope = "global", projectDir) {
|
|
63276
64205
|
const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
|
|
63277
|
-
|
|
64206
|
+
mkdirSync26(dir, { recursive: true });
|
|
63278
64207
|
const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
63279
|
-
const filePath =
|
|
64208
|
+
const filePath = join69(dir, `${sanitized}.json`);
|
|
63280
64209
|
profile.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
63281
64210
|
if (password) {
|
|
63282
64211
|
const encrypted = encryptProfile(profile, password);
|
|
63283
|
-
|
|
64212
|
+
writeFileSync25(filePath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
63284
64213
|
} else {
|
|
63285
64214
|
profile.encrypted = false;
|
|
63286
|
-
|
|
64215
|
+
writeFileSync25(filePath, JSON.stringify(profile, null, 2), { mode: 420 });
|
|
63287
64216
|
}
|
|
63288
64217
|
}
|
|
63289
64218
|
function deleteProfile(name, scope = "global", projectDir) {
|
|
63290
64219
|
const sanitized = name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
63291
64220
|
const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
|
|
63292
|
-
const filePath =
|
|
63293
|
-
if (
|
|
64221
|
+
const filePath = join69(dir, `${sanitized}.json`);
|
|
64222
|
+
if (existsSync52(filePath)) {
|
|
63294
64223
|
unlinkSync12(filePath);
|
|
63295
64224
|
return true;
|
|
63296
64225
|
}
|
|
@@ -63382,23 +64311,23 @@ __export(serve_exports, {
|
|
|
63382
64311
|
import * as http from "node:http";
|
|
63383
64312
|
import * as https from "node:https";
|
|
63384
64313
|
import { createRequire as createRequire3 } from "node:module";
|
|
63385
|
-
import { fileURLToPath as
|
|
63386
|
-
import { dirname as
|
|
63387
|
-
import { spawn as
|
|
63388
|
-
import { mkdirSync as
|
|
64314
|
+
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
64315
|
+
import { dirname as dirname21, join as join70, resolve as resolve31 } from "node:path";
|
|
64316
|
+
import { spawn as spawn21 } from "node:child_process";
|
|
64317
|
+
import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync26, readFileSync as readFileSync42, readdirSync as readdirSync21, existsSync as existsSync53 } from "node:fs";
|
|
63389
64318
|
import { randomBytes as randomBytes16 } from "node:crypto";
|
|
63390
64319
|
function getVersion3() {
|
|
63391
64320
|
try {
|
|
63392
64321
|
const require2 = createRequire3(import.meta.url);
|
|
63393
|
-
const thisDir =
|
|
64322
|
+
const thisDir = dirname21(fileURLToPath13(import.meta.url));
|
|
63394
64323
|
const candidates = [
|
|
63395
|
-
|
|
63396
|
-
|
|
63397
|
-
|
|
64324
|
+
join70(thisDir, "..", "package.json"),
|
|
64325
|
+
join70(thisDir, "..", "..", "package.json"),
|
|
64326
|
+
join70(thisDir, "..", "..", "..", "package.json")
|
|
63398
64327
|
];
|
|
63399
64328
|
for (const pkgPath of candidates) {
|
|
63400
64329
|
try {
|
|
63401
|
-
if (!
|
|
64330
|
+
if (!existsSync53(pkgPath))
|
|
63402
64331
|
continue;
|
|
63403
64332
|
const pkg = require2(pkgPath);
|
|
63404
64333
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
@@ -63693,29 +64622,29 @@ function ollamaStream(ollamaUrl, path, method, body, onData, onEnd, onError) {
|
|
|
63693
64622
|
}
|
|
63694
64623
|
function jobsDir() {
|
|
63695
64624
|
const root = resolve31(process.cwd());
|
|
63696
|
-
const dir =
|
|
63697
|
-
|
|
64625
|
+
const dir = join70(root, ".oa", "jobs");
|
|
64626
|
+
mkdirSync27(dir, { recursive: true });
|
|
63698
64627
|
return dir;
|
|
63699
64628
|
}
|
|
63700
64629
|
function loadJob(id) {
|
|
63701
|
-
const file =
|
|
63702
|
-
if (!
|
|
64630
|
+
const file = join70(jobsDir(), `${id}.json`);
|
|
64631
|
+
if (!existsSync53(file))
|
|
63703
64632
|
return null;
|
|
63704
64633
|
try {
|
|
63705
|
-
return JSON.parse(
|
|
64634
|
+
return JSON.parse(readFileSync42(file, "utf-8"));
|
|
63706
64635
|
} catch {
|
|
63707
64636
|
return null;
|
|
63708
64637
|
}
|
|
63709
64638
|
}
|
|
63710
64639
|
function listJobs() {
|
|
63711
64640
|
const dir = jobsDir();
|
|
63712
|
-
if (!
|
|
64641
|
+
if (!existsSync53(dir))
|
|
63713
64642
|
return [];
|
|
63714
|
-
const files =
|
|
64643
|
+
const files = readdirSync21(dir).filter((f) => f.endsWith(".json")).sort();
|
|
63715
64644
|
const jobs = [];
|
|
63716
64645
|
for (const file of files) {
|
|
63717
64646
|
try {
|
|
63718
|
-
jobs.push(JSON.parse(
|
|
64647
|
+
jobs.push(JSON.parse(readFileSync42(join70(dir, file), "utf-8")));
|
|
63719
64648
|
} catch {
|
|
63720
64649
|
}
|
|
63721
64650
|
}
|
|
@@ -64108,8 +65037,8 @@ async function handleV1Run(req, res) {
|
|
|
64108
65037
|
if (workingDir) {
|
|
64109
65038
|
cwd4 = resolve31(workingDir);
|
|
64110
65039
|
} else if (isolate) {
|
|
64111
|
-
const wsDir =
|
|
64112
|
-
|
|
65040
|
+
const wsDir = join70(dir, "..", "workspaces", id);
|
|
65041
|
+
mkdirSync27(wsDir, { recursive: true });
|
|
64113
65042
|
cwd4 = wsDir;
|
|
64114
65043
|
} else {
|
|
64115
65044
|
cwd4 = resolve31(process.cwd());
|
|
@@ -64173,7 +65102,7 @@ async function handleV1Run(req, res) {
|
|
|
64173
65102
|
}
|
|
64174
65103
|
}
|
|
64175
65104
|
}
|
|
64176
|
-
const child =
|
|
65105
|
+
const child = spawn21("node", [oaBin, ...args], {
|
|
64177
65106
|
cwd: cwd4,
|
|
64178
65107
|
env: runEnv,
|
|
64179
65108
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -64181,7 +65110,7 @@ async function handleV1Run(req, res) {
|
|
|
64181
65110
|
});
|
|
64182
65111
|
child.unref();
|
|
64183
65112
|
job.pid = child.pid ?? 0;
|
|
64184
|
-
|
|
65113
|
+
writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
64185
65114
|
runningProcesses.set(id, child);
|
|
64186
65115
|
if (streamMode) {
|
|
64187
65116
|
res.writeHead(200, {
|
|
@@ -64211,7 +65140,7 @@ async function handleV1Run(req, res) {
|
|
|
64211
65140
|
job.status = code === 0 ? "completed" : "failed";
|
|
64212
65141
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64213
65142
|
try {
|
|
64214
|
-
|
|
65143
|
+
writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
64215
65144
|
} catch {
|
|
64216
65145
|
}
|
|
64217
65146
|
runningProcesses.delete(id);
|
|
@@ -64242,7 +65171,7 @@ async function handleV1Run(req, res) {
|
|
|
64242
65171
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64243
65172
|
}
|
|
64244
65173
|
try {
|
|
64245
|
-
|
|
65174
|
+
writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
64246
65175
|
} catch {
|
|
64247
65176
|
}
|
|
64248
65177
|
runningProcesses.delete(id);
|
|
@@ -64283,7 +65212,7 @@ function handleV1RunsDelete(res, id) {
|
|
|
64283
65212
|
job.error = "Aborted via API";
|
|
64284
65213
|
const dir = jobsDir();
|
|
64285
65214
|
try {
|
|
64286
|
-
|
|
65215
|
+
writeFileSync26(join70(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
64287
65216
|
} catch {
|
|
64288
65217
|
}
|
|
64289
65218
|
runningProcesses.delete(id);
|
|
@@ -64395,7 +65324,7 @@ async function handlePostCommand(res, cmd) {
|
|
|
64395
65324
|
return;
|
|
64396
65325
|
}
|
|
64397
65326
|
try {
|
|
64398
|
-
const child =
|
|
65327
|
+
const child = spawn21("node", [oaBin, "run", `/${cmd}`, "--json"], {
|
|
64399
65328
|
env: { ...process.env, __OPEN_AGENTS_NO_AUTO_RUN: "" },
|
|
64400
65329
|
stdio: ["ignore", "pipe", "pipe"],
|
|
64401
65330
|
timeout: 3e4
|
|
@@ -64808,13 +65737,13 @@ var init_serve = __esm({
|
|
|
64808
65737
|
|
|
64809
65738
|
// packages/cli/dist/tui/interactive.js
|
|
64810
65739
|
import { cwd } from "node:process";
|
|
64811
|
-
import { resolve as resolve32, join as
|
|
65740
|
+
import { resolve as resolve32, join as join71, dirname as dirname22, extname as extname11 } from "node:path";
|
|
64812
65741
|
import { createRequire as createRequire4 } from "node:module";
|
|
64813
|
-
import { fileURLToPath as
|
|
64814
|
-
import { readFileSync as
|
|
64815
|
-
import { existsSync as
|
|
64816
|
-
import { execSync as
|
|
64817
|
-
import { homedir as
|
|
65742
|
+
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
65743
|
+
import { readFileSync as readFileSync43, writeFileSync as writeFileSync27, appendFileSync as appendFileSync4, rmSync as rmSync3, readdirSync as readdirSync22, mkdirSync as mkdirSync28 } from "node:fs";
|
|
65744
|
+
import { existsSync as existsSync54 } from "node:fs";
|
|
65745
|
+
import { execSync as execSync34 } from "node:child_process";
|
|
65746
|
+
import { homedir as homedir19 } from "node:os";
|
|
64818
65747
|
function formatTimeAgo(date) {
|
|
64819
65748
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
64820
65749
|
if (seconds < 60)
|
|
@@ -64831,14 +65760,14 @@ function formatTimeAgo(date) {
|
|
|
64831
65760
|
function getVersion4() {
|
|
64832
65761
|
try {
|
|
64833
65762
|
const require2 = createRequire4(import.meta.url);
|
|
64834
|
-
const thisDir =
|
|
65763
|
+
const thisDir = dirname22(fileURLToPath14(import.meta.url));
|
|
64835
65764
|
const candidates = [
|
|
64836
|
-
|
|
64837
|
-
|
|
64838
|
-
|
|
65765
|
+
join71(thisDir, "..", "package.json"),
|
|
65766
|
+
join71(thisDir, "..", "..", "package.json"),
|
|
65767
|
+
join71(thisDir, "..", "..", "..", "package.json")
|
|
64839
65768
|
];
|
|
64840
65769
|
for (const pkgPath of candidates) {
|
|
64841
|
-
if (
|
|
65770
|
+
if (existsSync54(pkgPath)) {
|
|
64842
65771
|
const pkg = require2(pkgPath);
|
|
64843
65772
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
64844
65773
|
return pkg.version ?? "0.0.0";
|
|
@@ -65074,15 +66003,15 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
|
|
|
65074
66003
|
function gatherMemorySnippets(root) {
|
|
65075
66004
|
const snippets = [];
|
|
65076
66005
|
const dirs = [
|
|
65077
|
-
|
|
65078
|
-
|
|
66006
|
+
join71(root, ".oa", "memory"),
|
|
66007
|
+
join71(root, ".open-agents", "memory")
|
|
65079
66008
|
];
|
|
65080
66009
|
for (const dir of dirs) {
|
|
65081
|
-
if (!
|
|
66010
|
+
if (!existsSync54(dir))
|
|
65082
66011
|
continue;
|
|
65083
66012
|
try {
|
|
65084
|
-
for (const f of
|
|
65085
|
-
const data = JSON.parse(
|
|
66013
|
+
for (const f of readdirSync22(dir).filter((f2) => f2.endsWith(".json"))) {
|
|
66014
|
+
const data = JSON.parse(readFileSync43(join71(dir, f), "utf-8"));
|
|
65086
66015
|
for (const val of Object.values(data)) {
|
|
65087
66016
|
const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
65088
66017
|
if (v.length > 10)
|
|
@@ -65239,9 +66168,9 @@ ${metabolismMemories}
|
|
|
65239
66168
|
} catch {
|
|
65240
66169
|
}
|
|
65241
66170
|
try {
|
|
65242
|
-
const archeFile =
|
|
65243
|
-
if (
|
|
65244
|
-
const variants = JSON.parse(
|
|
66171
|
+
const archeFile = join71(repoRoot, ".oa", "arche", "variants.json");
|
|
66172
|
+
if (existsSync54(archeFile)) {
|
|
66173
|
+
const variants = JSON.parse(readFileSync43(archeFile, "utf8"));
|
|
65245
66174
|
if (variants.length > 0) {
|
|
65246
66175
|
let filtered = variants;
|
|
65247
66176
|
if (taskType) {
|
|
@@ -65410,9 +66339,9 @@ RULES:
|
|
|
65410
66339
|
const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
|
|
65411
66340
|
let identityInjection = "";
|
|
65412
66341
|
try {
|
|
65413
|
-
const ikStateFile =
|
|
65414
|
-
if (
|
|
65415
|
-
const selfState = JSON.parse(
|
|
66342
|
+
const ikStateFile = join71(repoRoot, ".oa", "identity", "self-state.json");
|
|
66343
|
+
if (existsSync54(ikStateFile)) {
|
|
66344
|
+
const selfState = JSON.parse(readFileSync43(ikStateFile, "utf8"));
|
|
65416
66345
|
const lines = [
|
|
65417
66346
|
`[Identity State v${selfState.version}]`,
|
|
65418
66347
|
`Self: ${selfState.narrative_summary}`,
|
|
@@ -66055,13 +66984,13 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
66055
66984
|
});
|
|
66056
66985
|
}
|
|
66057
66986
|
try {
|
|
66058
|
-
const ikDir =
|
|
66059
|
-
const ikFile =
|
|
66987
|
+
const ikDir = join71(repoRoot, ".oa", "identity");
|
|
66988
|
+
const ikFile = join71(ikDir, "self-state.json");
|
|
66060
66989
|
let ikState;
|
|
66061
|
-
if (
|
|
66062
|
-
ikState = JSON.parse(
|
|
66990
|
+
if (existsSync54(ikFile)) {
|
|
66991
|
+
ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
|
|
66063
66992
|
} else {
|
|
66064
|
-
|
|
66993
|
+
mkdirSync28(ikDir, { recursive: true });
|
|
66065
66994
|
const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
66066
66995
|
ikState = {
|
|
66067
66996
|
self_id: `oa-${machineId}`,
|
|
@@ -66087,7 +67016,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
66087
67016
|
}
|
|
66088
67017
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
66089
67018
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
66090
|
-
|
|
67019
|
+
writeFileSync27(ikFile, JSON.stringify(ikState, null, 2));
|
|
66091
67020
|
} catch (ikErr) {
|
|
66092
67021
|
try {
|
|
66093
67022
|
console.error("[IK-OBSERVE]", ikErr);
|
|
@@ -66102,14 +67031,14 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
66102
67031
|
} else {
|
|
66103
67032
|
renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
|
|
66104
67033
|
try {
|
|
66105
|
-
const ikFile =
|
|
66106
|
-
if (
|
|
66107
|
-
const ikState = JSON.parse(
|
|
67034
|
+
const ikFile = join71(repoRoot, ".oa", "identity", "self-state.json");
|
|
67035
|
+
if (existsSync54(ikFile)) {
|
|
67036
|
+
const ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
|
|
66108
67037
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
66109
67038
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
66110
67039
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
66111
67040
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
66112
|
-
|
|
67041
|
+
writeFileSync27(ikFile, JSON.stringify(ikState, null, 2));
|
|
66113
67042
|
}
|
|
66114
67043
|
} catch {
|
|
66115
67044
|
}
|
|
@@ -66206,10 +67135,10 @@ async function startInteractive(config, repoPath) {
|
|
|
66206
67135
|
process.stdin.pause();
|
|
66207
67136
|
}
|
|
66208
67137
|
try {
|
|
66209
|
-
const oaDir =
|
|
66210
|
-
const nexusPidFile =
|
|
66211
|
-
if (
|
|
66212
|
-
const pid = parseInt(
|
|
67138
|
+
const oaDir = join71(repoRoot, ".oa");
|
|
67139
|
+
const nexusPidFile = join71(oaDir, "nexus", "daemon.pid");
|
|
67140
|
+
if (existsSync54(nexusPidFile)) {
|
|
67141
|
+
const pid = parseInt(readFileSync43(nexusPidFile, "utf8").trim(), 10);
|
|
66213
67142
|
if (pid > 0) {
|
|
66214
67143
|
try {
|
|
66215
67144
|
process.kill(pid, 0);
|
|
@@ -66518,7 +67447,7 @@ Review its full output in the [${id}] tab or via full_sub_agent(action='output',
|
|
|
66518
67447
|
let p2pGateway = null;
|
|
66519
67448
|
let peerMesh = null;
|
|
66520
67449
|
let inferenceRouter = null;
|
|
66521
|
-
const secretVault = new SecretVault(
|
|
67450
|
+
const secretVault = new SecretVault(join71(repoRoot, ".oa", "vault.enc"));
|
|
66522
67451
|
let adminSessionKey = null;
|
|
66523
67452
|
const callSubAgents = /* @__PURE__ */ new Map();
|
|
66524
67453
|
const streamRenderer = new StreamRenderer();
|
|
@@ -66741,13 +67670,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
66741
67670
|
const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
|
|
66742
67671
|
return [hits, line];
|
|
66743
67672
|
}
|
|
66744
|
-
const HISTORY_DIR =
|
|
66745
|
-
const HISTORY_FILE =
|
|
67673
|
+
const HISTORY_DIR = join71(homedir19(), ".open-agents");
|
|
67674
|
+
const HISTORY_FILE = join71(HISTORY_DIR, "repl-history");
|
|
66746
67675
|
const MAX_HISTORY_LINES = 500;
|
|
66747
67676
|
let savedHistory = [];
|
|
66748
67677
|
try {
|
|
66749
|
-
if (
|
|
66750
|
-
const raw =
|
|
67678
|
+
if (existsSync54(HISTORY_FILE)) {
|
|
67679
|
+
const raw = readFileSync43(HISTORY_FILE, "utf8").trim();
|
|
66751
67680
|
if (raw)
|
|
66752
67681
|
savedHistory = raw.split("\n").reverse();
|
|
66753
67682
|
}
|
|
@@ -66850,12 +67779,12 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
66850
67779
|
if (!line.trim())
|
|
66851
67780
|
return;
|
|
66852
67781
|
try {
|
|
66853
|
-
|
|
67782
|
+
mkdirSync28(HISTORY_DIR, { recursive: true });
|
|
66854
67783
|
appendFileSync4(HISTORY_FILE, line + "\n", "utf8");
|
|
66855
67784
|
if (Math.random() < 0.02) {
|
|
66856
|
-
const all =
|
|
67785
|
+
const all = readFileSync43(HISTORY_FILE, "utf8").trim().split("\n");
|
|
66857
67786
|
if (all.length > MAX_HISTORY_LINES) {
|
|
66858
|
-
|
|
67787
|
+
writeFileSync27(HISTORY_FILE, all.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
|
|
66859
67788
|
}
|
|
66860
67789
|
}
|
|
66861
67790
|
} catch {
|
|
@@ -67039,7 +67968,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
67039
67968
|
} catch {
|
|
67040
67969
|
}
|
|
67041
67970
|
try {
|
|
67042
|
-
const oaDir =
|
|
67971
|
+
const oaDir = join71(repoRoot, ".oa");
|
|
67043
67972
|
const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
|
|
67044
67973
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
67045
67974
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -67071,7 +68000,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
67071
68000
|
} catch {
|
|
67072
68001
|
}
|
|
67073
68002
|
try {
|
|
67074
|
-
const oaDir =
|
|
68003
|
+
const oaDir = join71(repoRoot, ".oa");
|
|
67075
68004
|
const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
|
|
67076
68005
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
67077
68006
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -67112,11 +68041,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
67112
68041
|
}
|
|
67113
68042
|
try {
|
|
67114
68043
|
const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
|
|
67115
|
-
const globalNamePath =
|
|
68044
|
+
const globalNamePath = join71(_hd(), ".open-agents", "agent-name");
|
|
67116
68045
|
let agName = "";
|
|
67117
68046
|
try {
|
|
67118
|
-
if (
|
|
67119
|
-
agName =
|
|
68047
|
+
if (existsSync54(globalNamePath))
|
|
68048
|
+
agName = readFileSync43(globalNamePath, "utf8").trim();
|
|
67120
68049
|
} catch {
|
|
67121
68050
|
}
|
|
67122
68051
|
if (!agName) {
|
|
@@ -67894,6 +68823,17 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
67894
68823
|
adminSessionKey = generateSessionKey();
|
|
67895
68824
|
}
|
|
67896
68825
|
voiceSession = new VoiceSession();
|
|
68826
|
+
try {
|
|
68827
|
+
const { isPersonaPlexRunning: isPersonaPlexRunning2, getPersonaPlexWSUrl: getPersonaPlexWSUrl2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
68828
|
+
if (isPersonaPlexRunning2()) {
|
|
68829
|
+
const ppUrl = getPersonaPlexWSUrl2();
|
|
68830
|
+
if (ppUrl) {
|
|
68831
|
+
voiceSession.personaPlexWsUrl = ppUrl;
|
|
68832
|
+
writeContent(() => renderInfo(`PersonaPlex active \u2014 full-duplex mode at ${ppUrl}`));
|
|
68833
|
+
}
|
|
68834
|
+
}
|
|
68835
|
+
} catch {
|
|
68836
|
+
}
|
|
67897
68837
|
const callState = {
|
|
67898
68838
|
transcribers: /* @__PURE__ */ new Map(),
|
|
67899
68839
|
loading: false,
|
|
@@ -68081,7 +69021,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
68081
69021
|
kind,
|
|
68082
69022
|
targetUrl,
|
|
68083
69023
|
authKey,
|
|
68084
|
-
stateDir:
|
|
69024
|
+
stateDir: join71(repoRoot, ".oa"),
|
|
68085
69025
|
passthrough: passthrough ?? false,
|
|
68086
69026
|
loadbalance: loadbalance ?? false,
|
|
68087
69027
|
endpointAuth: passthrough ? currentConfig.apiKey : void 0,
|
|
@@ -68129,7 +69069,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
68129
69069
|
await tunnelGateway.stop();
|
|
68130
69070
|
tunnelGateway = null;
|
|
68131
69071
|
}
|
|
68132
|
-
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir:
|
|
69072
|
+
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join71(repoRoot, ".oa") });
|
|
68133
69073
|
newTunnel.on("stats", (stats) => {
|
|
68134
69074
|
statusBar.setExposeStatus({
|
|
68135
69075
|
status: stats.status,
|
|
@@ -68401,15 +69341,15 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
68401
69341
|
writeContent(() => renderInfo(`Killed ${bgKilled} background task(s).`));
|
|
68402
69342
|
}
|
|
68403
69343
|
try {
|
|
68404
|
-
const nexusDir =
|
|
68405
|
-
const pidFile =
|
|
68406
|
-
if (
|
|
68407
|
-
const pid = parseInt(
|
|
69344
|
+
const nexusDir = join71(repoRoot, OA_DIR, "nexus");
|
|
69345
|
+
const pidFile = join71(nexusDir, "daemon.pid");
|
|
69346
|
+
if (existsSync54(pidFile)) {
|
|
69347
|
+
const pid = parseInt(readFileSync43(pidFile, "utf8").trim(), 10);
|
|
68408
69348
|
if (pid > 0) {
|
|
68409
69349
|
try {
|
|
68410
69350
|
if (process.platform === "win32") {
|
|
68411
69351
|
try {
|
|
68412
|
-
|
|
69352
|
+
execSync34(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
68413
69353
|
} catch {
|
|
68414
69354
|
}
|
|
68415
69355
|
} else {
|
|
@@ -68426,17 +69366,17 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
68426
69366
|
} catch {
|
|
68427
69367
|
}
|
|
68428
69368
|
try {
|
|
68429
|
-
const voiceDir2 =
|
|
69369
|
+
const voiceDir2 = join71(homedir19(), ".open-agents", "voice");
|
|
68430
69370
|
const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
|
|
68431
69371
|
for (const pf of voicePidFiles) {
|
|
68432
|
-
const pidPath =
|
|
68433
|
-
if (
|
|
69372
|
+
const pidPath = join71(voiceDir2, pf);
|
|
69373
|
+
if (existsSync54(pidPath)) {
|
|
68434
69374
|
try {
|
|
68435
|
-
const pid = parseInt(
|
|
69375
|
+
const pid = parseInt(readFileSync43(pidPath, "utf8").trim(), 10);
|
|
68436
69376
|
if (pid > 0) {
|
|
68437
69377
|
if (process.platform === "win32") {
|
|
68438
69378
|
try {
|
|
68439
|
-
|
|
69379
|
+
execSync34(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
68440
69380
|
} catch {
|
|
68441
69381
|
}
|
|
68442
69382
|
} else {
|
|
@@ -68453,11 +69393,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
68453
69393
|
} catch {
|
|
68454
69394
|
}
|
|
68455
69395
|
try {
|
|
68456
|
-
|
|
69396
|
+
execSync34(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
|
|
68457
69397
|
} catch {
|
|
68458
69398
|
}
|
|
68459
|
-
const oaPath =
|
|
68460
|
-
if (
|
|
69399
|
+
const oaPath = join71(repoRoot, OA_DIR);
|
|
69400
|
+
if (existsSync54(oaPath)) {
|
|
68461
69401
|
let deleted = false;
|
|
68462
69402
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
68463
69403
|
try {
|
|
@@ -68467,14 +69407,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
68467
69407
|
} catch (err) {
|
|
68468
69408
|
if (attempt < 2) {
|
|
68469
69409
|
try {
|
|
68470
|
-
|
|
69410
|
+
execSync34(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.3", { timeout: 3e3, stdio: "ignore" });
|
|
68471
69411
|
} catch {
|
|
68472
69412
|
}
|
|
68473
69413
|
} else {
|
|
68474
69414
|
writeContent(() => renderWarning(`Could not fully remove ${OA_DIR}/: ${err instanceof Error ? err.message : String(err)}`));
|
|
68475
69415
|
if (process.platform === "win32") {
|
|
68476
69416
|
try {
|
|
68477
|
-
|
|
69417
|
+
execSync34(`rd /s /q "${oaPath}"`, { timeout: 1e4, stdio: "ignore" });
|
|
68478
69418
|
deleted = true;
|
|
68479
69419
|
} catch {
|
|
68480
69420
|
}
|
|
@@ -68867,8 +69807,8 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
68867
69807
|
}
|
|
68868
69808
|
}
|
|
68869
69809
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
68870
|
-
const isImage = isImagePath(cleanPath) &&
|
|
68871
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) &&
|
|
69810
|
+
const isImage = isImagePath(cleanPath) && existsSync54(resolve32(repoRoot, cleanPath));
|
|
69811
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync54(resolve32(repoRoot, cleanPath));
|
|
68872
69812
|
if (activeTask) {
|
|
68873
69813
|
if (activeTask.runner.isPaused) {
|
|
68874
69814
|
activeTask.runner.resume();
|
|
@@ -68877,7 +69817,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
68877
69817
|
if (isImage) {
|
|
68878
69818
|
try {
|
|
68879
69819
|
const imgPath = resolve32(repoRoot, cleanPath);
|
|
68880
|
-
const imgBuffer =
|
|
69820
|
+
const imgBuffer = readFileSync43(imgPath);
|
|
68881
69821
|
const base64 = imgBuffer.toString("base64");
|
|
68882
69822
|
const ext = extname11(cleanPath).toLowerCase();
|
|
68883
69823
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -69405,13 +70345,13 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
69405
70345
|
const handle = startTask(task, config, repoRoot);
|
|
69406
70346
|
await handle.promise;
|
|
69407
70347
|
try {
|
|
69408
|
-
const ikDir =
|
|
69409
|
-
const ikFile =
|
|
70348
|
+
const ikDir = join71(repoRoot, ".oa", "identity");
|
|
70349
|
+
const ikFile = join71(ikDir, "self-state.json");
|
|
69410
70350
|
let ikState;
|
|
69411
|
-
if (
|
|
69412
|
-
ikState = JSON.parse(
|
|
70351
|
+
if (existsSync54(ikFile)) {
|
|
70352
|
+
ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
|
|
69413
70353
|
} else {
|
|
69414
|
-
|
|
70354
|
+
mkdirSync28(ikDir, { recursive: true });
|
|
69415
70355
|
ikState = {
|
|
69416
70356
|
self_id: `oa-${Date.now().toString(36)}`,
|
|
69417
70357
|
version: 1,
|
|
@@ -69433,7 +70373,7 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
69433
70373
|
ikState.homeostasis.coherence = Math.min(1, ikState.homeostasis.coherence + 0.05);
|
|
69434
70374
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
69435
70375
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
69436
|
-
|
|
70376
|
+
writeFileSync27(ikFile, JSON.stringify(ikState, null, 2));
|
|
69437
70377
|
} catch (ikErr) {
|
|
69438
70378
|
}
|
|
69439
70379
|
try {
|
|
@@ -69442,12 +70382,12 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
69442
70382
|
ec.archiveVariantSync(`Task: ${task.slice(0, 200)}`, "success \u2014 completed", ["general"]);
|
|
69443
70383
|
} catch {
|
|
69444
70384
|
try {
|
|
69445
|
-
const archeDir =
|
|
69446
|
-
const archeFile =
|
|
70385
|
+
const archeDir = join71(repoRoot, ".oa", "arche");
|
|
70386
|
+
const archeFile = join71(archeDir, "variants.json");
|
|
69447
70387
|
let variants = [];
|
|
69448
70388
|
try {
|
|
69449
|
-
if (
|
|
69450
|
-
variants = JSON.parse(
|
|
70389
|
+
if (existsSync54(archeFile))
|
|
70390
|
+
variants = JSON.parse(readFileSync43(archeFile, "utf8"));
|
|
69451
70391
|
} catch {
|
|
69452
70392
|
}
|
|
69453
70393
|
variants.push({
|
|
@@ -69462,15 +70402,15 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
69462
70402
|
});
|
|
69463
70403
|
if (variants.length > 50)
|
|
69464
70404
|
variants = variants.slice(-50);
|
|
69465
|
-
|
|
69466
|
-
|
|
70405
|
+
mkdirSync28(archeDir, { recursive: true });
|
|
70406
|
+
writeFileSync27(archeFile, JSON.stringify(variants, null, 2));
|
|
69467
70407
|
} catch {
|
|
69468
70408
|
}
|
|
69469
70409
|
}
|
|
69470
70410
|
try {
|
|
69471
|
-
const metaFile =
|
|
69472
|
-
if (
|
|
69473
|
-
const store = JSON.parse(
|
|
70411
|
+
const metaFile = join71(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
70412
|
+
if (existsSync54(metaFile)) {
|
|
70413
|
+
const store = JSON.parse(readFileSync43(metaFile, "utf8"));
|
|
69474
70414
|
const surfaced = store.filter((m) => m.type !== "quarantine" && m.scores?.confidence > 0.15).sort((a, b) => b.scores.utility * b.scores.confidence - a.scores.utility * a.scores.confidence).slice(0, 5);
|
|
69475
70415
|
let updated = false;
|
|
69476
70416
|
for (const item of surfaced) {
|
|
@@ -69481,7 +70421,7 @@ async function runWithTUI(task, config, repoPath) {
|
|
|
69481
70421
|
updated = true;
|
|
69482
70422
|
}
|
|
69483
70423
|
if (updated) {
|
|
69484
|
-
|
|
70424
|
+
writeFileSync27(metaFile, JSON.stringify(store, null, 2));
|
|
69485
70425
|
}
|
|
69486
70426
|
}
|
|
69487
70427
|
} catch {
|
|
@@ -69534,9 +70474,9 @@ Rules:
|
|
|
69534
70474
|
try {
|
|
69535
70475
|
const { initDb: initDb2 } = __require("@open-agents/memory");
|
|
69536
70476
|
const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
69537
|
-
const dbDir =
|
|
69538
|
-
|
|
69539
|
-
const db = initDb2(
|
|
70477
|
+
const dbDir = join71(repoRoot, ".oa", "memory");
|
|
70478
|
+
mkdirSync28(dbDir, { recursive: true });
|
|
70479
|
+
const db = initDb2(join71(dbDir, "structured.db"));
|
|
69540
70480
|
const memStore = new ProceduralMemoryStore2(db);
|
|
69541
70481
|
memStore.createWithEmbedding({
|
|
69542
70482
|
content: content.slice(0, 600),
|
|
@@ -69551,12 +70491,12 @@ Rules:
|
|
|
69551
70491
|
db.close();
|
|
69552
70492
|
} catch {
|
|
69553
70493
|
}
|
|
69554
|
-
const metaDir =
|
|
69555
|
-
const storeFile =
|
|
70494
|
+
const metaDir = join71(repoRoot, ".oa", "memory", "metabolism");
|
|
70495
|
+
const storeFile = join71(metaDir, "store.json");
|
|
69556
70496
|
let store = [];
|
|
69557
70497
|
try {
|
|
69558
|
-
if (
|
|
69559
|
-
store = JSON.parse(
|
|
70498
|
+
if (existsSync54(storeFile))
|
|
70499
|
+
store = JSON.parse(readFileSync43(storeFile, "utf8"));
|
|
69560
70500
|
} catch {
|
|
69561
70501
|
}
|
|
69562
70502
|
store.push({
|
|
@@ -69572,26 +70512,26 @@ Rules:
|
|
|
69572
70512
|
});
|
|
69573
70513
|
if (store.length > 100)
|
|
69574
70514
|
store = store.slice(-100);
|
|
69575
|
-
|
|
69576
|
-
|
|
70515
|
+
mkdirSync28(metaDir, { recursive: true });
|
|
70516
|
+
writeFileSync27(storeFile, JSON.stringify(store, null, 2));
|
|
69577
70517
|
}
|
|
69578
70518
|
}
|
|
69579
70519
|
} catch {
|
|
69580
70520
|
}
|
|
69581
70521
|
try {
|
|
69582
|
-
const cohereSettingsFile =
|
|
70522
|
+
const cohereSettingsFile = join71(repoRoot, ".oa", "settings.json");
|
|
69583
70523
|
let cohereActive = false;
|
|
69584
70524
|
try {
|
|
69585
|
-
if (
|
|
69586
|
-
const settings = JSON.parse(
|
|
70525
|
+
if (existsSync54(cohereSettingsFile)) {
|
|
70526
|
+
const settings = JSON.parse(readFileSync43(cohereSettingsFile, "utf8"));
|
|
69587
70527
|
cohereActive = settings.cohere === true;
|
|
69588
70528
|
}
|
|
69589
70529
|
} catch {
|
|
69590
70530
|
}
|
|
69591
70531
|
if (cohereActive) {
|
|
69592
|
-
const metaFile =
|
|
69593
|
-
if (
|
|
69594
|
-
const store = JSON.parse(
|
|
70532
|
+
const metaFile = join71(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
70533
|
+
if (existsSync54(metaFile)) {
|
|
70534
|
+
const store = JSON.parse(readFileSync43(metaFile, "utf8"));
|
|
69595
70535
|
const latest = store.filter((m) => m.sourceTrace === "trajectory-extraction" || m.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
|
|
69596
70536
|
if (latest && latest.scores?.confidence >= 0.6) {
|
|
69597
70537
|
try {
|
|
@@ -69616,18 +70556,18 @@ Rules:
|
|
|
69616
70556
|
}
|
|
69617
70557
|
} catch (err) {
|
|
69618
70558
|
try {
|
|
69619
|
-
const ikFile =
|
|
69620
|
-
if (
|
|
69621
|
-
const ikState = JSON.parse(
|
|
70559
|
+
const ikFile = join71(repoRoot, ".oa", "identity", "self-state.json");
|
|
70560
|
+
if (existsSync54(ikFile)) {
|
|
70561
|
+
const ikState = JSON.parse(readFileSync43(ikFile, "utf8"));
|
|
69622
70562
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
69623
70563
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
69624
70564
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
69625
70565
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
69626
|
-
|
|
70566
|
+
writeFileSync27(ikFile, JSON.stringify(ikState, null, 2));
|
|
69627
70567
|
}
|
|
69628
|
-
const metaFile =
|
|
69629
|
-
if (
|
|
69630
|
-
const store = JSON.parse(
|
|
70568
|
+
const metaFile = join71(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
70569
|
+
if (existsSync54(metaFile)) {
|
|
70570
|
+
const store = JSON.parse(readFileSync43(metaFile, "utf8"));
|
|
69631
70571
|
const surfaced = store.filter((m) => m.type !== "quarantine" && m.scores?.confidence > 0.15).sort((a, b) => b.scores.utility * b.scores.confidence - a.scores.utility * a.scores.confidence).slice(0, 5);
|
|
69632
70572
|
for (const item of surfaced) {
|
|
69633
70573
|
item.accessCount = (item.accessCount || 0) + 1;
|
|
@@ -69635,15 +70575,15 @@ Rules:
|
|
|
69635
70575
|
item.scores.utility = Math.max(0, (item.scores.utility || 0.5) - 0.05);
|
|
69636
70576
|
item.scores.confidence = Math.max(0, (item.scores.confidence || 0.5) - 0.02);
|
|
69637
70577
|
}
|
|
69638
|
-
|
|
70578
|
+
writeFileSync27(metaFile, JSON.stringify(store, null, 2));
|
|
69639
70579
|
}
|
|
69640
70580
|
try {
|
|
69641
|
-
const archeDir =
|
|
69642
|
-
const archeFile =
|
|
70581
|
+
const archeDir = join71(repoRoot, ".oa", "arche");
|
|
70582
|
+
const archeFile = join71(archeDir, "variants.json");
|
|
69643
70583
|
let variants = [];
|
|
69644
70584
|
try {
|
|
69645
|
-
if (
|
|
69646
|
-
variants = JSON.parse(
|
|
70585
|
+
if (existsSync54(archeFile))
|
|
70586
|
+
variants = JSON.parse(readFileSync43(archeFile, "utf8"));
|
|
69647
70587
|
} catch {
|
|
69648
70588
|
}
|
|
69649
70589
|
variants.push({
|
|
@@ -69658,8 +70598,8 @@ Rules:
|
|
|
69658
70598
|
});
|
|
69659
70599
|
if (variants.length > 50)
|
|
69660
70600
|
variants = variants.slice(-50);
|
|
69661
|
-
|
|
69662
|
-
|
|
70601
|
+
mkdirSync28(archeDir, { recursive: true });
|
|
70602
|
+
writeFileSync27(archeFile, JSON.stringify(variants, null, 2));
|
|
69663
70603
|
} catch {
|
|
69664
70604
|
}
|
|
69665
70605
|
} catch {
|
|
@@ -69725,14 +70665,14 @@ __export(run_exports, {
|
|
|
69725
70665
|
statusCommand: () => statusCommand
|
|
69726
70666
|
});
|
|
69727
70667
|
import { resolve as resolve33 } from "node:path";
|
|
69728
|
-
import { spawn as
|
|
69729
|
-
import { mkdirSync as
|
|
70668
|
+
import { spawn as spawn22 } from "node:child_process";
|
|
70669
|
+
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync28, readFileSync as readFileSync44, readdirSync as readdirSync23, existsSync as existsSync55 } from "node:fs";
|
|
69730
70670
|
import { randomBytes as randomBytes17 } from "node:crypto";
|
|
69731
|
-
import { join as
|
|
70671
|
+
import { join as join72 } from "node:path";
|
|
69732
70672
|
function jobsDir2(repoPath) {
|
|
69733
70673
|
const root = resolve33(repoPath ?? process.cwd());
|
|
69734
|
-
const dir =
|
|
69735
|
-
|
|
70674
|
+
const dir = join72(root, ".oa", "jobs");
|
|
70675
|
+
mkdirSync29(dir, { recursive: true });
|
|
69736
70676
|
return dir;
|
|
69737
70677
|
}
|
|
69738
70678
|
async function runCommand(opts, config) {
|
|
@@ -69809,7 +70749,7 @@ async function runBackground(task, config, opts) {
|
|
|
69809
70749
|
const args = [task, "--json"];
|
|
69810
70750
|
if (config.model)
|
|
69811
70751
|
args.push("--model", config.model);
|
|
69812
|
-
const child =
|
|
70752
|
+
const child = spawn22("node", [oaBin, ...args], {
|
|
69813
70753
|
cwd: repoRoot,
|
|
69814
70754
|
env: { ...process.env, OA_JOB_ID: id },
|
|
69815
70755
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -69817,7 +70757,7 @@ async function runBackground(task, config, opts) {
|
|
|
69817
70757
|
});
|
|
69818
70758
|
child.unref();
|
|
69819
70759
|
job.pid = child.pid ?? 0;
|
|
69820
|
-
|
|
70760
|
+
writeFileSync28(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
69821
70761
|
let output = "";
|
|
69822
70762
|
child.stdout?.on("data", (chunk) => {
|
|
69823
70763
|
output += chunk.toString();
|
|
@@ -69833,7 +70773,7 @@ async function runBackground(task, config, opts) {
|
|
|
69833
70773
|
job.summary = result.summary;
|
|
69834
70774
|
job.durationMs = result.durationMs;
|
|
69835
70775
|
job.error = result.error;
|
|
69836
|
-
|
|
70776
|
+
writeFileSync28(join72(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
69837
70777
|
} catch {
|
|
69838
70778
|
}
|
|
69839
70779
|
});
|
|
@@ -69849,13 +70789,13 @@ async function runBackground(task, config, opts) {
|
|
|
69849
70789
|
}
|
|
69850
70790
|
function statusCommand(jobId, repoPath) {
|
|
69851
70791
|
const dir = jobsDir2(repoPath);
|
|
69852
|
-
const file =
|
|
69853
|
-
if (!
|
|
70792
|
+
const file = join72(dir, `${jobId}.json`);
|
|
70793
|
+
if (!existsSync55(file)) {
|
|
69854
70794
|
console.error(`Job not found: ${jobId}`);
|
|
69855
70795
|
console.log(`Available jobs: oa jobs`);
|
|
69856
70796
|
process.exit(1);
|
|
69857
70797
|
}
|
|
69858
|
-
const job = JSON.parse(
|
|
70798
|
+
const job = JSON.parse(readFileSync44(file, "utf-8"));
|
|
69859
70799
|
const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
|
|
69860
70800
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
69861
70801
|
console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
|
|
@@ -69870,7 +70810,7 @@ function statusCommand(jobId, repoPath) {
|
|
|
69870
70810
|
}
|
|
69871
70811
|
function jobsCommand(repoPath) {
|
|
69872
70812
|
const dir = jobsDir2(repoPath);
|
|
69873
|
-
const files =
|
|
70813
|
+
const files = readdirSync23(dir).filter((f) => f.endsWith(".json")).sort();
|
|
69874
70814
|
if (files.length === 0) {
|
|
69875
70815
|
console.log("No jobs found.");
|
|
69876
70816
|
return;
|
|
@@ -69878,7 +70818,7 @@ function jobsCommand(repoPath) {
|
|
|
69878
70818
|
console.log("Jobs:");
|
|
69879
70819
|
for (const file of files) {
|
|
69880
70820
|
try {
|
|
69881
|
-
const job = JSON.parse(
|
|
70821
|
+
const job = JSON.parse(readFileSync44(join72(dir, file), "utf-8"));
|
|
69882
70822
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
69883
70823
|
const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
|
|
69884
70824
|
console.log(` ${icon} ${job.id} [${job.status}] ${runtime} \u2014 ${job.task.slice(0, 60)}`);
|
|
@@ -69898,7 +70838,7 @@ import { glob } from "glob";
|
|
|
69898
70838
|
import ignore from "ignore";
|
|
69899
70839
|
import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
|
|
69900
70840
|
import { createHash as createHash6 } from "node:crypto";
|
|
69901
|
-
import { join as
|
|
70841
|
+
import { join as join73, relative as relative4, extname as extname12, basename as basename17 } from "node:path";
|
|
69902
70842
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
69903
70843
|
var init_codebase_indexer = __esm({
|
|
69904
70844
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -69942,7 +70882,7 @@ var init_codebase_indexer = __esm({
|
|
|
69942
70882
|
const ig = ignore.default();
|
|
69943
70883
|
if (this.config.respectGitignore) {
|
|
69944
70884
|
try {
|
|
69945
|
-
const gitignoreContent = await readFile23(
|
|
70885
|
+
const gitignoreContent = await readFile23(join73(this.config.rootDir, ".gitignore"), "utf-8");
|
|
69946
70886
|
ig.add(gitignoreContent);
|
|
69947
70887
|
} catch {
|
|
69948
70888
|
}
|
|
@@ -69957,7 +70897,7 @@ var init_codebase_indexer = __esm({
|
|
|
69957
70897
|
for (const relativePath of files) {
|
|
69958
70898
|
if (ig.ignores(relativePath))
|
|
69959
70899
|
continue;
|
|
69960
|
-
const fullPath =
|
|
70900
|
+
const fullPath = join73(this.config.rootDir, relativePath);
|
|
69961
70901
|
try {
|
|
69962
70902
|
const fileStat = await stat4(fullPath);
|
|
69963
70903
|
if (fileStat.size > this.config.maxFileSize)
|
|
@@ -70003,7 +70943,7 @@ var init_codebase_indexer = __esm({
|
|
|
70003
70943
|
if (!child) {
|
|
70004
70944
|
child = {
|
|
70005
70945
|
name: part,
|
|
70006
|
-
path:
|
|
70946
|
+
path: join73(current.path, part),
|
|
70007
70947
|
type: "directory",
|
|
70008
70948
|
children: []
|
|
70009
70949
|
};
|
|
@@ -70086,13 +71026,13 @@ __export(index_repo_exports, {
|
|
|
70086
71026
|
indexRepoCommand: () => indexRepoCommand
|
|
70087
71027
|
});
|
|
70088
71028
|
import { resolve as resolve34 } from "node:path";
|
|
70089
|
-
import { existsSync as
|
|
71029
|
+
import { existsSync as existsSync56, statSync as statSync16 } from "node:fs";
|
|
70090
71030
|
import { cwd as cwd2 } from "node:process";
|
|
70091
71031
|
async function indexRepoCommand(opts, _config) {
|
|
70092
71032
|
const repoRoot = resolve34(opts.repoPath ?? cwd2());
|
|
70093
71033
|
printHeader("Index Repository");
|
|
70094
71034
|
printInfo(`Indexing: ${repoRoot}`);
|
|
70095
|
-
if (!
|
|
71035
|
+
if (!existsSync56(repoRoot)) {
|
|
70096
71036
|
printError(`Path does not exist: ${repoRoot}`);
|
|
70097
71037
|
process.exit(1);
|
|
70098
71038
|
}
|
|
@@ -70344,8 +71284,8 @@ var config_exports2 = {};
|
|
|
70344
71284
|
__export(config_exports2, {
|
|
70345
71285
|
configCommand: () => configCommand
|
|
70346
71286
|
});
|
|
70347
|
-
import { join as
|
|
70348
|
-
import { homedir as
|
|
71287
|
+
import { join as join74, resolve as resolve35 } from "node:path";
|
|
71288
|
+
import { homedir as homedir20 } from "node:os";
|
|
70349
71289
|
import { cwd as cwd3 } from "node:process";
|
|
70350
71290
|
function redactIfSensitive(key, value) {
|
|
70351
71291
|
if (SENSITIVE_KEYS.has(key) && typeof value === "string" && value.length > 0) {
|
|
@@ -70427,7 +71367,7 @@ function handleShow(opts, config) {
|
|
|
70427
71367
|
}
|
|
70428
71368
|
}
|
|
70429
71369
|
printSection("Config File");
|
|
70430
|
-
printInfo(`~/.open-agents/config.json (${
|
|
71370
|
+
printInfo(`~/.open-agents/config.json (${join74(homedir20(), ".open-agents", "config.json")})`);
|
|
70431
71371
|
printSection("Priority Chain");
|
|
70432
71372
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
70433
71373
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -70466,7 +71406,7 @@ function handleSet(opts, _config) {
|
|
|
70466
71406
|
const coerced = coerceForSettings(key, value);
|
|
70467
71407
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
70468
71408
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
|
|
70469
|
-
printInfo(`Saved to ${
|
|
71409
|
+
printInfo(`Saved to ${join74(repoRoot, ".oa", "settings.json")}`);
|
|
70470
71410
|
printInfo("This override applies only when running in this workspace.");
|
|
70471
71411
|
} catch (err) {
|
|
70472
71412
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -70609,8 +71549,8 @@ __export(eval_exports, {
|
|
|
70609
71549
|
evalCommand: () => evalCommand
|
|
70610
71550
|
});
|
|
70611
71551
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
70612
|
-
import { mkdirSync as
|
|
70613
|
-
import { join as
|
|
71552
|
+
import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync29 } from "node:fs";
|
|
71553
|
+
import { join as join75 } from "node:path";
|
|
70614
71554
|
async function evalCommand(opts, config) {
|
|
70615
71555
|
const suiteName = opts.suite ?? "basic";
|
|
70616
71556
|
const suite = SUITES[suiteName];
|
|
@@ -70735,9 +71675,9 @@ async function evalCommand(opts, config) {
|
|
|
70735
71675
|
process.exit(failed > 0 ? 1 : 0);
|
|
70736
71676
|
}
|
|
70737
71677
|
function createTempEvalRepo() {
|
|
70738
|
-
const dir =
|
|
70739
|
-
|
|
70740
|
-
|
|
71678
|
+
const dir = join75(tmpdir10(), `open-agents-eval-${Date.now()}`);
|
|
71679
|
+
mkdirSync30(dir, { recursive: true });
|
|
71680
|
+
writeFileSync29(join75(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
|
|
70741
71681
|
return dir;
|
|
70742
71682
|
}
|
|
70743
71683
|
var BASIC_SUITE, FULL_SUITE, SUITES;
|
|
@@ -70796,8 +71736,8 @@ init_output();
|
|
|
70796
71736
|
init_updater();
|
|
70797
71737
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
70798
71738
|
import { createRequire as createRequire5 } from "node:module";
|
|
70799
|
-
import { fileURLToPath as
|
|
70800
|
-
import { dirname as
|
|
71739
|
+
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
71740
|
+
import { dirname as dirname23, join as join76 } from "node:path";
|
|
70801
71741
|
|
|
70802
71742
|
// packages/cli/dist/cli.js
|
|
70803
71743
|
import { createInterface } from "node:readline";
|
|
@@ -70904,7 +71844,7 @@ init_output();
|
|
|
70904
71844
|
function getVersion5() {
|
|
70905
71845
|
try {
|
|
70906
71846
|
const require2 = createRequire5(import.meta.url);
|
|
70907
|
-
const pkgPath =
|
|
71847
|
+
const pkgPath = join76(dirname23(fileURLToPath15(import.meta.url)), "..", "package.json");
|
|
70908
71848
|
const pkg = require2(pkgPath);
|
|
70909
71849
|
return pkg.version;
|
|
70910
71850
|
} catch {
|
|
@@ -71179,12 +72119,12 @@ function crashLog(label, err) {
|
|
|
71179
72119
|
const logLine = `[${timestamp}] ${label}: ${msg}
|
|
71180
72120
|
`;
|
|
71181
72121
|
try {
|
|
71182
|
-
const { appendFileSync: appendFileSync5, mkdirSync:
|
|
71183
|
-
const { join:
|
|
71184
|
-
const { homedir:
|
|
71185
|
-
const logDir =
|
|
71186
|
-
|
|
71187
|
-
appendFileSync5(
|
|
72122
|
+
const { appendFileSync: appendFileSync5, mkdirSync: mkdirSync31 } = __require("node:fs");
|
|
72123
|
+
const { join: join77 } = __require("node:path");
|
|
72124
|
+
const { homedir: homedir21 } = __require("node:os");
|
|
72125
|
+
const logDir = join77(homedir21(), ".open-agents");
|
|
72126
|
+
mkdirSync31(logDir, { recursive: true });
|
|
72127
|
+
appendFileSync5(join77(logDir, "crash.log"), logLine);
|
|
71188
72128
|
} catch {
|
|
71189
72129
|
}
|
|
71190
72130
|
try {
|