@8gi-foundation/8gent-code 0.20.15 → 0.20.17
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/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/dist/cli.js +862 -426
- package/dist/node/cli.js +862 -426
- package/dist/node/tui.js +1553 -1244
- package/dist/tui.js +1561 -1252
- package/package.json +1 -1
package/dist/tui.js
CHANGED
|
@@ -18697,8 +18697,6 @@ var init_allowlist = __esm(() => {
|
|
|
18697
18697
|
"node",
|
|
18698
18698
|
"npm",
|
|
18699
18699
|
"npx",
|
|
18700
|
-
"pnpm",
|
|
18701
|
-
"yarn",
|
|
18702
18700
|
"deno",
|
|
18703
18701
|
"python",
|
|
18704
18702
|
"python3",
|
|
@@ -18706,9 +18704,6 @@ var init_allowlist = __esm(() => {
|
|
|
18706
18704
|
"pip3",
|
|
18707
18705
|
"uv",
|
|
18708
18706
|
"git",
|
|
18709
|
-
"go",
|
|
18710
|
-
"cargo",
|
|
18711
|
-
"rustc",
|
|
18712
18707
|
"tsc",
|
|
18713
18708
|
"gh",
|
|
18714
18709
|
"docker",
|
|
@@ -18733,20 +18728,18 @@ var init_allowlist = __esm(() => {
|
|
|
18733
18728
|
"biome",
|
|
18734
18729
|
"eslint",
|
|
18735
18730
|
"prettier",
|
|
18736
|
-
"vite"
|
|
18731
|
+
"vite",
|
|
18732
|
+
"8gent"
|
|
18737
18733
|
]);
|
|
18738
18734
|
SHORT_VERSION = {
|
|
18739
18735
|
node: "-v",
|
|
18740
18736
|
bun: "-v",
|
|
18741
18737
|
npm: "-v",
|
|
18742
|
-
pnpm: "-v",
|
|
18743
|
-
yarn: "-v",
|
|
18744
18738
|
deno: "-V",
|
|
18745
18739
|
python: "-V",
|
|
18746
18740
|
python3: "-V",
|
|
18747
18741
|
ffmpeg: "-version",
|
|
18748
|
-
ffprobe: "-version"
|
|
18749
|
-
go: "version"
|
|
18742
|
+
ffprobe: "-version"
|
|
18750
18743
|
};
|
|
18751
18744
|
SECRET_ARG = /(^|\/)\.env(\.[\w.-]+)?$|(^|\/)\.env\b|id_rsa|id_ed25519|id_ecdsa|(^|\/)\.ssh(\/|$)|\.aws\/|credentials|\.netrc|\.npmrc|\.git-credentials|keychain|\.pem$|\.key$|\.p12$/;
|
|
18752
18745
|
REDIR_RE2 = /(?<![<>&\d])(\d?|&)(>>?|<)(\|?)\s*(&\d+|[^\s;|&<>()]+)/g;
|
|
@@ -29981,7 +29974,7 @@ var init_permissions = __esm(() => {
|
|
|
29981
29974
|
var require_package = __commonJS(function(exports2, module2) {
|
|
29982
29975
|
module2.exports = {
|
|
29983
29976
|
name: "@8gi-foundation/8gent-code",
|
|
29984
|
-
version: "0.20.
|
|
29977
|
+
version: "0.20.17",
|
|
29985
29978
|
private: false,
|
|
29986
29979
|
engines: {
|
|
29987
29980
|
node: ">=22.5"
|
|
@@ -63483,6 +63476,12 @@ var init_slash_commands = __esm(() => {
|
|
|
63483
63476
|
description: "Enable infinite mode (autonomous until done)",
|
|
63484
63477
|
usage: "/infinite [task]"
|
|
63485
63478
|
},
|
|
63479
|
+
{
|
|
63480
|
+
name: "mode",
|
|
63481
|
+
aliases: [],
|
|
63482
|
+
description: "Set this tab's permission mode: plan, ask, guarded or infinite (same as Shift+Tab)",
|
|
63483
|
+
usage: "/mode <plan|ask|guarded|infinite>"
|
|
63484
|
+
},
|
|
63486
63485
|
{
|
|
63487
63486
|
name: "onboarding",
|
|
63488
63487
|
aliases: ["onboard", "setup", "intro"],
|
|
@@ -74427,8 +74426,31 @@ function emptyReplyStall(toolCalls) {
|
|
|
74427
74426
|
function isEmptyReplyStall(line) {
|
|
74428
74427
|
return line.startsWith(EMPTY_REPLY_STALL_PREFIX);
|
|
74429
74428
|
}
|
|
74430
|
-
function
|
|
74431
|
-
|
|
74429
|
+
function refusedCalls(log, max = 3) {
|
|
74430
|
+
const out = [];
|
|
74431
|
+
let total = 0;
|
|
74432
|
+
for (const e of log) {
|
|
74433
|
+
const m = /^\[[^\]]*\b(?:BLOCKED|DENIED)\b[^\]]*\]\s*([^\n]*)/.exec((e.result ?? "").trimStart());
|
|
74434
|
+
if (!m)
|
|
74435
|
+
continue;
|
|
74436
|
+
total++;
|
|
74437
|
+
if (out.length >= max)
|
|
74438
|
+
continue;
|
|
74439
|
+
const a = e.args;
|
|
74440
|
+
const first = typeof a?.command === "string" ? a.command.trim().split(/\s+/)[0] ?? "" : "";
|
|
74441
|
+
const bin = /^[A-Za-z][\w.+-]{0,40}$/.test(first) ? ` ${first}` : "";
|
|
74442
|
+
const why = /declin/i.test(m[1]) ? "declined" : "blocked by policy";
|
|
74443
|
+
out.push(`${e.name}${bin}: ${why}`);
|
|
74444
|
+
}
|
|
74445
|
+
return { total, shown: out };
|
|
74446
|
+
}
|
|
74447
|
+
function emptyReplyNote(toolCalls, log = []) {
|
|
74448
|
+
const base = `[harness] No reply: ${emptyReplyStall(toolCalls)}.`;
|
|
74449
|
+
const { total, shown } = refusedCalls(log);
|
|
74450
|
+
if (total === 0)
|
|
74451
|
+
return base;
|
|
74452
|
+
const more = total > shown.length ? ` (and ${total - shown.length} more)` : "";
|
|
74453
|
+
return `${base} ${total} of the calls were refused, so they did not run: ${shown.join("; ")}${more}.`;
|
|
74432
74454
|
}
|
|
74433
74455
|
function isEmptyReplyNote(reply) {
|
|
74434
74456
|
return reply.startsWith("[harness] No reply:");
|
|
@@ -74521,7 +74543,7 @@ ${summary}`;
|
|
|
74521
74543
|
if (unverified.length === 0)
|
|
74522
74544
|
return { content, rounds, toolLog, unverified: [] };
|
|
74523
74545
|
const notes = [
|
|
74524
|
-
empty ? emptyReplyNote(toolLog.length) : content.trimEnd(),
|
|
74546
|
+
empty ? emptyReplyNote(toolLog.length, toolLog) : content.trimEnd(),
|
|
74525
74547
|
unfulfilled.length > 0 ? formatHarnessNote(unfulfilled) : ""
|
|
74526
74548
|
].filter((n) => n.trim() !== "");
|
|
74527
74549
|
return { content: notes.join(`
|
|
@@ -547329,7 +547351,7 @@ onboarding preferences skip animations adhd quarantine toolshed skills design ev
|
|
|
547329
547351
|
resume history continue compact chat agent github debug music dj pet export fork rewind branch cron deploy
|
|
547330
547352
|
vercel telegram router rename spawn settings quiet term create-app hands eyes handeyes goal subgoal build
|
|
547331
547353
|
notes ideas btw questions projects terminal reload exit
|
|
547332
|
-
copy hotkeys tree import update route privacy consult bug me allow-read`.split(/\s+/));
|
|
547354
|
+
copy hotkeys tree import update route privacy consult bug me allow-read mode`.split(/\s+/));
|
|
547333
547355
|
});
|
|
547334
547356
|
|
|
547335
547357
|
// packages/extensions/index.ts
|
|
@@ -553413,7 +553435,9 @@ function defaultSessionsDir2() {
|
|
|
553413
553435
|
|
|
553414
553436
|
class SessionWriter {
|
|
553415
553437
|
filePath;
|
|
553416
|
-
fd;
|
|
553438
|
+
fd = -1;
|
|
553439
|
+
dev = -1;
|
|
553440
|
+
ino = -1;
|
|
553417
553441
|
persist;
|
|
553418
553442
|
seq = 0;
|
|
553419
553443
|
sessionId;
|
|
@@ -553445,15 +553469,47 @@ class SessionWriter {
|
|
|
553445
553469
|
fs78.mkdirSync(dir, { recursive: true });
|
|
553446
553470
|
}
|
|
553447
553471
|
this.filePath = path107.join(dir, `${sessionId}.jsonl`);
|
|
553448
|
-
this.
|
|
553472
|
+
this.open();
|
|
553473
|
+
}
|
|
553474
|
+
open() {
|
|
553475
|
+
const c = fs78.constants;
|
|
553476
|
+
const fd = fs78.openSync(this.filePath, c.O_WRONLY | c.O_APPEND | c.O_CREAT | (c.O_NOFOLLOW ?? 0), 384);
|
|
553477
|
+
const st = fs78.fstatSync(fd);
|
|
553478
|
+
if (!st.isFile()) {
|
|
553479
|
+
fs78.closeSync(fd);
|
|
553480
|
+
throw new Error(`${this.filePath} is not a regular file`);
|
|
553481
|
+
}
|
|
553482
|
+
this.fd = fd;
|
|
553483
|
+
this.dev = st.dev;
|
|
553484
|
+
this.ino = st.ino;
|
|
553485
|
+
}
|
|
553486
|
+
fdIsOurs() {
|
|
553487
|
+
if (this.fd < 0)
|
|
553488
|
+
return false;
|
|
553489
|
+
try {
|
|
553490
|
+
const st = fs78.fstatSync(this.fd);
|
|
553491
|
+
return st.dev === this.dev && st.ino === this.ino;
|
|
553492
|
+
} catch {
|
|
553493
|
+
return false;
|
|
553494
|
+
}
|
|
553449
553495
|
}
|
|
553450
553496
|
write(entry) {
|
|
553451
553497
|
if (!this.persist)
|
|
553452
553498
|
return;
|
|
553453
553499
|
const line = `${JSON.stringify(entry)}
|
|
553454
553500
|
`;
|
|
553455
|
-
|
|
553501
|
+
try {
|
|
553502
|
+
if (!this.fdIsOurs())
|
|
553503
|
+
this.open();
|
|
553504
|
+
fs78.writeSync(this.fd, line);
|
|
553505
|
+
} catch (err) {
|
|
553506
|
+
this.fd = -1;
|
|
553507
|
+
this.skippedWrites++;
|
|
553508
|
+
this.lastWriteError = `session log not written: ${err instanceof Error ? err.message : String(err)}`;
|
|
553509
|
+
}
|
|
553456
553510
|
}
|
|
553511
|
+
lastWriteError = null;
|
|
553512
|
+
skippedWrites = 0;
|
|
553457
553513
|
nextSeq() {
|
|
553458
553514
|
return this.seq++;
|
|
553459
553515
|
}
|
|
@@ -553663,8 +553719,9 @@ class SessionWriter {
|
|
|
553663
553719
|
reportId: reportId ?? null
|
|
553664
553720
|
}
|
|
553665
553721
|
});
|
|
553666
|
-
if (this.persist)
|
|
553722
|
+
if (this.persist && this.fdIsOurs())
|
|
553667
553723
|
fs78.closeSync(this.fd);
|
|
553724
|
+
this.fd = -1;
|
|
553668
553725
|
}
|
|
553669
553726
|
getFilePath() {
|
|
553670
553727
|
return this.filePath;
|
|
@@ -557382,6 +557439,52 @@ var init_registry = __esm(() => {
|
|
|
557382
557439
|
];
|
|
557383
557440
|
});
|
|
557384
557441
|
|
|
557442
|
+
// packages/eight/small-talk.ts
|
|
557443
|
+
function flatten2(text) {
|
|
557444
|
+
return text.toLowerCase().replace(/^\[mode: [^\]]*\]\s*/, "").replace(/['\u2019]/g, "").replace(/[^a-z0-9 ]+/g, " ").replace(/\s+/g, " ").trim();
|
|
557445
|
+
}
|
|
557446
|
+
function isSmallTalk(text) {
|
|
557447
|
+
const flat = flatten2(text);
|
|
557448
|
+
return flat.length > 0 && flat.length <= 40 && GREETING.test(flat);
|
|
557449
|
+
}
|
|
557450
|
+
function isGreeting(text) {
|
|
557451
|
+
return isSmallTalk(text) && !THANKS.test(flatten2(text));
|
|
557452
|
+
}
|
|
557453
|
+
var CORE, GREETING, THANKS, SMALL_TALK_NOTE = "[SMALL TALK] The person said hello and asked for nothing. Reply in one or two plain sentences and ask what they want to work on. No tools this turn: do not look around, list files or describe their folders.";
|
|
557454
|
+
var init_small_talk = __esm(() => {
|
|
557455
|
+
CORE = [
|
|
557456
|
+
"h+i+",
|
|
557457
|
+
"h+e+y+",
|
|
557458
|
+
"h+e+l+o+",
|
|
557459
|
+
"hiya",
|
|
557460
|
+
"howdy",
|
|
557461
|
+
"y+o+",
|
|
557462
|
+
"sup",
|
|
557463
|
+
"wa+s+s?u+p+",
|
|
557464
|
+
"w?h?a+t?s? ?u+p+",
|
|
557465
|
+
"wh?a+t+s? go+d+",
|
|
557466
|
+
"good (?:morning|afternoon|evening|night)",
|
|
557467
|
+
"gm",
|
|
557468
|
+
"gn",
|
|
557469
|
+
"morning",
|
|
557470
|
+
"evening",
|
|
557471
|
+
"how are you(?: doing| today)?",
|
|
557472
|
+
"how are things",
|
|
557473
|
+
"hows it going",
|
|
557474
|
+
"how you doing",
|
|
557475
|
+
"you there",
|
|
557476
|
+
"anyone there",
|
|
557477
|
+
"ping",
|
|
557478
|
+
"thanks(?: a lot| so much)?",
|
|
557479
|
+
"thank you(?: so much)?",
|
|
557480
|
+
"thx",
|
|
557481
|
+
"ty",
|
|
557482
|
+
"cheers"
|
|
557483
|
+
].join("|");
|
|
557484
|
+
GREETING = new RegExp(`^(?:(?:hi+|hey+|hello+|yo+|hiya|howdy) )?(?:${CORE})(?: (?:there|again|everyone|all|team|mate|man|bro|friend|8gent|eight))?$`);
|
|
557485
|
+
THANKS = /^(?:thanks|thank you|thx|ty|cheers)\b/;
|
|
557486
|
+
});
|
|
557487
|
+
|
|
557385
557488
|
// packages/eight/verify-gate.ts
|
|
557386
557489
|
function isVerifyGateEnabled(env = process.env) {
|
|
557387
557490
|
const v = (env.EIGHT_VERIFY_GATE ?? "").trim().toLowerCase();
|
|
@@ -557424,6 +557527,755 @@ var init_verify_gate = __esm(() => {
|
|
|
557424
557527
|
`);
|
|
557425
557528
|
});
|
|
557426
557529
|
|
|
557530
|
+
// packages/voice/termux.ts
|
|
557531
|
+
import { constants as constants16, accessSync as accessSync4, readFileSync as readFileSync96 } from "fs";
|
|
557532
|
+
import { delimiter as delimiter7, join as join154 } from "path";
|
|
557533
|
+
function isAndroidHost(platform = process.platform, env = process.env) {
|
|
557534
|
+
return platform === "android" || !!env.TERMUX_VERSION || String(env.PREFIX ?? "").includes("/com.termux/");
|
|
557535
|
+
}
|
|
557536
|
+
function findOnPath(name, env = process.env) {
|
|
557537
|
+
for (const dir of String(env.PATH ?? "").split(delimiter7)) {
|
|
557538
|
+
if (!dir)
|
|
557539
|
+
continue;
|
|
557540
|
+
const candidate = join154(dir, name);
|
|
557541
|
+
try {
|
|
557542
|
+
accessSync4(candidate, constants16.X_OK);
|
|
557543
|
+
return candidate;
|
|
557544
|
+
} catch {}
|
|
557545
|
+
}
|
|
557546
|
+
return null;
|
|
557547
|
+
}
|
|
557548
|
+
function voiceOutputOn(env = process.env, readSettings = () => {
|
|
557549
|
+
const home = env.EIGHT_HOME || join154(env.HOME ?? "", ".8gent");
|
|
557550
|
+
return readFileSync96(join154(home, "settings.json"), "utf8");
|
|
557551
|
+
}) {
|
|
557552
|
+
if (env.EIGHT_VOICE === "1")
|
|
557553
|
+
return true;
|
|
557554
|
+
try {
|
|
557555
|
+
return JSON.parse(readSettings())?.voice?.outputEnabled === true;
|
|
557556
|
+
} catch {
|
|
557557
|
+
return false;
|
|
557558
|
+
}
|
|
557559
|
+
}
|
|
557560
|
+
function ctrlRAction(key, input, android = isAndroidHost()) {
|
|
557561
|
+
if (!key.ctrl || input !== "r")
|
|
557562
|
+
return "ignore";
|
|
557563
|
+
return android ? "android-line" : "toggle";
|
|
557564
|
+
}
|
|
557565
|
+
var ANDROID_DICTATION_LINE = "On Android, tap the microphone key on your keyboard; dictation lands in the prompt. Spoken replies: /voice on (needs termux-tts-speak: pkg install termux-api plus the Termux:API app).", TERMUX_TTS_HINT = "Spoken replies need termux-tts-speak: pkg install termux-api, plus the Termux:API app from F-Droid.", ANDROID_VOICE_LINE_SUBS;
|
|
557566
|
+
var init_termux = __esm(() => {
|
|
557567
|
+
ANDROID_VOICE_LINE_SUBS = [
|
|
557568
|
+
"",
|
|
557569
|
+
"chat",
|
|
557570
|
+
"conversation",
|
|
557571
|
+
"talk",
|
|
557572
|
+
"record",
|
|
557573
|
+
"listen",
|
|
557574
|
+
"stt",
|
|
557575
|
+
"status",
|
|
557576
|
+
"stop"
|
|
557577
|
+
];
|
|
557578
|
+
});
|
|
557579
|
+
|
|
557580
|
+
// packages/runtime/node-runtime.ts
|
|
557581
|
+
import { execFile as execFile7 } from "child_process";
|
|
557582
|
+
import { existsSync as existsSync104 } from "fs";
|
|
557583
|
+
import { homedir as homedir78 } from "os";
|
|
557584
|
+
import { join as join155 } from "path";
|
|
557585
|
+
import { promisify as promisify6 } from "util";
|
|
557586
|
+
function parseNodeVersion(raw) {
|
|
557587
|
+
const trimmed = raw.trim();
|
|
557588
|
+
const match = trimmed.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
557589
|
+
if (!match)
|
|
557590
|
+
return null;
|
|
557591
|
+
return {
|
|
557592
|
+
major: Number.parseInt(match[1], 10),
|
|
557593
|
+
minor: Number.parseInt(match[2], 10),
|
|
557594
|
+
patch: Number.parseInt(match[3], 10)
|
|
557595
|
+
};
|
|
557596
|
+
}
|
|
557597
|
+
function satisfiesMinVersion(v, min) {
|
|
557598
|
+
const minParsed = parseNodeVersion(min);
|
|
557599
|
+
if (!minParsed)
|
|
557600
|
+
return true;
|
|
557601
|
+
if (v.major !== minParsed.major)
|
|
557602
|
+
return v.major > minParsed.major;
|
|
557603
|
+
if (v.minor !== minParsed.minor)
|
|
557604
|
+
return v.minor > minParsed.minor;
|
|
557605
|
+
return v.patch >= minParsed.patch;
|
|
557606
|
+
}
|
|
557607
|
+
function pickPlatformAsset(input) {
|
|
557608
|
+
const byArch = SUPPORTED[input.platform];
|
|
557609
|
+
if (!byArch) {
|
|
557610
|
+
throw new Error(`unsupported platform: ${input.platform}`);
|
|
557611
|
+
}
|
|
557612
|
+
const asset = byArch[input.arch];
|
|
557613
|
+
if (!asset) {
|
|
557614
|
+
throw new Error(`unsupported arch: ${input.arch} on ${input.platform}`);
|
|
557615
|
+
}
|
|
557616
|
+
return asset;
|
|
557617
|
+
}
|
|
557618
|
+
function buildDownloadUrl(opts) {
|
|
557619
|
+
const cleanVersion = opts.version.startsWith("v") ? opts.version.slice(1) : opts.version;
|
|
557620
|
+
const v = `v${cleanVersion}`;
|
|
557621
|
+
const fileBase = `node-${v}-${opts.asset.os}-${opts.asset.arch}`;
|
|
557622
|
+
return `https://nodejs.org/dist/${v}/${fileBase}.${opts.asset.ext}`;
|
|
557623
|
+
}
|
|
557624
|
+
function defaultRoot() {
|
|
557625
|
+
return join155(homedir78(), ".8gent", "runtime");
|
|
557626
|
+
}
|
|
557627
|
+
function getRuntimeDir(loc) {
|
|
557628
|
+
const root = loc.root ?? defaultRoot();
|
|
557629
|
+
return join155(root, `node-${loc.version}`);
|
|
557630
|
+
}
|
|
557631
|
+
function resolvedNodeBinPath(opts) {
|
|
557632
|
+
const dir = getRuntimeDir(opts);
|
|
557633
|
+
if (opts.platform === "win32") {
|
|
557634
|
+
return join155(dir, "node.exe");
|
|
557635
|
+
}
|
|
557636
|
+
return join155(dir, "bin", "node");
|
|
557637
|
+
}
|
|
557638
|
+
async function isRuntimeReady(opts) {
|
|
557639
|
+
const platform = opts.platform ?? process.platform;
|
|
557640
|
+
const bin = resolvedNodeBinPath({
|
|
557641
|
+
root: opts.root,
|
|
557642
|
+
version: opts.version,
|
|
557643
|
+
platform
|
|
557644
|
+
});
|
|
557645
|
+
if (!existsSync104(bin))
|
|
557646
|
+
return false;
|
|
557647
|
+
const min = opts.minVersion ?? opts.version;
|
|
557648
|
+
try {
|
|
557649
|
+
const { stdout } = await execFileAsync4(bin, ["--version"], {
|
|
557650
|
+
timeout: 3000
|
|
557651
|
+
});
|
|
557652
|
+
const parsed = parseNodeVersion(stdout);
|
|
557653
|
+
if (!parsed)
|
|
557654
|
+
return false;
|
|
557655
|
+
return satisfiesMinVersion(parsed, min);
|
|
557656
|
+
} catch {
|
|
557657
|
+
return false;
|
|
557658
|
+
}
|
|
557659
|
+
}
|
|
557660
|
+
var execFileAsync4, SUPPORTED;
|
|
557661
|
+
var init_node_runtime = __esm(() => {
|
|
557662
|
+
execFileAsync4 = promisify6(execFile7);
|
|
557663
|
+
SUPPORTED = {
|
|
557664
|
+
darwin: {
|
|
557665
|
+
arm64: { os: "darwin", arch: "arm64", ext: "tar.gz" },
|
|
557666
|
+
x64: { os: "darwin", arch: "x64", ext: "tar.gz" }
|
|
557667
|
+
},
|
|
557668
|
+
linux: {
|
|
557669
|
+
arm64: { os: "linux", arch: "arm64", ext: "tar.xz" },
|
|
557670
|
+
x64: { os: "linux", arch: "x64", ext: "tar.xz" }
|
|
557671
|
+
},
|
|
557672
|
+
win32: {
|
|
557673
|
+
x64: { os: "win", arch: "x64", ext: "zip" },
|
|
557674
|
+
arm64: { os: "win", arch: "arm64", ext: "zip" }
|
|
557675
|
+
}
|
|
557676
|
+
};
|
|
557677
|
+
});
|
|
557678
|
+
|
|
557679
|
+
// packages/runtime/installer.ts
|
|
557680
|
+
import { spawn as spawn26 } from "child_process";
|
|
557681
|
+
import {
|
|
557682
|
+
createWriteStream,
|
|
557683
|
+
existsSync as existsSync105,
|
|
557684
|
+
mkdirSync as mkdirSync74,
|
|
557685
|
+
mkdtempSync as mkdtempSync11,
|
|
557686
|
+
readdirSync as readdirSync26,
|
|
557687
|
+
renameSync as renameSync16,
|
|
557688
|
+
rmSync as rmSync14
|
|
557689
|
+
} from "fs";
|
|
557690
|
+
import { join as join156 } from "path";
|
|
557691
|
+
import { Readable } from "stream";
|
|
557692
|
+
import { pipeline } from "stream/promises";
|
|
557693
|
+
function planInstall(input) {
|
|
557694
|
+
const platform = input.platform ?? process.platform;
|
|
557695
|
+
const arch = input.arch ?? process.arch;
|
|
557696
|
+
const asset = pickPlatformAsset({ platform, arch });
|
|
557697
|
+
const url = buildDownloadUrl({ version: input.version, asset });
|
|
557698
|
+
const runtimeDir = getRuntimeDir({ root: input.root, version: input.version });
|
|
557699
|
+
const binPath = resolvedNodeBinPath({
|
|
557700
|
+
root: input.root,
|
|
557701
|
+
version: input.version,
|
|
557702
|
+
platform
|
|
557703
|
+
});
|
|
557704
|
+
return {
|
|
557705
|
+
version: input.version,
|
|
557706
|
+
url,
|
|
557707
|
+
asset,
|
|
557708
|
+
runtimeDir,
|
|
557709
|
+
binPath,
|
|
557710
|
+
archiveExt: asset.ext
|
|
557711
|
+
};
|
|
557712
|
+
}
|
|
557713
|
+
async function installRuntime(input) {
|
|
557714
|
+
const plan = planInstall(input);
|
|
557715
|
+
const platform = input.platform ?? process.platform;
|
|
557716
|
+
const minVersion = input.minVersion ?? input.version;
|
|
557717
|
+
const ready = await isRuntimeReady({
|
|
557718
|
+
root: input.root,
|
|
557719
|
+
version: input.version,
|
|
557720
|
+
platform,
|
|
557721
|
+
minVersion
|
|
557722
|
+
});
|
|
557723
|
+
if (ready || input.dryRun) {
|
|
557724
|
+
return {
|
|
557725
|
+
...plan,
|
|
557726
|
+
action: ready ? "already-ready" : "dry-run"
|
|
557727
|
+
};
|
|
557728
|
+
}
|
|
557729
|
+
const runtimeRoot = plan.runtimeDir.replace(/\/node-[^/]+$/, "");
|
|
557730
|
+
mkdirSync74(runtimeRoot, { recursive: true });
|
|
557731
|
+
const stagingDir = mkdtempSync11(join156(runtimeRoot, ".dl-"));
|
|
557732
|
+
const archivePath = join156(stagingDir, `node.${plan.archiveExt}`);
|
|
557733
|
+
try {
|
|
557734
|
+
await downloadFile(plan.url, archivePath);
|
|
557735
|
+
const extractRoot = join156(stagingDir, "extract");
|
|
557736
|
+
mkdirSync74(extractRoot, { recursive: true });
|
|
557737
|
+
await extractArchive(archivePath, extractRoot, plan.archiveExt);
|
|
557738
|
+
const children = readdirSync26(extractRoot);
|
|
557739
|
+
const nodeDir = children.find((n) => n.startsWith("node-"));
|
|
557740
|
+
if (!nodeDir) {
|
|
557741
|
+
throw new Error(`could not find node-* dir inside ${extractRoot}`);
|
|
557742
|
+
}
|
|
557743
|
+
const extractedPath = join156(extractRoot, nodeDir);
|
|
557744
|
+
if (existsSync105(plan.runtimeDir)) {
|
|
557745
|
+
rmSync14(plan.runtimeDir, { recursive: true, force: true });
|
|
557746
|
+
}
|
|
557747
|
+
renameSync16(extractedPath, plan.runtimeDir);
|
|
557748
|
+
} catch (err) {
|
|
557749
|
+
return {
|
|
557750
|
+
...plan,
|
|
557751
|
+
action: "failed",
|
|
557752
|
+
error: err instanceof Error ? err.message : String(err)
|
|
557753
|
+
};
|
|
557754
|
+
} finally {
|
|
557755
|
+
try {
|
|
557756
|
+
rmSync14(stagingDir, { recursive: true, force: true });
|
|
557757
|
+
} catch {}
|
|
557758
|
+
}
|
|
557759
|
+
const reReady = await isRuntimeReady({
|
|
557760
|
+
root: input.root,
|
|
557761
|
+
version: input.version,
|
|
557762
|
+
platform,
|
|
557763
|
+
minVersion
|
|
557764
|
+
});
|
|
557765
|
+
if (!reReady) {
|
|
557766
|
+
return {
|
|
557767
|
+
...plan,
|
|
557768
|
+
action: "failed",
|
|
557769
|
+
error: `installed runtime at ${plan.binPath} but it does not satisfy minVersion ${minVersion}`
|
|
557770
|
+
};
|
|
557771
|
+
}
|
|
557772
|
+
return {
|
|
557773
|
+
...plan,
|
|
557774
|
+
action: "installed"
|
|
557775
|
+
};
|
|
557776
|
+
}
|
|
557777
|
+
async function downloadFile(url, dest) {
|
|
557778
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
557779
|
+
if (!res.ok || !res.body) {
|
|
557780
|
+
throw new Error(`download failed: HTTP ${res.status} ${res.statusText} for ${url}`);
|
|
557781
|
+
}
|
|
557782
|
+
const out = createWriteStream(dest);
|
|
557783
|
+
await pipeline(Readable.fromWeb(res.body), out);
|
|
557784
|
+
}
|
|
557785
|
+
async function extractArchive(archivePath, destDir, ext) {
|
|
557786
|
+
if (ext === "tar.gz" || ext === "tar.xz") {
|
|
557787
|
+
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
557788
|
+
} else if (ext === "zip") {
|
|
557789
|
+
try {
|
|
557790
|
+
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
557791
|
+
} catch {
|
|
557792
|
+
await runCmd("powershell", [
|
|
557793
|
+
"-Command",
|
|
557794
|
+
`Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force`
|
|
557795
|
+
]);
|
|
557796
|
+
}
|
|
557797
|
+
} else {
|
|
557798
|
+
throw new Error(`unsupported archive ext: ${ext}`);
|
|
557799
|
+
}
|
|
557800
|
+
}
|
|
557801
|
+
function runCmd(command, args) {
|
|
557802
|
+
return new Promise((resolve, reject) => {
|
|
557803
|
+
const proc = spawn26(command, args, { stdio: "ignore" });
|
|
557804
|
+
proc.on("error", (err) => reject(err));
|
|
557805
|
+
proc.on("close", (code) => {
|
|
557806
|
+
if (code === 0)
|
|
557807
|
+
resolve();
|
|
557808
|
+
else
|
|
557809
|
+
reject(new Error(`${command} ${args.join(" ")} exited ${code}`));
|
|
557810
|
+
});
|
|
557811
|
+
});
|
|
557812
|
+
}
|
|
557813
|
+
var init_installer = __esm(() => {
|
|
557814
|
+
init_node_runtime();
|
|
557815
|
+
});
|
|
557816
|
+
|
|
557817
|
+
// packages/runtime/contract-validator.ts
|
|
557818
|
+
var init_contract_validator = __esm(() => {
|
|
557819
|
+
init_types3();
|
|
557820
|
+
});
|
|
557821
|
+
|
|
557822
|
+
// packages/runtime/index.ts
|
|
557823
|
+
import { join as join157 } from "path";
|
|
557824
|
+
import { execFile as execFile8 } from "child_process";
|
|
557825
|
+
import { promisify as promisify7 } from "util";
|
|
557826
|
+
async function ensureNodeFor(minVersion) {
|
|
557827
|
+
try {
|
|
557828
|
+
const { stdout } = await execFileAsync5("node", ["--version"], {
|
|
557829
|
+
timeout: 3000
|
|
557830
|
+
});
|
|
557831
|
+
const parsed = parseNodeVersion(stdout);
|
|
557832
|
+
if (parsed && satisfiesMinVersion(parsed, minVersion)) {
|
|
557833
|
+
return null;
|
|
557834
|
+
}
|
|
557835
|
+
} catch {}
|
|
557836
|
+
const ready = await isRuntimeReady({
|
|
557837
|
+
version: MANAGED_NODE_VERSION,
|
|
557838
|
+
minVersion
|
|
557839
|
+
});
|
|
557840
|
+
const dir = getRuntimeDir({ version: MANAGED_NODE_VERSION });
|
|
557841
|
+
const binDir = process.platform === "win32" ? dir : join157(dir, "bin");
|
|
557842
|
+
if (ready)
|
|
557843
|
+
return binDir;
|
|
557844
|
+
const result = await installRuntime({
|
|
557845
|
+
version: MANAGED_NODE_VERSION,
|
|
557846
|
+
minVersion
|
|
557847
|
+
});
|
|
557848
|
+
if (result.action === "failed") {
|
|
557849
|
+
throw new Error(`failed to install Node ${MANAGED_NODE_VERSION}: ${result.error ?? "unknown"}`);
|
|
557850
|
+
}
|
|
557851
|
+
return binDir;
|
|
557852
|
+
}
|
|
557853
|
+
var execFileAsync5, MANAGED_NODE_VERSION = "22.14.0";
|
|
557854
|
+
var init_runtime = __esm(() => {
|
|
557855
|
+
init_installer();
|
|
557856
|
+
init_node_runtime();
|
|
557857
|
+
init_node_runtime();
|
|
557858
|
+
init_installer();
|
|
557859
|
+
init_contract_validator();
|
|
557860
|
+
execFileAsync5 = promisify7(execFile8);
|
|
557861
|
+
});
|
|
557862
|
+
|
|
557863
|
+
// apps/tui/src/lib/external-agent-runner.ts
|
|
557864
|
+
import { execSync as execSync6, spawn as spawn27 } from "child_process";
|
|
557865
|
+
function getPreset(id) {
|
|
557866
|
+
return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
|
|
557867
|
+
}
|
|
557868
|
+
function listPresetIds() {
|
|
557869
|
+
return Object.keys(EXTERNAL_AGENT_PRESETS);
|
|
557870
|
+
}
|
|
557871
|
+
function isInstalled(preset) {
|
|
557872
|
+
try {
|
|
557873
|
+
execSync6(`command -v "${preset.command}"`, {
|
|
557874
|
+
stdio: "ignore",
|
|
557875
|
+
timeout: 1500
|
|
557876
|
+
});
|
|
557877
|
+
return true;
|
|
557878
|
+
} catch {
|
|
557879
|
+
return false;
|
|
557880
|
+
}
|
|
557881
|
+
}
|
|
557882
|
+
async function installAgent(preset, onLine) {
|
|
557883
|
+
const start = performance.now();
|
|
557884
|
+
if (!preset.install) {
|
|
557885
|
+
return {
|
|
557886
|
+
ok: false,
|
|
557887
|
+
stdout: "",
|
|
557888
|
+
stderr: "",
|
|
557889
|
+
durationMs: 0,
|
|
557890
|
+
command: "",
|
|
557891
|
+
error: `No install recipe for ${preset.id}. Install ${preset.command} manually and try again.`
|
|
557892
|
+
};
|
|
557893
|
+
}
|
|
557894
|
+
const command = preset.install.command;
|
|
557895
|
+
return new Promise((resolve) => {
|
|
557896
|
+
let stdout = "";
|
|
557897
|
+
let stderr = "";
|
|
557898
|
+
let exited = false;
|
|
557899
|
+
const proc = spawnShell(command, {
|
|
557900
|
+
posix: ["bash", "-lc"],
|
|
557901
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
557902
|
+
env: { ...process.env, NO_COLOR: "1", FORCE_COLOR: "0" }
|
|
557903
|
+
});
|
|
557904
|
+
const finish = (result) => {
|
|
557905
|
+
if (exited)
|
|
557906
|
+
return;
|
|
557907
|
+
exited = true;
|
|
557908
|
+
clearTimeout(timer);
|
|
557909
|
+
resolve({
|
|
557910
|
+
...result,
|
|
557911
|
+
durationMs: Math.round(performance.now() - start),
|
|
557912
|
+
command
|
|
557913
|
+
});
|
|
557914
|
+
};
|
|
557915
|
+
const pipeLines = (chunk, source) => {
|
|
557916
|
+
const text = chunk.toString();
|
|
557917
|
+
if (source === "stdout")
|
|
557918
|
+
stdout += text;
|
|
557919
|
+
else
|
|
557920
|
+
stderr += text;
|
|
557921
|
+
if (onLine) {
|
|
557922
|
+
for (const line of text.split(/\r?\n/)) {
|
|
557923
|
+
if (line.trim().length > 0)
|
|
557924
|
+
onLine(line, source);
|
|
557925
|
+
}
|
|
557926
|
+
}
|
|
557927
|
+
};
|
|
557928
|
+
proc.stdout?.on("data", (c) => pipeLines(c, "stdout"));
|
|
557929
|
+
proc.stderr?.on("data", (c) => pipeLines(c, "stderr"));
|
|
557930
|
+
proc.on("error", (err) => {
|
|
557931
|
+
finish({ ok: false, stdout, stderr, error: err.message });
|
|
557932
|
+
});
|
|
557933
|
+
proc.on("close", (code) => {
|
|
557934
|
+
finish({
|
|
557935
|
+
ok: code === 0,
|
|
557936
|
+
stdout,
|
|
557937
|
+
stderr,
|
|
557938
|
+
error: code === 0 ? undefined : stderr.trim().slice(0, 800) || `installer exited with code ${code}`
|
|
557939
|
+
});
|
|
557940
|
+
});
|
|
557941
|
+
const timer = setTimeout(() => {
|
|
557942
|
+
proc.kill("SIGTERM");
|
|
557943
|
+
finish({ ok: false, stdout, stderr, error: "install timed out after 5 minutes" });
|
|
557944
|
+
}, 5 * 60 * 1000);
|
|
557945
|
+
});
|
|
557946
|
+
}
|
|
557947
|
+
async function ensureInstalled(preset, onLine) {
|
|
557948
|
+
if (isInstalled(preset))
|
|
557949
|
+
return true;
|
|
557950
|
+
if (!preset.install) {
|
|
557951
|
+
onLine?.(`${preset.command}: not installed and no auto-install recipe is configured.`, "info");
|
|
557952
|
+
return false;
|
|
557953
|
+
}
|
|
557954
|
+
onLine?.(`${preset.command}: not installed, running ${preset.install.command}`, "info");
|
|
557955
|
+
const result = await installAgent(preset, (line, source) => onLine?.(line, source));
|
|
557956
|
+
if (!result.ok) {
|
|
557957
|
+
onLine?.(`Install failed: ${result.error ?? "unknown error"}`, "info");
|
|
557958
|
+
return false;
|
|
557959
|
+
}
|
|
557960
|
+
const stillThere = isInstalled(preset);
|
|
557961
|
+
if (!stillThere) {
|
|
557962
|
+
onLine?.(`Install reported success but ${preset.command} is still not on $PATH. You may need to open a new shell or add the install dir to PATH.`, "info");
|
|
557963
|
+
}
|
|
557964
|
+
return stillThere;
|
|
557965
|
+
}
|
|
557966
|
+
function composePrompt(history, prompt) {
|
|
557967
|
+
const lines = [];
|
|
557968
|
+
for (const m of history) {
|
|
557969
|
+
const tag = m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : m.role;
|
|
557970
|
+
lines.push(`${tag}: ${m.content}`);
|
|
557971
|
+
}
|
|
557972
|
+
lines.push(`User: ${prompt}`);
|
|
557973
|
+
lines.push("Assistant:");
|
|
557974
|
+
return lines.join(`
|
|
557975
|
+
|
|
557976
|
+
`);
|
|
557977
|
+
}
|
|
557978
|
+
async function runExternalAgent(preset, prompt, signal) {
|
|
557979
|
+
const start = performance.now();
|
|
557980
|
+
const argv = [...preset.args];
|
|
557981
|
+
if (preset.promptMode === "flag") {
|
|
557982
|
+
argv.push(preset.flagName ?? "-p", prompt);
|
|
557983
|
+
} else if (preset.promptMode === "arg") {
|
|
557984
|
+
argv.push(prompt);
|
|
557985
|
+
}
|
|
557986
|
+
let pathPrefix = "";
|
|
557987
|
+
if (preset.requiresNodeVersion) {
|
|
557988
|
+
try {
|
|
557989
|
+
await Promise.resolve().then(() => init_runtime());
|
|
557990
|
+
const binDir = await ensureNodeFor(preset.requiresNodeVersion);
|
|
557991
|
+
if (binDir)
|
|
557992
|
+
pathPrefix = `${binDir}:`;
|
|
557993
|
+
} catch (err) {
|
|
557994
|
+
return {
|
|
557995
|
+
ok: false,
|
|
557996
|
+
text: "",
|
|
557997
|
+
durationMs: Math.round(performance.now() - start),
|
|
557998
|
+
command: `${preset.command} ${argv.join(" ")}`,
|
|
557999
|
+
error: `managed Node runtime install failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
558000
|
+
exitCode: null
|
|
558001
|
+
};
|
|
558002
|
+
}
|
|
558003
|
+
}
|
|
558004
|
+
return new Promise((resolve) => {
|
|
558005
|
+
let stdout = "";
|
|
558006
|
+
let stderr = "";
|
|
558007
|
+
let exited = false;
|
|
558008
|
+
const proc = spawn27(preset.command, argv, {
|
|
558009
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
558010
|
+
env: {
|
|
558011
|
+
...process.env,
|
|
558012
|
+
PATH: `${pathPrefix}${process.env.PATH ?? ""}`,
|
|
558013
|
+
NO_COLOR: "1",
|
|
558014
|
+
FORCE_COLOR: "0",
|
|
558015
|
+
"8GENT_NO_INTRO": "1",
|
|
558016
|
+
AI_SDK_LOG_WARNINGS: "false"
|
|
558017
|
+
}
|
|
558018
|
+
});
|
|
558019
|
+
const finish = (result) => {
|
|
558020
|
+
if (exited)
|
|
558021
|
+
return;
|
|
558022
|
+
exited = true;
|
|
558023
|
+
clearTimeout(timer);
|
|
558024
|
+
signal?.removeEventListener("abort", onAbort);
|
|
558025
|
+
resolve({
|
|
558026
|
+
...result,
|
|
558027
|
+
durationMs: Math.round(performance.now() - start),
|
|
558028
|
+
command: `${preset.command} ${argv.map((a) => a.includes(" ") ? `"${a}"` : a).join(" ")}`
|
|
558029
|
+
});
|
|
558030
|
+
};
|
|
558031
|
+
proc.on("error", (err) => {
|
|
558032
|
+
finish({
|
|
558033
|
+
ok: false,
|
|
558034
|
+
text: "",
|
|
558035
|
+
error: err.code === "ENOENT" ? `${preset.command}: not installed (no binary on $PATH)` : err.message,
|
|
558036
|
+
exitCode: null
|
|
558037
|
+
});
|
|
558038
|
+
});
|
|
558039
|
+
proc.stdout?.on("data", (chunk) => {
|
|
558040
|
+
stdout += chunk.toString();
|
|
558041
|
+
});
|
|
558042
|
+
proc.stderr?.on("data", (chunk) => {
|
|
558043
|
+
stderr += chunk.toString();
|
|
558044
|
+
});
|
|
558045
|
+
proc.on("close", (code) => {
|
|
558046
|
+
let text = preset.parseStdout ? preset.parseStdout(stdout).trim() : stdout.trim();
|
|
558047
|
+
try {
|
|
558048
|
+
init_keys();
|
|
558049
|
+
if (text)
|
|
558050
|
+
text = redactAndWarn(text);
|
|
558051
|
+
} catch {}
|
|
558052
|
+
if (code === 0 || code !== null && text.length > 0) {
|
|
558053
|
+
finish({ ok: code === 0, text, exitCode: code, error: code === 0 ? undefined : stderr.trim().slice(0, 400) });
|
|
558054
|
+
} else {
|
|
558055
|
+
finish({
|
|
558056
|
+
ok: false,
|
|
558057
|
+
text,
|
|
558058
|
+
exitCode: code,
|
|
558059
|
+
error: stderr.trim().slice(0, 400) || `exited with code ${code}`
|
|
558060
|
+
});
|
|
558061
|
+
}
|
|
558062
|
+
});
|
|
558063
|
+
if (preset.promptMode === "stdin" && proc.stdin) {
|
|
558064
|
+
proc.stdin.write(prompt);
|
|
558065
|
+
proc.stdin.end();
|
|
558066
|
+
} else if (proc.stdin) {
|
|
558067
|
+
proc.stdin.end();
|
|
558068
|
+
}
|
|
558069
|
+
const timer = setTimeout(() => {
|
|
558070
|
+
proc.kill("SIGTERM");
|
|
558071
|
+
finish({
|
|
558072
|
+
ok: false,
|
|
558073
|
+
text: stdout,
|
|
558074
|
+
error: `timeout after ${preset.timeoutMs ?? 90000}ms`,
|
|
558075
|
+
exitCode: null
|
|
558076
|
+
});
|
|
558077
|
+
}, preset.timeoutMs ?? 90000);
|
|
558078
|
+
const onAbort = () => {
|
|
558079
|
+
proc.kill("SIGTERM");
|
|
558080
|
+
finish({ ok: false, text: stdout, error: "aborted", exitCode: null });
|
|
558081
|
+
};
|
|
558082
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
558083
|
+
});
|
|
558084
|
+
}
|
|
558085
|
+
var stripAnsi2 = (s) => s.replace(/\u001B\[[0-9;?]*[a-zA-Z]/g, "").replace(/\u001B\][^\u0007]*\u0007/g, ""), EXTERNAL_AGENT_PRESETS;
|
|
558086
|
+
var init_external_agent_runner = __esm(() => {
|
|
558087
|
+
init_shell();
|
|
558088
|
+
EXTERNAL_AGENT_PRESETS = {
|
|
558089
|
+
claude: {
|
|
558090
|
+
id: "claude",
|
|
558091
|
+
label: "Sparring",
|
|
558092
|
+
command: "claude",
|
|
558093
|
+
promptMode: "flag",
|
|
558094
|
+
flagName: "-p",
|
|
558095
|
+
args: [],
|
|
558096
|
+
timeoutMs: 120000,
|
|
558097
|
+
parseStdout: stripAnsi2,
|
|
558098
|
+
homepage: "https://docs.claude.com/en/docs/claude-code",
|
|
558099
|
+
preferWindow: true,
|
|
558100
|
+
install: {
|
|
558101
|
+
command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
|
|
558102
|
+
notes: 'Binary at ~/.npm-global/bin/claude. If `claude` isn\'t on PATH after install, add `export PATH="$HOME/.npm-global/bin:$PATH"` to your shell rc. Then run `claude` once outside the TUI to authenticate with Anthropic.'
|
|
558103
|
+
}
|
|
558104
|
+
},
|
|
558105
|
+
codex: {
|
|
558106
|
+
id: "codex",
|
|
558107
|
+
label: "OpenAI Codex",
|
|
558108
|
+
command: "codex",
|
|
558109
|
+
promptMode: "arg",
|
|
558110
|
+
args: ["exec"],
|
|
558111
|
+
timeoutMs: 120000,
|
|
558112
|
+
parseStdout: stripAnsi2,
|
|
558113
|
+
homepage: "https://github.com/openai/codex",
|
|
558114
|
+
preferWindow: true,
|
|
558115
|
+
install: {
|
|
558116
|
+
command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
|
|
558117
|
+
notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
|
|
558118
|
+
}
|
|
558119
|
+
},
|
|
558120
|
+
hermes: {
|
|
558121
|
+
id: "hermes",
|
|
558122
|
+
label: "Hermes Agent",
|
|
558123
|
+
command: "hermes",
|
|
558124
|
+
preferWindow: true,
|
|
558125
|
+
promptMode: "flag",
|
|
558126
|
+
flagName: "-z",
|
|
558127
|
+
args: [],
|
|
558128
|
+
timeoutMs: 120000,
|
|
558129
|
+
parseStdout: stripAnsi2,
|
|
558130
|
+
homepage: "https://github.com/NousResearch/hermes-agent",
|
|
558131
|
+
install: {
|
|
558132
|
+
command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
|
|
558133
|
+
notes: "Hermes needs Python \u2265 3.11 (anaconda's default 3.10 won't work; use pyenv or brew install python@3.11). Installer symlinks `hermes` into ~/.local/bin; add it to PATH if needed. After install, run `hermes setup` or `hermes model` outside the TUI to configure a provider. Without that, /spawn'd Hermes tabs will fail with auth errors (Bedrock is the default provider)."
|
|
558134
|
+
}
|
|
558135
|
+
},
|
|
558136
|
+
openclaw: {
|
|
558137
|
+
id: "openclaw",
|
|
558138
|
+
label: "OpenClaw",
|
|
558139
|
+
command: "openclaw",
|
|
558140
|
+
preferWindow: true,
|
|
558141
|
+
promptMode: "arg",
|
|
558142
|
+
args: ["run", "--headless"],
|
|
558143
|
+
timeoutMs: 120000,
|
|
558144
|
+
parseStdout: stripAnsi2,
|
|
558145
|
+
homepage: "https://github.com/openclaw/openclaw",
|
|
558146
|
+
install: {
|
|
558147
|
+
command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
|
|
558148
|
+
notes: "Binary at ~/.npm-global/bin/openclaw. Add `~/.npm-global/bin` to PATH if needed. After install run `openclaw onboard` outside the TUI to set up the gateway, workspace, and skills. (8gent now provides a managed Node 22 runtime automatically when needed; no separate nvm step required.)"
|
|
558149
|
+
},
|
|
558150
|
+
requiresNodeVersion: "22.14.0"
|
|
558151
|
+
},
|
|
558152
|
+
pi: {
|
|
558153
|
+
preferWindow: true,
|
|
558154
|
+
id: "pi",
|
|
558155
|
+
label: "Pi (pi-mono)",
|
|
558156
|
+
command: "pi",
|
|
558157
|
+
promptMode: "flag",
|
|
558158
|
+
flagName: "-p",
|
|
558159
|
+
args: [],
|
|
558160
|
+
timeoutMs: 120000,
|
|
558161
|
+
parseStdout: stripAnsi2,
|
|
558162
|
+
homepage: "https://pi.dev",
|
|
558163
|
+
install: {
|
|
558164
|
+
command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
|
|
558165
|
+
notes: "Binary at ~/.npm-global/bin/pi. Add `~/.npm-global/bin` to PATH if needed. Default provider is Google (Gemini). Set GEMINI_API_KEY, or override with --provider/--model and the matching API key env var (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY)."
|
|
558166
|
+
}
|
|
558167
|
+
},
|
|
558168
|
+
"8gent": {
|
|
558169
|
+
id: "8gent",
|
|
558170
|
+
label: "8gent (nested)",
|
|
558171
|
+
command: "8gent",
|
|
558172
|
+
promptMode: "arg",
|
|
558173
|
+
args: ["run"],
|
|
558174
|
+
timeoutMs: 180000,
|
|
558175
|
+
parseStdout: stripAnsi2,
|
|
558176
|
+
homepage: "https://8gent.dev",
|
|
558177
|
+
install: {
|
|
558178
|
+
command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
|
|
558179
|
+
notes: "Binary at ~/.npm-global/bin/8gent. --force overwrites stale `8` / `8gent` / `8gent-code` bin symlinks (npm 9+ EEXIST). Add `~/.npm-global/bin` to PATH if not already."
|
|
558180
|
+
}
|
|
558181
|
+
}
|
|
558182
|
+
};
|
|
558183
|
+
});
|
|
558184
|
+
|
|
558185
|
+
// packages/eight/welcome.ts
|
|
558186
|
+
import { existsSync as existsSync106 } from "fs";
|
|
558187
|
+
import { basename as basename51, delimiter as delimiter8, dirname as dirname74, isAbsolute as isAbsolute49, join as join158, relative as relative34, resolve as resolve72 } from "path";
|
|
558188
|
+
function pathOutsideFolder(path, cwd) {
|
|
558189
|
+
const root = resolve72(cwd);
|
|
558190
|
+
return path.split(delimiter8).filter((dir) => {
|
|
558191
|
+
if (!dir || !isAbsolute49(dir))
|
|
558192
|
+
return false;
|
|
558193
|
+
const rel = relative34(root, resolve72(dir));
|
|
558194
|
+
return rel.startsWith("..") || isAbsolute49(rel);
|
|
558195
|
+
}).join(delimiter8);
|
|
558196
|
+
}
|
|
558197
|
+
function safeModelLabel(model) {
|
|
558198
|
+
const m = model.trim();
|
|
558199
|
+
if (!m || m.length > 80 || /:\/\/|[@?\s]/.test(m))
|
|
558200
|
+
return "a custom model";
|
|
558201
|
+
return m;
|
|
558202
|
+
}
|
|
558203
|
+
function inGitRepo(dir) {
|
|
558204
|
+
let d = dir;
|
|
558205
|
+
for (let i = 0;i < 64; i++) {
|
|
558206
|
+
if (existsSync106(join158(d, ".git")))
|
|
558207
|
+
return true;
|
|
558208
|
+
const up = dirname74(d);
|
|
558209
|
+
if (up === d)
|
|
558210
|
+
return false;
|
|
558211
|
+
d = up;
|
|
558212
|
+
}
|
|
558213
|
+
return false;
|
|
558214
|
+
}
|
|
558215
|
+
function hostLabel(android, platform, arch) {
|
|
558216
|
+
if (android)
|
|
558217
|
+
return `Android (Termux, ${arch})`;
|
|
558218
|
+
const os = platform === "darwin" ? "macOS" : platform === "linux" ? "Linux" : platform === "win32" ? "Windows" : platform;
|
|
558219
|
+
return `${os} ${arch}`;
|
|
558220
|
+
}
|
|
558221
|
+
async function knownPresets() {
|
|
558222
|
+
const runner = await Promise.resolve().then(() => (init_external_agent_runner(), {}));
|
|
558223
|
+
const out = [];
|
|
558224
|
+
for (const id of listPresetIds()) {
|
|
558225
|
+
const p = getPreset(id);
|
|
558226
|
+
if (p)
|
|
558227
|
+
out.push({ id: p.id, command: p.command });
|
|
558228
|
+
}
|
|
558229
|
+
return out;
|
|
558230
|
+
}
|
|
558231
|
+
async function gatherWelcomeFacts(opts) {
|
|
558232
|
+
const env = opts.env ?? process.env;
|
|
558233
|
+
const android = isAndroidHost(opts.platform ?? process.platform, env);
|
|
558234
|
+
const cwd = resolve72(opts.cwd);
|
|
558235
|
+
const home = env.HOME ? resolve72(env.HOME) : null;
|
|
558236
|
+
const lookupEnv = { ...env, PATH: pathOutsideFolder(String(env.PATH ?? ""), cwd) };
|
|
558237
|
+
const presets = (opts.presets ?? await knownPresets()).filter((p) => p.id !== "8gent");
|
|
558238
|
+
return {
|
|
558239
|
+
version: String(import_package.default.version),
|
|
558240
|
+
host: hostLabel(android, opts.platform ?? process.platform, opts.arch ?? process.arch),
|
|
558241
|
+
android,
|
|
558242
|
+
model: safeModelLabel(opts.model),
|
|
558243
|
+
provider: opts.provider,
|
|
558244
|
+
presetIds: presets.map((p) => p.id),
|
|
558245
|
+
installed: presets.filter((p) => findOnPath(p.command, lookupEnv) !== null).map((p) => p.id),
|
|
558246
|
+
folder: cwd === home ? "~" : basename51(cwd) || "/",
|
|
558247
|
+
gitRepo: inGitRepo(cwd)
|
|
558248
|
+
};
|
|
558249
|
+
}
|
|
558250
|
+
function listWords(items) {
|
|
558251
|
+
if (items.length <= 1)
|
|
558252
|
+
return items.join("");
|
|
558253
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
558254
|
+
}
|
|
558255
|
+
function buildWelcome(f) {
|
|
558256
|
+
const where = f.android ? "phone" : "machine";
|
|
558257
|
+
const lines = [`Hi, I'm 8gent v${f.version} on ${f.host}, using ${f.model} via ${f.provider}.`];
|
|
558258
|
+
if (f.installed.length > 0) {
|
|
558259
|
+
lines.push(`On this ${where} I found ${listWords(f.installed)}. Say "run ${f.installed[0]}" and I'll open it in a tab beside me.`);
|
|
558260
|
+
} else {
|
|
558261
|
+
lines.push(`I checked PATH for ${listWords(f.presetIds)}: none installed, so it's just me here.`);
|
|
558262
|
+
}
|
|
558263
|
+
lines.push(f.gitRepo ? `This folder (${f.folder}) is a git repo, so I can read its history and run its tests.` : `This folder (${f.folder}) is not a git repo. I won't look through it unless you ask.`);
|
|
558264
|
+
const next = [];
|
|
558265
|
+
if (f.installed.length > 0)
|
|
558266
|
+
next.push(`run ${f.installed[0]}`);
|
|
558267
|
+
next.push(f.gitRepo ? "what changed in the last commit" : "make a folder called demo with a hello web page");
|
|
558268
|
+
next.push("what can you do");
|
|
558269
|
+
lines.push("Try:", ...next.map((n) => ` "${n}"`));
|
|
558270
|
+
return lines.join(`
|
|
558271
|
+
`);
|
|
558272
|
+
}
|
|
558273
|
+
var import_package;
|
|
558274
|
+
var init_welcome = __esm(() => {
|
|
558275
|
+
init_termux();
|
|
558276
|
+
import_package = __toESM(require_package(), 1);
|
|
558277
|
+
});
|
|
558278
|
+
|
|
557427
558279
|
// packages/eight/failover-provider-config.ts
|
|
557428
558280
|
function providerConfigForStep(session, step) {
|
|
557429
558281
|
if (step.provider === session.name) {
|
|
@@ -557945,8 +558797,8 @@ var init_local_turn_error = __esm(() => {
|
|
|
557945
558797
|
});
|
|
557946
558798
|
|
|
557947
558799
|
// packages/eight/output-gate.ts
|
|
557948
|
-
import { existsSync as
|
|
557949
|
-
import { isAbsolute as
|
|
558800
|
+
import { existsSync as existsSync107 } from "fs";
|
|
558801
|
+
import { isAbsolute as isAbsolute50, relative as relative35, resolve as resolve73 } from "path";
|
|
557950
558802
|
function isOutputGateEnabled(env = process.env, option) {
|
|
557951
558803
|
if (option !== undefined)
|
|
557952
558804
|
return option;
|
|
@@ -557978,10 +558830,10 @@ class OutputGate {
|
|
|
557978
558830
|
events = [];
|
|
557979
558831
|
constructor(task, cwd, enabled) {
|
|
557980
558832
|
this.cwd = cwd;
|
|
557981
|
-
this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs:
|
|
558833
|
+
this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs: resolve73(cwd, shown) })).filter(({ abs }) => !relative35(cwd, abs).startsWith("..") && !isAbsolute50(relative35(cwd, abs))).filter(({ abs }) => !existsSync107(abs));
|
|
557982
558834
|
}
|
|
557983
558835
|
missing() {
|
|
557984
|
-
return this.required.filter(({ abs }) => !
|
|
558836
|
+
return this.required.filter(({ abs }) => !existsSync107(abs)).map(({ shown }) => shown);
|
|
557985
558837
|
}
|
|
557986
558838
|
check(reply) {
|
|
557987
558839
|
const missing = this.missing();
|
|
@@ -558019,7 +558871,7 @@ var init_output_gate = __esm(() => {
|
|
|
558019
558871
|
function stripPunctuation(s) {
|
|
558020
558872
|
return s.replace(/[.,;:!?]+$/g, "").trim();
|
|
558021
558873
|
}
|
|
558022
|
-
function
|
|
558874
|
+
function isGreeting2(message) {
|
|
558023
558875
|
const stripped = stripPunctuation(message.toLowerCase()).trim();
|
|
558024
558876
|
if (stripped.length === 0)
|
|
558025
558877
|
return true;
|
|
@@ -558040,7 +558892,7 @@ class PreToolRouter {
|
|
|
558040
558892
|
classify(userMessage, _projectContext) {
|
|
558041
558893
|
const msg = userMessage ?? "";
|
|
558042
558894
|
const trimmed = msg.trim();
|
|
558043
|
-
if (trimmed.length === 0 ||
|
|
558895
|
+
if (trimmed.length === 0 || isGreeting2(trimmed)) {
|
|
558044
558896
|
return {
|
|
558045
558897
|
strategy: "none",
|
|
558046
558898
|
args: {},
|
|
@@ -558312,12 +559164,12 @@ __export(exports_system_prompt, {
|
|
|
558312
559164
|
styleHasGuide: () => styleHasGuide,
|
|
558313
559165
|
workingProjectNote: () => workingProjectNote
|
|
558314
559166
|
});
|
|
558315
|
-
import { readFileSync as
|
|
558316
|
-
import { basename as
|
|
559167
|
+
import { existsSync as existsSync108, readFileSync as readFileSync97 } from "fs";
|
|
559168
|
+
import { basename as basename52, join as join159, resolve as resolve74 } from "path";
|
|
558317
559169
|
function buildBoardContextSegment(path = BOARD_CONTEXT_PATH) {
|
|
558318
559170
|
let text;
|
|
558319
559171
|
try {
|
|
558320
|
-
text =
|
|
559172
|
+
text = readFileSync97(path, "utf-8").trim();
|
|
558321
559173
|
} catch {
|
|
558322
559174
|
return "";
|
|
558323
559175
|
}
|
|
@@ -558344,8 +559196,20 @@ function communicationStyleLine(style) {
|
|
|
558344
559196
|
function styleHasGuide(style) {
|
|
558345
559197
|
return isCommunicationStyle(style) && STYLE_GUIDE[style] !== "";
|
|
558346
559198
|
}
|
|
559199
|
+
function isPlainHome(dir, home = resolveHome()) {
|
|
559200
|
+
try {
|
|
559201
|
+
return home !== "" && resolve74(dir) === resolve74(home) && !existsSync108(join159(dir, ".git"));
|
|
559202
|
+
} catch {
|
|
559203
|
+
return false;
|
|
559204
|
+
}
|
|
559205
|
+
}
|
|
558347
559206
|
function workingProjectNote(dir) {
|
|
558348
|
-
const name =
|
|
559207
|
+
const name = basename52(dir) || dir;
|
|
559208
|
+
if (isPlainHome(dir)) {
|
|
559209
|
+
return `
|
|
559210
|
+
|
|
559211
|
+
**Working folder: \`${dir}\` is the person's home folder, not a project. Do not list, search or summarise it unless they ask. Ask what they want to work on.**`;
|
|
559212
|
+
}
|
|
558349
559213
|
if (name === "8gent-code") {
|
|
558350
559214
|
return `
|
|
558351
559215
|
|
|
@@ -558689,7 +559553,7 @@ var init_system_prompt = __esm(() => {
|
|
|
558689
559553
|
init_tool_registry();
|
|
558690
559554
|
init_soul_layers();
|
|
558691
559555
|
IDENTITY_SEGMENT = composeSoulPrompt("owner");
|
|
558692
|
-
BOARD_CONTEXT_PATH =
|
|
559556
|
+
BOARD_CONTEXT_PATH = join159(resolveHome(), ".8gent", "board-context.md");
|
|
558693
559557
|
ACTION_FIRST_STYLE = [
|
|
558694
559558
|
"Shape every reply so the reader can act without rereading:",
|
|
558695
559559
|
ACTION_FIRST_PRECEDENCE,
|
|
@@ -559043,11 +559907,11 @@ var init_toolshed_bridge = __esm(() => {
|
|
|
559043
559907
|
});
|
|
559044
559908
|
|
|
559045
559909
|
// packages/ai/embedding-cache.ts
|
|
559046
|
-
import { join as
|
|
559910
|
+
import { join as join160 } from "path";
|
|
559047
559911
|
var CACHE_DIR, CACHE_PATH;
|
|
559048
559912
|
var init_embedding_cache = __esm(() => {
|
|
559049
|
-
CACHE_DIR =
|
|
559050
|
-
CACHE_PATH =
|
|
559913
|
+
CACHE_DIR = join160(process.env.HOME || "~", ".8gent");
|
|
559914
|
+
CACHE_PATH = join160(CACHE_DIR, "embedding-cache.json");
|
|
559051
559915
|
});
|
|
559052
559916
|
|
|
559053
559917
|
// packages/ai/edge-inference.ts
|
|
@@ -559326,20 +560190,20 @@ var init_quick_answer = __esm(() => {
|
|
|
559326
560190
|
});
|
|
559327
560191
|
|
|
559328
560192
|
// packages/eight/session-scratch.ts
|
|
559329
|
-
import { lstatSync as lstatSync30, mkdirSync as
|
|
560193
|
+
import { lstatSync as lstatSync30, mkdirSync as mkdirSync75, rmSync as rmSync15 } from "fs";
|
|
559330
560194
|
import { tmpdir as tmpdir19 } from "os";
|
|
559331
|
-
import { join as
|
|
560195
|
+
import { join as join161 } from "path";
|
|
559332
560196
|
function removeAllAtExit() {
|
|
559333
560197
|
for (const dir of [...live2])
|
|
559334
560198
|
removeSessionScratch(dir);
|
|
559335
560199
|
}
|
|
559336
560200
|
function sessionScratchPath(sessionId) {
|
|
559337
|
-
return
|
|
560201
|
+
return join161(tmpdir19(), `8gent-${sessionId}`);
|
|
559338
560202
|
}
|
|
559339
560203
|
function createSessionScratch(sessionId) {
|
|
559340
560204
|
const dir = sessionScratchPath(sessionId);
|
|
559341
560205
|
try {
|
|
559342
|
-
|
|
560206
|
+
mkdirSync75(dir, { mode: 448 });
|
|
559343
560207
|
live2.add(dir);
|
|
559344
560208
|
if (!exitHandlerSet) {
|
|
559345
560209
|
exitHandlerSet = true;
|
|
@@ -559360,7 +560224,7 @@ function removeSessionScratch(dir) {
|
|
|
559360
560224
|
return;
|
|
559361
560225
|
if (typeof process.getuid === "function" && st.uid !== process.getuid())
|
|
559362
560226
|
return;
|
|
559363
|
-
|
|
560227
|
+
rmSync15(dir, { recursive: true, force: true });
|
|
559364
560228
|
} catch {}
|
|
559365
560229
|
}
|
|
559366
560230
|
function sessionScratchNote(dir) {
|
|
@@ -567239,19 +568103,19 @@ var init_opportunity_scanner = () => {};
|
|
|
567239
568103
|
var init_capability_matcher = () => {};
|
|
567240
568104
|
|
|
567241
568105
|
// packages/proactive/work-tracker.ts
|
|
567242
|
-
import { join as
|
|
568106
|
+
import { join as join164 } from "path";
|
|
567243
568107
|
var DATA_DIR3, STORE_PATH;
|
|
567244
568108
|
var init_work_tracker = __esm(() => {
|
|
567245
|
-
DATA_DIR3 =
|
|
567246
|
-
STORE_PATH =
|
|
568109
|
+
DATA_DIR3 = join164(process.env.HOME || "~", ".8gent");
|
|
568110
|
+
STORE_PATH = join164(DATA_DIR3, "opportunities.json");
|
|
567247
568111
|
});
|
|
567248
568112
|
|
|
567249
568113
|
// packages/proactive/revenue-engine.ts
|
|
567250
|
-
import { join as
|
|
568114
|
+
import { join as join165 } from "path";
|
|
567251
568115
|
var DATA_DIR4, STORE_PATH2;
|
|
567252
568116
|
var init_revenue_engine = __esm(() => {
|
|
567253
|
-
DATA_DIR4 =
|
|
567254
|
-
STORE_PATH2 =
|
|
568117
|
+
DATA_DIR4 = join165(process.env.HOME || "~", ".8gent");
|
|
568118
|
+
STORE_PATH2 = join165(DATA_DIR4, "revenue.json");
|
|
567255
568119
|
});
|
|
567256
568120
|
|
|
567257
568121
|
// packages/proactive/deliverable-generator.ts
|
|
@@ -567264,11 +568128,11 @@ var init_client_outreach = () => {};
|
|
|
567264
568128
|
var init_content_packaging = () => {};
|
|
567265
568129
|
|
|
567266
568130
|
// packages/tools/browser/cache.ts
|
|
567267
|
-
import { homedir as
|
|
567268
|
-
import { join as
|
|
568131
|
+
import { homedir as homedir81 } from "os";
|
|
568132
|
+
import { join as join166 } from "path";
|
|
567269
568133
|
var CACHE_DIR2, TTL_MS, MAX_CACHE_BYTES;
|
|
567270
568134
|
var init_cache2 = __esm(() => {
|
|
567271
|
-
CACHE_DIR2 =
|
|
568135
|
+
CACHE_DIR2 = join166(process.env.EIGHT_DATA_DIR || join166(homedir81(), ".8gent"), "browser-cache");
|
|
567272
568136
|
TTL_MS = 60 * 60 * 1000;
|
|
567273
568137
|
MAX_CACHE_BYTES = 100 * 1024 * 1024;
|
|
567274
568138
|
});
|
|
@@ -568011,7 +568875,7 @@ var init_voice3 = __esm(() => {
|
|
|
568011
568875
|
|
|
568012
568876
|
// packages/eight/observation-pack.ts
|
|
568013
568877
|
import { createHash as createHash21 } from "crypto";
|
|
568014
|
-
import { readFileSync as
|
|
568878
|
+
import { readFileSync as readFileSync99 } from "fs";
|
|
568015
568879
|
function observationPackEnabled(env = process.env) {
|
|
568016
568880
|
return env.EIGHT_OBSERVATION_PACK === "1";
|
|
568017
568881
|
}
|
|
@@ -568031,7 +568895,7 @@ class ObservationStore {
|
|
|
568031
568895
|
const path = this.paths.get(handle);
|
|
568032
568896
|
if (!path)
|
|
568033
568897
|
throw new Error(`no saved output with handle "${handle}" in this session`);
|
|
568034
|
-
return
|
|
568898
|
+
return readFileSync99(path, "utf8").slice(offset, offset + limit);
|
|
568035
568899
|
}
|
|
568036
568900
|
size(handle) {
|
|
568037
568901
|
return this.read(handle).length;
|
|
@@ -569040,6 +569904,7 @@ class Agent {
|
|
|
569040
569904
|
steerQueue = [];
|
|
569041
569905
|
activeTurn = null;
|
|
569042
569906
|
turnCounter = 0;
|
|
569907
|
+
welcomed = false;
|
|
569043
569908
|
stopRequested = false;
|
|
569044
569909
|
orchestratorBus;
|
|
569045
569910
|
toolRegistry;
|
|
@@ -569507,14 +570372,15 @@ ${LOCAL_LOGIN_NOTE}`;
|
|
|
569507
570372
|
instructions,
|
|
569508
570373
|
localCoreTools,
|
|
569509
570374
|
chatStartTime,
|
|
569510
|
-
textForAgent
|
|
570375
|
+
textForAgent,
|
|
570376
|
+
smallTalk = false
|
|
569511
570377
|
} = opts;
|
|
569512
570378
|
const signal = this.armController().signal;
|
|
569513
570379
|
const allow = new Set(localCoreTools);
|
|
569514
570380
|
const specs = toolDefsToSpecs(this.executor.getToolDefinitions(), allow);
|
|
569515
570381
|
let stepNumber = 0;
|
|
569516
570382
|
let breakerStop = null;
|
|
569517
|
-
if (this.extensionToolsAllowed()) {
|
|
570383
|
+
if (this.extensionToolsAllowed() && !smallTalk) {
|
|
569518
570384
|
for (const t of this.extensionHost.listTools()) {
|
|
569519
570385
|
if (this.modeAllows(t.name)) {
|
|
569520
570386
|
specs.push({ name: t.name, description: t.description, parameters: t.parameters });
|
|
@@ -570078,6 +570944,21 @@ ${LOCAL_LOGIN_NOTE}`;
|
|
|
570078
570944
|
console.log(`[turn-review] ${line}`);
|
|
570079
570945
|
}
|
|
570080
570946
|
}
|
|
570947
|
+
async greetingWelcome(text) {
|
|
570948
|
+
if (this.welcomed || this.config.headless || this.agentDepth > 0 || !isGreeting(text))
|
|
570949
|
+
return null;
|
|
570950
|
+
try {
|
|
570951
|
+
const facts = await gatherWelcomeFacts({
|
|
570952
|
+
model: String(this.config.model),
|
|
570953
|
+
provider: String(this.config.runtime),
|
|
570954
|
+
cwd: this.config.workingDirectory || process.cwd()
|
|
570955
|
+
});
|
|
570956
|
+
this.welcomed = true;
|
|
570957
|
+
return buildWelcome(facts);
|
|
570958
|
+
} catch {
|
|
570959
|
+
return null;
|
|
570960
|
+
}
|
|
570961
|
+
}
|
|
570081
570962
|
async runTurn(userMessage, imageBase64, imageMimeType, imageOriginal) {
|
|
570082
570963
|
await this.extensionsReady;
|
|
570083
570964
|
this.loopDetector.reset();
|
|
@@ -570092,6 +570973,17 @@ ${LOCAL_LOGIN_NOTE}`;
|
|
|
570092
570973
|
this.turnGitBaseline = asksForCommit(userMessage) ? gitSnapshot(this.config.workingDirectory || process.cwd()) : null;
|
|
570093
570974
|
this.executor.beginTurn(userMessage);
|
|
570094
570975
|
const textForAgent = userMessage.trim() || (imageBase64 ? "The user attached an image with no text. Describe what you see and help with anything relevant in the image." : userMessage);
|
|
570976
|
+
const smallTalkTurn = isSmallTalk(textForAgent) && !imageBase64 && this.config.agentScope !== "__table__";
|
|
570977
|
+
if (smallTalkTurn) {
|
|
570978
|
+
const welcome = await this.greetingWelcome(textForAgent);
|
|
570979
|
+
if (welcome) {
|
|
570980
|
+
this.messageHistory.push({ role: "user", content: textForAgent });
|
|
570981
|
+
this.messageHistory.push({ role: "assistant", content: welcome });
|
|
570982
|
+
this.sessionWriter.writeUserMessage(textForAgent);
|
|
570983
|
+
return welcome;
|
|
570984
|
+
}
|
|
570985
|
+
this.messageHistory.push({ role: "user", content: harnessNote(SMALL_TALK_NOTE) });
|
|
570986
|
+
}
|
|
570095
570987
|
let visionId = null;
|
|
570096
570988
|
let visionFailed = false;
|
|
570097
570989
|
if (imageBase64 && await this.promptImageSeen()) {
|
|
@@ -570162,7 +571054,7 @@ ${result.description.slice(0, 200)}${result.description.length > 200 ? "..." : "
|
|
|
570162
571054
|
}
|
|
570163
571055
|
}
|
|
570164
571056
|
const quickPrompt = quickLaneEnabled() && classifyPrompt(textForAgent) === "quick";
|
|
570165
|
-
if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !isNoToolScope(this.config.agentScope)) {
|
|
571057
|
+
if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !smallTalkTurn && !isNoToolScope(this.config.agentScope)) {
|
|
570166
571058
|
this.proactiveGatherer = createGatherer(textForAgent);
|
|
570167
571059
|
const question = this.proactiveGatherer.getCurrentQuestion();
|
|
570168
571060
|
if (question) {
|
|
@@ -570184,7 +571076,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
570184
571076
|
this.kanban.moveTask(this.currentBmadTask.id, "ready");
|
|
570185
571077
|
this.kanban.moveTask(this.currentBmadTask.id, "in_progress");
|
|
570186
571078
|
}
|
|
570187
|
-
if (!this.proactiveGatherer && !quickPrompt) {
|
|
571079
|
+
if (!this.proactiveGatherer && !quickPrompt && !smallTalkTurn) {
|
|
570188
571080
|
await this.tryRunPreToolRouter(textForAgent);
|
|
570189
571081
|
}
|
|
570190
571082
|
const needsPlanningGate2 = !isVerbatimScope(this.config.agentScope) && needsPlanningGate(textForAgent);
|
|
@@ -570329,9 +571221,9 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
570329
571221
|
"search_symbols",
|
|
570330
571222
|
"recall"
|
|
570331
571223
|
]);
|
|
570332
|
-
const scopedTools = isNoToolScope(this.config.agentScope) ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
|
|
571224
|
+
const scopedTools = isNoToolScope(this.config.agentScope) || smallTalkTurn ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
|
|
570333
571225
|
const withExtensions = { ...scopedTools };
|
|
570334
|
-
if (this.extensionToolsAllowed()) {
|
|
571226
|
+
if (this.extensionToolsAllowed() && !smallTalkTurn) {
|
|
570335
571227
|
for (const t of this.extensionHost.listTools()) {
|
|
570336
571228
|
if (t.name in withExtensions)
|
|
570337
571229
|
continue;
|
|
@@ -570343,7 +571235,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
570343
571235
|
}
|
|
570344
571236
|
}
|
|
570345
571237
|
const effectiveTools = this.modeFilter(withExtensions);
|
|
570346
|
-
const textToolAllowlist = (isNoToolScope(this.config.agentScope) ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
|
|
571238
|
+
const textToolAllowlist = (isNoToolScope(this.config.agentScope) || smallTalkTurn ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
|
|
570347
571239
|
const harness = this.harnessProfileFor(providerConfig.model, isLocalProvider);
|
|
570348
571240
|
Object.assign(this.runtimeParams, {
|
|
570349
571241
|
voiceChatActive: getRuntimeParams().voiceChatActive,
|
|
@@ -570368,7 +571260,8 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
570368
571260
|
`),
|
|
570369
571261
|
localCoreTools: textToolAllowlist,
|
|
570370
571262
|
chatStartTime,
|
|
570371
|
-
textForAgent
|
|
571263
|
+
textForAgent,
|
|
571264
|
+
smallTalk: smallTalkTurn
|
|
570372
571265
|
});
|
|
570373
571266
|
await this.readServerContextWindow();
|
|
570374
571267
|
await this.compactIfNeeded(providerConfig);
|
|
@@ -571053,7 +571946,7 @@ ${summary || " (no provider errors recorded)"}`);
|
|
|
571053
571946
|
};
|
|
571054
571947
|
}
|
|
571055
571948
|
const blankNative = gatedNative.content.trim() === "";
|
|
571056
|
-
const content = blankNative ? emptyReplyNote(this.turnToolLedger.length) : gatedNative.content;
|
|
571949
|
+
const content = blankNative ? emptyReplyNote(this.turnToolLedger.length, this.turnToolLedger) : gatedNative.content;
|
|
571057
571950
|
const flavor = voice.getFlavor("complete");
|
|
571058
571951
|
const flavoredContent = fixCompletedLine(gatedNative.violated || isVerbatimScope(this.config.agentScope) ? content : flavorResponse(content, flavor)).text;
|
|
571059
571952
|
this.messageHistory.push({ role: "assistant", content: flavoredContent });
|
|
@@ -571768,7 +572661,9 @@ var init_agent2 = __esm(() => {
|
|
|
571768
572661
|
init_modes();
|
|
571769
572662
|
init_planning_gate();
|
|
571770
572663
|
init_registry();
|
|
572664
|
+
init_small_talk();
|
|
571771
572665
|
init_verify_gate();
|
|
572666
|
+
init_welcome();
|
|
571772
572667
|
init_local_tool_scope();
|
|
571773
572668
|
init_local_turn_error();
|
|
571774
572669
|
init_output_gate();
|
|
@@ -572262,9 +573157,9 @@ var init_install = __esm(() => {
|
|
|
572262
573157
|
});
|
|
572263
573158
|
|
|
572264
573159
|
// packages/eight/source-update.ts
|
|
572265
|
-
import { execFile as
|
|
572266
|
-
import { existsSync as
|
|
572267
|
-
import { homedir as
|
|
573160
|
+
import { execFile as execFile9 } from "child_process";
|
|
573161
|
+
import { existsSync as existsSync113, realpathSync as realpathSync36, statSync as statSync36 } from "fs";
|
|
573162
|
+
import { homedir as homedir85 } from "os";
|
|
572268
573163
|
import * as nodePath from "path";
|
|
572269
573164
|
function scrubbedEnv(base) {
|
|
572270
573165
|
const out = {};
|
|
@@ -572362,7 +573257,7 @@ function modulePathToFs(modulePath) {
|
|
|
572362
573257
|
}
|
|
572363
573258
|
return s;
|
|
572364
573259
|
}
|
|
572365
|
-
function findCheckoutRoot(modulePath, platform, hasGit = (d) =>
|
|
573260
|
+
function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync113(lib(platform).join(d, ".git"))) {
|
|
572366
573261
|
const p = lib(platform);
|
|
572367
573262
|
const fsPath = modulePathToFs(modulePath);
|
|
572368
573263
|
let dir = p.dirname(platform === "win32" ? fsPath.replace(/\//g, "\\") : fsPath);
|
|
@@ -572378,7 +573273,7 @@ function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync109(li
|
|
|
572378
573273
|
}
|
|
572379
573274
|
function findBrowserCheckout(o) {
|
|
572380
573275
|
const p = lib(o.platform);
|
|
572381
|
-
const hasGit = o.hasGit ?? ((d) =>
|
|
573276
|
+
const hasGit = o.hasGit ?? ((d) => existsSync113(p.join(d, ".git")));
|
|
572382
573277
|
const looked = [];
|
|
572383
573278
|
let note;
|
|
572384
573279
|
const cands = [];
|
|
@@ -572704,7 +573599,7 @@ async function runSourceUpdate(deps, opts, report) {
|
|
|
572704
573599
|
git,
|
|
572705
573600
|
bun: bun ?? "bun",
|
|
572706
573601
|
platform,
|
|
572707
|
-
fileExists: deps.fileExists ?? ((f) =>
|
|
573602
|
+
fileExists: deps.fileExists ?? ((f) => existsSync113(f)),
|
|
572708
573603
|
now: deps.now ?? (() => new Date),
|
|
572709
573604
|
baseEnv: env,
|
|
572710
573605
|
forgeHost: env.EIGHT_FORGE_HOST,
|
|
@@ -572728,7 +573623,7 @@ async function runSourceUpdate(deps, opts, report) {
|
|
|
572728
573623
|
report?.({ updated: true, to: short2(code.to ?? "") });
|
|
572729
573624
|
const found = findBrowserCheckout({
|
|
572730
573625
|
env,
|
|
572731
|
-
home: deps.home ??
|
|
573626
|
+
home: deps.home ?? homedir85(),
|
|
572732
573627
|
platform,
|
|
572733
573628
|
codeRoot: root,
|
|
572734
573629
|
hasGit: deps.hasGit
|
|
@@ -572754,7 +573649,7 @@ async function runSourceUpdate(deps, opts, report) {
|
|
|
572754
573649
|
return bad ? 1 : 0;
|
|
572755
573650
|
}
|
|
572756
573651
|
var T_LOCAL = 30000, T_FETCH = 120000, T_INSTALL = 600000, ENV_KEEP, defaultExec = (file, args, opts) => new Promise((resolve) => {
|
|
572757
|
-
|
|
573652
|
+
execFile9(file, args, {
|
|
572758
573653
|
cwd: opts.cwd,
|
|
572759
573654
|
timeout: opts.timeoutMs,
|
|
572760
573655
|
maxBuffer: 33554432,
|
|
@@ -573017,16 +573912,16 @@ var init_cli_maintenance = __esm(() => {
|
|
|
573017
573912
|
});
|
|
573018
573913
|
|
|
573019
573914
|
// packages/eight/update-resume.ts
|
|
573020
|
-
import { mkdirSync as
|
|
573021
|
-
import { join as
|
|
573915
|
+
import { mkdirSync as mkdirSync79, readFileSync as readFileSync103, rmSync as rmSync16, writeFileSync as writeFileSync61 } from "fs";
|
|
573916
|
+
import { join as join171 } from "path";
|
|
573022
573917
|
function dataDir4(env = process.env) {
|
|
573023
|
-
return
|
|
573918
|
+
return join171(resolveHome(env), ".8gent");
|
|
573024
573919
|
}
|
|
573025
573920
|
function writeResumeRequest(req, env = process.env) {
|
|
573026
|
-
|
|
573921
|
+
mkdirSync79(dataDir4(env), { recursive: true });
|
|
573027
573922
|
writeFileSync61(file(env), JSON.stringify(req), "utf8");
|
|
573028
573923
|
}
|
|
573029
|
-
var RELAUNCH_EXIT_CODE = 75, file = (env) =>
|
|
573924
|
+
var RELAUNCH_EXIT_CODE = 75, file = (env) => join171(dataDir4(env), "update-resume.json");
|
|
573030
573925
|
var init_update_resume = __esm(() => {
|
|
573031
573926
|
init_home();
|
|
573032
573927
|
});
|
|
@@ -573038,8 +573933,8 @@ __export(exports_update_notice, {
|
|
|
573038
573933
|
maybeUpdateNotice: () => maybeUpdateNotice,
|
|
573039
573934
|
realNoticeDeps: () => realNoticeDeps
|
|
573040
573935
|
});
|
|
573041
|
-
import { mkdirSync as
|
|
573042
|
-
import { join as
|
|
573936
|
+
import { mkdirSync as mkdirSync80, readFileSync as readFileSync104, writeFileSync as writeFileSync62 } from "fs";
|
|
573937
|
+
import { join as join172 } from "path";
|
|
573043
573938
|
function noticeText(from, to) {
|
|
573044
573939
|
return `Update available (${from} -> ${to}). Run 8gent update, or type /update.`;
|
|
573045
573940
|
}
|
|
@@ -573053,7 +573948,7 @@ function updateCheckDisabled(env, settingsFile) {
|
|
|
573053
573948
|
return true;
|
|
573054
573949
|
if (settingsFile) {
|
|
573055
573950
|
try {
|
|
573056
|
-
const s = JSON.parse(
|
|
573951
|
+
const s = JSON.parse(readFileSync104(settingsFile, "utf8"));
|
|
573057
573952
|
if (s.updateCheck === false)
|
|
573058
573953
|
return true;
|
|
573059
573954
|
} catch {}
|
|
@@ -573090,7 +573985,7 @@ async function maybeUpdateNotice(d) {
|
|
|
573090
573985
|
function realNoticeDeps(o) {
|
|
573091
573986
|
const env = o.env ?? process.env;
|
|
573092
573987
|
const platform = o.platform ?? process.platform;
|
|
573093
|
-
const stateFile =
|
|
573988
|
+
const stateFile = join172(dataDir4(env), "update-check.json");
|
|
573094
573989
|
const channel = detectChannel({ modulePath: o.modulePath, embedded: o.embedded });
|
|
573095
573990
|
const srcDeps = { modulePath: o.modulePath, env, platform, exec: o.exec };
|
|
573096
573991
|
return {
|
|
@@ -573098,7 +573993,7 @@ function realNoticeDeps(o) {
|
|
|
573098
573993
|
disabled: () => !isUpdateCheckEnabled(env) || updateCheckDisabled(env, o.settingsFile),
|
|
573099
573994
|
readState: () => {
|
|
573100
573995
|
try {
|
|
573101
|
-
const s = JSON.parse(
|
|
573996
|
+
const s = JSON.parse(readFileSync104(stateFile, "utf8"));
|
|
573102
573997
|
return typeof s.checkedAt === "number" ? s : null;
|
|
573103
573998
|
} catch {
|
|
573104
573999
|
return null;
|
|
@@ -573106,7 +574001,7 @@ function realNoticeDeps(o) {
|
|
|
573106
574001
|
},
|
|
573107
574002
|
writeState: (s) => {
|
|
573108
574003
|
try {
|
|
573109
|
-
|
|
574004
|
+
mkdirSync80(dataDir4(env), { recursive: true });
|
|
573110
574005
|
writeFileSync62(stateFile, JSON.stringify(s), "utf8");
|
|
573111
574006
|
} catch {}
|
|
573112
574007
|
},
|
|
@@ -573150,7 +574045,7 @@ var init_update_notice = __esm(() => {
|
|
|
573150
574045
|
});
|
|
573151
574046
|
|
|
573152
574047
|
// packages/voice/cloud-transcriber.ts
|
|
573153
|
-
import { existsSync as
|
|
574048
|
+
import { existsSync as existsSync114 } from "fs";
|
|
573154
574049
|
async function transcribeCloud(wavPath, options) {
|
|
573155
574050
|
const {
|
|
573156
574051
|
apiKey,
|
|
@@ -573162,7 +574057,7 @@ async function transcribeCloud(wavPath, options) {
|
|
|
573162
574057
|
if (!apiKey) {
|
|
573163
574058
|
throw new Error("OpenAI API key is required for cloud transcription. Set OPENAI_API_KEY environment variable.");
|
|
573164
574059
|
}
|
|
573165
|
-
if (!
|
|
574060
|
+
if (!existsSync114(wavPath)) {
|
|
573166
574061
|
throw new Error(`WAV file not found: ${wavPath}`);
|
|
573167
574062
|
}
|
|
573168
574063
|
const startTime = Date.now();
|
|
@@ -573266,11 +574161,11 @@ var init_types5 = __esm(() => {
|
|
|
573266
574161
|
|
|
573267
574162
|
// packages/voice/model-manager.ts
|
|
573268
574163
|
import { EventEmitter as EventEmitter15 } from "events";
|
|
573269
|
-
import { existsSync as
|
|
573270
|
-
import { homedir as
|
|
573271
|
-
import { join as
|
|
574164
|
+
import { existsSync as existsSync115, mkdirSync as mkdirSync81, realpathSync as realpathSync37, unlinkSync as unlinkSync4 } from "fs";
|
|
574165
|
+
import { homedir as homedir86 } from "os";
|
|
574166
|
+
import { join as join173, sep as sep30 } from "path";
|
|
573272
574167
|
function resolveWhisperModel(opts = {}) {
|
|
573273
|
-
const exists = opts.exists ??
|
|
574168
|
+
const exists = opts.exists ?? existsSync115;
|
|
573274
574169
|
const dirs = [
|
|
573275
574170
|
resolveModelsPath(opts.modelsDir ?? "~/.8gent/models/whisper"),
|
|
573276
574171
|
...opts.extraDirs ?? []
|
|
@@ -573280,7 +574175,7 @@ function resolveWhisperModel(opts = {}) {
|
|
|
573280
574175
|
for (const m of WHISPER_MODEL_RANK) {
|
|
573281
574176
|
if (!english && m.filename.endsWith(".en.bin"))
|
|
573282
574177
|
continue;
|
|
573283
|
-
const path =
|
|
574178
|
+
const path = join173(dir, m.filename);
|
|
573284
574179
|
if (!exists(path))
|
|
573285
574180
|
continue;
|
|
573286
574181
|
if (!opts.exists && !isInside2(dir, path))
|
|
@@ -573309,7 +574204,7 @@ function missingWhisperModelMessage(modelsDir = "~/.8gent/models/whisper") {
|
|
|
573309
574204
|
}
|
|
573310
574205
|
function resolveModelsPath(configPath) {
|
|
573311
574206
|
if (configPath.startsWith("~")) {
|
|
573312
|
-
return
|
|
574207
|
+
return join173(homedir86(), configPath.slice(1));
|
|
573313
574208
|
}
|
|
573314
574209
|
return configPath;
|
|
573315
574210
|
}
|
|
@@ -573331,8 +574226,8 @@ var init_model_manager = __esm(() => {
|
|
|
573331
574226
|
this.modelsDir = resolveModelsPath(modelsPath);
|
|
573332
574227
|
}
|
|
573333
574228
|
ensureModelsDir() {
|
|
573334
|
-
if (!
|
|
573335
|
-
|
|
574229
|
+
if (!existsSync115(this.modelsDir)) {
|
|
574230
|
+
mkdirSync81(this.modelsDir, { recursive: true });
|
|
573336
574231
|
}
|
|
573337
574232
|
}
|
|
573338
574233
|
getModelsDir() {
|
|
@@ -573342,10 +574237,10 @@ var init_model_manager = __esm(() => {
|
|
|
573342
574237
|
return WHISPER_MODELS[name];
|
|
573343
574238
|
}
|
|
573344
574239
|
getModelPath(name) {
|
|
573345
|
-
return
|
|
574240
|
+
return join173(this.modelsDir, WHISPER_MODELS[name].filename);
|
|
573346
574241
|
}
|
|
573347
574242
|
isModelDownloaded(name) {
|
|
573348
|
-
return
|
|
574243
|
+
return existsSync115(this.getModelPath(name));
|
|
573349
574244
|
}
|
|
573350
574245
|
listModels() {
|
|
573351
574246
|
return Object.keys(WHISPER_MODELS).map((name) => ({
|
|
@@ -573360,7 +574255,7 @@ var init_model_manager = __esm(() => {
|
|
|
573360
574255
|
async downloadModel(name) {
|
|
573361
574256
|
const info = WHISPER_MODELS[name];
|
|
573362
574257
|
const destPath = this.getModelPath(name);
|
|
573363
|
-
if (
|
|
574258
|
+
if (existsSync115(destPath)) {
|
|
573364
574259
|
return destPath;
|
|
573365
574260
|
}
|
|
573366
574261
|
this.ensureModelsDir();
|
|
@@ -573411,9 +574306,9 @@ var init_model_manager = __esm(() => {
|
|
|
573411
574306
|
this.emit("download-complete", { model: name, path: destPath });
|
|
573412
574307
|
return destPath;
|
|
573413
574308
|
} catch (err) {
|
|
573414
|
-
if (
|
|
574309
|
+
if (existsSync115(destPath)) {
|
|
573415
574310
|
try {
|
|
573416
|
-
|
|
574311
|
+
unlinkSync4(destPath);
|
|
573417
574312
|
} catch {}
|
|
573418
574313
|
}
|
|
573419
574314
|
const message = err instanceof Error ? err.message : "Download failed";
|
|
@@ -573423,8 +574318,8 @@ var init_model_manager = __esm(() => {
|
|
|
573423
574318
|
}
|
|
573424
574319
|
deleteModel(name) {
|
|
573425
574320
|
const path = this.getModelPath(name);
|
|
573426
|
-
if (
|
|
573427
|
-
|
|
574321
|
+
if (existsSync115(path)) {
|
|
574322
|
+
unlinkSync4(path);
|
|
573428
574323
|
return true;
|
|
573429
574324
|
}
|
|
573430
574325
|
return false;
|
|
@@ -573434,7 +574329,7 @@ var init_model_manager = __esm(() => {
|
|
|
573434
574329
|
let totalBytes = 0;
|
|
573435
574330
|
for (const name of Object.keys(WHISPER_MODELS)) {
|
|
573436
574331
|
const path = this.getModelPath(name);
|
|
573437
|
-
if (
|
|
574332
|
+
if (existsSync115(path)) {
|
|
573438
574333
|
try {
|
|
573439
574334
|
const stat = Bun.file(path);
|
|
573440
574335
|
models[name] = stat.size;
|
|
@@ -573447,65 +574342,15 @@ var init_model_manager = __esm(() => {
|
|
|
573447
574342
|
};
|
|
573448
574343
|
});
|
|
573449
574344
|
|
|
573450
|
-
// packages/voice/termux.ts
|
|
573451
|
-
import { constants as constants15, accessSync as accessSync4, readFileSync as readFileSync104 } from "fs";
|
|
573452
|
-
import { delimiter as delimiter7, join as join169 } from "path";
|
|
573453
|
-
function isAndroidHost(platform = process.platform, env = process.env) {
|
|
573454
|
-
return platform === "android" || !!env.TERMUX_VERSION || String(env.PREFIX ?? "").includes("/com.termux/");
|
|
573455
|
-
}
|
|
573456
|
-
function findOnPath(name, env = process.env) {
|
|
573457
|
-
for (const dir of String(env.PATH ?? "").split(delimiter7)) {
|
|
573458
|
-
if (!dir)
|
|
573459
|
-
continue;
|
|
573460
|
-
const candidate = join169(dir, name);
|
|
573461
|
-
try {
|
|
573462
|
-
accessSync4(candidate, constants15.X_OK);
|
|
573463
|
-
return candidate;
|
|
573464
|
-
} catch {}
|
|
573465
|
-
}
|
|
573466
|
-
return null;
|
|
573467
|
-
}
|
|
573468
|
-
function voiceOutputOn(env = process.env, readSettings = () => {
|
|
573469
|
-
const home = env.EIGHT_HOME || join169(env.HOME ?? "", ".8gent");
|
|
573470
|
-
return readFileSync104(join169(home, "settings.json"), "utf8");
|
|
573471
|
-
}) {
|
|
573472
|
-
if (env.EIGHT_VOICE === "1")
|
|
573473
|
-
return true;
|
|
573474
|
-
try {
|
|
573475
|
-
return JSON.parse(readSettings())?.voice?.outputEnabled === true;
|
|
573476
|
-
} catch {
|
|
573477
|
-
return false;
|
|
573478
|
-
}
|
|
573479
|
-
}
|
|
573480
|
-
function ctrlRAction(key, input, android = isAndroidHost()) {
|
|
573481
|
-
if (!key.ctrl || input !== "r")
|
|
573482
|
-
return "ignore";
|
|
573483
|
-
return android ? "android-line" : "toggle";
|
|
573484
|
-
}
|
|
573485
|
-
var ANDROID_DICTATION_LINE = "On Android, tap the microphone key on your keyboard; dictation lands in the prompt. Spoken replies: /voice on (needs termux-tts-speak: pkg install termux-api plus the Termux:API app).", TERMUX_TTS_HINT = "Spoken replies need termux-tts-speak: pkg install termux-api, plus the Termux:API app from F-Droid.", ANDROID_VOICE_LINE_SUBS;
|
|
573486
|
-
var init_termux = __esm(() => {
|
|
573487
|
-
ANDROID_VOICE_LINE_SUBS = [
|
|
573488
|
-
"",
|
|
573489
|
-
"chat",
|
|
573490
|
-
"conversation",
|
|
573491
|
-
"talk",
|
|
573492
|
-
"record",
|
|
573493
|
-
"listen",
|
|
573494
|
-
"stt",
|
|
573495
|
-
"status",
|
|
573496
|
-
"stop"
|
|
573497
|
-
];
|
|
573498
|
-
});
|
|
573499
|
-
|
|
573500
574345
|
// packages/voice/recorder.ts
|
|
573501
574346
|
import { EventEmitter as EventEmitter16 } from "events";
|
|
573502
|
-
import { closeSync as closeSync21, existsSync as
|
|
574347
|
+
import { closeSync as closeSync21, existsSync as existsSync116, openSync as openSync21, readSync as readSync13, statSync as statSync37, unlinkSync as unlinkSync5 } from "fs";
|
|
573503
574348
|
import { tmpdir as tmpdir20 } from "os";
|
|
573504
|
-
import { join as
|
|
573505
|
-
var {spawn:
|
|
574349
|
+
import { join as join174 } from "path";
|
|
574350
|
+
var {spawn: spawn28 } = globalThis.Bun;
|
|
573506
574351
|
async function findSoxPath() {
|
|
573507
574352
|
try {
|
|
573508
|
-
const proc =
|
|
574353
|
+
const proc = spawn28(["which", "rec"], {
|
|
573509
574354
|
stdout: "pipe",
|
|
573510
574355
|
stderr: "pipe"
|
|
573511
574356
|
});
|
|
@@ -573581,7 +574426,7 @@ var init_recorder = __esm(() => {
|
|
|
573581
574426
|
channels: opts.channels ?? 1,
|
|
573582
574427
|
bitDepth: opts.bitDepth ?? 16,
|
|
573583
574428
|
maxDurationSeconds: opts.maxDurationSeconds ?? 30,
|
|
573584
|
-
outputPath: opts.outputPath ??
|
|
574429
|
+
outputPath: opts.outputPath ?? join174(tmpdir20(), `8gent-voice-${Date.now()}.wav`)
|
|
573585
574430
|
};
|
|
573586
574431
|
this.outputPath = this.options.outputPath;
|
|
573587
574432
|
}
|
|
@@ -573597,7 +574442,7 @@ var init_recorder = __esm(() => {
|
|
|
573597
574442
|
throw new Error(`sox not installed. ${soxCheck.installHint}`);
|
|
573598
574443
|
}
|
|
573599
574444
|
this.device = null;
|
|
573600
|
-
this.outputPath = this.options.outputPath.includes("8gent-voice-") ?
|
|
574445
|
+
this.outputPath = this.options.outputPath.includes("8gent-voice-") ? join174(tmpdir20(), `8gent-voice-${Date.now()}.wav`) : this.options.outputPath;
|
|
573601
574446
|
const args = [
|
|
573602
574447
|
"-q",
|
|
573603
574448
|
"-r",
|
|
@@ -573611,7 +574456,7 @@ var init_recorder = __esm(() => {
|
|
|
573611
574456
|
this.outputPath
|
|
573612
574457
|
];
|
|
573613
574458
|
try {
|
|
573614
|
-
this.process = this.deps.spawnRec ? this.deps.spawnRec(args) :
|
|
574459
|
+
this.process = this.deps.spawnRec ? this.deps.spawnRec(args) : spawn28(["rec", ...args], { stdout: "ignore", stderr: "ignore" });
|
|
573615
574460
|
this.isRecording = true;
|
|
573616
574461
|
this.startTime = Date.now();
|
|
573617
574462
|
this.emit("start");
|
|
@@ -573701,8 +574546,8 @@ var init_recorder = __esm(() => {
|
|
|
573701
574546
|
}
|
|
573702
574547
|
static cleanupFile(path) {
|
|
573703
574548
|
try {
|
|
573704
|
-
if (
|
|
573705
|
-
|
|
574549
|
+
if (existsSync116(path)) {
|
|
574550
|
+
unlinkSync5(path);
|
|
573706
574551
|
}
|
|
573707
574552
|
} catch {}
|
|
573708
574553
|
}
|
|
@@ -573721,22 +574566,22 @@ var init_recorder = __esm(() => {
|
|
|
573721
574566
|
});
|
|
573722
574567
|
|
|
573723
574568
|
// packages/voice/transcriber.ts
|
|
573724
|
-
import { existsSync as
|
|
573725
|
-
import { arch as arch2, homedir as
|
|
573726
|
-
import { join as
|
|
573727
|
-
var {spawn:
|
|
574569
|
+
import { existsSync as existsSync117 } from "fs";
|
|
574570
|
+
import { arch as arch2, homedir as homedir87, platform as platform9 } from "os";
|
|
574571
|
+
import { join as join175 } from "path";
|
|
574572
|
+
var {spawn: spawn29 } = globalThis.Bun;
|
|
573728
574573
|
function getWhisperBinaryPath() {
|
|
573729
|
-
return
|
|
574574
|
+
return join175(WHISPER_BIN_DIR, WHISPER_BIN_NAME);
|
|
573730
574575
|
}
|
|
573731
574576
|
async function findWhisperBinary() {
|
|
573732
574577
|
const managedPath = getWhisperBinaryPath();
|
|
573733
|
-
if (
|
|
574578
|
+
if (existsSync117(managedPath)) {
|
|
573734
574579
|
return managedPath;
|
|
573735
574580
|
}
|
|
573736
574581
|
const names = ["whisper-cpp", "whisper-cli", "whisper", "main"];
|
|
573737
574582
|
for (const name of names) {
|
|
573738
574583
|
try {
|
|
573739
|
-
const proc =
|
|
574584
|
+
const proc = spawn29(["which", name], { stdout: "pipe", stderr: "pipe", env: process.env });
|
|
573740
574585
|
const output = await new Response(proc.stdout).text();
|
|
573741
574586
|
const exitCode = await proc.exited;
|
|
573742
574587
|
if (exitCode === 0 && output.trim()) {
|
|
@@ -573745,7 +574590,7 @@ async function findWhisperBinary() {
|
|
|
573745
574590
|
} catch {}
|
|
573746
574591
|
}
|
|
573747
574592
|
for (const brewName of ["/opt/homebrew/bin/whisper-cpp", "/opt/homebrew/bin/whisper-cli"]) {
|
|
573748
|
-
if (
|
|
574593
|
+
if (existsSync117(brewName)) {
|
|
573749
574594
|
return brewName;
|
|
573750
574595
|
}
|
|
573751
574596
|
}
|
|
@@ -573753,13 +574598,13 @@ async function findWhisperBinary() {
|
|
|
573753
574598
|
}
|
|
573754
574599
|
async function transcribeLocal(wavPath, options) {
|
|
573755
574600
|
const { binaryPath, modelPath, language = "en", timeoutMs = 30000, threads } = options;
|
|
573756
|
-
if (!
|
|
574601
|
+
if (!existsSync117(wavPath)) {
|
|
573757
574602
|
throw new Error(`WAV file not found: ${wavPath}`);
|
|
573758
574603
|
}
|
|
573759
|
-
if (!
|
|
574604
|
+
if (!existsSync117(binaryPath)) {
|
|
573760
574605
|
throw new Error(`Whisper binary not found: ${binaryPath}`);
|
|
573761
574606
|
}
|
|
573762
|
-
if (!
|
|
574607
|
+
if (!existsSync117(modelPath)) {
|
|
573763
574608
|
throw new Error(`Model file not found: ${modelPath}`);
|
|
573764
574609
|
}
|
|
573765
574610
|
const startTime = Date.now();
|
|
@@ -573777,7 +574622,7 @@ async function transcribeLocal(wavPath, options) {
|
|
|
573777
574622
|
args.push("-t", String(threads));
|
|
573778
574623
|
}
|
|
573779
574624
|
if (platform9() === "darwin" && arch2() === "arm64") {}
|
|
573780
|
-
const proc =
|
|
574625
|
+
const proc = spawn29([binaryPath, ...args], {
|
|
573781
574626
|
stdout: "pipe",
|
|
573782
574627
|
stderr: "pipe",
|
|
573783
574628
|
env: process.env
|
|
@@ -573846,13 +574691,13 @@ function extractModelName(modelPath) {
|
|
|
573846
574691
|
}
|
|
573847
574692
|
var WHISPER_BIN_DIR, WHISPER_BIN_NAME = "whisper-cpp";
|
|
573848
574693
|
var init_transcriber = __esm(() => {
|
|
573849
|
-
WHISPER_BIN_DIR =
|
|
574694
|
+
WHISPER_BIN_DIR = join175(homedir87(), ".8gent", "bin");
|
|
573850
574695
|
});
|
|
573851
574696
|
|
|
573852
574697
|
// packages/decide/backends/neudecide.ts
|
|
573853
|
-
import { mkdtempSync as
|
|
574698
|
+
import { mkdtempSync as mkdtempSync12, rmSync as rmSync17, writeFileSync as writeFileSync63 } from "fs";
|
|
573854
574699
|
import { tmpdir as tmpdir22 } from "os";
|
|
573855
|
-
import { dirname as
|
|
574700
|
+
import { dirname as dirname78, join as join178 } from "path";
|
|
573856
574701
|
function wavDurationMs(buf) {
|
|
573857
574702
|
if (buf.length < 12)
|
|
573858
574703
|
return null;
|
|
@@ -573909,7 +574754,7 @@ function pythonRunner(env = process.env, spawn = Bun.spawn) {
|
|
|
573909
574754
|
const proc = spawn([python, "-I", "-c", PY, wavPath, toolsJson], {
|
|
573910
574755
|
stdout: "pipe",
|
|
573911
574756
|
stderr: "pipe",
|
|
573912
|
-
cwd:
|
|
574757
|
+
cwd: dirname78(wavPath),
|
|
573913
574758
|
env: { ...env, HF_HUB_OFFLINE: "1" }
|
|
573914
574759
|
});
|
|
573915
574760
|
const kill = () => {
|
|
@@ -573947,15 +574792,15 @@ class NeuDecideBackend {
|
|
|
573947
574792
|
description: c.description,
|
|
573948
574793
|
parameters: { type: "object", properties: {} }
|
|
573949
574794
|
}));
|
|
573950
|
-
const dir =
|
|
573951
|
-
const wavPath =
|
|
574795
|
+
const dir = mkdtempSync12(join178(tmpdir22(), "8gent-neudecide-"));
|
|
574796
|
+
const wavPath = join178(dir, "in.wav");
|
|
573952
574797
|
const t0 = performance.now();
|
|
573953
574798
|
let out;
|
|
573954
574799
|
try {
|
|
573955
574800
|
writeFileSync63(wavPath, request.audio);
|
|
573956
574801
|
out = await this.run(wavPath, JSON.stringify(tools), request.signal);
|
|
573957
574802
|
} finally {
|
|
573958
|
-
|
|
574803
|
+
rmSync17(dir, { recursive: true, force: true });
|
|
573959
574804
|
}
|
|
573960
574805
|
const latencyMs = performance.now() - t0;
|
|
573961
574806
|
let calls;
|
|
@@ -574033,289 +574878,6 @@ var init_neudecide = __esm(() => {
|
|
|
574033
574878
|
];
|
|
574034
574879
|
});
|
|
574035
574880
|
|
|
574036
|
-
// packages/runtime/node-runtime.ts
|
|
574037
|
-
import { execFile as execFile8 } from "child_process";
|
|
574038
|
-
import { existsSync as existsSync118 } from "fs";
|
|
574039
|
-
import { homedir as homedir88 } from "os";
|
|
574040
|
-
import { join as join178 } from "path";
|
|
574041
|
-
import { promisify as promisify6 } from "util";
|
|
574042
|
-
function parseNodeVersion(raw) {
|
|
574043
|
-
const trimmed = raw.trim();
|
|
574044
|
-
const match = trimmed.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
574045
|
-
if (!match)
|
|
574046
|
-
return null;
|
|
574047
|
-
return {
|
|
574048
|
-
major: Number.parseInt(match[1], 10),
|
|
574049
|
-
minor: Number.parseInt(match[2], 10),
|
|
574050
|
-
patch: Number.parseInt(match[3], 10)
|
|
574051
|
-
};
|
|
574052
|
-
}
|
|
574053
|
-
function satisfiesMinVersion(v, min) {
|
|
574054
|
-
const minParsed = parseNodeVersion(min);
|
|
574055
|
-
if (!minParsed)
|
|
574056
|
-
return true;
|
|
574057
|
-
if (v.major !== minParsed.major)
|
|
574058
|
-
return v.major > minParsed.major;
|
|
574059
|
-
if (v.minor !== minParsed.minor)
|
|
574060
|
-
return v.minor > minParsed.minor;
|
|
574061
|
-
return v.patch >= minParsed.patch;
|
|
574062
|
-
}
|
|
574063
|
-
function pickPlatformAsset(input) {
|
|
574064
|
-
const byArch = SUPPORTED[input.platform];
|
|
574065
|
-
if (!byArch) {
|
|
574066
|
-
throw new Error(`unsupported platform: ${input.platform}`);
|
|
574067
|
-
}
|
|
574068
|
-
const asset = byArch[input.arch];
|
|
574069
|
-
if (!asset) {
|
|
574070
|
-
throw new Error(`unsupported arch: ${input.arch} on ${input.platform}`);
|
|
574071
|
-
}
|
|
574072
|
-
return asset;
|
|
574073
|
-
}
|
|
574074
|
-
function buildDownloadUrl(opts) {
|
|
574075
|
-
const cleanVersion = opts.version.startsWith("v") ? opts.version.slice(1) : opts.version;
|
|
574076
|
-
const v = `v${cleanVersion}`;
|
|
574077
|
-
const fileBase = `node-${v}-${opts.asset.os}-${opts.asset.arch}`;
|
|
574078
|
-
return `https://nodejs.org/dist/${v}/${fileBase}.${opts.asset.ext}`;
|
|
574079
|
-
}
|
|
574080
|
-
function defaultRoot() {
|
|
574081
|
-
return join178(homedir88(), ".8gent", "runtime");
|
|
574082
|
-
}
|
|
574083
|
-
function getRuntimeDir(loc) {
|
|
574084
|
-
const root = loc.root ?? defaultRoot();
|
|
574085
|
-
return join178(root, `node-${loc.version}`);
|
|
574086
|
-
}
|
|
574087
|
-
function resolvedNodeBinPath(opts) {
|
|
574088
|
-
const dir = getRuntimeDir(opts);
|
|
574089
|
-
if (opts.platform === "win32") {
|
|
574090
|
-
return join178(dir, "node.exe");
|
|
574091
|
-
}
|
|
574092
|
-
return join178(dir, "bin", "node");
|
|
574093
|
-
}
|
|
574094
|
-
async function isRuntimeReady(opts) {
|
|
574095
|
-
const platform = opts.platform ?? process.platform;
|
|
574096
|
-
const bin = resolvedNodeBinPath({
|
|
574097
|
-
root: opts.root,
|
|
574098
|
-
version: opts.version,
|
|
574099
|
-
platform
|
|
574100
|
-
});
|
|
574101
|
-
if (!existsSync118(bin))
|
|
574102
|
-
return false;
|
|
574103
|
-
const min = opts.minVersion ?? opts.version;
|
|
574104
|
-
try {
|
|
574105
|
-
const { stdout } = await execFileAsync4(bin, ["--version"], {
|
|
574106
|
-
timeout: 3000
|
|
574107
|
-
});
|
|
574108
|
-
const parsed = parseNodeVersion(stdout);
|
|
574109
|
-
if (!parsed)
|
|
574110
|
-
return false;
|
|
574111
|
-
return satisfiesMinVersion(parsed, min);
|
|
574112
|
-
} catch {
|
|
574113
|
-
return false;
|
|
574114
|
-
}
|
|
574115
|
-
}
|
|
574116
|
-
var execFileAsync4, SUPPORTED;
|
|
574117
|
-
var init_node_runtime = __esm(() => {
|
|
574118
|
-
execFileAsync4 = promisify6(execFile8);
|
|
574119
|
-
SUPPORTED = {
|
|
574120
|
-
darwin: {
|
|
574121
|
-
arm64: { os: "darwin", arch: "arm64", ext: "tar.gz" },
|
|
574122
|
-
x64: { os: "darwin", arch: "x64", ext: "tar.gz" }
|
|
574123
|
-
},
|
|
574124
|
-
linux: {
|
|
574125
|
-
arm64: { os: "linux", arch: "arm64", ext: "tar.xz" },
|
|
574126
|
-
x64: { os: "linux", arch: "x64", ext: "tar.xz" }
|
|
574127
|
-
},
|
|
574128
|
-
win32: {
|
|
574129
|
-
x64: { os: "win", arch: "x64", ext: "zip" },
|
|
574130
|
-
arm64: { os: "win", arch: "arm64", ext: "zip" }
|
|
574131
|
-
}
|
|
574132
|
-
};
|
|
574133
|
-
});
|
|
574134
|
-
|
|
574135
|
-
// packages/runtime/installer.ts
|
|
574136
|
-
import { spawn as spawn29 } from "child_process";
|
|
574137
|
-
import {
|
|
574138
|
-
createWriteStream,
|
|
574139
|
-
existsSync as existsSync119,
|
|
574140
|
-
mkdirSync as mkdirSync83,
|
|
574141
|
-
mkdtempSync as mkdtempSync12,
|
|
574142
|
-
readdirSync as readdirSync27,
|
|
574143
|
-
renameSync as renameSync17,
|
|
574144
|
-
rmSync as rmSync17
|
|
574145
|
-
} from "fs";
|
|
574146
|
-
import { join as join179 } from "path";
|
|
574147
|
-
import { Readable } from "stream";
|
|
574148
|
-
import { pipeline } from "stream/promises";
|
|
574149
|
-
function planInstall(input) {
|
|
574150
|
-
const platform = input.platform ?? process.platform;
|
|
574151
|
-
const arch = input.arch ?? process.arch;
|
|
574152
|
-
const asset = pickPlatformAsset({ platform, arch });
|
|
574153
|
-
const url = buildDownloadUrl({ version: input.version, asset });
|
|
574154
|
-
const runtimeDir = getRuntimeDir({ root: input.root, version: input.version });
|
|
574155
|
-
const binPath = resolvedNodeBinPath({
|
|
574156
|
-
root: input.root,
|
|
574157
|
-
version: input.version,
|
|
574158
|
-
platform
|
|
574159
|
-
});
|
|
574160
|
-
return {
|
|
574161
|
-
version: input.version,
|
|
574162
|
-
url,
|
|
574163
|
-
asset,
|
|
574164
|
-
runtimeDir,
|
|
574165
|
-
binPath,
|
|
574166
|
-
archiveExt: asset.ext
|
|
574167
|
-
};
|
|
574168
|
-
}
|
|
574169
|
-
async function installRuntime(input) {
|
|
574170
|
-
const plan = planInstall(input);
|
|
574171
|
-
const platform = input.platform ?? process.platform;
|
|
574172
|
-
const minVersion = input.minVersion ?? input.version;
|
|
574173
|
-
const ready = await isRuntimeReady({
|
|
574174
|
-
root: input.root,
|
|
574175
|
-
version: input.version,
|
|
574176
|
-
platform,
|
|
574177
|
-
minVersion
|
|
574178
|
-
});
|
|
574179
|
-
if (ready || input.dryRun) {
|
|
574180
|
-
return {
|
|
574181
|
-
...plan,
|
|
574182
|
-
action: ready ? "already-ready" : "dry-run"
|
|
574183
|
-
};
|
|
574184
|
-
}
|
|
574185
|
-
const runtimeRoot = plan.runtimeDir.replace(/\/node-[^/]+$/, "");
|
|
574186
|
-
mkdirSync83(runtimeRoot, { recursive: true });
|
|
574187
|
-
const stagingDir = mkdtempSync12(join179(runtimeRoot, ".dl-"));
|
|
574188
|
-
const archivePath = join179(stagingDir, `node.${plan.archiveExt}`);
|
|
574189
|
-
try {
|
|
574190
|
-
await downloadFile(plan.url, archivePath);
|
|
574191
|
-
const extractRoot = join179(stagingDir, "extract");
|
|
574192
|
-
mkdirSync83(extractRoot, { recursive: true });
|
|
574193
|
-
await extractArchive(archivePath, extractRoot, plan.archiveExt);
|
|
574194
|
-
const children = readdirSync27(extractRoot);
|
|
574195
|
-
const nodeDir = children.find((n) => n.startsWith("node-"));
|
|
574196
|
-
if (!nodeDir) {
|
|
574197
|
-
throw new Error(`could not find node-* dir inside ${extractRoot}`);
|
|
574198
|
-
}
|
|
574199
|
-
const extractedPath = join179(extractRoot, nodeDir);
|
|
574200
|
-
if (existsSync119(plan.runtimeDir)) {
|
|
574201
|
-
rmSync17(plan.runtimeDir, { recursive: true, force: true });
|
|
574202
|
-
}
|
|
574203
|
-
renameSync17(extractedPath, plan.runtimeDir);
|
|
574204
|
-
} catch (err) {
|
|
574205
|
-
return {
|
|
574206
|
-
...plan,
|
|
574207
|
-
action: "failed",
|
|
574208
|
-
error: err instanceof Error ? err.message : String(err)
|
|
574209
|
-
};
|
|
574210
|
-
} finally {
|
|
574211
|
-
try {
|
|
574212
|
-
rmSync17(stagingDir, { recursive: true, force: true });
|
|
574213
|
-
} catch {}
|
|
574214
|
-
}
|
|
574215
|
-
const reReady = await isRuntimeReady({
|
|
574216
|
-
root: input.root,
|
|
574217
|
-
version: input.version,
|
|
574218
|
-
platform,
|
|
574219
|
-
minVersion
|
|
574220
|
-
});
|
|
574221
|
-
if (!reReady) {
|
|
574222
|
-
return {
|
|
574223
|
-
...plan,
|
|
574224
|
-
action: "failed",
|
|
574225
|
-
error: `installed runtime at ${plan.binPath} but it does not satisfy minVersion ${minVersion}`
|
|
574226
|
-
};
|
|
574227
|
-
}
|
|
574228
|
-
return {
|
|
574229
|
-
...plan,
|
|
574230
|
-
action: "installed"
|
|
574231
|
-
};
|
|
574232
|
-
}
|
|
574233
|
-
async function downloadFile(url, dest) {
|
|
574234
|
-
const res = await fetch(url, { redirect: "follow" });
|
|
574235
|
-
if (!res.ok || !res.body) {
|
|
574236
|
-
throw new Error(`download failed: HTTP ${res.status} ${res.statusText} for ${url}`);
|
|
574237
|
-
}
|
|
574238
|
-
const out = createWriteStream(dest);
|
|
574239
|
-
await pipeline(Readable.fromWeb(res.body), out);
|
|
574240
|
-
}
|
|
574241
|
-
async function extractArchive(archivePath, destDir, ext) {
|
|
574242
|
-
if (ext === "tar.gz" || ext === "tar.xz") {
|
|
574243
|
-
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
574244
|
-
} else if (ext === "zip") {
|
|
574245
|
-
try {
|
|
574246
|
-
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
574247
|
-
} catch {
|
|
574248
|
-
await runCmd("powershell", [
|
|
574249
|
-
"-Command",
|
|
574250
|
-
`Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force`
|
|
574251
|
-
]);
|
|
574252
|
-
}
|
|
574253
|
-
} else {
|
|
574254
|
-
throw new Error(`unsupported archive ext: ${ext}`);
|
|
574255
|
-
}
|
|
574256
|
-
}
|
|
574257
|
-
function runCmd(command, args) {
|
|
574258
|
-
return new Promise((resolve, reject) => {
|
|
574259
|
-
const proc = spawn29(command, args, { stdio: "ignore" });
|
|
574260
|
-
proc.on("error", (err) => reject(err));
|
|
574261
|
-
proc.on("close", (code) => {
|
|
574262
|
-
if (code === 0)
|
|
574263
|
-
resolve();
|
|
574264
|
-
else
|
|
574265
|
-
reject(new Error(`${command} ${args.join(" ")} exited ${code}`));
|
|
574266
|
-
});
|
|
574267
|
-
});
|
|
574268
|
-
}
|
|
574269
|
-
var init_installer = __esm(() => {
|
|
574270
|
-
init_node_runtime();
|
|
574271
|
-
});
|
|
574272
|
-
|
|
574273
|
-
// packages/runtime/contract-validator.ts
|
|
574274
|
-
var init_contract_validator = __esm(() => {
|
|
574275
|
-
init_types3();
|
|
574276
|
-
});
|
|
574277
|
-
|
|
574278
|
-
// packages/runtime/index.ts
|
|
574279
|
-
import { join as join180 } from "path";
|
|
574280
|
-
import { execFile as execFile9 } from "child_process";
|
|
574281
|
-
import { promisify as promisify7 } from "util";
|
|
574282
|
-
async function ensureNodeFor(minVersion) {
|
|
574283
|
-
try {
|
|
574284
|
-
const { stdout } = await execFileAsync5("node", ["--version"], {
|
|
574285
|
-
timeout: 3000
|
|
574286
|
-
});
|
|
574287
|
-
const parsed = parseNodeVersion(stdout);
|
|
574288
|
-
if (parsed && satisfiesMinVersion(parsed, minVersion)) {
|
|
574289
|
-
return null;
|
|
574290
|
-
}
|
|
574291
|
-
} catch {}
|
|
574292
|
-
const ready = await isRuntimeReady({
|
|
574293
|
-
version: MANAGED_NODE_VERSION,
|
|
574294
|
-
minVersion
|
|
574295
|
-
});
|
|
574296
|
-
const dir = getRuntimeDir({ version: MANAGED_NODE_VERSION });
|
|
574297
|
-
const binDir = process.platform === "win32" ? dir : join180(dir, "bin");
|
|
574298
|
-
if (ready)
|
|
574299
|
-
return binDir;
|
|
574300
|
-
const result = await installRuntime({
|
|
574301
|
-
version: MANAGED_NODE_VERSION,
|
|
574302
|
-
minVersion
|
|
574303
|
-
});
|
|
574304
|
-
if (result.action === "failed") {
|
|
574305
|
-
throw new Error(`failed to install Node ${MANAGED_NODE_VERSION}: ${result.error ?? "unknown"}`);
|
|
574306
|
-
}
|
|
574307
|
-
return binDir;
|
|
574308
|
-
}
|
|
574309
|
-
var execFileAsync5, MANAGED_NODE_VERSION = "22.14.0";
|
|
574310
|
-
var init_runtime = __esm(() => {
|
|
574311
|
-
init_installer();
|
|
574312
|
-
init_node_runtime();
|
|
574313
|
-
init_node_runtime();
|
|
574314
|
-
init_installer();
|
|
574315
|
-
init_contract_validator();
|
|
574316
|
-
execFileAsync5 = promisify7(execFile9);
|
|
574317
|
-
});
|
|
574318
|
-
|
|
574319
574881
|
// packages/goal/types.ts
|
|
574320
574882
|
var DEFAULT_BUDGET, SATISFIED_CONFIDENCE_FLOOR = 0.75;
|
|
574321
574883
|
var init_types6 = __esm(() => {
|
|
@@ -576179,7 +576741,7 @@ Nothing was changed. Type /update again to apply.`);
|
|
|
576179
576741
|
// apps/tui/src/lib/telegram-setup.ts
|
|
576180
576742
|
import {
|
|
576181
576743
|
chmodSync as chmodSync6,
|
|
576182
|
-
existsSync as
|
|
576744
|
+
existsSync as existsSync136,
|
|
576183
576745
|
lstatSync as lstatSync31,
|
|
576184
576746
|
mkdirSync as mkdirSync96,
|
|
576185
576747
|
readFileSync as readFileSync120,
|
|
@@ -576188,7 +576750,7 @@ import {
|
|
|
576188
576750
|
writeFileSync as writeFileSync76
|
|
576189
576751
|
} from "fs";
|
|
576190
576752
|
import { homedir as homedir95 } from "os";
|
|
576191
|
-
import { dirname as
|
|
576753
|
+
import { dirname as dirname83, join as join201 } from "path";
|
|
576192
576754
|
function redact3(text, key) {
|
|
576193
576755
|
let out = text;
|
|
576194
576756
|
if (key) {
|
|
@@ -576205,7 +576767,7 @@ function cleanLabel(raw, max = 40) {
|
|
|
576205
576767
|
}
|
|
576206
576768
|
function ensureEnvFile(file) {
|
|
576207
576769
|
const path = expand4(file);
|
|
576208
|
-
const dir =
|
|
576770
|
+
const dir = dirname83(path);
|
|
576209
576771
|
const notes = [];
|
|
576210
576772
|
const kind = (p) => {
|
|
576211
576773
|
try {
|
|
@@ -576299,9 +576861,9 @@ async function getSeenChats(key) {
|
|
|
576299
576861
|
return { chats: [...seen.values()] };
|
|
576300
576862
|
}
|
|
576301
576863
|
function mergeSettings(chatIds, envFile, tokenVar) {
|
|
576302
|
-
const path =
|
|
576864
|
+
const path = join201(homeDir4(), ".8gent", "settings.json");
|
|
576303
576865
|
let settings = {};
|
|
576304
|
-
if (
|
|
576866
|
+
if (existsSync136(path)) {
|
|
576305
576867
|
try {
|
|
576306
576868
|
const parsed = JSON.parse(readFileSync120(path, "utf8"));
|
|
576307
576869
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -576324,7 +576886,7 @@ function mergeSettings(chatIds, envFile, tokenVar) {
|
|
|
576324
576886
|
botEnvFile: envFile,
|
|
576325
576887
|
botTokenVar: tokenVar
|
|
576326
576888
|
};
|
|
576327
|
-
mkdirSync96(
|
|
576889
|
+
mkdirSync96(dirname83(path), { recursive: true });
|
|
576328
576890
|
const tmp = `${path}.tmp-${process.pid}`;
|
|
576329
576891
|
rmSync18(tmp, { force: true });
|
|
576330
576892
|
writeFileSync76(tmp, `${JSON.stringify(settings, null, 2)}
|
|
@@ -576334,7 +576896,7 @@ function mergeSettings(chatIds, envFile, tokenVar) {
|
|
|
576334
576896
|
}
|
|
576335
576897
|
function configured() {
|
|
576336
576898
|
try {
|
|
576337
|
-
const pm = JSON.parse(readFileSync120(
|
|
576899
|
+
const pm = JSON.parse(readFileSync120(join201(homeDir4(), ".8gent", "settings.json"), "utf8"))?.postMessage;
|
|
576338
576900
|
const file = typeof pm?.botEnvFile === "string" ? pm.botEnvFile : DEFAULT_ENV_FILE;
|
|
576339
576901
|
const name = typeof pm?.botTokenVar === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(pm.botTokenVar) ? pm.botTokenVar : DEFAULT_TOKEN_VAR;
|
|
576340
576902
|
return { file, name };
|
|
@@ -576409,7 +576971,7 @@ async function runTelegramSetup2(args) {
|
|
|
576409
576971
|
].join(`
|
|
576410
576972
|
`));
|
|
576411
576973
|
}
|
|
576412
|
-
var DEFAULT_ENV_FILE = "~/.8gent/secrets/telegram-bot.env", DEFAULT_TOKEN_VAR = "TELEGRAM_BOT_TOKEN", BOT_TOKEN_RE2, CHAT_ID_RE, homeDir4 = () => process.env.HOME || homedir95(), expand4 = (p) => p.startsWith("~/") ?
|
|
576974
|
+
var DEFAULT_ENV_FILE = "~/.8gent/secrets/telegram-bot.env", DEFAULT_TOKEN_VAR = "TELEGRAM_BOT_TOKEN", BOT_TOKEN_RE2, CHAT_ID_RE, homeDir4 = () => process.env.HOME || homedir95(), expand4 = (p) => p.startsWith("~/") ? join201(homeDir4(), p.slice(2)) : p, looser = (mode, allowed) => (mode & 511 & ~allowed) !== 0, RESTART = "Restart 8gent for this to take effect. The first post to each chat then asks you to approve it.";
|
|
576413
576975
|
var init_telegram_setup = __esm(() => {
|
|
576414
576976
|
init_post_message();
|
|
576415
576977
|
BOT_TOKEN_RE2 = /(?:bot)?\d{6,}:[A-Za-z0-9_-]{20,}/g;
|
|
@@ -576668,11 +577230,11 @@ Personal 8gent mini-app. Iteration is driven by \`SKILL.md\`. Run tests with \`b
|
|
|
576668
577230
|
}
|
|
576669
577231
|
|
|
576670
577232
|
// packages/app-creator/creator.ts
|
|
576671
|
-
import { existsSync as
|
|
577233
|
+
import { existsSync as existsSync137, mkdirSync as mkdirSync98, writeFileSync as writeFileSync78 } from "fs";
|
|
576672
577234
|
import { homedir as homedir96 } from "os";
|
|
576673
|
-
import { dirname as
|
|
577235
|
+
import { dirname as dirname84, join as join203 } from "path";
|
|
576674
577236
|
function defaultAppsRoot() {
|
|
576675
|
-
return
|
|
577237
|
+
return join203(homedir96(), ".8gent", "apps");
|
|
576676
577238
|
}
|
|
576677
577239
|
function buildManifest2(input) {
|
|
576678
577240
|
const slug = slugify3(input.name);
|
|
@@ -576706,7 +577268,7 @@ function draftApp(input) {
|
|
|
576706
577268
|
};
|
|
576707
577269
|
}
|
|
576708
577270
|
const m = built.manifest;
|
|
576709
|
-
const dir =
|
|
577271
|
+
const dir = join203(root, m.name);
|
|
576710
577272
|
const files = {
|
|
576711
577273
|
"manifest.json": `${JSON.stringify(m, null, 2)}
|
|
576712
577274
|
`,
|
|
@@ -576726,7 +577288,7 @@ function createApp(input) {
|
|
|
576726
577288
|
return { ...draft, persisted: false, written: [] };
|
|
576727
577289
|
}
|
|
576728
577290
|
const dir = draft.dir;
|
|
576729
|
-
const targetExists =
|
|
577291
|
+
const targetExists = existsSync137(dir);
|
|
576730
577292
|
if (targetExists && !input.allowOverwrite) {
|
|
576731
577293
|
return {
|
|
576732
577294
|
...draft,
|
|
@@ -576737,11 +577299,11 @@ function createApp(input) {
|
|
|
576737
577299
|
]
|
|
576738
577300
|
};
|
|
576739
577301
|
}
|
|
576740
|
-
mkdirSync98(
|
|
577302
|
+
mkdirSync98(join203(dir, "tests"), { recursive: true });
|
|
576741
577303
|
const written = [];
|
|
576742
577304
|
for (const [rel, contents] of Object.entries(draft.files)) {
|
|
576743
|
-
const full =
|
|
576744
|
-
mkdirSync98(
|
|
577305
|
+
const full = join203(dir, rel);
|
|
577306
|
+
mkdirSync98(dirname84(full), { recursive: true });
|
|
576745
577307
|
writeFileSync78(full, contents);
|
|
576746
577308
|
written.push(full);
|
|
576747
577309
|
}
|
|
@@ -577573,8 +578135,8 @@ var init_producer = __esm(() => {
|
|
|
577573
578135
|
});
|
|
577574
578136
|
|
|
577575
578137
|
// packages/pet/companion.ts
|
|
577576
|
-
import { existsSync as
|
|
577577
|
-
import { join as
|
|
578138
|
+
import { existsSync as existsSync141, mkdirSync as mkdirSync104, readFileSync as readFileSync122, writeFileSync as writeFileSync80 } from "fs";
|
|
578139
|
+
import { join as join205 } from "path";
|
|
577578
578140
|
function seedRng(seed) {
|
|
577579
578141
|
let h = 0;
|
|
577580
578142
|
for (let i = 0;i < seed.length; i++) {
|
|
@@ -577712,12 +578274,12 @@ function generateCompanion(sessionId) {
|
|
|
577712
578274
|
}
|
|
577713
578275
|
function getDeckPath() {
|
|
577714
578276
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
577715
|
-
return
|
|
578277
|
+
return join205(home, ".8gent", "companion-deck.json");
|
|
577716
578278
|
}
|
|
577717
578279
|
function loadDeck() {
|
|
577718
578280
|
const deckPath = getDeckPath();
|
|
577719
578281
|
try {
|
|
577720
|
-
if (
|
|
578282
|
+
if (existsSync141(deckPath)) {
|
|
577721
578283
|
return JSON.parse(readFileSync122(deckPath, "utf-8"));
|
|
577722
578284
|
}
|
|
577723
578285
|
} catch {}
|
|
@@ -578161,7 +578723,7 @@ var init_companion = __esm(() => {
|
|
|
578161
578723
|
// packages/orchestration/adaptive-pipeline.ts
|
|
578162
578724
|
import { spawn as spawn32 } from "child_process";
|
|
578163
578725
|
import { homedir as homedir97 } from "os";
|
|
578164
|
-
import { join as
|
|
578726
|
+
import { join as join206 } from "path";
|
|
578165
578727
|
|
|
578166
578728
|
class Obstacle {
|
|
578167
578729
|
type;
|
|
@@ -578650,7 +579212,7 @@ var init_adaptive_pipeline = __esm(() => {
|
|
|
578650
579212
|
init_role_config();
|
|
578651
579213
|
OLLAMA_URL2 = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
|
|
578652
579214
|
LMSTUDIO_URL2 = process.env.LMSTUDIO_BASE_URL || "http://localhost:1234/v1";
|
|
578653
|
-
BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE ||
|
|
579215
|
+
BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE || join206(homedir97(), ".8gent", "bin", "apple-foundation-bridge");
|
|
578654
579216
|
((Severity) => {
|
|
578655
579217
|
Severity[Severity["Trivial"] = 1] = "Trivial";
|
|
578656
579218
|
Severity[Severity["Moderate"] = 2] = "Moderate";
|
|
@@ -588527,7 +589089,7 @@ init_local_model_server();
|
|
|
588527
589089
|
init_sequential_pipeline();
|
|
588528
589090
|
init_speak();
|
|
588529
589091
|
var import_react104 = __toESM(require_react(), 1);
|
|
588530
|
-
var
|
|
589092
|
+
var import_package2 = __toESM(require_package(), 1);
|
|
588531
589093
|
|
|
588532
589094
|
// apps/tui/src/components/ActivityMonitor.tsx
|
|
588533
589095
|
var import_react31 = __toESM(require_react(), 1);
|
|
@@ -598971,234 +599533,6 @@ function useImageInput(options = {}) {
|
|
|
598971
599533
|
// apps/tui/src/components/message-list.tsx
|
|
598972
599534
|
var import_react63 = __toESM(require_react(), 1);
|
|
598973
599535
|
|
|
598974
|
-
// apps/tui/src/lib/chat-layout.ts
|
|
598975
|
-
var SHELL_CHROME = 4;
|
|
598976
|
-
var COLUMN_GAP = 1;
|
|
598977
|
-
var ACTIVITY_RAIL_WIDTH = 34;
|
|
598978
|
-
function chatColumnWidth(cols, shell, min = 24) {
|
|
598979
|
-
let width = cols - SHELL_CHROME;
|
|
598980
|
-
if (shell.planWidth && shell.planWidth > 0)
|
|
598981
|
-
width -= shell.planWidth + COLUMN_GAP;
|
|
598982
|
-
if (shell.activity)
|
|
598983
|
-
width -= ACTIVITY_RAIL_WIDTH + COLUMN_GAP;
|
|
598984
|
-
return Math.max(min, width);
|
|
598985
|
-
}
|
|
598986
|
-
var USER_BUBBLE_SHARE = 0.78;
|
|
598987
|
-
function bubbleWidths(contentWidth, role) {
|
|
598988
|
-
const inner = Math.max(16, contentWidth - 2);
|
|
598989
|
-
const bubble = role === "user" ? Math.max(16, Math.floor(inner * USER_BUBBLE_SHARE)) : inner;
|
|
598990
|
-
return { bubble, wrap: Math.max(8, bubble - 2) };
|
|
598991
|
-
}
|
|
598992
|
-
|
|
598993
|
-
// apps/tui/src/lib/tool-trail.ts
|
|
598994
|
-
var COLLAPSE_THRESHOLD = 8;
|
|
598995
|
-
var MAX_TRAIL_ROWS = 12;
|
|
598996
|
-
var PATH_KEYS = ["path", "file_path", "filePath", "file", "directory", "dir"];
|
|
598997
|
-
var COMMAND_KEYS = ["command", "cmd"];
|
|
598998
|
-
var QUERY_KEYS = ["query", "pattern", "q", "search", "url"];
|
|
598999
|
-
function oneLine(s) {
|
|
599000
|
-
return s.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
599001
|
-
}
|
|
599002
|
-
function pick3(args, keys) {
|
|
599003
|
-
for (const k of keys) {
|
|
599004
|
-
const v = args[k];
|
|
599005
|
-
if (typeof v === "string" && v.trim())
|
|
599006
|
-
return oneLine(v);
|
|
599007
|
-
}
|
|
599008
|
-
return null;
|
|
599009
|
-
}
|
|
599010
|
-
function summarizeToolArgs(tool, args) {
|
|
599011
|
-
if (!args || typeof args !== "object")
|
|
599012
|
-
return "";
|
|
599013
|
-
const isCommand = /command|shell|exec|bash/.test(tool);
|
|
599014
|
-
const order = isCommand ? [COMMAND_KEYS, PATH_KEYS, QUERY_KEYS] : /search|grep|glob|find|fetch/.test(tool) ? [QUERY_KEYS, PATH_KEYS, COMMAND_KEYS] : [PATH_KEYS, COMMAND_KEYS, QUERY_KEYS];
|
|
599015
|
-
for (const keys of order) {
|
|
599016
|
-
const hit = pick3(args, keys);
|
|
599017
|
-
if (hit)
|
|
599018
|
-
return hit;
|
|
599019
|
-
}
|
|
599020
|
-
for (const v of Object.values(args)) {
|
|
599021
|
-
if (typeof v === "string" && v.trim())
|
|
599022
|
-
return oneLine(v);
|
|
599023
|
-
}
|
|
599024
|
-
return "";
|
|
599025
|
-
}
|
|
599026
|
-
var GATE_PREFIX = /^\s*\[([A-Z0-9_ -]*\b(?:BLOCKED|DENIED)\b[A-Z0-9_ -]*)\]/;
|
|
599027
|
-
var OTHER_BLOCK = /^\s*(?:Path blocked by path-guard|Path traversal blocked)|Hook blocked tool/;
|
|
599028
|
-
var RULE_NAME = /\[([a-z0-9]+(?:-[a-z0-9]+)+)\]/;
|
|
599029
|
-
function classifyToolResult(success, preview) {
|
|
599030
|
-
const text = preview ?? "";
|
|
599031
|
-
const gate = text.match(GATE_PREFIX);
|
|
599032
|
-
if (gate || OTHER_BLOCK.test(text)) {
|
|
599033
|
-
if (gate && /DENIED/.test(gate[1]))
|
|
599034
|
-
return { status: "blocked", reason: "denied" };
|
|
599035
|
-
const rule = text.match(RULE_NAME);
|
|
599036
|
-
return { status: "blocked", reason: rule ? `blocked: [${rule[1]}]` : "blocked" };
|
|
599037
|
-
}
|
|
599038
|
-
const exit = text.match(/^\s*Exit code (-?\d+)/);
|
|
599039
|
-
if (exit && exit[1] !== "0")
|
|
599040
|
-
return { status: "fail", reason: `exit ${exit[1]}` };
|
|
599041
|
-
if (!success || /^\s*(?:Error\b|Unknown tool:)/.test(text)) {
|
|
599042
|
-
const first = (text.split(`
|
|
599043
|
-
`).find((l) => l.trim()) ?? "").replace(/^\s*Error(?: running tool "[^"]*")?:?\s*/, "").trim();
|
|
599044
|
-
if (!first)
|
|
599045
|
-
return { status: "fail", reason: "error" };
|
|
599046
|
-
return { status: "fail", reason: first.length > 40 ? `${first.slice(0, 39)}\u2026` : first };
|
|
599047
|
-
}
|
|
599048
|
-
return { status: "ok" };
|
|
599049
|
-
}
|
|
599050
|
-
function toTrailEntry(event) {
|
|
599051
|
-
const { status, reason } = classifyToolResult(event.success !== false, event.resultPreview);
|
|
599052
|
-
const entry = {
|
|
599053
|
-
tool: event.toolName,
|
|
599054
|
-
summary: summarizeToolArgs(event.toolName, event.args),
|
|
599055
|
-
status
|
|
599056
|
-
};
|
|
599057
|
-
if (reason)
|
|
599058
|
-
entry.reason = reason;
|
|
599059
|
-
if (event.toolName === "update_plan") {
|
|
599060
|
-
const items = event.args?.plan;
|
|
599061
|
-
if (Array.isArray(items)) {
|
|
599062
|
-
const plan = items.map((i) => i && typeof i === "object" ? i : {}).filter((i) => typeof i.step === "string" && i.step.trim() !== "").map((i) => ({ step: i.step, status: typeof i.status === "string" ? i.status : "pending" }));
|
|
599063
|
-
if (plan.length > 0)
|
|
599064
|
-
entry.plan = plan;
|
|
599065
|
-
}
|
|
599066
|
-
}
|
|
599067
|
-
return entry;
|
|
599068
|
-
}
|
|
599069
|
-
function isReadTool(tool) {
|
|
599070
|
-
return /^(?:read_|list_|get_|search|grep|glob|find|view|web_search|web_fetch)/.test(tool);
|
|
599071
|
-
}
|
|
599072
|
-
function commonDir(paths) {
|
|
599073
|
-
const split = paths.map((p) => p.split("/").slice(0, -1));
|
|
599074
|
-
const first = split[0] ?? [];
|
|
599075
|
-
let n = 0;
|
|
599076
|
-
while (n < first.length && split.every((s) => s[n] === first[n]))
|
|
599077
|
-
n++;
|
|
599078
|
-
return n > 0 ? `${first.slice(0, n).join("/")}/` : "";
|
|
599079
|
-
}
|
|
599080
|
-
function collapseTrail(entries, maxRows = MAX_TRAIL_ROWS) {
|
|
599081
|
-
let rows = entries.map((e) => ({ ...e, count: 1 }));
|
|
599082
|
-
if (entries.length > COLLAPSE_THRESHOLD) {
|
|
599083
|
-
const out = [];
|
|
599084
|
-
for (let i = 0;i < entries.length; ) {
|
|
599085
|
-
const e = entries[i];
|
|
599086
|
-
let j = i + 1;
|
|
599087
|
-
if (e.status === "ok" && isReadTool(e.tool)) {
|
|
599088
|
-
while (j < entries.length && entries[j].tool === e.tool && entries[j].status === "ok")
|
|
599089
|
-
j++;
|
|
599090
|
-
}
|
|
599091
|
-
if (j - i > 1) {
|
|
599092
|
-
const run = entries.slice(i, j);
|
|
599093
|
-
out.push({
|
|
599094
|
-
tool: e.tool,
|
|
599095
|
-
status: "ok",
|
|
599096
|
-
count: run.length,
|
|
599097
|
-
summary: commonDir(run.map((r) => r.summary))
|
|
599098
|
-
});
|
|
599099
|
-
} else {
|
|
599100
|
-
out.push({ ...e, count: 1 });
|
|
599101
|
-
}
|
|
599102
|
-
i = j;
|
|
599103
|
-
}
|
|
599104
|
-
rows = out;
|
|
599105
|
-
}
|
|
599106
|
-
const cap = Math.max(1, Math.floor(maxRows));
|
|
599107
|
-
if (rows.length > cap) {
|
|
599108
|
-
let toFold = rows.length - cap + 1;
|
|
599109
|
-
const fold = new Set;
|
|
599110
|
-
for (const wantOk of [true, false]) {
|
|
599111
|
-
for (let i = 0;i < rows.length && toFold > 0; i++) {
|
|
599112
|
-
if (fold.has(i) || wantOk && rows[i].status !== "ok")
|
|
599113
|
-
continue;
|
|
599114
|
-
fold.add(i);
|
|
599115
|
-
toFold--;
|
|
599116
|
-
}
|
|
599117
|
-
}
|
|
599118
|
-
const folded = rows.filter((_, i) => fold.has(i));
|
|
599119
|
-
const count = (s) => folded.filter((r) => r.status === s).reduce((n, r) => n + r.count, 0);
|
|
599120
|
-
const failed = count("fail");
|
|
599121
|
-
const blocked = count("blocked");
|
|
599122
|
-
const summary = {
|
|
599123
|
-
tool: "",
|
|
599124
|
-
summary: "",
|
|
599125
|
-
status: failed > 0 ? "fail" : blocked > 0 ? "blocked" : "ok",
|
|
599126
|
-
count: folded.reduce((n, r) => n + r.count, 0),
|
|
599127
|
-
folded: true,
|
|
599128
|
-
all: fold.size === rows.length
|
|
599129
|
-
};
|
|
599130
|
-
if (failed > 0)
|
|
599131
|
-
summary.failed = failed;
|
|
599132
|
-
if (blocked > 0)
|
|
599133
|
-
summary.blocked = blocked;
|
|
599134
|
-
rows = [summary, ...rows.filter((_, i) => !fold.has(i))];
|
|
599135
|
-
}
|
|
599136
|
-
return rows;
|
|
599137
|
-
}
|
|
599138
|
-
var ICONS = { ok: "\u2713", fail: "\u2717", blocked: "\u2298" };
|
|
599139
|
-
function formatTrailRow(row, width) {
|
|
599140
|
-
const icon = ICONS[row.status];
|
|
599141
|
-
const budget = Math.max(1, width - icon.length - 1);
|
|
599142
|
-
if (row.folded) {
|
|
599143
|
-
const parts = [`${row.count} ${row.all ? "calls" : "earlier calls"}`];
|
|
599144
|
-
if (row.failed)
|
|
599145
|
-
parts.push(`${row.failed} failed`);
|
|
599146
|
-
if (row.blocked)
|
|
599147
|
-
parts.push(`${row.blocked} blocked`);
|
|
599148
|
-
return { icon, text: clip(parts.join(", "), budget) };
|
|
599149
|
-
}
|
|
599150
|
-
const head = row.count > 1 ? `${row.tool} \xD7${row.count}` : row.tool;
|
|
599151
|
-
const tail = row.reason ? ` (${row.reason})` : "";
|
|
599152
|
-
let summary = row.count > 1 ? row.summary ? `(${row.summary}\u2026)` : "" : row.summary;
|
|
599153
|
-
if (!summary)
|
|
599154
|
-
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
599155
|
-
const room = budget - head.length - 1 - tail.length;
|
|
599156
|
-
if (room < 4)
|
|
599157
|
-
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
599158
|
-
if (summary.length > room)
|
|
599159
|
-
summary = `${summary.slice(0, room - 1)}\u2026`;
|
|
599160
|
-
return { icon, text: `${head} ${summary}${tail}` };
|
|
599161
|
-
}
|
|
599162
|
-
function clip(s, width) {
|
|
599163
|
-
return s.length <= width ? s : `${s.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
599164
|
-
}
|
|
599165
|
-
function buildChatItems(messages) {
|
|
599166
|
-
const items = [];
|
|
599167
|
-
let pending = [];
|
|
599168
|
-
let pendingFirst = null;
|
|
599169
|
-
const flush = () => {
|
|
599170
|
-
if (pending.length > 0 && pendingFirst) {
|
|
599171
|
-
items.push({
|
|
599172
|
-
message: { ...pendingFirst, id: `trail-${pendingFirst.id}`, role: "tool", content: "" },
|
|
599173
|
-
trail: pending
|
|
599174
|
-
});
|
|
599175
|
-
}
|
|
599176
|
-
pending = [];
|
|
599177
|
-
pendingFirst = null;
|
|
599178
|
-
};
|
|
599179
|
-
for (const m of messages) {
|
|
599180
|
-
if (m.role === "tool") {
|
|
599181
|
-
if (m.toolTrail) {
|
|
599182
|
-
if (!pendingFirst)
|
|
599183
|
-
pendingFirst = m;
|
|
599184
|
-
pending.push(m.toolTrail);
|
|
599185
|
-
}
|
|
599186
|
-
continue;
|
|
599187
|
-
}
|
|
599188
|
-
if (m.role === "assistant") {
|
|
599189
|
-
items.push({ message: m, trail: pending });
|
|
599190
|
-
pending = [];
|
|
599191
|
-
pendingFirst = null;
|
|
599192
|
-
continue;
|
|
599193
|
-
}
|
|
599194
|
-
if (m.role === "user")
|
|
599195
|
-
flush();
|
|
599196
|
-
items.push({ message: m, trail: [] });
|
|
599197
|
-
}
|
|
599198
|
-
flush();
|
|
599199
|
-
return items;
|
|
599200
|
-
}
|
|
599201
|
-
|
|
599202
599536
|
// apps/tui/src/hooks/useMouseScroll.ts
|
|
599203
599537
|
var import_react57 = __toESM(require_react(), 1);
|
|
599204
599538
|
function useMouseScroll({
|
|
@@ -599224,111 +599558,25 @@ function useMouseScroll({
|
|
|
599224
599558
|
}, [enabled, step]);
|
|
599225
599559
|
}
|
|
599226
599560
|
|
|
599227
|
-
// apps/tui/src/
|
|
599228
|
-
var
|
|
599229
|
-
var
|
|
599230
|
-
|
|
599231
|
-
|
|
599232
|
-
|
|
599233
|
-
|
|
599234
|
-
|
|
599235
|
-
|
|
599236
|
-
|
|
599237
|
-
|
|
599238
|
-
import_react58.useEffect(() => {
|
|
599239
|
-
if (!started)
|
|
599240
|
-
return;
|
|
599241
|
-
const timeout = setTimeout(() => {
|
|
599242
|
-
onComplete?.();
|
|
599243
|
-
}, duration);
|
|
599244
|
-
return () => clearTimeout(timeout);
|
|
599245
|
-
}, [started, duration, onComplete]);
|
|
599246
|
-
if (!started)
|
|
599247
|
-
return null;
|
|
599248
|
-
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
|
|
599249
|
-
children
|
|
599250
|
-
}, undefined, false, undefined, this);
|
|
599251
|
-
}
|
|
599252
|
-
|
|
599253
|
-
// apps/tui/src/components/ToolTrail.tsx
|
|
599254
|
-
var import_react59 = __toESM(require_react(), 1);
|
|
599255
|
-
var jsx_dev_runtime31 = __toESM(require_jsx_dev_runtime(), 1);
|
|
599256
|
-
function iconColor(status) {
|
|
599257
|
-
return status === "ok" ? t.green : status === "fail" ? t.red : t.orange;
|
|
599258
|
-
}
|
|
599259
|
-
function useLandingRows(total, animate) {
|
|
599260
|
-
const [shown, setShown] = import_react59.useState(total);
|
|
599261
|
-
const shownRef = import_react59.useRef(total);
|
|
599262
|
-
shownRef.current = shown;
|
|
599263
|
-
const landingRef = import_react59.useRef(null);
|
|
599264
|
-
import_react59.useEffect(() => {
|
|
599265
|
-
const from = shownRef.current;
|
|
599266
|
-
if (total <= from + 1 || !motionEnabled(animate)) {
|
|
599267
|
-
landingRef.current = null;
|
|
599268
|
-
setShown(total);
|
|
599269
|
-
return;
|
|
599270
|
-
}
|
|
599271
|
-
landingRef.current = total;
|
|
599272
|
-
const step = staggerFor(total - from);
|
|
599273
|
-
let n = from + 1;
|
|
599274
|
-
setShown(n);
|
|
599275
|
-
const id = setInterval(() => {
|
|
599276
|
-
n += 1;
|
|
599277
|
-
setShown(Math.min(total, n));
|
|
599278
|
-
if (n >= total) {
|
|
599279
|
-
landingRef.current = null;
|
|
599280
|
-
clearInterval(id);
|
|
599281
|
-
}
|
|
599282
|
-
}, step);
|
|
599283
|
-
return () => clearInterval(id);
|
|
599284
|
-
}, [total, animate]);
|
|
599285
|
-
if (landingRef.current === total)
|
|
599286
|
-
return Math.min(shown, total);
|
|
599287
|
-
if (total <= shown + 1)
|
|
599288
|
-
return total;
|
|
599289
|
-
return shown;
|
|
599290
|
-
}
|
|
599291
|
-
function ToolTrail({
|
|
599292
|
-
entries,
|
|
599293
|
-
width,
|
|
599294
|
-
maxRows,
|
|
599295
|
-
animate = true
|
|
599296
|
-
}) {
|
|
599297
|
-
const rows = collapseTrail(entries, maxRows);
|
|
599298
|
-
const visible = useLandingRows(rows.length, animate);
|
|
599299
|
-
if (rows.length === 0)
|
|
599300
|
-
return null;
|
|
599301
|
-
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
599302
|
-
flexDirection: "column",
|
|
599303
|
-
flexShrink: 0,
|
|
599304
|
-
children: rows.slice(0, visible).map((row, i) => {
|
|
599305
|
-
const { text } = formatTrailRow(row, width);
|
|
599306
|
-
const g = glyphs();
|
|
599307
|
-
const icon = row.status === "ok" ? g.ok : row.status === "fail" ? g.fail : g.blocked;
|
|
599308
|
-
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
599309
|
-
width,
|
|
599310
|
-
children: [
|
|
599311
|
-
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
599312
|
-
color: iconColor(row.status),
|
|
599313
|
-
children: icon
|
|
599314
|
-
}, undefined, false, undefined, this),
|
|
599315
|
-
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
599316
|
-
color: row.status === "ok" ? t.muted : t.textPrimary,
|
|
599317
|
-
wrap: "truncate-end",
|
|
599318
|
-
children: ` ${text}`
|
|
599319
|
-
}, undefined, false, undefined, this)
|
|
599320
|
-
]
|
|
599321
|
-
}, i, true, undefined, this);
|
|
599322
|
-
})
|
|
599323
|
-
}, undefined, false, undefined, this);
|
|
599561
|
+
// apps/tui/src/lib/chat-layout.ts
|
|
599562
|
+
var SHELL_CHROME = 4;
|
|
599563
|
+
var COLUMN_GAP = 1;
|
|
599564
|
+
var ACTIVITY_RAIL_WIDTH = 34;
|
|
599565
|
+
function chatColumnWidth(cols, shell, min = 24) {
|
|
599566
|
+
let width = cols - SHELL_CHROME;
|
|
599567
|
+
if (shell.planWidth && shell.planWidth > 0)
|
|
599568
|
+
width -= shell.planWidth + COLUMN_GAP;
|
|
599569
|
+
if (shell.activity)
|
|
599570
|
+
width -= ACTIVITY_RAIL_WIDTH + COLUMN_GAP;
|
|
599571
|
+
return Math.max(min, width);
|
|
599324
599572
|
}
|
|
599325
|
-
|
|
599326
|
-
|
|
599573
|
+
var USER_BUBBLE_SHARE = 0.78;
|
|
599574
|
+
function bubbleWidths(contentWidth, role) {
|
|
599575
|
+
const inner = Math.max(16, contentWidth - 2);
|
|
599576
|
+
const bubble = role === "user" ? Math.max(16, Math.floor(inner * USER_BUBBLE_SHARE)) : inner;
|
|
599577
|
+
return { bubble, wrap: Math.max(8, bubble - 2) };
|
|
599327
599578
|
}
|
|
599328
599579
|
|
|
599329
|
-
// apps/tui/src/components/TurnResults.tsx
|
|
599330
|
-
var import_react60 = __toESM(require_react(), 1);
|
|
599331
|
-
|
|
599332
599580
|
// apps/tui/src/lib/inline-markdown.ts
|
|
599333
599581
|
var MAX_DEPTH3 = 3;
|
|
599334
599582
|
var INDENT_STEP = 2;
|
|
@@ -599643,6 +599891,215 @@ function blockRows(block, width) {
|
|
|
599643
599891
|
}
|
|
599644
599892
|
}
|
|
599645
599893
|
|
|
599894
|
+
// apps/tui/src/lib/tool-trail.ts
|
|
599895
|
+
var COLLAPSE_THRESHOLD = 8;
|
|
599896
|
+
var MAX_TRAIL_ROWS = 12;
|
|
599897
|
+
var PATH_KEYS = ["path", "file_path", "filePath", "file", "directory", "dir"];
|
|
599898
|
+
var COMMAND_KEYS = ["command", "cmd"];
|
|
599899
|
+
var QUERY_KEYS = ["query", "pattern", "q", "search", "url"];
|
|
599900
|
+
function oneLine(s) {
|
|
599901
|
+
return s.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
599902
|
+
}
|
|
599903
|
+
function pick3(args, keys) {
|
|
599904
|
+
for (const k of keys) {
|
|
599905
|
+
const v = args[k];
|
|
599906
|
+
if (typeof v === "string" && v.trim())
|
|
599907
|
+
return oneLine(v);
|
|
599908
|
+
}
|
|
599909
|
+
return null;
|
|
599910
|
+
}
|
|
599911
|
+
function summarizeToolArgs(tool, args) {
|
|
599912
|
+
if (!args || typeof args !== "object")
|
|
599913
|
+
return "";
|
|
599914
|
+
const isCommand = /command|shell|exec|bash/.test(tool);
|
|
599915
|
+
const order = isCommand ? [COMMAND_KEYS, PATH_KEYS, QUERY_KEYS] : /search|grep|glob|find|fetch/.test(tool) ? [QUERY_KEYS, PATH_KEYS, COMMAND_KEYS] : [PATH_KEYS, COMMAND_KEYS, QUERY_KEYS];
|
|
599916
|
+
for (const keys of order) {
|
|
599917
|
+
const hit = pick3(args, keys);
|
|
599918
|
+
if (hit)
|
|
599919
|
+
return hit;
|
|
599920
|
+
}
|
|
599921
|
+
for (const v of Object.values(args)) {
|
|
599922
|
+
if (typeof v === "string" && v.trim())
|
|
599923
|
+
return oneLine(v);
|
|
599924
|
+
}
|
|
599925
|
+
return "";
|
|
599926
|
+
}
|
|
599927
|
+
var GATE_PREFIX = /^\s*\[([A-Z0-9_ -]*\b(?:BLOCKED|DENIED)\b[A-Z0-9_ -]*)\]/;
|
|
599928
|
+
var OTHER_BLOCK = /^\s*(?:Path blocked by path-guard|Path traversal blocked)|Hook blocked tool/;
|
|
599929
|
+
var RULE_NAME = /\[([a-z0-9]+(?:-[a-z0-9]+)+)\]/;
|
|
599930
|
+
function classifyToolResult(success, preview) {
|
|
599931
|
+
const text = preview ?? "";
|
|
599932
|
+
const gate = text.match(GATE_PREFIX);
|
|
599933
|
+
if (gate || OTHER_BLOCK.test(text)) {
|
|
599934
|
+
if (gate && /DENIED/.test(gate[1]))
|
|
599935
|
+
return { status: "blocked", reason: "denied" };
|
|
599936
|
+
const rule = text.match(RULE_NAME);
|
|
599937
|
+
return { status: "blocked", reason: rule ? `blocked: [${rule[1]}]` : "blocked" };
|
|
599938
|
+
}
|
|
599939
|
+
const exit = text.match(/^\s*Exit code (-?\d+)/);
|
|
599940
|
+
if (exit && exit[1] !== "0")
|
|
599941
|
+
return { status: "fail", reason: `exit ${exit[1]}` };
|
|
599942
|
+
if (!success || /^\s*(?:Error\b|Unknown tool:)/.test(text)) {
|
|
599943
|
+
const first = (text.split(`
|
|
599944
|
+
`).find((l) => l.trim()) ?? "").replace(/^\s*Error(?: running tool "[^"]*")?:?\s*/, "").trim();
|
|
599945
|
+
if (!first)
|
|
599946
|
+
return { status: "fail", reason: "error" };
|
|
599947
|
+
return { status: "fail", reason: first.length > 40 ? `${first.slice(0, 39)}\u2026` : first };
|
|
599948
|
+
}
|
|
599949
|
+
return { status: "ok" };
|
|
599950
|
+
}
|
|
599951
|
+
function toTrailEntry(event) {
|
|
599952
|
+
const { status, reason } = classifyToolResult(event.success !== false, event.resultPreview);
|
|
599953
|
+
const entry = {
|
|
599954
|
+
tool: event.toolName,
|
|
599955
|
+
summary: summarizeToolArgs(event.toolName, event.args),
|
|
599956
|
+
status
|
|
599957
|
+
};
|
|
599958
|
+
if (reason)
|
|
599959
|
+
entry.reason = reason;
|
|
599960
|
+
if (event.toolName === "update_plan") {
|
|
599961
|
+
const items = event.args?.plan;
|
|
599962
|
+
if (Array.isArray(items)) {
|
|
599963
|
+
const plan = items.map((i) => i && typeof i === "object" ? i : {}).filter((i) => typeof i.step === "string" && i.step.trim() !== "").map((i) => ({ step: i.step, status: typeof i.status === "string" ? i.status : "pending" }));
|
|
599964
|
+
if (plan.length > 0)
|
|
599965
|
+
entry.plan = plan;
|
|
599966
|
+
}
|
|
599967
|
+
}
|
|
599968
|
+
return entry;
|
|
599969
|
+
}
|
|
599970
|
+
function isReadTool(tool) {
|
|
599971
|
+
return /^(?:read_|list_|get_|search|grep|glob|find|view|web_search|web_fetch)/.test(tool);
|
|
599972
|
+
}
|
|
599973
|
+
function commonDir(paths) {
|
|
599974
|
+
const split = paths.map((p) => p.split("/").slice(0, -1));
|
|
599975
|
+
const first = split[0] ?? [];
|
|
599976
|
+
let n = 0;
|
|
599977
|
+
while (n < first.length && split.every((s) => s[n] === first[n]))
|
|
599978
|
+
n++;
|
|
599979
|
+
return n > 0 ? `${first.slice(0, n).join("/")}/` : "";
|
|
599980
|
+
}
|
|
599981
|
+
function collapseTrail(entries, maxRows = MAX_TRAIL_ROWS) {
|
|
599982
|
+
let rows = entries.map((e) => ({ ...e, count: 1 }));
|
|
599983
|
+
if (entries.length > COLLAPSE_THRESHOLD) {
|
|
599984
|
+
const out = [];
|
|
599985
|
+
for (let i = 0;i < entries.length; ) {
|
|
599986
|
+
const e = entries[i];
|
|
599987
|
+
let j = i + 1;
|
|
599988
|
+
if (e.status === "ok" && isReadTool(e.tool)) {
|
|
599989
|
+
while (j < entries.length && entries[j].tool === e.tool && entries[j].status === "ok")
|
|
599990
|
+
j++;
|
|
599991
|
+
}
|
|
599992
|
+
if (j - i > 1) {
|
|
599993
|
+
const run = entries.slice(i, j);
|
|
599994
|
+
out.push({
|
|
599995
|
+
tool: e.tool,
|
|
599996
|
+
status: "ok",
|
|
599997
|
+
count: run.length,
|
|
599998
|
+
summary: commonDir(run.map((r) => r.summary))
|
|
599999
|
+
});
|
|
600000
|
+
} else {
|
|
600001
|
+
out.push({ ...e, count: 1 });
|
|
600002
|
+
}
|
|
600003
|
+
i = j;
|
|
600004
|
+
}
|
|
600005
|
+
rows = out;
|
|
600006
|
+
}
|
|
600007
|
+
const cap = Math.max(1, Math.floor(maxRows));
|
|
600008
|
+
if (rows.length > cap) {
|
|
600009
|
+
let toFold = rows.length - cap + 1;
|
|
600010
|
+
const fold = new Set;
|
|
600011
|
+
for (const wantOk of [true, false]) {
|
|
600012
|
+
for (let i = 0;i < rows.length && toFold > 0; i++) {
|
|
600013
|
+
if (fold.has(i) || wantOk && rows[i].status !== "ok")
|
|
600014
|
+
continue;
|
|
600015
|
+
fold.add(i);
|
|
600016
|
+
toFold--;
|
|
600017
|
+
}
|
|
600018
|
+
}
|
|
600019
|
+
const folded = rows.filter((_, i) => fold.has(i));
|
|
600020
|
+
const count = (s) => folded.filter((r) => r.status === s).reduce((n, r) => n + r.count, 0);
|
|
600021
|
+
const failed = count("fail");
|
|
600022
|
+
const blocked = count("blocked");
|
|
600023
|
+
const summary = {
|
|
600024
|
+
tool: "",
|
|
600025
|
+
summary: "",
|
|
600026
|
+
status: failed > 0 ? "fail" : blocked > 0 ? "blocked" : "ok",
|
|
600027
|
+
count: folded.reduce((n, r) => n + r.count, 0),
|
|
600028
|
+
folded: true,
|
|
600029
|
+
all: fold.size === rows.length
|
|
600030
|
+
};
|
|
600031
|
+
if (failed > 0)
|
|
600032
|
+
summary.failed = failed;
|
|
600033
|
+
if (blocked > 0)
|
|
600034
|
+
summary.blocked = blocked;
|
|
600035
|
+
rows = [summary, ...rows.filter((_, i) => !fold.has(i))];
|
|
600036
|
+
}
|
|
600037
|
+
return rows;
|
|
600038
|
+
}
|
|
600039
|
+
var ICONS = { ok: "\u2713", fail: "\u2717", blocked: "\u2298" };
|
|
600040
|
+
function formatTrailRow(row, width) {
|
|
600041
|
+
const icon = ICONS[row.status];
|
|
600042
|
+
const budget = Math.max(1, width - icon.length - 1);
|
|
600043
|
+
if (row.folded) {
|
|
600044
|
+
const parts = [`${row.count} ${row.all ? "calls" : "earlier calls"}`];
|
|
600045
|
+
if (row.failed)
|
|
600046
|
+
parts.push(`${row.failed} failed`);
|
|
600047
|
+
if (row.blocked)
|
|
600048
|
+
parts.push(`${row.blocked} blocked`);
|
|
600049
|
+
return { icon, text: clip(parts.join(", "), budget) };
|
|
600050
|
+
}
|
|
600051
|
+
const head = row.count > 1 ? `${row.tool} \xD7${row.count}` : row.tool;
|
|
600052
|
+
const tail = row.reason ? ` (${row.reason})` : "";
|
|
600053
|
+
let summary = row.count > 1 ? row.summary ? `(${row.summary}\u2026)` : "" : row.summary;
|
|
600054
|
+
if (!summary)
|
|
600055
|
+
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
600056
|
+
const room = budget - head.length - 1 - tail.length;
|
|
600057
|
+
if (room < 4)
|
|
600058
|
+
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
600059
|
+
if (summary.length > room)
|
|
600060
|
+
summary = `${summary.slice(0, room - 1)}\u2026`;
|
|
600061
|
+
return { icon, text: `${head} ${summary}${tail}` };
|
|
600062
|
+
}
|
|
600063
|
+
function clip(s, width) {
|
|
600064
|
+
return s.length <= width ? s : `${s.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
600065
|
+
}
|
|
600066
|
+
function buildChatItems(messages) {
|
|
600067
|
+
const items = [];
|
|
600068
|
+
let pending = [];
|
|
600069
|
+
let pendingFirst = null;
|
|
600070
|
+
const flush = () => {
|
|
600071
|
+
if (pending.length > 0 && pendingFirst) {
|
|
600072
|
+
items.push({
|
|
600073
|
+
message: { ...pendingFirst, id: `trail-${pendingFirst.id}`, role: "tool", content: "" },
|
|
600074
|
+
trail: pending
|
|
600075
|
+
});
|
|
600076
|
+
}
|
|
600077
|
+
pending = [];
|
|
600078
|
+
pendingFirst = null;
|
|
600079
|
+
};
|
|
600080
|
+
for (const m of messages) {
|
|
600081
|
+
if (m.role === "tool") {
|
|
600082
|
+
if (m.toolTrail) {
|
|
600083
|
+
if (!pendingFirst)
|
|
600084
|
+
pendingFirst = m;
|
|
600085
|
+
pending.push(m.toolTrail);
|
|
600086
|
+
}
|
|
600087
|
+
continue;
|
|
600088
|
+
}
|
|
600089
|
+
if (m.role === "assistant") {
|
|
600090
|
+
items.push({ message: m, trail: pending });
|
|
600091
|
+
pending = [];
|
|
600092
|
+
pendingFirst = null;
|
|
600093
|
+
continue;
|
|
600094
|
+
}
|
|
600095
|
+
if (m.role === "user")
|
|
600096
|
+
flush();
|
|
600097
|
+
items.push({ message: m, trail: [] });
|
|
600098
|
+
}
|
|
600099
|
+
flush();
|
|
600100
|
+
return items;
|
|
600101
|
+
}
|
|
600102
|
+
|
|
599646
600103
|
// apps/tui/src/lib/activity-rail-derivation.ts
|
|
599647
600104
|
function deriveTools(messages, isProcessing, limit = 5) {
|
|
599648
600105
|
const ended = new Map;
|
|
@@ -600114,8 +600571,85 @@ function turnResultRows(trail, maxRows, plan) {
|
|
|
600114
600571
|
return buildTurnResults(trail, maxRows, plan).length;
|
|
600115
600572
|
}
|
|
600116
600573
|
|
|
600574
|
+
// apps/tui/src/components/ToolTrail.tsx
|
|
600575
|
+
var import_react58 = __toESM(require_react(), 1);
|
|
600576
|
+
var jsx_dev_runtime30 = __toESM(require_jsx_dev_runtime(), 1);
|
|
600577
|
+
function iconColor(status) {
|
|
600578
|
+
return status === "ok" ? t.green : status === "fail" ? t.red : t.orange;
|
|
600579
|
+
}
|
|
600580
|
+
function useLandingRows(total, animate) {
|
|
600581
|
+
const [shown, setShown] = import_react58.useState(total);
|
|
600582
|
+
const shownRef = import_react58.useRef(total);
|
|
600583
|
+
shownRef.current = shown;
|
|
600584
|
+
const landingRef = import_react58.useRef(null);
|
|
600585
|
+
import_react58.useEffect(() => {
|
|
600586
|
+
const from = shownRef.current;
|
|
600587
|
+
if (total <= from + 1 || !motionEnabled(animate)) {
|
|
600588
|
+
landingRef.current = null;
|
|
600589
|
+
setShown(total);
|
|
600590
|
+
return;
|
|
600591
|
+
}
|
|
600592
|
+
landingRef.current = total;
|
|
600593
|
+
const step = staggerFor(total - from);
|
|
600594
|
+
let n = from + 1;
|
|
600595
|
+
setShown(n);
|
|
600596
|
+
const id = setInterval(() => {
|
|
600597
|
+
n += 1;
|
|
600598
|
+
setShown(Math.min(total, n));
|
|
600599
|
+
if (n >= total) {
|
|
600600
|
+
landingRef.current = null;
|
|
600601
|
+
clearInterval(id);
|
|
600602
|
+
}
|
|
600603
|
+
}, step);
|
|
600604
|
+
return () => clearInterval(id);
|
|
600605
|
+
}, [total, animate]);
|
|
600606
|
+
if (landingRef.current === total)
|
|
600607
|
+
return Math.min(shown, total);
|
|
600608
|
+
if (total <= shown + 1)
|
|
600609
|
+
return total;
|
|
600610
|
+
return shown;
|
|
600611
|
+
}
|
|
600612
|
+
function ToolTrail({
|
|
600613
|
+
entries,
|
|
600614
|
+
width,
|
|
600615
|
+
maxRows,
|
|
600616
|
+
animate = true
|
|
600617
|
+
}) {
|
|
600618
|
+
const rows = collapseTrail(entries, maxRows);
|
|
600619
|
+
const visible = useLandingRows(rows.length, animate);
|
|
600620
|
+
if (rows.length === 0)
|
|
600621
|
+
return null;
|
|
600622
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
|
|
600623
|
+
flexDirection: "column",
|
|
600624
|
+
flexShrink: 0,
|
|
600625
|
+
children: rows.slice(0, visible).map((row, i) => {
|
|
600626
|
+
const { text } = formatTrailRow(row, width);
|
|
600627
|
+
const g = glyphs();
|
|
600628
|
+
const icon = row.status === "ok" ? g.ok : row.status === "fail" ? g.fail : g.blocked;
|
|
600629
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
|
|
600630
|
+
width,
|
|
600631
|
+
children: [
|
|
600632
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Text, {
|
|
600633
|
+
color: iconColor(row.status),
|
|
600634
|
+
children: icon
|
|
600635
|
+
}, undefined, false, undefined, this),
|
|
600636
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Text, {
|
|
600637
|
+
color: row.status === "ok" ? t.muted : t.textPrimary,
|
|
600638
|
+
wrap: "truncate-end",
|
|
600639
|
+
children: ` ${text}`
|
|
600640
|
+
}, undefined, false, undefined, this)
|
|
600641
|
+
]
|
|
600642
|
+
}, i, true, undefined, this);
|
|
600643
|
+
})
|
|
600644
|
+
}, undefined, false, undefined, this);
|
|
600645
|
+
}
|
|
600646
|
+
function toolTrailRows(entries, maxRows) {
|
|
600647
|
+
return entries.length === 0 ? 0 : collapseTrail(entries, maxRows).length;
|
|
600648
|
+
}
|
|
600649
|
+
|
|
600117
600650
|
// apps/tui/src/components/TurnResults.tsx
|
|
600118
|
-
var
|
|
600651
|
+
var import_react59 = __toESM(require_react(), 1);
|
|
600652
|
+
var jsx_dev_runtime31 = __toESM(require_jsx_dev_runtime(), 1);
|
|
600119
600653
|
function iconFor(status) {
|
|
600120
600654
|
const g = glyphs();
|
|
600121
600655
|
if (status === "ok")
|
|
@@ -600127,8 +600661,8 @@ function iconFor(status) {
|
|
|
600127
600661
|
return { icon: g.pending, color: t.muted };
|
|
600128
600662
|
}
|
|
600129
600663
|
function useResultLanding(total, land) {
|
|
600130
|
-
const [shown, setShown] =
|
|
600131
|
-
|
|
600664
|
+
const [shown, setShown] = import_react59.useState(land ? 0 : total);
|
|
600665
|
+
import_react59.useEffect(() => {
|
|
600132
600666
|
if (!land) {
|
|
600133
600667
|
setShown(total);
|
|
600134
600668
|
return;
|
|
@@ -600168,12 +600702,12 @@ function TurnResults({
|
|
|
600168
600702
|
const visible = useResultLanding(rows.length, land && motionEnabled(animate));
|
|
600169
600703
|
if (rows.length === 0)
|
|
600170
600704
|
return null;
|
|
600171
|
-
return /* @__PURE__ */
|
|
600705
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
600172
600706
|
flexDirection: "column",
|
|
600173
600707
|
flexShrink: 0,
|
|
600174
600708
|
children: rows.map((row, i) => {
|
|
600175
600709
|
if (i >= visible) {
|
|
600176
|
-
return /* @__PURE__ */
|
|
600710
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
600177
600711
|
height: 1,
|
|
600178
600712
|
width
|
|
600179
600713
|
}, i, false, undefined, this);
|
|
@@ -600181,55 +600715,55 @@ function TurnResults({
|
|
|
600181
600715
|
const { icon, color } = iconFor(row.status);
|
|
600182
600716
|
const fit = fitResultRow(row, width);
|
|
600183
600717
|
const quiet = row.status === "pending" || row.kind === "fold";
|
|
600184
|
-
return /* @__PURE__ */
|
|
600718
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
600185
600719
|
width,
|
|
600186
600720
|
height: 1,
|
|
600187
|
-
children: /* @__PURE__ */
|
|
600721
|
+
children: /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600188
600722
|
wrap: "truncate-end",
|
|
600189
600723
|
children: [
|
|
600190
|
-
/* @__PURE__ */
|
|
600724
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600191
600725
|
color,
|
|
600192
600726
|
children: icon
|
|
600193
600727
|
}, undefined, false, undefined, this),
|
|
600194
|
-
/* @__PURE__ */
|
|
600728
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600195
600729
|
children: " "
|
|
600196
600730
|
}, undefined, false, undefined, this),
|
|
600197
|
-
/* @__PURE__ */
|
|
600731
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600198
600732
|
bold: !quiet,
|
|
600199
600733
|
color: quiet ? t.muted : t.textPrimary,
|
|
600200
600734
|
children: fit.verb
|
|
600201
600735
|
}, undefined, false, undefined, this),
|
|
600202
|
-
fit.spans ? /* @__PURE__ */
|
|
600736
|
+
fit.spans ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(jsx_dev_runtime31.Fragment, {
|
|
600203
600737
|
children: [
|
|
600204
|
-
fit.verb ? /* @__PURE__ */
|
|
600738
|
+
fit.verb ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600205
600739
|
children: " "
|
|
600206
600740
|
}, undefined, false, undefined, this) : null,
|
|
600207
|
-
fit.spans.map((s, j) => s.code ? /* @__PURE__ */
|
|
600741
|
+
fit.spans.map((s, j) => s.code ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600208
600742
|
color: t.textPrimary,
|
|
600209
600743
|
backgroundColor: t.border,
|
|
600210
600744
|
children: s.text
|
|
600211
|
-
}, j, false, undefined, this) : /* @__PURE__ */
|
|
600745
|
+
}, j, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600212
600746
|
color: quiet ? t.muted : t.textSecondary,
|
|
600213
600747
|
children: s.text
|
|
600214
600748
|
}, j, false, undefined, this))
|
|
600215
600749
|
]
|
|
600216
|
-
}, undefined, true, undefined, this) : fit.text ? /* @__PURE__ */
|
|
600750
|
+
}, undefined, true, undefined, this) : fit.text ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600217
600751
|
color: quiet ? t.muted : t.textSecondary,
|
|
600218
600752
|
children: ` ${fit.text}`
|
|
600219
600753
|
}, undefined, false, undefined, this) : null,
|
|
600220
|
-
fit.chip ? /* @__PURE__ */
|
|
600754
|
+
fit.chip ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(jsx_dev_runtime31.Fragment, {
|
|
600221
600755
|
children: [
|
|
600222
|
-
/* @__PURE__ */
|
|
600756
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600223
600757
|
children: " "
|
|
600224
600758
|
}, undefined, false, undefined, this),
|
|
600225
|
-
/* @__PURE__ */
|
|
600759
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600226
600760
|
color: t.textPrimary,
|
|
600227
600761
|
backgroundColor: t.border,
|
|
600228
600762
|
children: ` ${fit.chip} `
|
|
600229
600763
|
}, undefined, false, undefined, this)
|
|
600230
600764
|
]
|
|
600231
600765
|
}, undefined, true, undefined, this) : null,
|
|
600232
|
-
fit.note ? /* @__PURE__ */
|
|
600766
|
+
fit.note ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
600233
600767
|
color: row.status === "fail" ? t.red : t.muted,
|
|
600234
600768
|
children: `${" ".repeat(fit.noteGap ?? 2)}${fit.note}`
|
|
600235
600769
|
}, undefined, false, undefined, this) : null
|
|
@@ -600240,6 +600774,32 @@ function TurnResults({
|
|
|
600240
600774
|
}, undefined, false, undefined, this);
|
|
600241
600775
|
}
|
|
600242
600776
|
|
|
600777
|
+
// apps/tui/src/components/fade-transition.tsx
|
|
600778
|
+
var import_react60 = __toESM(require_react(), 1);
|
|
600779
|
+
var jsx_dev_runtime32 = __toESM(require_jsx_dev_runtime(), 1);
|
|
600780
|
+
function FadeIn({ children, duration = 300, delay = 0, onComplete }) {
|
|
600781
|
+
const [started, setStarted] = import_react60.useState(false);
|
|
600782
|
+
import_react60.useEffect(() => {
|
|
600783
|
+
const timeout = setTimeout(() => {
|
|
600784
|
+
setStarted(true);
|
|
600785
|
+
}, delay);
|
|
600786
|
+
return () => clearTimeout(timeout);
|
|
600787
|
+
}, [delay]);
|
|
600788
|
+
import_react60.useEffect(() => {
|
|
600789
|
+
if (!started)
|
|
600790
|
+
return;
|
|
600791
|
+
const timeout = setTimeout(() => {
|
|
600792
|
+
onComplete?.();
|
|
600793
|
+
}, duration);
|
|
600794
|
+
return () => clearTimeout(timeout);
|
|
600795
|
+
}, [started, duration, onComplete]);
|
|
600796
|
+
if (!started)
|
|
600797
|
+
return null;
|
|
600798
|
+
return /* @__PURE__ */ jsx_dev_runtime32.jsxDEV(Box_default, {
|
|
600799
|
+
children
|
|
600800
|
+
}, undefined, false, undefined, this);
|
|
600801
|
+
}
|
|
600802
|
+
|
|
600243
600803
|
// apps/tui/src/components/sound-effects.tsx
|
|
600244
600804
|
var import_react61 = __toESM(require_react(), 1);
|
|
600245
600805
|
var BELL = "\x07";
|
|
@@ -600652,6 +601212,7 @@ function MessageList({
|
|
|
600652
601212
|
showAnimations,
|
|
600653
601213
|
isLatestAssistant: message.id === lastAssistantId,
|
|
600654
601214
|
trail: trailById.get(message.id) ?? [],
|
|
601215
|
+
turnRunning,
|
|
600655
601216
|
trailMaxRows: trailCaps.get(message.id),
|
|
600656
601217
|
onAnimationStart: (id) => {
|
|
600657
601218
|
animatedIdsRef.current.add(id);
|
|
@@ -600683,6 +601244,7 @@ function MessageItem({
|
|
|
600683
601244
|
showAnimations,
|
|
600684
601245
|
isLatestAssistant = false,
|
|
600685
601246
|
trail = [],
|
|
601247
|
+
turnRunning = false,
|
|
600686
601248
|
trailMaxRows,
|
|
600687
601249
|
onAnimationStart
|
|
600688
601250
|
}) {
|
|
@@ -600868,7 +601430,7 @@ function MessageItem({
|
|
|
600868
601430
|
animate: showAnimations
|
|
600869
601431
|
}, undefined, false, undefined, this)
|
|
600870
601432
|
}, undefined, false, undefined, this),
|
|
600871
|
-
!isUser && !message.content.trim() && trail.length > 0 ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(MutedText, {
|
|
601433
|
+
!isUser && !turnRunning && !message.content.trim() && trail.length > 0 ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(MutedText, {
|
|
600872
601434
|
children: "No reply."
|
|
600873
601435
|
}, undefined, false, undefined, this) : null,
|
|
600874
601436
|
message.content.trim() || trail.length === 0 ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
@@ -601030,7 +601592,11 @@ function MarkdownBody({
|
|
|
601030
601592
|
})
|
|
601031
601593
|
}, undefined, false, undefined, this);
|
|
601032
601594
|
}
|
|
601033
|
-
function InlineSpans({
|
|
601595
|
+
function InlineSpans({
|
|
601596
|
+
spans,
|
|
601597
|
+
color,
|
|
601598
|
+
adhdMode
|
|
601599
|
+
}) {
|
|
601034
601600
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
601035
601601
|
color,
|
|
601036
601602
|
wrap: "wrap",
|
|
@@ -603441,9 +604007,9 @@ init_cloud_transcriber();
|
|
|
603441
604007
|
init_types5();
|
|
603442
604008
|
|
|
603443
604009
|
// packages/voice/voice-chat.ts
|
|
603444
|
-
import { existsSync as
|
|
604010
|
+
import { existsSync as existsSync118, unlinkSync as unlinkSync6 } from "fs";
|
|
603445
604011
|
import { tmpdir as tmpdir21 } from "os";
|
|
603446
|
-
import { join as
|
|
604012
|
+
import { join as join176 } from "path";
|
|
603447
604013
|
|
|
603448
604014
|
// packages/voice/tts-engine.ts
|
|
603449
604015
|
init_termux();
|
|
@@ -603851,7 +604417,7 @@ class VoiceChatLoop {
|
|
|
603851
604417
|
await this.speakText(response);
|
|
603852
604418
|
}
|
|
603853
604419
|
async listenForSpeech() {
|
|
603854
|
-
const wavPath =
|
|
604420
|
+
const wavPath = join176(tmpdir21(), `8gent-voicechat-${Date.now()}.wav`);
|
|
603855
604421
|
const silenceSec = (this.silenceMs / 1000).toFixed(1);
|
|
603856
604422
|
try {
|
|
603857
604423
|
const recProc = Bun.spawn([
|
|
@@ -603900,7 +604466,7 @@ class VoiceChatLoop {
|
|
|
603900
604466
|
cleanupFile(wavPath);
|
|
603901
604467
|
throw new VoiceChatFatalError(describeRecFailure(exitCode, why));
|
|
603902
604468
|
}
|
|
603903
|
-
if (!
|
|
604469
|
+
if (!existsSync118(wavPath)) {
|
|
603904
604470
|
this.reportError("No audio was recorded. Check that your microphone is the system input.");
|
|
603905
604471
|
return null;
|
|
603906
604472
|
}
|
|
@@ -604024,8 +604590,8 @@ function sleep2(ms) {
|
|
|
604024
604590
|
}
|
|
604025
604591
|
function cleanupFile(path) {
|
|
604026
604592
|
try {
|
|
604027
|
-
if (
|
|
604028
|
-
|
|
604593
|
+
if (existsSync118(path))
|
|
604594
|
+
unlinkSync6(path);
|
|
604029
604595
|
} catch {}
|
|
604030
604596
|
}
|
|
604031
604597
|
var HEARD_ONLY_MARK = "[interrupted]";
|
|
@@ -604083,14 +604649,14 @@ function splitIntoSentences(text) {
|
|
|
604083
604649
|
return chunks.length ? chunks : [text];
|
|
604084
604650
|
}
|
|
604085
604651
|
// packages/voice/full-duplex-provider.ts
|
|
604086
|
-
import { execSync as
|
|
604087
|
-
import { existsSync as
|
|
604088
|
-
import { homedir as
|
|
604089
|
-
import { join as
|
|
604090
|
-
var MOSHI_HF_CACHE_PATH =
|
|
604652
|
+
import { execSync as execSync7 } from "child_process";
|
|
604653
|
+
import { existsSync as existsSync119 } from "fs";
|
|
604654
|
+
import { homedir as homedir88 } from "os";
|
|
604655
|
+
import { join as join177 } from "path";
|
|
604656
|
+
var MOSHI_HF_CACHE_PATH = join177(homedir88(), ".cache", "huggingface", "hub", "models--kyutai--moshiko-pytorch-bf16", "snapshots");
|
|
604091
604657
|
function tryExec(cmd) {
|
|
604092
604658
|
try {
|
|
604093
|
-
|
|
604659
|
+
execSync7(cmd, { stdio: "ignore", timeout: 5000 });
|
|
604094
604660
|
return true;
|
|
604095
604661
|
} catch {
|
|
604096
604662
|
return false;
|
|
@@ -604102,7 +604668,7 @@ async function detectCapabilities() {
|
|
|
604102
604668
|
const hasAppleSilicon = platform === "darwin" && arch === "arm64";
|
|
604103
604669
|
const hasMLX = hasAppleSilicon && tryExec('python3 -c "import mlx"');
|
|
604104
604670
|
const hasMoshiInstalled = tryExec('python3 -c "import moshi"');
|
|
604105
|
-
const hasMoshiModel =
|
|
604671
|
+
const hasMoshiModel = existsSync119(MOSHI_HF_CACHE_PATH);
|
|
604106
604672
|
const hasCUDA = tryExec("nvidia-smi");
|
|
604107
604673
|
const hasNIMKey = !!process.env.NVIDIA_NIM_KEY;
|
|
604108
604674
|
return {
|
|
@@ -605133,9 +605699,9 @@ function useWorkspaceTabs() {
|
|
|
605133
605699
|
}
|
|
605134
605700
|
|
|
605135
605701
|
// apps/tui/src/lib/adhd-audio.ts
|
|
605136
|
-
import { existsSync as
|
|
605137
|
-
import { join as
|
|
605138
|
-
var {spawn:
|
|
605702
|
+
import { existsSync as existsSync121, mkdirSync as mkdirSync83 } from "fs";
|
|
605703
|
+
import { join as join180 } from "path";
|
|
605704
|
+
var {spawn: spawn30 } = globalThis.Bun;
|
|
605139
605705
|
var DEFAULT_CONFIG4 = {
|
|
605140
605706
|
duration: 180,
|
|
605141
605707
|
bpm: null,
|
|
@@ -605174,11 +605740,11 @@ var SOUNDSCAPES = {
|
|
|
605174
605740
|
bpm: 70
|
|
605175
605741
|
}
|
|
605176
605742
|
};
|
|
605177
|
-
var CACHE_DIR3 =
|
|
605178
|
-
var CONFIG_PATH =
|
|
605743
|
+
var CACHE_DIR3 = join180(process.env.HOME || "~", ".8gent", "adhd-audio");
|
|
605744
|
+
var CONFIG_PATH = join180(CACHE_DIR3, "config.json");
|
|
605179
605745
|
function loadConfig2() {
|
|
605180
605746
|
try {
|
|
605181
|
-
if (
|
|
605747
|
+
if (existsSync121(CONFIG_PATH)) {
|
|
605182
605748
|
const raw = JSON.parse(__require("fs").readFileSync(CONFIG_PATH, "utf-8"));
|
|
605183
605749
|
return { ...DEFAULT_CONFIG4, ...raw };
|
|
605184
605750
|
}
|
|
@@ -605187,8 +605753,8 @@ function loadConfig2() {
|
|
|
605187
605753
|
}
|
|
605188
605754
|
function saveConfig2(config) {
|
|
605189
605755
|
try {
|
|
605190
|
-
if (!
|
|
605191
|
-
|
|
605756
|
+
if (!existsSync121(CACHE_DIR3))
|
|
605757
|
+
mkdirSync83(CACHE_DIR3, { recursive: true });
|
|
605192
605758
|
__require("fs").writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
605193
605759
|
} catch {}
|
|
605194
605760
|
}
|
|
@@ -605199,8 +605765,8 @@ class ADHDAudio {
|
|
|
605199
605765
|
generating = false;
|
|
605200
605766
|
_config;
|
|
605201
605767
|
constructor() {
|
|
605202
|
-
if (!
|
|
605203
|
-
|
|
605768
|
+
if (!existsSync121(CACHE_DIR3)) {
|
|
605769
|
+
mkdirSync83(CACHE_DIR3, { recursive: true });
|
|
605204
605770
|
}
|
|
605205
605771
|
this._config = loadConfig2();
|
|
605206
605772
|
}
|
|
@@ -605226,7 +605792,7 @@ class ADHDAudio {
|
|
|
605226
605792
|
for (const soundscape of Object.keys(SOUNDSCAPES)) {
|
|
605227
605793
|
const path = this.getCachePath(soundscape);
|
|
605228
605794
|
try {
|
|
605229
|
-
if (
|
|
605795
|
+
if (existsSync121(path))
|
|
605230
605796
|
__require("fs").unlinkSync(path);
|
|
605231
605797
|
} catch {}
|
|
605232
605798
|
}
|
|
@@ -605242,10 +605808,10 @@ class ADHDAudio {
|
|
|
605242
605808
|
}
|
|
605243
605809
|
}
|
|
605244
605810
|
getCachePath(soundscape) {
|
|
605245
|
-
return
|
|
605811
|
+
return join180(CACHE_DIR3, `${soundscape}.mp3`);
|
|
605246
605812
|
}
|
|
605247
605813
|
hasCached(soundscape) {
|
|
605248
|
-
return
|
|
605814
|
+
return existsSync121(this.getCachePath(soundscape));
|
|
605249
605815
|
}
|
|
605250
605816
|
async generate(soundscape) {
|
|
605251
605817
|
const preset = SOUNDSCAPES[soundscape];
|
|
@@ -605338,7 +605904,7 @@ class ADHDAudio {
|
|
|
605338
605904
|
if (!this._playingFile)
|
|
605339
605905
|
return;
|
|
605340
605906
|
try {
|
|
605341
|
-
this.playerProcess =
|
|
605907
|
+
this.playerProcess = spawn30(["afplay", filePath], {
|
|
605342
605908
|
stdout: "ignore",
|
|
605343
605909
|
stderr: "ignore",
|
|
605344
605910
|
onExit: () => {
|
|
@@ -605654,325 +606220,8 @@ class DaemonSessionClient {
|
|
|
605654
606220
|
}
|
|
605655
606221
|
}
|
|
605656
606222
|
|
|
605657
|
-
// apps/tui/src/
|
|
605658
|
-
|
|
605659
|
-
import { execSync as execSync7, spawn as spawn30 } from "child_process";
|
|
605660
|
-
var stripAnsi2 = (s) => s.replace(/\u001B\[[0-9;?]*[a-zA-Z]/g, "").replace(/\u001B\][^\u0007]*\u0007/g, "");
|
|
605661
|
-
var EXTERNAL_AGENT_PRESETS = {
|
|
605662
|
-
claude: {
|
|
605663
|
-
id: "claude",
|
|
605664
|
-
label: "Sparring",
|
|
605665
|
-
command: "claude",
|
|
605666
|
-
promptMode: "flag",
|
|
605667
|
-
flagName: "-p",
|
|
605668
|
-
args: [],
|
|
605669
|
-
timeoutMs: 120000,
|
|
605670
|
-
parseStdout: stripAnsi2,
|
|
605671
|
-
homepage: "https://docs.claude.com/en/docs/claude-code",
|
|
605672
|
-
preferWindow: true,
|
|
605673
|
-
install: {
|
|
605674
|
-
command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
|
|
605675
|
-
notes: 'Binary at ~/.npm-global/bin/claude. If `claude` isn\'t on PATH after install, add `export PATH="$HOME/.npm-global/bin:$PATH"` to your shell rc. Then run `claude` once outside the TUI to authenticate with Anthropic.'
|
|
605676
|
-
}
|
|
605677
|
-
},
|
|
605678
|
-
codex: {
|
|
605679
|
-
id: "codex",
|
|
605680
|
-
label: "OpenAI Codex",
|
|
605681
|
-
command: "codex",
|
|
605682
|
-
promptMode: "arg",
|
|
605683
|
-
args: ["exec"],
|
|
605684
|
-
timeoutMs: 120000,
|
|
605685
|
-
parseStdout: stripAnsi2,
|
|
605686
|
-
homepage: "https://github.com/openai/codex",
|
|
605687
|
-
preferWindow: true,
|
|
605688
|
-
install: {
|
|
605689
|
-
command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
|
|
605690
|
-
notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
|
|
605691
|
-
}
|
|
605692
|
-
},
|
|
605693
|
-
hermes: {
|
|
605694
|
-
id: "hermes",
|
|
605695
|
-
label: "Hermes Agent",
|
|
605696
|
-
command: "hermes",
|
|
605697
|
-
preferWindow: true,
|
|
605698
|
-
promptMode: "flag",
|
|
605699
|
-
flagName: "-z",
|
|
605700
|
-
args: [],
|
|
605701
|
-
timeoutMs: 120000,
|
|
605702
|
-
parseStdout: stripAnsi2,
|
|
605703
|
-
homepage: "https://github.com/NousResearch/hermes-agent",
|
|
605704
|
-
install: {
|
|
605705
|
-
command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
|
|
605706
|
-
notes: "Hermes needs Python \u2265 3.11 (anaconda's default 3.10 won't work; use pyenv or brew install python@3.11). Installer symlinks `hermes` into ~/.local/bin; add it to PATH if needed. After install, run `hermes setup` or `hermes model` outside the TUI to configure a provider. Without that, /spawn'd Hermes tabs will fail with auth errors (Bedrock is the default provider)."
|
|
605707
|
-
}
|
|
605708
|
-
},
|
|
605709
|
-
openclaw: {
|
|
605710
|
-
id: "openclaw",
|
|
605711
|
-
label: "OpenClaw",
|
|
605712
|
-
command: "openclaw",
|
|
605713
|
-
preferWindow: true,
|
|
605714
|
-
promptMode: "arg",
|
|
605715
|
-
args: ["run", "--headless"],
|
|
605716
|
-
timeoutMs: 120000,
|
|
605717
|
-
parseStdout: stripAnsi2,
|
|
605718
|
-
homepage: "https://github.com/openclaw/openclaw",
|
|
605719
|
-
install: {
|
|
605720
|
-
command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
|
|
605721
|
-
notes: "Binary at ~/.npm-global/bin/openclaw. Add `~/.npm-global/bin` to PATH if needed. After install run `openclaw onboard` outside the TUI to set up the gateway, workspace, and skills. (8gent now provides a managed Node 22 runtime automatically when needed; no separate nvm step required.)"
|
|
605722
|
-
},
|
|
605723
|
-
requiresNodeVersion: "22.14.0"
|
|
605724
|
-
},
|
|
605725
|
-
pi: {
|
|
605726
|
-
preferWindow: true,
|
|
605727
|
-
id: "pi",
|
|
605728
|
-
label: "Pi (pi-mono)",
|
|
605729
|
-
command: "pi",
|
|
605730
|
-
promptMode: "flag",
|
|
605731
|
-
flagName: "-p",
|
|
605732
|
-
args: [],
|
|
605733
|
-
timeoutMs: 120000,
|
|
605734
|
-
parseStdout: stripAnsi2,
|
|
605735
|
-
homepage: "https://pi.dev",
|
|
605736
|
-
install: {
|
|
605737
|
-
command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
|
|
605738
|
-
notes: "Binary at ~/.npm-global/bin/pi. Add `~/.npm-global/bin` to PATH if needed. Default provider is Google (Gemini). Set GEMINI_API_KEY, or override with --provider/--model and the matching API key env var (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY)."
|
|
605739
|
-
}
|
|
605740
|
-
},
|
|
605741
|
-
"8gent": {
|
|
605742
|
-
id: "8gent",
|
|
605743
|
-
label: "8gent (nested)",
|
|
605744
|
-
command: "8gent",
|
|
605745
|
-
promptMode: "arg",
|
|
605746
|
-
args: ["run"],
|
|
605747
|
-
timeoutMs: 180000,
|
|
605748
|
-
parseStdout: stripAnsi2,
|
|
605749
|
-
homepage: "https://8gent.dev",
|
|
605750
|
-
install: {
|
|
605751
|
-
command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
|
|
605752
|
-
notes: "Binary at ~/.npm-global/bin/8gent. --force overwrites stale `8` / `8gent` / `8gent-code` bin symlinks (npm 9+ EEXIST). Add `~/.npm-global/bin` to PATH if not already."
|
|
605753
|
-
}
|
|
605754
|
-
}
|
|
605755
|
-
};
|
|
605756
|
-
function getPreset(id) {
|
|
605757
|
-
return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
|
|
605758
|
-
}
|
|
605759
|
-
function listPresetIds() {
|
|
605760
|
-
return Object.keys(EXTERNAL_AGENT_PRESETS);
|
|
605761
|
-
}
|
|
605762
|
-
function isInstalled(preset) {
|
|
605763
|
-
try {
|
|
605764
|
-
execSync7(`command -v "${preset.command}"`, {
|
|
605765
|
-
stdio: "ignore",
|
|
605766
|
-
timeout: 1500
|
|
605767
|
-
});
|
|
605768
|
-
return true;
|
|
605769
|
-
} catch {
|
|
605770
|
-
return false;
|
|
605771
|
-
}
|
|
605772
|
-
}
|
|
605773
|
-
async function installAgent(preset, onLine) {
|
|
605774
|
-
const start = performance.now();
|
|
605775
|
-
if (!preset.install) {
|
|
605776
|
-
return {
|
|
605777
|
-
ok: false,
|
|
605778
|
-
stdout: "",
|
|
605779
|
-
stderr: "",
|
|
605780
|
-
durationMs: 0,
|
|
605781
|
-
command: "",
|
|
605782
|
-
error: `No install recipe for ${preset.id}. Install ${preset.command} manually and try again.`
|
|
605783
|
-
};
|
|
605784
|
-
}
|
|
605785
|
-
const command = preset.install.command;
|
|
605786
|
-
return new Promise((resolve) => {
|
|
605787
|
-
let stdout = "";
|
|
605788
|
-
let stderr = "";
|
|
605789
|
-
let exited = false;
|
|
605790
|
-
const proc = spawnShell(command, {
|
|
605791
|
-
posix: ["bash", "-lc"],
|
|
605792
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
605793
|
-
env: { ...process.env, NO_COLOR: "1", FORCE_COLOR: "0" }
|
|
605794
|
-
});
|
|
605795
|
-
const finish = (result) => {
|
|
605796
|
-
if (exited)
|
|
605797
|
-
return;
|
|
605798
|
-
exited = true;
|
|
605799
|
-
clearTimeout(timer);
|
|
605800
|
-
resolve({
|
|
605801
|
-
...result,
|
|
605802
|
-
durationMs: Math.round(performance.now() - start),
|
|
605803
|
-
command
|
|
605804
|
-
});
|
|
605805
|
-
};
|
|
605806
|
-
const pipeLines = (chunk, source) => {
|
|
605807
|
-
const text = chunk.toString();
|
|
605808
|
-
if (source === "stdout")
|
|
605809
|
-
stdout += text;
|
|
605810
|
-
else
|
|
605811
|
-
stderr += text;
|
|
605812
|
-
if (onLine) {
|
|
605813
|
-
for (const line of text.split(/\r?\n/)) {
|
|
605814
|
-
if (line.trim().length > 0)
|
|
605815
|
-
onLine(line, source);
|
|
605816
|
-
}
|
|
605817
|
-
}
|
|
605818
|
-
};
|
|
605819
|
-
proc.stdout?.on("data", (c) => pipeLines(c, "stdout"));
|
|
605820
|
-
proc.stderr?.on("data", (c) => pipeLines(c, "stderr"));
|
|
605821
|
-
proc.on("error", (err) => {
|
|
605822
|
-
finish({ ok: false, stdout, stderr, error: err.message });
|
|
605823
|
-
});
|
|
605824
|
-
proc.on("close", (code) => {
|
|
605825
|
-
finish({
|
|
605826
|
-
ok: code === 0,
|
|
605827
|
-
stdout,
|
|
605828
|
-
stderr,
|
|
605829
|
-
error: code === 0 ? undefined : stderr.trim().slice(0, 800) || `installer exited with code ${code}`
|
|
605830
|
-
});
|
|
605831
|
-
});
|
|
605832
|
-
const timer = setTimeout(() => {
|
|
605833
|
-
proc.kill("SIGTERM");
|
|
605834
|
-
finish({ ok: false, stdout, stderr, error: "install timed out after 5 minutes" });
|
|
605835
|
-
}, 5 * 60 * 1000);
|
|
605836
|
-
});
|
|
605837
|
-
}
|
|
605838
|
-
async function ensureInstalled(preset, onLine) {
|
|
605839
|
-
if (isInstalled(preset))
|
|
605840
|
-
return true;
|
|
605841
|
-
if (!preset.install) {
|
|
605842
|
-
onLine?.(`${preset.command}: not installed and no auto-install recipe is configured.`, "info");
|
|
605843
|
-
return false;
|
|
605844
|
-
}
|
|
605845
|
-
onLine?.(`${preset.command}: not installed, running ${preset.install.command}`, "info");
|
|
605846
|
-
const result = await installAgent(preset, (line, source) => onLine?.(line, source));
|
|
605847
|
-
if (!result.ok) {
|
|
605848
|
-
onLine?.(`Install failed: ${result.error ?? "unknown error"}`, "info");
|
|
605849
|
-
return false;
|
|
605850
|
-
}
|
|
605851
|
-
const stillThere = isInstalled(preset);
|
|
605852
|
-
if (!stillThere) {
|
|
605853
|
-
onLine?.(`Install reported success but ${preset.command} is still not on $PATH. You may need to open a new shell or add the install dir to PATH.`, "info");
|
|
605854
|
-
}
|
|
605855
|
-
return stillThere;
|
|
605856
|
-
}
|
|
605857
|
-
function composePrompt(history, prompt) {
|
|
605858
|
-
const lines = [];
|
|
605859
|
-
for (const m of history) {
|
|
605860
|
-
const tag = m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : m.role;
|
|
605861
|
-
lines.push(`${tag}: ${m.content}`);
|
|
605862
|
-
}
|
|
605863
|
-
lines.push(`User: ${prompt}`);
|
|
605864
|
-
lines.push("Assistant:");
|
|
605865
|
-
return lines.join(`
|
|
605866
|
-
|
|
605867
|
-
`);
|
|
605868
|
-
}
|
|
605869
|
-
async function runExternalAgent(preset, prompt, signal) {
|
|
605870
|
-
const start = performance.now();
|
|
605871
|
-
const argv = [...preset.args];
|
|
605872
|
-
if (preset.promptMode === "flag") {
|
|
605873
|
-
argv.push(preset.flagName ?? "-p", prompt);
|
|
605874
|
-
} else if (preset.promptMode === "arg") {
|
|
605875
|
-
argv.push(prompt);
|
|
605876
|
-
}
|
|
605877
|
-
let pathPrefix = "";
|
|
605878
|
-
if (preset.requiresNodeVersion) {
|
|
605879
|
-
try {
|
|
605880
|
-
await Promise.resolve().then(() => init_runtime());
|
|
605881
|
-
const binDir = await ensureNodeFor(preset.requiresNodeVersion);
|
|
605882
|
-
if (binDir)
|
|
605883
|
-
pathPrefix = `${binDir}:`;
|
|
605884
|
-
} catch (err) {
|
|
605885
|
-
return {
|
|
605886
|
-
ok: false,
|
|
605887
|
-
text: "",
|
|
605888
|
-
durationMs: Math.round(performance.now() - start),
|
|
605889
|
-
command: `${preset.command} ${argv.join(" ")}`,
|
|
605890
|
-
error: `managed Node runtime install failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
605891
|
-
exitCode: null
|
|
605892
|
-
};
|
|
605893
|
-
}
|
|
605894
|
-
}
|
|
605895
|
-
return new Promise((resolve) => {
|
|
605896
|
-
let stdout = "";
|
|
605897
|
-
let stderr = "";
|
|
605898
|
-
let exited = false;
|
|
605899
|
-
const proc = spawn30(preset.command, argv, {
|
|
605900
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
605901
|
-
env: {
|
|
605902
|
-
...process.env,
|
|
605903
|
-
PATH: `${pathPrefix}${process.env.PATH ?? ""}`,
|
|
605904
|
-
NO_COLOR: "1",
|
|
605905
|
-
FORCE_COLOR: "0",
|
|
605906
|
-
"8GENT_NO_INTRO": "1",
|
|
605907
|
-
AI_SDK_LOG_WARNINGS: "false"
|
|
605908
|
-
}
|
|
605909
|
-
});
|
|
605910
|
-
const finish = (result) => {
|
|
605911
|
-
if (exited)
|
|
605912
|
-
return;
|
|
605913
|
-
exited = true;
|
|
605914
|
-
clearTimeout(timer);
|
|
605915
|
-
signal?.removeEventListener("abort", onAbort);
|
|
605916
|
-
resolve({
|
|
605917
|
-
...result,
|
|
605918
|
-
durationMs: Math.round(performance.now() - start),
|
|
605919
|
-
command: `${preset.command} ${argv.map((a) => a.includes(" ") ? `"${a}"` : a).join(" ")}`
|
|
605920
|
-
});
|
|
605921
|
-
};
|
|
605922
|
-
proc.on("error", (err) => {
|
|
605923
|
-
finish({
|
|
605924
|
-
ok: false,
|
|
605925
|
-
text: "",
|
|
605926
|
-
error: err.code === "ENOENT" ? `${preset.command}: not installed (no binary on $PATH)` : err.message,
|
|
605927
|
-
exitCode: null
|
|
605928
|
-
});
|
|
605929
|
-
});
|
|
605930
|
-
proc.stdout?.on("data", (chunk) => {
|
|
605931
|
-
stdout += chunk.toString();
|
|
605932
|
-
});
|
|
605933
|
-
proc.stderr?.on("data", (chunk) => {
|
|
605934
|
-
stderr += chunk.toString();
|
|
605935
|
-
});
|
|
605936
|
-
proc.on("close", (code) => {
|
|
605937
|
-
let text = preset.parseStdout ? preset.parseStdout(stdout).trim() : stdout.trim();
|
|
605938
|
-
try {
|
|
605939
|
-
init_keys();
|
|
605940
|
-
if (text)
|
|
605941
|
-
text = redactAndWarn(text);
|
|
605942
|
-
} catch {}
|
|
605943
|
-
if (code === 0 || code !== null && text.length > 0) {
|
|
605944
|
-
finish({ ok: code === 0, text, exitCode: code, error: code === 0 ? undefined : stderr.trim().slice(0, 400) });
|
|
605945
|
-
} else {
|
|
605946
|
-
finish({
|
|
605947
|
-
ok: false,
|
|
605948
|
-
text,
|
|
605949
|
-
exitCode: code,
|
|
605950
|
-
error: stderr.trim().slice(0, 400) || `exited with code ${code}`
|
|
605951
|
-
});
|
|
605952
|
-
}
|
|
605953
|
-
});
|
|
605954
|
-
if (preset.promptMode === "stdin" && proc.stdin) {
|
|
605955
|
-
proc.stdin.write(prompt);
|
|
605956
|
-
proc.stdin.end();
|
|
605957
|
-
} else if (proc.stdin) {
|
|
605958
|
-
proc.stdin.end();
|
|
605959
|
-
}
|
|
605960
|
-
const timer = setTimeout(() => {
|
|
605961
|
-
proc.kill("SIGTERM");
|
|
605962
|
-
finish({
|
|
605963
|
-
ok: false,
|
|
605964
|
-
text: stdout,
|
|
605965
|
-
error: `timeout after ${preset.timeoutMs ?? 90000}ms`,
|
|
605966
|
-
exitCode: null
|
|
605967
|
-
});
|
|
605968
|
-
}, preset.timeoutMs ?? 90000);
|
|
605969
|
-
const onAbort = () => {
|
|
605970
|
-
proc.kill("SIGTERM");
|
|
605971
|
-
finish({ ok: false, text: stdout, error: "aborted", exitCode: null });
|
|
605972
|
-
};
|
|
605973
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
605974
|
-
});
|
|
605975
|
-
}
|
|
606223
|
+
// apps/tui/src/app.tsx
|
|
606224
|
+
init_external_agent_runner();
|
|
605976
606225
|
|
|
605977
606226
|
// packages/daemon/goal-rpc.ts
|
|
605978
606227
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
@@ -607255,7 +607504,7 @@ class InProcessGoalTransport {
|
|
|
607255
607504
|
// apps/tui/src/lib/intro-gate.ts
|
|
607256
607505
|
init_home();
|
|
607257
607506
|
import { mkdirSync as mkdirSync85, readFileSync as readFileSync108, writeFileSync as writeFileSync65 } from "fs";
|
|
607258
|
-
import { join as
|
|
607507
|
+
import { join as join184 } from "path";
|
|
607259
607508
|
function shouldShowIntro({ setting, env, seenVersion, version }) {
|
|
607260
607509
|
if (setting === "off")
|
|
607261
607510
|
return false;
|
|
@@ -607266,7 +607515,7 @@ function shouldShowIntro({ setting, env, seenVersion, version }) {
|
|
|
607266
607515
|
return seenVersion !== version;
|
|
607267
607516
|
}
|
|
607268
607517
|
function seenPath(home) {
|
|
607269
|
-
return
|
|
607518
|
+
return join184(home, ".8gent", "intro-seen");
|
|
607270
607519
|
}
|
|
607271
607520
|
function readSeenVersion(home = resolveHome()) {
|
|
607272
607521
|
try {
|
|
@@ -607278,7 +607527,7 @@ function readSeenVersion(home = resolveHome()) {
|
|
|
607278
607527
|
}
|
|
607279
607528
|
function markIntroSeen(version, home = resolveHome()) {
|
|
607280
607529
|
try {
|
|
607281
|
-
mkdirSync85(
|
|
607530
|
+
mkdirSync85(join184(home, ".8gent"), { recursive: true });
|
|
607282
607531
|
writeFileSync65(seenPath(home), `${version}
|
|
607283
607532
|
`);
|
|
607284
607533
|
} catch {}
|
|
@@ -608971,12 +609220,12 @@ function sanitizeFreeText(value) {
|
|
|
608971
609220
|
// packages/voice/audio-gate.ts
|
|
608972
609221
|
init_home();
|
|
608973
609222
|
import { readFileSync as readFileSync110 } from "fs";
|
|
608974
|
-
import { join as
|
|
609223
|
+
import { join as join187 } from "path";
|
|
608975
609224
|
function audioOutputAllowed(env = process.env) {
|
|
608976
609225
|
if (env.EIGHT_VOICE === "1")
|
|
608977
609226
|
return true;
|
|
608978
609227
|
try {
|
|
608979
|
-
const raw = JSON.parse(readFileSync110(
|
|
609228
|
+
const raw = JSON.parse(readFileSync110(join187(resolveHome(env), ".8gent", "settings.json"), "utf8"));
|
|
608980
609229
|
return raw?.voice?.outputEnabled === true;
|
|
608981
609230
|
} catch {
|
|
608982
609231
|
return false;
|
|
@@ -610150,10 +610399,10 @@ function snapshot(manager) {
|
|
|
610150
610399
|
|
|
610151
610400
|
// apps/tui/src/hooks/useBodyParts.ts
|
|
610152
610401
|
var import_react83 = __toESM(require_react(), 1);
|
|
610153
|
-
import { existsSync as
|
|
610402
|
+
import { existsSync as existsSync124 } from "fs";
|
|
610154
610403
|
import { execSync as execSync8 } from "child_process";
|
|
610155
610404
|
import { homedir as homedir90 } from "os";
|
|
610156
|
-
import { join as
|
|
610405
|
+
import { join as join188 } from "path";
|
|
610157
610406
|
var PULSE_FLASH_MS = 150;
|
|
610158
610407
|
function hasCliclick() {
|
|
610159
610408
|
try {
|
|
@@ -610164,7 +610413,7 @@ function hasCliclick() {
|
|
|
610164
610413
|
}
|
|
610165
610414
|
}
|
|
610166
610415
|
function hasAxBridge() {
|
|
610167
|
-
return
|
|
610416
|
+
return existsSync124(join188(homedir90(), ".8gent", "bin", "8gent-ax-bridge"));
|
|
610168
610417
|
}
|
|
610169
610418
|
function detectDefaultBodyPartsState() {
|
|
610170
610419
|
const handsOk = hasCliclick();
|
|
@@ -610452,6 +610701,7 @@ function onChange(fn) {
|
|
|
610452
610701
|
init_shell();
|
|
610453
610702
|
init_secret_scanner();
|
|
610454
610703
|
init_path_guard();
|
|
610704
|
+
init_permission_mode();
|
|
610455
610705
|
init_eight_browser();
|
|
610456
610706
|
|
|
610457
610707
|
// apps/tui/src/lib/consult-command.ts
|
|
@@ -610492,8 +610742,16 @@ function sendRefusal(command) {
|
|
|
610492
610742
|
return null;
|
|
610493
610743
|
}
|
|
610494
610744
|
function planModeRefusal2(mode) {
|
|
610495
|
-
return mode === "plan" ? "Plan mode runs nothing, shell lines included. Shift+Tab to change mode, then run it again." : null;
|
|
610745
|
+
return mode === "plan" ? "Plan mode runs nothing, shell lines included. Type /mode ask (or press Shift+Tab) to change mode, then run it again." : null;
|
|
610746
|
+
}
|
|
610747
|
+
function parseModeArgs(args) {
|
|
610748
|
+
const words = args.flatMap((a) => a.trim().split(/\s+/)).filter(Boolean);
|
|
610749
|
+
if (words.length !== 1)
|
|
610750
|
+
return null;
|
|
610751
|
+
const name = words[0].toLowerCase();
|
|
610752
|
+
return isPermissionMode(name) ? name : null;
|
|
610496
610753
|
}
|
|
610754
|
+
var MODE_USAGE = "Usage: /mode plan | ask | guarded | infinite (this tab's permission mode).";
|
|
610497
610755
|
var ANSI2 = /\x1b\[[0-?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[ -/]*[0-~]/g;
|
|
610498
610756
|
var CONTROL4 = /[\x00-\x08\x0b-\x1f\x7f]/g;
|
|
610499
610757
|
function cleanOutput(raw) {
|
|
@@ -611752,6 +612010,24 @@ ${r.message}`;
|
|
|
611752
612010
|
// apps/tui/src/app.tsx
|
|
611753
612011
|
init_slash_commands();
|
|
611754
612012
|
|
|
612013
|
+
// apps/tui/src/lib/term-intent.ts
|
|
612014
|
+
var VERBS2 = "run|open|start|launch|fire up|spin up|boot";
|
|
612015
|
+
var POLITE = "(?:please\\s+|can you\\s+|could you\\s+)?";
|
|
612016
|
+
var WHERE = "(?:\\s+in\\s+(?:a\\s+)?(?:new\\s+)?(?:tab|terminal(?:\\s+tab)?))?";
|
|
612017
|
+
var PRESET_INTENT = new RegExp(`^${POLITE}(?:${VERBS2})\\s+(?:up\\s+)?([a-z0-9][a-z0-9_-]*)(${WHERE})(?:\\s+please)?$`);
|
|
612018
|
+
function detectTermPresetIntent(input, presetIds) {
|
|
612019
|
+
const text = input.trim().toLowerCase().replace(/[.!?]+$/, "").replace(/\s+/g, " ");
|
|
612020
|
+
if (!text || text.length > 60)
|
|
612021
|
+
return null;
|
|
612022
|
+
const m = PRESET_INTENT.exec(text);
|
|
612023
|
+
if (!m)
|
|
612024
|
+
return null;
|
|
612025
|
+
const id = presetIds.find((p) => p.toLowerCase() === m[1]);
|
|
612026
|
+
if (!id)
|
|
612027
|
+
return null;
|
|
612028
|
+
return m[2] ? [id, "--in-tab"] : [id];
|
|
612029
|
+
}
|
|
612030
|
+
|
|
611755
612031
|
// apps/tui/src/lib/turn-outcome.ts
|
|
611756
612032
|
init_local_turn_error();
|
|
611757
612033
|
function turnEndedInError(messages) {
|
|
@@ -611769,8 +612045,8 @@ function turnEndedInError(messages) {
|
|
|
611769
612045
|
}
|
|
611770
612046
|
|
|
611771
612047
|
// apps/tui/src/screens/BTWView.tsx
|
|
611772
|
-
import { existsSync as
|
|
611773
|
-
import { join as
|
|
612048
|
+
import { existsSync as existsSync126, mkdirSync as mkdirSync89, readFileSync as readFileSync112, writeFileSync as writeFileSync69 } from "fs";
|
|
612049
|
+
import { join as join190 } from "path";
|
|
611774
612050
|
var import_react85 = __toESM(require_react(), 1);
|
|
611775
612051
|
|
|
611776
612052
|
// apps/tui/src/components/primitives/Divider.tsx
|
|
@@ -611782,13 +612058,13 @@ var Divider = ({ width = 60, character = "\u2500" }) => /* @__PURE__ */ jsx_dev_
|
|
|
611782
612058
|
|
|
611783
612059
|
// apps/tui/src/screens/BTWView.tsx
|
|
611784
612060
|
var jsx_dev_runtime50 = __toESM(require_jsx_dev_runtime(), 1);
|
|
611785
|
-
var DATA_DIR5 =
|
|
612061
|
+
var DATA_DIR5 = join190(process.env.HOME || "~", ".8gent", "tabs");
|
|
611786
612062
|
function loadBTW() {
|
|
611787
612063
|
try {
|
|
611788
|
-
if (!
|
|
612064
|
+
if (!existsSync126(DATA_DIR5))
|
|
611789
612065
|
mkdirSync89(DATA_DIR5, { recursive: true });
|
|
611790
|
-
const filepath =
|
|
611791
|
-
if (
|
|
612066
|
+
const filepath = join190(DATA_DIR5, "btw.json");
|
|
612067
|
+
if (existsSync126(filepath)) {
|
|
611792
612068
|
const raw = JSON.parse(readFileSync112(filepath, "utf-8"));
|
|
611793
612069
|
return raw.items || [];
|
|
611794
612070
|
}
|
|
@@ -611797,9 +612073,9 @@ function loadBTW() {
|
|
|
611797
612073
|
}
|
|
611798
612074
|
function saveBTW(items) {
|
|
611799
612075
|
try {
|
|
611800
|
-
if (!
|
|
612076
|
+
if (!existsSync126(DATA_DIR5))
|
|
611801
612077
|
mkdirSync89(DATA_DIR5, { recursive: true });
|
|
611802
|
-
writeFileSync69(
|
|
612078
|
+
writeFileSync69(join190(DATA_DIR5, "btw.json"), JSON.stringify({ items }, null, 2));
|
|
611803
612079
|
} catch {}
|
|
611804
612080
|
}
|
|
611805
612081
|
function sortItems(items) {
|
|
@@ -612132,17 +612408,17 @@ function HistoryScreen({ conversations, onSelect, onBack }) {
|
|
|
612132
612408
|
}
|
|
612133
612409
|
|
|
612134
612410
|
// apps/tui/src/screens/IdeasView.tsx
|
|
612135
|
-
import { existsSync as
|
|
612136
|
-
import { join as
|
|
612411
|
+
import { existsSync as existsSync127, mkdirSync as mkdirSync90, readFileSync as readFileSync113, writeFileSync as writeFileSync70 } from "fs";
|
|
612412
|
+
import { join as join191 } from "path";
|
|
612137
612413
|
var import_react87 = __toESM(require_react(), 1);
|
|
612138
612414
|
var jsx_dev_runtime52 = __toESM(require_jsx_dev_runtime(), 1);
|
|
612139
|
-
var DATA_DIR6 =
|
|
612415
|
+
var DATA_DIR6 = join191(process.env.HOME || "~", ".8gent", "tabs");
|
|
612140
612416
|
function loadIdeas() {
|
|
612141
612417
|
try {
|
|
612142
|
-
if (!
|
|
612418
|
+
if (!existsSync127(DATA_DIR6))
|
|
612143
612419
|
mkdirSync90(DATA_DIR6, { recursive: true });
|
|
612144
|
-
const filepath =
|
|
612145
|
-
if (
|
|
612420
|
+
const filepath = join191(DATA_DIR6, "ideas.json");
|
|
612421
|
+
if (existsSync127(filepath)) {
|
|
612146
612422
|
const raw = JSON.parse(readFileSync113(filepath, "utf-8"));
|
|
612147
612423
|
return raw.ideas || [];
|
|
612148
612424
|
}
|
|
@@ -612151,9 +612427,9 @@ function loadIdeas() {
|
|
|
612151
612427
|
}
|
|
612152
612428
|
function saveIdeas(ideas) {
|
|
612153
612429
|
try {
|
|
612154
|
-
if (!
|
|
612430
|
+
if (!existsSync127(DATA_DIR6))
|
|
612155
612431
|
mkdirSync90(DATA_DIR6, { recursive: true });
|
|
612156
|
-
writeFileSync70(
|
|
612432
|
+
writeFileSync70(join191(DATA_DIR6, "ideas.json"), JSON.stringify({ ideas }, null, 2));
|
|
612157
612433
|
} catch {}
|
|
612158
612434
|
}
|
|
612159
612435
|
function extractTags2(text) {
|
|
@@ -612614,11 +612890,11 @@ function KeyVaultScreen({
|
|
|
612614
612890
|
}
|
|
612615
612891
|
|
|
612616
612892
|
// apps/tui/src/screens/MusicPlayerView.tsx
|
|
612617
|
-
import { existsSync as
|
|
612618
|
-
import { basename as
|
|
612893
|
+
import { existsSync as existsSync128, readdirSync as readdirSync28, statSync as statSync38 } from "fs";
|
|
612894
|
+
import { basename as basename54, join as join192 } from "path";
|
|
612619
612895
|
var import_react89 = __toESM(require_react(), 1);
|
|
612620
612896
|
var jsx_dev_runtime54 = __toESM(require_jsx_dev_runtime(), 1);
|
|
612621
|
-
var CACHE_DIR4 =
|
|
612897
|
+
var CACHE_DIR4 = join192(process.env.HOME || "~", ".8gent", "adhd-audio");
|
|
612622
612898
|
function formatBytes(bytes) {
|
|
612623
612899
|
if (bytes < 1024)
|
|
612624
612900
|
return `${bytes}B`;
|
|
@@ -612636,20 +612912,20 @@ function formatDate(date) {
|
|
|
612636
612912
|
}
|
|
612637
612913
|
function loadTracks(currentTrack) {
|
|
612638
612914
|
const tracks = [];
|
|
612639
|
-
if (!
|
|
612915
|
+
if (!existsSync128(CACHE_DIR4))
|
|
612640
612916
|
return tracks;
|
|
612641
612917
|
try {
|
|
612642
612918
|
const files = readdirSync28(CACHE_DIR4).filter((f) => f.endsWith(".mp3") || f.endsWith(".wav"));
|
|
612643
612919
|
for (const file of files) {
|
|
612644
|
-
const filePath =
|
|
612920
|
+
const filePath = join192(CACHE_DIR4, file);
|
|
612645
612921
|
const stat = statSync38(filePath);
|
|
612646
|
-
const name =
|
|
612922
|
+
const name = basename54(file, ".mp3").replace(/-/g, " ");
|
|
612647
612923
|
tracks.push({
|
|
612648
612924
|
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
612649
612925
|
path: filePath,
|
|
612650
612926
|
size: formatBytes(stat.size),
|
|
612651
612927
|
modified: formatDate(stat.mtime),
|
|
612652
|
-
playing: currentTrack === name.toLowerCase() || currentTrack ===
|
|
612928
|
+
playing: currentTrack === name.toLowerCase() || currentTrack === basename54(file, ".mp3")
|
|
612653
612929
|
});
|
|
612654
612930
|
}
|
|
612655
612931
|
} catch {}
|
|
@@ -613145,18 +613421,18 @@ function NarratorView({ tasks, narratorText, maxHeight }) {
|
|
|
613145
613421
|
}
|
|
613146
613422
|
|
|
613147
613423
|
// apps/tui/src/screens/NotesView.tsx
|
|
613148
|
-
import { existsSync as
|
|
613149
|
-
import { join as
|
|
613424
|
+
import { existsSync as existsSync129, mkdirSync as mkdirSync91, readFileSync as readFileSync114, writeFileSync as writeFileSync71 } from "fs";
|
|
613425
|
+
import { join as join193 } from "path";
|
|
613150
613426
|
var import_react91 = __toESM(require_react(), 1);
|
|
613151
613427
|
var jsx_dev_runtime59 = __toESM(require_jsx_dev_runtime(), 1);
|
|
613152
|
-
var DATA_DIR7 =
|
|
613428
|
+
var DATA_DIR7 = join193(process.env.HOME || "~", ".8gent", "tabs");
|
|
613153
613429
|
var EMPTY_TAB_NAMES = [];
|
|
613154
613430
|
function loadNotes() {
|
|
613155
613431
|
try {
|
|
613156
|
-
if (!
|
|
613432
|
+
if (!existsSync129(DATA_DIR7))
|
|
613157
613433
|
mkdirSync91(DATA_DIR7, { recursive: true });
|
|
613158
|
-
const filepath =
|
|
613159
|
-
if (
|
|
613434
|
+
const filepath = join193(DATA_DIR7, "notes.json");
|
|
613435
|
+
if (existsSync129(filepath)) {
|
|
613160
613436
|
const raw = JSON.parse(readFileSync114(filepath, "utf-8"));
|
|
613161
613437
|
return raw.notes || [];
|
|
613162
613438
|
}
|
|
@@ -613165,9 +613441,9 @@ function loadNotes() {
|
|
|
613165
613441
|
}
|
|
613166
613442
|
function saveNotes(notes) {
|
|
613167
613443
|
try {
|
|
613168
|
-
if (!
|
|
613444
|
+
if (!existsSync129(DATA_DIR7))
|
|
613169
613445
|
mkdirSync91(DATA_DIR7, { recursive: true });
|
|
613170
|
-
writeFileSync71(
|
|
613446
|
+
writeFileSync71(join193(DATA_DIR7, "notes.json"), JSON.stringify({ notes }, null, 2));
|
|
613171
613447
|
} catch {}
|
|
613172
613448
|
}
|
|
613173
613449
|
function NotesView({
|
|
@@ -614360,40 +614636,40 @@ function OnboardingScreen({
|
|
|
614360
614636
|
|
|
614361
614637
|
// apps/tui/src/screens/ProjectsView.tsx
|
|
614362
614638
|
import { execSync as execSync9 } from "child_process";
|
|
614363
|
-
import { existsSync as
|
|
614639
|
+
import { existsSync as existsSync130, mkdirSync as mkdirSync92, readFileSync as readFileSync115, readdirSync as readdirSync29, statSync as statSync39, writeFileSync as writeFileSync72 } from "fs";
|
|
614364
614640
|
import { homedir as homedir91 } from "os";
|
|
614365
|
-
import { basename as
|
|
614641
|
+
import { basename as basename55, join as join194 } from "path";
|
|
614366
614642
|
var import_react96 = __toESM(require_react(), 1);
|
|
614367
614643
|
var jsx_dev_runtime61 = __toESM(require_jsx_dev_runtime(), 1);
|
|
614368
|
-
var SAVED_PROJECTS_PATH =
|
|
614644
|
+
var SAVED_PROJECTS_PATH = join194(homedir91(), ".8gent", "tabs", "projects.json");
|
|
614369
614645
|
var SCAN_DIRS = [
|
|
614370
614646
|
homedir91(),
|
|
614371
|
-
|
|
614372
|
-
|
|
614373
|
-
|
|
614647
|
+
join194(homedir91(), "Documents"),
|
|
614648
|
+
join194(homedir91(), "Projects"),
|
|
614649
|
+
join194(homedir91(), "Code")
|
|
614374
614650
|
];
|
|
614375
614651
|
var PROJECT_MARKERS = ["package.json", ".git", "CLAUDE.md", ".8gent"];
|
|
614376
614652
|
function isProjectDir(dirPath) {
|
|
614377
614653
|
try {
|
|
614378
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
614654
|
+
return PROJECT_MARKERS.some((marker) => existsSync130(join194(dirPath, marker)));
|
|
614379
614655
|
} catch {
|
|
614380
614656
|
return false;
|
|
614381
614657
|
}
|
|
614382
614658
|
}
|
|
614383
614659
|
function getProjectName(dirPath) {
|
|
614384
614660
|
try {
|
|
614385
|
-
const pkgPath =
|
|
614386
|
-
if (
|
|
614661
|
+
const pkgPath = join194(dirPath, "package.json");
|
|
614662
|
+
if (existsSync130(pkgPath)) {
|
|
614387
614663
|
const pkg = JSON.parse(readFileSync115(pkgPath, "utf8"));
|
|
614388
614664
|
if (pkg.name)
|
|
614389
614665
|
return pkg.name;
|
|
614390
614666
|
}
|
|
614391
614667
|
} catch {}
|
|
614392
|
-
return
|
|
614668
|
+
return basename55(dirPath);
|
|
614393
614669
|
}
|
|
614394
614670
|
function getGitBranch2(dirPath) {
|
|
614395
614671
|
try {
|
|
614396
|
-
if (!
|
|
614672
|
+
if (!existsSync130(join194(dirPath, ".git")))
|
|
614397
614673
|
return;
|
|
614398
614674
|
const result = execSync9(`git -C "${dirPath}" branch --show-current 2>/dev/null`, {
|
|
614399
614675
|
encoding: "utf8",
|
|
@@ -614413,7 +614689,7 @@ function getLastModified(dirPath) {
|
|
|
614413
614689
|
}
|
|
614414
614690
|
}
|
|
614415
614691
|
function has8gent(dirPath) {
|
|
614416
|
-
return
|
|
614692
|
+
return existsSync130(join194(dirPath, ".8gent"));
|
|
614417
614693
|
}
|
|
614418
614694
|
function buildProjectEntry(dirPath) {
|
|
614419
614695
|
return {
|
|
@@ -614430,7 +614706,7 @@ function scanForProjects(currentPath) {
|
|
|
614430
614706
|
found.add(currentPath);
|
|
614431
614707
|
results.push(buildProjectEntry(currentPath));
|
|
614432
614708
|
for (const scanDir of SCAN_DIRS) {
|
|
614433
|
-
if (!
|
|
614709
|
+
if (!existsSync130(scanDir))
|
|
614434
614710
|
continue;
|
|
614435
614711
|
try {
|
|
614436
614712
|
const entries = readdirSync29(scanDir, { withFileTypes: true });
|
|
@@ -614439,7 +614715,7 @@ function scanForProjects(currentPath) {
|
|
|
614439
614715
|
continue;
|
|
614440
614716
|
if (entry.name.startsWith("."))
|
|
614441
614717
|
continue;
|
|
614442
|
-
const fullPath =
|
|
614718
|
+
const fullPath = join194(scanDir, entry.name);
|
|
614443
614719
|
if (found.has(fullPath))
|
|
614444
614720
|
continue;
|
|
614445
614721
|
if (isProjectDir(fullPath)) {
|
|
@@ -614462,7 +614738,7 @@ function scanForProjects(currentPath) {
|
|
|
614462
614738
|
}
|
|
614463
614739
|
function loadSavedProjects() {
|
|
614464
614740
|
try {
|
|
614465
|
-
if (!
|
|
614741
|
+
if (!existsSync130(SAVED_PROJECTS_PATH))
|
|
614466
614742
|
return [];
|
|
614467
614743
|
const raw = readFileSync115(SAVED_PROJECTS_PATH, "utf8");
|
|
614468
614744
|
const data = JSON.parse(raw);
|
|
@@ -614473,7 +614749,7 @@ function loadSavedProjects() {
|
|
|
614473
614749
|
}
|
|
614474
614750
|
function saveSavedProjects(projects) {
|
|
614475
614751
|
try {
|
|
614476
|
-
const dir =
|
|
614752
|
+
const dir = join194(homedir91(), ".8gent", "tabs");
|
|
614477
614753
|
mkdirSync92(dir, { recursive: true });
|
|
614478
614754
|
const data = { projects };
|
|
614479
614755
|
writeFileSync72(SAVED_PROJECTS_PATH, JSON.stringify(data, null, 2), "utf8");
|
|
@@ -614485,7 +614761,7 @@ function mergeProjects(scanned, saved) {
|
|
|
614485
614761
|
for (const s of saved) {
|
|
614486
614762
|
if (paths.has(s.path))
|
|
614487
614763
|
continue;
|
|
614488
|
-
if (!
|
|
614764
|
+
if (!existsSync130(s.path))
|
|
614489
614765
|
continue;
|
|
614490
614766
|
paths.add(s.path);
|
|
614491
614767
|
extra.push(buildProjectEntry(s.path));
|
|
@@ -614553,7 +614829,7 @@ function ProjectsView({
|
|
|
614553
614829
|
if (addMode) {
|
|
614554
614830
|
if (key.return) {
|
|
614555
614831
|
const trimmed = addInput.trim();
|
|
614556
|
-
if (trimmed &&
|
|
614832
|
+
if (trimmed && existsSync130(trimmed)) {
|
|
614557
614833
|
const newEntry = {
|
|
614558
614834
|
...buildProjectEntry(trimmed),
|
|
614559
614835
|
addedAt: new Date().toISOString()
|
|
@@ -614740,17 +615016,17 @@ function ProjectsView({
|
|
|
614740
615016
|
}
|
|
614741
615017
|
|
|
614742
615018
|
// apps/tui/src/screens/QuestionsView.tsx
|
|
614743
|
-
import { existsSync as
|
|
614744
|
-
import { join as
|
|
615019
|
+
import { existsSync as existsSync131, mkdirSync as mkdirSync93, readFileSync as readFileSync116, writeFileSync as writeFileSync73 } from "fs";
|
|
615020
|
+
import { join as join195 } from "path";
|
|
614745
615021
|
var import_react97 = __toESM(require_react(), 1);
|
|
614746
615022
|
var jsx_dev_runtime62 = __toESM(require_jsx_dev_runtime(), 1);
|
|
614747
|
-
var DATA_DIR8 =
|
|
615023
|
+
var DATA_DIR8 = join195(process.env.HOME || "~", ".8gent", "tabs");
|
|
614748
615024
|
function loadQuestions() {
|
|
614749
615025
|
try {
|
|
614750
|
-
if (!
|
|
615026
|
+
if (!existsSync131(DATA_DIR8))
|
|
614751
615027
|
mkdirSync93(DATA_DIR8, { recursive: true });
|
|
614752
|
-
const filepath =
|
|
614753
|
-
if (
|
|
615028
|
+
const filepath = join195(DATA_DIR8, "questions.json");
|
|
615029
|
+
if (existsSync131(filepath)) {
|
|
614754
615030
|
const raw = JSON.parse(readFileSync116(filepath, "utf-8"));
|
|
614755
615031
|
return raw.questions || [];
|
|
614756
615032
|
}
|
|
@@ -614759,9 +615035,9 @@ function loadQuestions() {
|
|
|
614759
615035
|
}
|
|
614760
615036
|
function saveQuestions(questions) {
|
|
614761
615037
|
try {
|
|
614762
|
-
if (!
|
|
615038
|
+
if (!existsSync131(DATA_DIR8))
|
|
614763
615039
|
mkdirSync93(DATA_DIR8, { recursive: true });
|
|
614764
|
-
writeFileSync73(
|
|
615040
|
+
writeFileSync73(join195(DATA_DIR8, "questions.json"), JSON.stringify({ questions }, null, 2));
|
|
614765
615041
|
} catch {}
|
|
614766
615042
|
}
|
|
614767
615043
|
function QuestionsView({ visible, data, onUpdateData, onClose }) {
|
|
@@ -616047,13 +616323,13 @@ import * as fs104 from "fs";
|
|
|
616047
616323
|
import * as pathMod from "path";
|
|
616048
616324
|
|
|
616049
616325
|
// apps/tui/src/lib/package-scripts.ts
|
|
616050
|
-
import { existsSync as
|
|
616051
|
-
import { join as
|
|
616326
|
+
import { existsSync as existsSync132 } from "fs";
|
|
616327
|
+
import { join as join196, resolve as resolve75 } from "path";
|
|
616052
616328
|
var __dirname = (import.meta.dir + "/../apps/tui/src/lib");
|
|
616053
|
-
var PACKAGE_ROOT =
|
|
616329
|
+
var PACKAGE_ROOT = resolve75(__dirname, "../../../..");
|
|
616054
616330
|
function packageBinScript(name, root = PACKAGE_ROOT) {
|
|
616055
|
-
const candidate =
|
|
616056
|
-
return
|
|
616331
|
+
const candidate = join196(root, "bin", name);
|
|
616332
|
+
return existsSync132(candidate) ? candidate : null;
|
|
616057
616333
|
}
|
|
616058
616334
|
|
|
616059
616335
|
// apps/tui/src/app.tsx
|
|
@@ -616658,10 +616934,10 @@ function App2({
|
|
|
616658
616934
|
setting,
|
|
616659
616935
|
env: process.env,
|
|
616660
616936
|
seenVersion: readSeenVersion(),
|
|
616661
|
-
version:
|
|
616937
|
+
version: import_package2.default.version
|
|
616662
616938
|
});
|
|
616663
616939
|
if (show)
|
|
616664
|
-
markIntroSeen(
|
|
616940
|
+
markIntroSeen(import_package2.default.version);
|
|
616665
616941
|
return show;
|
|
616666
616942
|
});
|
|
616667
616943
|
const [processingStage, setProcessingStage] = import_react104.useState("planning");
|
|
@@ -618560,7 +618836,7 @@ Keyboard shortcuts:
|
|
|
618560
618836
|
setViewMode((prev) => prev === "kanban" ? "chat" : "kanban");
|
|
618561
618837
|
break;
|
|
618562
618838
|
case "bug":
|
|
618563
|
-
addSystemMessage(runBugCommand(args, { version:
|
|
618839
|
+
addSystemMessage(runBugCommand(args, { version: import_package2.default.version }).text);
|
|
618564
618840
|
break;
|
|
618565
618841
|
case "allow-read":
|
|
618566
618842
|
addSystemMessage(runAllowReadCommand(args, process.cwd(), (d) => agent?.allowReadDir(d) ?? null));
|
|
@@ -618893,6 +619169,19 @@ ${lines.join(`
|
|
|
618893
619169
|
agent.cleanup().catch(() => {});
|
|
618894
619170
|
exit();
|
|
618895
619171
|
break;
|
|
619172
|
+
case "mode": {
|
|
619173
|
+
const next = parseModeArgs(args);
|
|
619174
|
+
if (!next) {
|
|
619175
|
+
addSystemMessage(`${permSwitchLine(activePermMode)}
|
|
619176
|
+
${MODE_USAGE}`);
|
|
619177
|
+
break;
|
|
619178
|
+
}
|
|
619179
|
+
setTabPermMode(activeTabId, next);
|
|
619180
|
+
const shown = permView(permHolderFor(activeTabId));
|
|
619181
|
+
addSystemMessage(permSwitchLine(shown.mode, shown.held));
|
|
619182
|
+
showPermToast({ tabId: activeTabId, ...shown });
|
|
619183
|
+
break;
|
|
619184
|
+
}
|
|
618896
619185
|
case "infinite": {
|
|
618897
619186
|
const next = infiniteModeActive ? "ask" : "infinite";
|
|
618898
619187
|
setTabPermMode(activeTabId, next);
|
|
@@ -620977,6 +621266,26 @@ ${found.slice(0, 40).map((k) => ` ${k.name} ${k.description}`).join(`
|
|
|
620977
621266
|
}
|
|
620978
621267
|
return;
|
|
620979
621268
|
}
|
|
621269
|
+
if (input && !attached) {
|
|
621270
|
+
const termArgs = detectTermPresetIntent(input, listPresetIds());
|
|
621271
|
+
if (termArgs) {
|
|
621272
|
+
appendToTab(tabId, {
|
|
621273
|
+
id: `user-${Date.now()}`,
|
|
621274
|
+
role: "user",
|
|
621275
|
+
content: bubbleContent,
|
|
621276
|
+
timestamp: new Date
|
|
621277
|
+
});
|
|
621278
|
+
setRecentCommands((prev) => [bubbleContent, ...prev].slice(0, 20));
|
|
621279
|
+
const refused = planModeRefusal2(permView(permHolderFor(tabId)).mode);
|
|
621280
|
+
if (refused) {
|
|
621281
|
+
addSystemMessage(refused);
|
|
621282
|
+
return;
|
|
621283
|
+
}
|
|
621284
|
+
addSystemMessage(`Opening ${termArgs[0]} (same as /term ${termArgs.join(" ")}).`);
|
|
621285
|
+
handleSlashCommand("term", termArgs);
|
|
621286
|
+
return;
|
|
621287
|
+
}
|
|
621288
|
+
}
|
|
620980
621289
|
if (input && !attached) {
|
|
620981
621290
|
const buildTask = detectBuildIntent(input);
|
|
620982
621291
|
if (buildTask) {
|
|
@@ -621726,7 +622035,7 @@ ${result.commands.map((c) => ` $ ${c}`).join(`
|
|
|
621726
622035
|
value: { enabled: adhdMode, ratio: 0.5 },
|
|
621727
622036
|
children: /* @__PURE__ */ jsx_dev_runtime67.jsxDEV(FixedFrame, {
|
|
621728
622037
|
children: /* @__PURE__ */ jsx_dev_runtime67.jsxDEV(IntroBanner, {
|
|
621729
|
-
version:
|
|
622038
|
+
version: import_package2.default.version,
|
|
621730
622039
|
animate: showAnimations,
|
|
621731
622040
|
onDone: (carried) => {
|
|
621732
622041
|
bootTrace("intro-done", carried ? "by-key" : "timeout");
|
|
@@ -621800,7 +622109,7 @@ ${result.commands.map((c) => ` $ ${c}`).join(`
|
|
|
621800
622109
|
flexShrink: 0,
|
|
621801
622110
|
children: /* @__PURE__ */ jsx_dev_runtime67.jsxDEV(HeaderBar, {
|
|
621802
622111
|
updateAvailable: updateInfo,
|
|
621803
|
-
version:
|
|
622112
|
+
version: import_package2.default.version,
|
|
621804
622113
|
workspacePath: process.cwd(),
|
|
621805
622114
|
branch: git.branch,
|
|
621806
622115
|
syncStatus: git.noRepo ? "no repo" : git.sync,
|