@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/node/tui.js
CHANGED
|
@@ -21831,8 +21831,6 @@ var init_allowlist = __esm(() => {
|
|
|
21831
21831
|
"node",
|
|
21832
21832
|
"npm",
|
|
21833
21833
|
"npx",
|
|
21834
|
-
"pnpm",
|
|
21835
|
-
"yarn",
|
|
21836
21834
|
"deno",
|
|
21837
21835
|
"python",
|
|
21838
21836
|
"python3",
|
|
@@ -21840,9 +21838,6 @@ var init_allowlist = __esm(() => {
|
|
|
21840
21838
|
"pip3",
|
|
21841
21839
|
"uv",
|
|
21842
21840
|
"git",
|
|
21843
|
-
"go",
|
|
21844
|
-
"cargo",
|
|
21845
|
-
"rustc",
|
|
21846
21841
|
"tsc",
|
|
21847
21842
|
"gh",
|
|
21848
21843
|
"docker",
|
|
@@ -21867,20 +21862,18 @@ var init_allowlist = __esm(() => {
|
|
|
21867
21862
|
"biome",
|
|
21868
21863
|
"eslint",
|
|
21869
21864
|
"prettier",
|
|
21870
|
-
"vite"
|
|
21865
|
+
"vite",
|
|
21866
|
+
"8gent"
|
|
21871
21867
|
]);
|
|
21872
21868
|
SHORT_VERSION = {
|
|
21873
21869
|
node: "-v",
|
|
21874
21870
|
bun: "-v",
|
|
21875
21871
|
npm: "-v",
|
|
21876
|
-
pnpm: "-v",
|
|
21877
|
-
yarn: "-v",
|
|
21878
21872
|
deno: "-V",
|
|
21879
21873
|
python: "-V",
|
|
21880
21874
|
python3: "-V",
|
|
21881
21875
|
ffmpeg: "-version",
|
|
21882
|
-
ffprobe: "-version"
|
|
21883
|
-
go: "version"
|
|
21876
|
+
ffprobe: "-version"
|
|
21884
21877
|
};
|
|
21885
21878
|
SECRET_ARG = /(^|\/)\.env(\.[\w.-]+)?$|(^|\/)\.env\b|id_rsa|id_ed25519|id_ecdsa|(^|\/)\.ssh(\/|$)|\.aws\/|credentials|\.netrc|\.npmrc|\.git-credentials|keychain|\.pem$|\.key$|\.p12$/;
|
|
21886
21879
|
REDIR_RE2 = /(?<![<>&\d])(\d?|&)(>>?|<)(\|?)\s*(&\d+|[^\s;|&<>()]+)/g;
|
|
@@ -33286,7 +33279,7 @@ var init_permissions = __esm(() => {
|
|
|
33286
33279
|
var require_package = __commonJS(function(exports2, module2) {
|
|
33287
33280
|
module2.exports = {
|
|
33288
33281
|
name: "@8gi-foundation/8gent-code",
|
|
33289
|
-
version: "0.20.
|
|
33282
|
+
version: "0.20.17",
|
|
33290
33283
|
private: false,
|
|
33291
33284
|
engines: {
|
|
33292
33285
|
node: ">=22.5"
|
|
@@ -66788,6 +66781,12 @@ var init_slash_commands = __esm(() => {
|
|
|
66788
66781
|
description: "Enable infinite mode (autonomous until done)",
|
|
66789
66782
|
usage: "/infinite [task]"
|
|
66790
66783
|
},
|
|
66784
|
+
{
|
|
66785
|
+
name: "mode",
|
|
66786
|
+
aliases: [],
|
|
66787
|
+
description: "Set this tab's permission mode: plan, ask, guarded or infinite (same as Shift+Tab)",
|
|
66788
|
+
usage: "/mode <plan|ask|guarded|infinite>"
|
|
66789
|
+
},
|
|
66791
66790
|
{
|
|
66792
66791
|
name: "onboarding",
|
|
66793
66792
|
aliases: ["onboard", "setup", "intro"],
|
|
@@ -77734,8 +77733,31 @@ function emptyReplyStall(toolCalls) {
|
|
|
77734
77733
|
function isEmptyReplyStall(line) {
|
|
77735
77734
|
return line.startsWith(EMPTY_REPLY_STALL_PREFIX);
|
|
77736
77735
|
}
|
|
77737
|
-
function
|
|
77738
|
-
|
|
77736
|
+
function refusedCalls(log, max = 3) {
|
|
77737
|
+
const out = [];
|
|
77738
|
+
let total = 0;
|
|
77739
|
+
for (const e of log) {
|
|
77740
|
+
const m = /^\[[^\]]*\b(?:BLOCKED|DENIED)\b[^\]]*\]\s*([^\n]*)/.exec((e.result ?? "").trimStart());
|
|
77741
|
+
if (!m)
|
|
77742
|
+
continue;
|
|
77743
|
+
total++;
|
|
77744
|
+
if (out.length >= max)
|
|
77745
|
+
continue;
|
|
77746
|
+
const a = e.args;
|
|
77747
|
+
const first = typeof a?.command === "string" ? a.command.trim().split(/\s+/)[0] ?? "" : "";
|
|
77748
|
+
const bin = /^[A-Za-z][\w.+-]{0,40}$/.test(first) ? ` ${first}` : "";
|
|
77749
|
+
const why = /declin/i.test(m[1]) ? "declined" : "blocked by policy";
|
|
77750
|
+
out.push(`${e.name}${bin}: ${why}`);
|
|
77751
|
+
}
|
|
77752
|
+
return { total, shown: out };
|
|
77753
|
+
}
|
|
77754
|
+
function emptyReplyNote(toolCalls, log = []) {
|
|
77755
|
+
const base = `[harness] No reply: ${emptyReplyStall(toolCalls)}.`;
|
|
77756
|
+
const { total, shown } = refusedCalls(log);
|
|
77757
|
+
if (total === 0)
|
|
77758
|
+
return base;
|
|
77759
|
+
const more = total > shown.length ? ` (and ${total - shown.length} more)` : "";
|
|
77760
|
+
return `${base} ${total} of the calls were refused, so they did not run: ${shown.join("; ")}${more}.`;
|
|
77739
77761
|
}
|
|
77740
77762
|
function isEmptyReplyNote(reply) {
|
|
77741
77763
|
return reply.startsWith("[harness] No reply:");
|
|
@@ -77828,7 +77850,7 @@ ${summary}`;
|
|
|
77828
77850
|
if (unverified.length === 0)
|
|
77829
77851
|
return { content, rounds, toolLog, unverified: [] };
|
|
77830
77852
|
const notes = [
|
|
77831
|
-
empty ? emptyReplyNote(toolLog.length) : content.trimEnd(),
|
|
77853
|
+
empty ? emptyReplyNote(toolLog.length, toolLog) : content.trimEnd(),
|
|
77832
77854
|
unfulfilled.length > 0 ? formatHarnessNote(unfulfilled) : ""
|
|
77833
77855
|
].filter((n) => n.trim() !== "");
|
|
77834
77856
|
return { content: notes.join(`
|
|
@@ -570362,7 +570384,7 @@ onboarding preferences skip animations adhd quarantine toolshed skills design ev
|
|
|
570362
570384
|
resume history continue compact chat agent github debug music dj pet export fork rewind branch cron deploy
|
|
570363
570385
|
vercel telegram router rename spawn settings quiet term create-app hands eyes handeyes goal subgoal build
|
|
570364
570386
|
notes ideas btw questions projects terminal reload exit
|
|
570365
|
-
copy hotkeys tree import update route privacy consult bug me allow-read`.split(/\s+/));
|
|
570387
|
+
copy hotkeys tree import update route privacy consult bug me allow-read mode`.split(/\s+/));
|
|
570366
570388
|
});
|
|
570367
570389
|
|
|
570368
570390
|
// packages/extensions/index.ts
|
|
@@ -576446,7 +576468,9 @@ function defaultSessionsDir2() {
|
|
|
576446
576468
|
|
|
576447
576469
|
class SessionWriter {
|
|
576448
576470
|
filePath;
|
|
576449
|
-
fd;
|
|
576471
|
+
fd = -1;
|
|
576472
|
+
dev = -1;
|
|
576473
|
+
ino = -1;
|
|
576450
576474
|
persist;
|
|
576451
576475
|
seq = 0;
|
|
576452
576476
|
sessionId;
|
|
@@ -576478,15 +576502,47 @@ class SessionWriter {
|
|
|
576478
576502
|
fs78.mkdirSync(dir, { recursive: true });
|
|
576479
576503
|
}
|
|
576480
576504
|
this.filePath = path107.join(dir, `${sessionId}.jsonl`);
|
|
576481
|
-
this.
|
|
576505
|
+
this.open();
|
|
576506
|
+
}
|
|
576507
|
+
open() {
|
|
576508
|
+
const c = fs78.constants;
|
|
576509
|
+
const fd = fs78.openSync(this.filePath, c.O_WRONLY | c.O_APPEND | c.O_CREAT | (c.O_NOFOLLOW ?? 0), 384);
|
|
576510
|
+
const st = fs78.fstatSync(fd);
|
|
576511
|
+
if (!st.isFile()) {
|
|
576512
|
+
fs78.closeSync(fd);
|
|
576513
|
+
throw new Error(`${this.filePath} is not a regular file`);
|
|
576514
|
+
}
|
|
576515
|
+
this.fd = fd;
|
|
576516
|
+
this.dev = st.dev;
|
|
576517
|
+
this.ino = st.ino;
|
|
576518
|
+
}
|
|
576519
|
+
fdIsOurs() {
|
|
576520
|
+
if (this.fd < 0)
|
|
576521
|
+
return false;
|
|
576522
|
+
try {
|
|
576523
|
+
const st = fs78.fstatSync(this.fd);
|
|
576524
|
+
return st.dev === this.dev && st.ino === this.ino;
|
|
576525
|
+
} catch {
|
|
576526
|
+
return false;
|
|
576527
|
+
}
|
|
576482
576528
|
}
|
|
576483
576529
|
write(entry) {
|
|
576484
576530
|
if (!this.persist)
|
|
576485
576531
|
return;
|
|
576486
576532
|
const line = `${JSON.stringify(entry)}
|
|
576487
576533
|
`;
|
|
576488
|
-
|
|
576534
|
+
try {
|
|
576535
|
+
if (!this.fdIsOurs())
|
|
576536
|
+
this.open();
|
|
576537
|
+
fs78.writeSync(this.fd, line);
|
|
576538
|
+
} catch (err) {
|
|
576539
|
+
this.fd = -1;
|
|
576540
|
+
this.skippedWrites++;
|
|
576541
|
+
this.lastWriteError = `session log not written: ${err instanceof Error ? err.message : String(err)}`;
|
|
576542
|
+
}
|
|
576489
576543
|
}
|
|
576544
|
+
lastWriteError = null;
|
|
576545
|
+
skippedWrites = 0;
|
|
576490
576546
|
nextSeq() {
|
|
576491
576547
|
return this.seq++;
|
|
576492
576548
|
}
|
|
@@ -576696,8 +576752,9 @@ class SessionWriter {
|
|
|
576696
576752
|
reportId: reportId ?? null
|
|
576697
576753
|
}
|
|
576698
576754
|
});
|
|
576699
|
-
if (this.persist)
|
|
576755
|
+
if (this.persist && this.fdIsOurs())
|
|
576700
576756
|
fs78.closeSync(this.fd);
|
|
576757
|
+
this.fd = -1;
|
|
576701
576758
|
}
|
|
576702
576759
|
getFilePath() {
|
|
576703
576760
|
return this.filePath;
|
|
@@ -580415,6 +580472,52 @@ var init_registry = __esm(() => {
|
|
|
580415
580472
|
];
|
|
580416
580473
|
});
|
|
580417
580474
|
|
|
580475
|
+
// packages/eight/small-talk.ts
|
|
580476
|
+
function flatten2(text) {
|
|
580477
|
+
return text.toLowerCase().replace(/^\[mode: [^\]]*\]\s*/, "").replace(/['’]/g, "").replace(/[^a-z0-9 ]+/g, " ").replace(/\s+/g, " ").trim();
|
|
580478
|
+
}
|
|
580479
|
+
function isSmallTalk(text) {
|
|
580480
|
+
const flat = flatten2(text);
|
|
580481
|
+
return flat.length > 0 && flat.length <= 40 && GREETING.test(flat);
|
|
580482
|
+
}
|
|
580483
|
+
function isGreeting(text) {
|
|
580484
|
+
return isSmallTalk(text) && !THANKS.test(flatten2(text));
|
|
580485
|
+
}
|
|
580486
|
+
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.";
|
|
580487
|
+
var init_small_talk = __esm(() => {
|
|
580488
|
+
CORE = [
|
|
580489
|
+
"h+i+",
|
|
580490
|
+
"h+e+y+",
|
|
580491
|
+
"h+e+l+o+",
|
|
580492
|
+
"hiya",
|
|
580493
|
+
"howdy",
|
|
580494
|
+
"y+o+",
|
|
580495
|
+
"sup",
|
|
580496
|
+
"wa+s+s?u+p+",
|
|
580497
|
+
"w?h?a+t?s? ?u+p+",
|
|
580498
|
+
"wh?a+t+s? go+d+",
|
|
580499
|
+
"good (?:morning|afternoon|evening|night)",
|
|
580500
|
+
"gm",
|
|
580501
|
+
"gn",
|
|
580502
|
+
"morning",
|
|
580503
|
+
"evening",
|
|
580504
|
+
"how are you(?: doing| today)?",
|
|
580505
|
+
"how are things",
|
|
580506
|
+
"hows it going",
|
|
580507
|
+
"how you doing",
|
|
580508
|
+
"you there",
|
|
580509
|
+
"anyone there",
|
|
580510
|
+
"ping",
|
|
580511
|
+
"thanks(?: a lot| so much)?",
|
|
580512
|
+
"thank you(?: so much)?",
|
|
580513
|
+
"thx",
|
|
580514
|
+
"ty",
|
|
580515
|
+
"cheers"
|
|
580516
|
+
].join("|");
|
|
580517
|
+
GREETING = new RegExp(`^(?:(?:hi+|hey+|hello+|yo+|hiya|howdy) )?(?:${CORE})(?: (?:there|again|everyone|all|team|mate|man|bro|friend|8gent|eight))?$`);
|
|
580518
|
+
THANKS = /^(?:thanks|thank you|thx|ty|cheers)\b/;
|
|
580519
|
+
});
|
|
580520
|
+
|
|
580418
580521
|
// packages/eight/verify-gate.ts
|
|
580419
580522
|
function isVerifyGateEnabled(env = process.env) {
|
|
580420
580523
|
const v = (env.EIGHT_VERIFY_GATE ?? "").trim().toLowerCase();
|
|
@@ -580457,6 +580560,755 @@ var init_verify_gate = __esm(() => {
|
|
|
580457
580560
|
`);
|
|
580458
580561
|
});
|
|
580459
580562
|
|
|
580563
|
+
// packages/voice/termux.ts
|
|
580564
|
+
import { constants as constants16, accessSync as accessSync5, readFileSync as readFileSync97 } from "node:fs";
|
|
580565
|
+
import { delimiter as delimiter8, join as join155 } from "node:path";
|
|
580566
|
+
function isAndroidHost(platform = process.platform, env = process.env) {
|
|
580567
|
+
return platform === "android" || !!env.TERMUX_VERSION || String(env.PREFIX ?? "").includes("/com.termux/");
|
|
580568
|
+
}
|
|
580569
|
+
function findOnPath(name, env = process.env) {
|
|
580570
|
+
for (const dir of String(env.PATH ?? "").split(delimiter8)) {
|
|
580571
|
+
if (!dir)
|
|
580572
|
+
continue;
|
|
580573
|
+
const candidate = join155(dir, name);
|
|
580574
|
+
try {
|
|
580575
|
+
accessSync5(candidate, constants16.X_OK);
|
|
580576
|
+
return candidate;
|
|
580577
|
+
} catch {}
|
|
580578
|
+
}
|
|
580579
|
+
return null;
|
|
580580
|
+
}
|
|
580581
|
+
function voiceOutputOn(env = process.env, readSettings = () => {
|
|
580582
|
+
const home = env.EIGHT_HOME || join155(env.HOME ?? "", ".8gent");
|
|
580583
|
+
return readFileSync97(join155(home, "settings.json"), "utf8");
|
|
580584
|
+
}) {
|
|
580585
|
+
if (env.EIGHT_VOICE === "1")
|
|
580586
|
+
return true;
|
|
580587
|
+
try {
|
|
580588
|
+
return JSON.parse(readSettings())?.voice?.outputEnabled === true;
|
|
580589
|
+
} catch {
|
|
580590
|
+
return false;
|
|
580591
|
+
}
|
|
580592
|
+
}
|
|
580593
|
+
function ctrlRAction(key, input, android = isAndroidHost()) {
|
|
580594
|
+
if (!key.ctrl || input !== "r")
|
|
580595
|
+
return "ignore";
|
|
580596
|
+
return android ? "android-line" : "toggle";
|
|
580597
|
+
}
|
|
580598
|
+
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;
|
|
580599
|
+
var init_termux = __esm(() => {
|
|
580600
|
+
ANDROID_VOICE_LINE_SUBS = [
|
|
580601
|
+
"",
|
|
580602
|
+
"chat",
|
|
580603
|
+
"conversation",
|
|
580604
|
+
"talk",
|
|
580605
|
+
"record",
|
|
580606
|
+
"listen",
|
|
580607
|
+
"stt",
|
|
580608
|
+
"status",
|
|
580609
|
+
"stop"
|
|
580610
|
+
];
|
|
580611
|
+
});
|
|
580612
|
+
|
|
580613
|
+
// packages/runtime/node-runtime.ts
|
|
580614
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
580615
|
+
import { existsSync as existsSync105 } from "node:fs";
|
|
580616
|
+
import { homedir as homedir78 } from "node:os";
|
|
580617
|
+
import { join as join156 } from "node:path";
|
|
580618
|
+
import { promisify as promisify6 } from "node:util";
|
|
580619
|
+
function parseNodeVersion(raw) {
|
|
580620
|
+
const trimmed = raw.trim();
|
|
580621
|
+
const match = trimmed.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
580622
|
+
if (!match)
|
|
580623
|
+
return null;
|
|
580624
|
+
return {
|
|
580625
|
+
major: Number.parseInt(match[1], 10),
|
|
580626
|
+
minor: Number.parseInt(match[2], 10),
|
|
580627
|
+
patch: Number.parseInt(match[3], 10)
|
|
580628
|
+
};
|
|
580629
|
+
}
|
|
580630
|
+
function satisfiesMinVersion(v, min) {
|
|
580631
|
+
const minParsed = parseNodeVersion(min);
|
|
580632
|
+
if (!minParsed)
|
|
580633
|
+
return true;
|
|
580634
|
+
if (v.major !== minParsed.major)
|
|
580635
|
+
return v.major > minParsed.major;
|
|
580636
|
+
if (v.minor !== minParsed.minor)
|
|
580637
|
+
return v.minor > minParsed.minor;
|
|
580638
|
+
return v.patch >= minParsed.patch;
|
|
580639
|
+
}
|
|
580640
|
+
function pickPlatformAsset(input) {
|
|
580641
|
+
const byArch = SUPPORTED[input.platform];
|
|
580642
|
+
if (!byArch) {
|
|
580643
|
+
throw new Error(`unsupported platform: ${input.platform}`);
|
|
580644
|
+
}
|
|
580645
|
+
const asset = byArch[input.arch];
|
|
580646
|
+
if (!asset) {
|
|
580647
|
+
throw new Error(`unsupported arch: ${input.arch} on ${input.platform}`);
|
|
580648
|
+
}
|
|
580649
|
+
return asset;
|
|
580650
|
+
}
|
|
580651
|
+
function buildDownloadUrl(opts) {
|
|
580652
|
+
const cleanVersion = opts.version.startsWith("v") ? opts.version.slice(1) : opts.version;
|
|
580653
|
+
const v = `v${cleanVersion}`;
|
|
580654
|
+
const fileBase = `node-${v}-${opts.asset.os}-${opts.asset.arch}`;
|
|
580655
|
+
return `https://nodejs.org/dist/${v}/${fileBase}.${opts.asset.ext}`;
|
|
580656
|
+
}
|
|
580657
|
+
function defaultRoot() {
|
|
580658
|
+
return join156(homedir78(), ".8gent", "runtime");
|
|
580659
|
+
}
|
|
580660
|
+
function getRuntimeDir(loc) {
|
|
580661
|
+
const root = loc.root ?? defaultRoot();
|
|
580662
|
+
return join156(root, `node-${loc.version}`);
|
|
580663
|
+
}
|
|
580664
|
+
function resolvedNodeBinPath(opts) {
|
|
580665
|
+
const dir = getRuntimeDir(opts);
|
|
580666
|
+
if (opts.platform === "win32") {
|
|
580667
|
+
return join156(dir, "node.exe");
|
|
580668
|
+
}
|
|
580669
|
+
return join156(dir, "bin", "node");
|
|
580670
|
+
}
|
|
580671
|
+
async function isRuntimeReady(opts) {
|
|
580672
|
+
const platform = opts.platform ?? process.platform;
|
|
580673
|
+
const bin = resolvedNodeBinPath({
|
|
580674
|
+
root: opts.root,
|
|
580675
|
+
version: opts.version,
|
|
580676
|
+
platform
|
|
580677
|
+
});
|
|
580678
|
+
if (!existsSync105(bin))
|
|
580679
|
+
return false;
|
|
580680
|
+
const min = opts.minVersion ?? opts.version;
|
|
580681
|
+
try {
|
|
580682
|
+
const { stdout } = await execFileAsync4(bin, ["--version"], {
|
|
580683
|
+
timeout: 3000
|
|
580684
|
+
});
|
|
580685
|
+
const parsed = parseNodeVersion(stdout);
|
|
580686
|
+
if (!parsed)
|
|
580687
|
+
return false;
|
|
580688
|
+
return satisfiesMinVersion(parsed, min);
|
|
580689
|
+
} catch {
|
|
580690
|
+
return false;
|
|
580691
|
+
}
|
|
580692
|
+
}
|
|
580693
|
+
var execFileAsync4, SUPPORTED;
|
|
580694
|
+
var init_node_runtime = __esm(() => {
|
|
580695
|
+
execFileAsync4 = promisify6(execFile7);
|
|
580696
|
+
SUPPORTED = {
|
|
580697
|
+
darwin: {
|
|
580698
|
+
arm64: { os: "darwin", arch: "arm64", ext: "tar.gz" },
|
|
580699
|
+
x64: { os: "darwin", arch: "x64", ext: "tar.gz" }
|
|
580700
|
+
},
|
|
580701
|
+
linux: {
|
|
580702
|
+
arm64: { os: "linux", arch: "arm64", ext: "tar.xz" },
|
|
580703
|
+
x64: { os: "linux", arch: "x64", ext: "tar.xz" }
|
|
580704
|
+
},
|
|
580705
|
+
win32: {
|
|
580706
|
+
x64: { os: "win", arch: "x64", ext: "zip" },
|
|
580707
|
+
arm64: { os: "win", arch: "arm64", ext: "zip" }
|
|
580708
|
+
}
|
|
580709
|
+
};
|
|
580710
|
+
});
|
|
580711
|
+
|
|
580712
|
+
// packages/runtime/installer.ts
|
|
580713
|
+
import { spawn as spawn23 } from "node:child_process";
|
|
580714
|
+
import {
|
|
580715
|
+
createWriteStream,
|
|
580716
|
+
existsSync as existsSync106,
|
|
580717
|
+
mkdirSync as mkdirSync74,
|
|
580718
|
+
mkdtempSync as mkdtempSync11,
|
|
580719
|
+
readdirSync as readdirSync26,
|
|
580720
|
+
renameSync as renameSync16,
|
|
580721
|
+
rmSync as rmSync14
|
|
580722
|
+
} from "node:fs";
|
|
580723
|
+
import { join as join157 } from "node:path";
|
|
580724
|
+
import { Readable as Readable2 } from "node:stream";
|
|
580725
|
+
import { pipeline } from "node:stream/promises";
|
|
580726
|
+
function planInstall(input) {
|
|
580727
|
+
const platform = input.platform ?? process.platform;
|
|
580728
|
+
const arch = input.arch ?? process.arch;
|
|
580729
|
+
const asset = pickPlatformAsset({ platform, arch });
|
|
580730
|
+
const url = buildDownloadUrl({ version: input.version, asset });
|
|
580731
|
+
const runtimeDir = getRuntimeDir({ root: input.root, version: input.version });
|
|
580732
|
+
const binPath = resolvedNodeBinPath({
|
|
580733
|
+
root: input.root,
|
|
580734
|
+
version: input.version,
|
|
580735
|
+
platform
|
|
580736
|
+
});
|
|
580737
|
+
return {
|
|
580738
|
+
version: input.version,
|
|
580739
|
+
url,
|
|
580740
|
+
asset,
|
|
580741
|
+
runtimeDir,
|
|
580742
|
+
binPath,
|
|
580743
|
+
archiveExt: asset.ext
|
|
580744
|
+
};
|
|
580745
|
+
}
|
|
580746
|
+
async function installRuntime(input) {
|
|
580747
|
+
const plan = planInstall(input);
|
|
580748
|
+
const platform = input.platform ?? process.platform;
|
|
580749
|
+
const minVersion = input.minVersion ?? input.version;
|
|
580750
|
+
const ready = await isRuntimeReady({
|
|
580751
|
+
root: input.root,
|
|
580752
|
+
version: input.version,
|
|
580753
|
+
platform,
|
|
580754
|
+
minVersion
|
|
580755
|
+
});
|
|
580756
|
+
if (ready || input.dryRun) {
|
|
580757
|
+
return {
|
|
580758
|
+
...plan,
|
|
580759
|
+
action: ready ? "already-ready" : "dry-run"
|
|
580760
|
+
};
|
|
580761
|
+
}
|
|
580762
|
+
const runtimeRoot = plan.runtimeDir.replace(/\/node-[^/]+$/, "");
|
|
580763
|
+
mkdirSync74(runtimeRoot, { recursive: true });
|
|
580764
|
+
const stagingDir = mkdtempSync11(join157(runtimeRoot, ".dl-"));
|
|
580765
|
+
const archivePath = join157(stagingDir, `node.${plan.archiveExt}`);
|
|
580766
|
+
try {
|
|
580767
|
+
await downloadFile(plan.url, archivePath);
|
|
580768
|
+
const extractRoot = join157(stagingDir, "extract");
|
|
580769
|
+
mkdirSync74(extractRoot, { recursive: true });
|
|
580770
|
+
await extractArchive(archivePath, extractRoot, plan.archiveExt);
|
|
580771
|
+
const children = readdirSync26(extractRoot);
|
|
580772
|
+
const nodeDir = children.find((n) => n.startsWith("node-"));
|
|
580773
|
+
if (!nodeDir) {
|
|
580774
|
+
throw new Error(`could not find node-* dir inside ${extractRoot}`);
|
|
580775
|
+
}
|
|
580776
|
+
const extractedPath = join157(extractRoot, nodeDir);
|
|
580777
|
+
if (existsSync106(plan.runtimeDir)) {
|
|
580778
|
+
rmSync14(plan.runtimeDir, { recursive: true, force: true });
|
|
580779
|
+
}
|
|
580780
|
+
renameSync16(extractedPath, plan.runtimeDir);
|
|
580781
|
+
} catch (err) {
|
|
580782
|
+
return {
|
|
580783
|
+
...plan,
|
|
580784
|
+
action: "failed",
|
|
580785
|
+
error: err instanceof Error ? err.message : String(err)
|
|
580786
|
+
};
|
|
580787
|
+
} finally {
|
|
580788
|
+
try {
|
|
580789
|
+
rmSync14(stagingDir, { recursive: true, force: true });
|
|
580790
|
+
} catch {}
|
|
580791
|
+
}
|
|
580792
|
+
const reReady = await isRuntimeReady({
|
|
580793
|
+
root: input.root,
|
|
580794
|
+
version: input.version,
|
|
580795
|
+
platform,
|
|
580796
|
+
minVersion
|
|
580797
|
+
});
|
|
580798
|
+
if (!reReady) {
|
|
580799
|
+
return {
|
|
580800
|
+
...plan,
|
|
580801
|
+
action: "failed",
|
|
580802
|
+
error: `installed runtime at ${plan.binPath} but it does not satisfy minVersion ${minVersion}`
|
|
580803
|
+
};
|
|
580804
|
+
}
|
|
580805
|
+
return {
|
|
580806
|
+
...plan,
|
|
580807
|
+
action: "installed"
|
|
580808
|
+
};
|
|
580809
|
+
}
|
|
580810
|
+
async function downloadFile(url, dest) {
|
|
580811
|
+
const res = await fetch(url, { redirect: "follow" });
|
|
580812
|
+
if (!res.ok || !res.body) {
|
|
580813
|
+
throw new Error(`download failed: HTTP ${res.status} ${res.statusText} for ${url}`);
|
|
580814
|
+
}
|
|
580815
|
+
const out = createWriteStream(dest);
|
|
580816
|
+
await pipeline(Readable2.fromWeb(res.body), out);
|
|
580817
|
+
}
|
|
580818
|
+
async function extractArchive(archivePath, destDir, ext) {
|
|
580819
|
+
if (ext === "tar.gz" || ext === "tar.xz") {
|
|
580820
|
+
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
580821
|
+
} else if (ext === "zip") {
|
|
580822
|
+
try {
|
|
580823
|
+
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
580824
|
+
} catch {
|
|
580825
|
+
await runCmd("powershell", [
|
|
580826
|
+
"-Command",
|
|
580827
|
+
`Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force`
|
|
580828
|
+
]);
|
|
580829
|
+
}
|
|
580830
|
+
} else {
|
|
580831
|
+
throw new Error(`unsupported archive ext: ${ext}`);
|
|
580832
|
+
}
|
|
580833
|
+
}
|
|
580834
|
+
function runCmd(command, args) {
|
|
580835
|
+
return new Promise((resolve, reject) => {
|
|
580836
|
+
const proc = spawn23(command, args, { stdio: "ignore" });
|
|
580837
|
+
proc.on("error", (err) => reject(err));
|
|
580838
|
+
proc.on("close", (code) => {
|
|
580839
|
+
if (code === 0)
|
|
580840
|
+
resolve();
|
|
580841
|
+
else
|
|
580842
|
+
reject(new Error(`${command} ${args.join(" ")} exited ${code}`));
|
|
580843
|
+
});
|
|
580844
|
+
});
|
|
580845
|
+
}
|
|
580846
|
+
var init_installer = __esm(() => {
|
|
580847
|
+
init_node_runtime();
|
|
580848
|
+
});
|
|
580849
|
+
|
|
580850
|
+
// packages/runtime/contract-validator.ts
|
|
580851
|
+
var init_contract_validator = __esm(() => {
|
|
580852
|
+
init_types3();
|
|
580853
|
+
});
|
|
580854
|
+
|
|
580855
|
+
// packages/runtime/index.ts
|
|
580856
|
+
import { join as join158 } from "node:path";
|
|
580857
|
+
import { execFile as execFile8 } from "node:child_process";
|
|
580858
|
+
import { promisify as promisify7 } from "node:util";
|
|
580859
|
+
async function ensureNodeFor(minVersion) {
|
|
580860
|
+
try {
|
|
580861
|
+
const { stdout } = await execFileAsync5("node", ["--version"], {
|
|
580862
|
+
timeout: 3000
|
|
580863
|
+
});
|
|
580864
|
+
const parsed = parseNodeVersion(stdout);
|
|
580865
|
+
if (parsed && satisfiesMinVersion(parsed, minVersion)) {
|
|
580866
|
+
return null;
|
|
580867
|
+
}
|
|
580868
|
+
} catch {}
|
|
580869
|
+
const ready = await isRuntimeReady({
|
|
580870
|
+
version: MANAGED_NODE_VERSION,
|
|
580871
|
+
minVersion
|
|
580872
|
+
});
|
|
580873
|
+
const dir = getRuntimeDir({ version: MANAGED_NODE_VERSION });
|
|
580874
|
+
const binDir = process.platform === "win32" ? dir : join158(dir, "bin");
|
|
580875
|
+
if (ready)
|
|
580876
|
+
return binDir;
|
|
580877
|
+
const result = await installRuntime({
|
|
580878
|
+
version: MANAGED_NODE_VERSION,
|
|
580879
|
+
minVersion
|
|
580880
|
+
});
|
|
580881
|
+
if (result.action === "failed") {
|
|
580882
|
+
throw new Error(`failed to install Node ${MANAGED_NODE_VERSION}: ${result.error ?? "unknown"}`);
|
|
580883
|
+
}
|
|
580884
|
+
return binDir;
|
|
580885
|
+
}
|
|
580886
|
+
var execFileAsync5, MANAGED_NODE_VERSION = "22.14.0";
|
|
580887
|
+
var init_runtime = __esm(() => {
|
|
580888
|
+
init_installer();
|
|
580889
|
+
init_node_runtime();
|
|
580890
|
+
init_node_runtime();
|
|
580891
|
+
init_installer();
|
|
580892
|
+
init_contract_validator();
|
|
580893
|
+
execFileAsync5 = promisify7(execFile8);
|
|
580894
|
+
});
|
|
580895
|
+
|
|
580896
|
+
// apps/tui/src/lib/external-agent-runner.ts
|
|
580897
|
+
import { execSync as execSync6, spawn as spawn24 } from "node:child_process";
|
|
580898
|
+
function getPreset(id) {
|
|
580899
|
+
return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
|
|
580900
|
+
}
|
|
580901
|
+
function listPresetIds() {
|
|
580902
|
+
return Object.keys(EXTERNAL_AGENT_PRESETS);
|
|
580903
|
+
}
|
|
580904
|
+
function isInstalled(preset) {
|
|
580905
|
+
try {
|
|
580906
|
+
execSync6(`command -v "${preset.command}"`, {
|
|
580907
|
+
stdio: "ignore",
|
|
580908
|
+
timeout: 1500
|
|
580909
|
+
});
|
|
580910
|
+
return true;
|
|
580911
|
+
} catch {
|
|
580912
|
+
return false;
|
|
580913
|
+
}
|
|
580914
|
+
}
|
|
580915
|
+
async function installAgent(preset, onLine) {
|
|
580916
|
+
const start = performance.now();
|
|
580917
|
+
if (!preset.install) {
|
|
580918
|
+
return {
|
|
580919
|
+
ok: false,
|
|
580920
|
+
stdout: "",
|
|
580921
|
+
stderr: "",
|
|
580922
|
+
durationMs: 0,
|
|
580923
|
+
command: "",
|
|
580924
|
+
error: `No install recipe for ${preset.id}. Install ${preset.command} manually and try again.`
|
|
580925
|
+
};
|
|
580926
|
+
}
|
|
580927
|
+
const command = preset.install.command;
|
|
580928
|
+
return new Promise((resolve) => {
|
|
580929
|
+
let stdout = "";
|
|
580930
|
+
let stderr = "";
|
|
580931
|
+
let exited = false;
|
|
580932
|
+
const proc = spawnShell(command, {
|
|
580933
|
+
posix: ["bash", "-lc"],
|
|
580934
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
580935
|
+
env: { ...process.env, NO_COLOR: "1", FORCE_COLOR: "0" }
|
|
580936
|
+
});
|
|
580937
|
+
const finish = (result) => {
|
|
580938
|
+
if (exited)
|
|
580939
|
+
return;
|
|
580940
|
+
exited = true;
|
|
580941
|
+
clearTimeout(timer);
|
|
580942
|
+
resolve({
|
|
580943
|
+
...result,
|
|
580944
|
+
durationMs: Math.round(performance.now() - start),
|
|
580945
|
+
command
|
|
580946
|
+
});
|
|
580947
|
+
};
|
|
580948
|
+
const pipeLines = (chunk, source) => {
|
|
580949
|
+
const text = chunk.toString();
|
|
580950
|
+
if (source === "stdout")
|
|
580951
|
+
stdout += text;
|
|
580952
|
+
else
|
|
580953
|
+
stderr += text;
|
|
580954
|
+
if (onLine) {
|
|
580955
|
+
for (const line of text.split(/\r?\n/)) {
|
|
580956
|
+
if (line.trim().length > 0)
|
|
580957
|
+
onLine(line, source);
|
|
580958
|
+
}
|
|
580959
|
+
}
|
|
580960
|
+
};
|
|
580961
|
+
proc.stdout?.on("data", (c) => pipeLines(c, "stdout"));
|
|
580962
|
+
proc.stderr?.on("data", (c) => pipeLines(c, "stderr"));
|
|
580963
|
+
proc.on("error", (err) => {
|
|
580964
|
+
finish({ ok: false, stdout, stderr, error: err.message });
|
|
580965
|
+
});
|
|
580966
|
+
proc.on("close", (code) => {
|
|
580967
|
+
finish({
|
|
580968
|
+
ok: code === 0,
|
|
580969
|
+
stdout,
|
|
580970
|
+
stderr,
|
|
580971
|
+
error: code === 0 ? undefined : stderr.trim().slice(0, 800) || `installer exited with code ${code}`
|
|
580972
|
+
});
|
|
580973
|
+
});
|
|
580974
|
+
const timer = setTimeout(() => {
|
|
580975
|
+
proc.kill("SIGTERM");
|
|
580976
|
+
finish({ ok: false, stdout, stderr, error: "install timed out after 5 minutes" });
|
|
580977
|
+
}, 5 * 60 * 1000);
|
|
580978
|
+
});
|
|
580979
|
+
}
|
|
580980
|
+
async function ensureInstalled(preset, onLine) {
|
|
580981
|
+
if (isInstalled(preset))
|
|
580982
|
+
return true;
|
|
580983
|
+
if (!preset.install) {
|
|
580984
|
+
onLine?.(`${preset.command}: not installed and no auto-install recipe is configured.`, "info");
|
|
580985
|
+
return false;
|
|
580986
|
+
}
|
|
580987
|
+
onLine?.(`${preset.command}: not installed, running ${preset.install.command}`, "info");
|
|
580988
|
+
const result = await installAgent(preset, (line, source) => onLine?.(line, source));
|
|
580989
|
+
if (!result.ok) {
|
|
580990
|
+
onLine?.(`Install failed: ${result.error ?? "unknown error"}`, "info");
|
|
580991
|
+
return false;
|
|
580992
|
+
}
|
|
580993
|
+
const stillThere = isInstalled(preset);
|
|
580994
|
+
if (!stillThere) {
|
|
580995
|
+
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");
|
|
580996
|
+
}
|
|
580997
|
+
return stillThere;
|
|
580998
|
+
}
|
|
580999
|
+
function composePrompt(history, prompt) {
|
|
581000
|
+
const lines = [];
|
|
581001
|
+
for (const m of history) {
|
|
581002
|
+
const tag = m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : m.role;
|
|
581003
|
+
lines.push(`${tag}: ${m.content}`);
|
|
581004
|
+
}
|
|
581005
|
+
lines.push(`User: ${prompt}`);
|
|
581006
|
+
lines.push("Assistant:");
|
|
581007
|
+
return lines.join(`
|
|
581008
|
+
|
|
581009
|
+
`);
|
|
581010
|
+
}
|
|
581011
|
+
async function runExternalAgent(preset, prompt, signal) {
|
|
581012
|
+
const start = performance.now();
|
|
581013
|
+
const argv = [...preset.args];
|
|
581014
|
+
if (preset.promptMode === "flag") {
|
|
581015
|
+
argv.push(preset.flagName ?? "-p", prompt);
|
|
581016
|
+
} else if (preset.promptMode === "arg") {
|
|
581017
|
+
argv.push(prompt);
|
|
581018
|
+
}
|
|
581019
|
+
let pathPrefix = "";
|
|
581020
|
+
if (preset.requiresNodeVersion) {
|
|
581021
|
+
try {
|
|
581022
|
+
await Promise.resolve().then(() => init_runtime());
|
|
581023
|
+
const binDir = await ensureNodeFor(preset.requiresNodeVersion);
|
|
581024
|
+
if (binDir)
|
|
581025
|
+
pathPrefix = `${binDir}:`;
|
|
581026
|
+
} catch (err) {
|
|
581027
|
+
return {
|
|
581028
|
+
ok: false,
|
|
581029
|
+
text: "",
|
|
581030
|
+
durationMs: Math.round(performance.now() - start),
|
|
581031
|
+
command: `${preset.command} ${argv.join(" ")}`,
|
|
581032
|
+
error: `managed Node runtime install failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
581033
|
+
exitCode: null
|
|
581034
|
+
};
|
|
581035
|
+
}
|
|
581036
|
+
}
|
|
581037
|
+
return new Promise((resolve) => {
|
|
581038
|
+
let stdout = "";
|
|
581039
|
+
let stderr = "";
|
|
581040
|
+
let exited = false;
|
|
581041
|
+
const proc = spawn24(preset.command, argv, {
|
|
581042
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
581043
|
+
env: {
|
|
581044
|
+
...process.env,
|
|
581045
|
+
PATH: `${pathPrefix}${process.env.PATH ?? ""}`,
|
|
581046
|
+
NO_COLOR: "1",
|
|
581047
|
+
FORCE_COLOR: "0",
|
|
581048
|
+
"8GENT_NO_INTRO": "1",
|
|
581049
|
+
AI_SDK_LOG_WARNINGS: "false"
|
|
581050
|
+
}
|
|
581051
|
+
});
|
|
581052
|
+
const finish = (result) => {
|
|
581053
|
+
if (exited)
|
|
581054
|
+
return;
|
|
581055
|
+
exited = true;
|
|
581056
|
+
clearTimeout(timer);
|
|
581057
|
+
signal?.removeEventListener("abort", onAbort);
|
|
581058
|
+
resolve({
|
|
581059
|
+
...result,
|
|
581060
|
+
durationMs: Math.round(performance.now() - start),
|
|
581061
|
+
command: `${preset.command} ${argv.map((a) => a.includes(" ") ? `"${a}"` : a).join(" ")}`
|
|
581062
|
+
});
|
|
581063
|
+
};
|
|
581064
|
+
proc.on("error", (err) => {
|
|
581065
|
+
finish({
|
|
581066
|
+
ok: false,
|
|
581067
|
+
text: "",
|
|
581068
|
+
error: err.code === "ENOENT" ? `${preset.command}: not installed (no binary on $PATH)` : err.message,
|
|
581069
|
+
exitCode: null
|
|
581070
|
+
});
|
|
581071
|
+
});
|
|
581072
|
+
proc.stdout?.on("data", (chunk) => {
|
|
581073
|
+
stdout += chunk.toString();
|
|
581074
|
+
});
|
|
581075
|
+
proc.stderr?.on("data", (chunk) => {
|
|
581076
|
+
stderr += chunk.toString();
|
|
581077
|
+
});
|
|
581078
|
+
proc.on("close", (code) => {
|
|
581079
|
+
let text = preset.parseStdout ? preset.parseStdout(stdout).trim() : stdout.trim();
|
|
581080
|
+
try {
|
|
581081
|
+
init_keys();
|
|
581082
|
+
if (text)
|
|
581083
|
+
text = redactAndWarn(text);
|
|
581084
|
+
} catch {}
|
|
581085
|
+
if (code === 0 || code !== null && text.length > 0) {
|
|
581086
|
+
finish({ ok: code === 0, text, exitCode: code, error: code === 0 ? undefined : stderr.trim().slice(0, 400) });
|
|
581087
|
+
} else {
|
|
581088
|
+
finish({
|
|
581089
|
+
ok: false,
|
|
581090
|
+
text,
|
|
581091
|
+
exitCode: code,
|
|
581092
|
+
error: stderr.trim().slice(0, 400) || `exited with code ${code}`
|
|
581093
|
+
});
|
|
581094
|
+
}
|
|
581095
|
+
});
|
|
581096
|
+
if (preset.promptMode === "stdin" && proc.stdin) {
|
|
581097
|
+
proc.stdin.write(prompt);
|
|
581098
|
+
proc.stdin.end();
|
|
581099
|
+
} else if (proc.stdin) {
|
|
581100
|
+
proc.stdin.end();
|
|
581101
|
+
}
|
|
581102
|
+
const timer = setTimeout(() => {
|
|
581103
|
+
proc.kill("SIGTERM");
|
|
581104
|
+
finish({
|
|
581105
|
+
ok: false,
|
|
581106
|
+
text: stdout,
|
|
581107
|
+
error: `timeout after ${preset.timeoutMs ?? 90000}ms`,
|
|
581108
|
+
exitCode: null
|
|
581109
|
+
});
|
|
581110
|
+
}, preset.timeoutMs ?? 90000);
|
|
581111
|
+
const onAbort = () => {
|
|
581112
|
+
proc.kill("SIGTERM");
|
|
581113
|
+
finish({ ok: false, text: stdout, error: "aborted", exitCode: null });
|
|
581114
|
+
};
|
|
581115
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
581116
|
+
});
|
|
581117
|
+
}
|
|
581118
|
+
var stripAnsi2 = (s) => s.replace(/\[[0-9;?]*[a-zA-Z]/g, "").replace(/\][^]*/g, ""), EXTERNAL_AGENT_PRESETS;
|
|
581119
|
+
var init_external_agent_runner = __esm(() => {
|
|
581120
|
+
init_shell();
|
|
581121
|
+
EXTERNAL_AGENT_PRESETS = {
|
|
581122
|
+
claude: {
|
|
581123
|
+
id: "claude",
|
|
581124
|
+
label: "Sparring",
|
|
581125
|
+
command: "claude",
|
|
581126
|
+
promptMode: "flag",
|
|
581127
|
+
flagName: "-p",
|
|
581128
|
+
args: [],
|
|
581129
|
+
timeoutMs: 120000,
|
|
581130
|
+
parseStdout: stripAnsi2,
|
|
581131
|
+
homepage: "https://docs.claude.com/en/docs/claude-code",
|
|
581132
|
+
preferWindow: true,
|
|
581133
|
+
install: {
|
|
581134
|
+
command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
|
|
581135
|
+
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.'
|
|
581136
|
+
}
|
|
581137
|
+
},
|
|
581138
|
+
codex: {
|
|
581139
|
+
id: "codex",
|
|
581140
|
+
label: "OpenAI Codex",
|
|
581141
|
+
command: "codex",
|
|
581142
|
+
promptMode: "arg",
|
|
581143
|
+
args: ["exec"],
|
|
581144
|
+
timeoutMs: 120000,
|
|
581145
|
+
parseStdout: stripAnsi2,
|
|
581146
|
+
homepage: "https://github.com/openai/codex",
|
|
581147
|
+
preferWindow: true,
|
|
581148
|
+
install: {
|
|
581149
|
+
command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
|
|
581150
|
+
notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
|
|
581151
|
+
}
|
|
581152
|
+
},
|
|
581153
|
+
hermes: {
|
|
581154
|
+
id: "hermes",
|
|
581155
|
+
label: "Hermes Agent",
|
|
581156
|
+
command: "hermes",
|
|
581157
|
+
preferWindow: true,
|
|
581158
|
+
promptMode: "flag",
|
|
581159
|
+
flagName: "-z",
|
|
581160
|
+
args: [],
|
|
581161
|
+
timeoutMs: 120000,
|
|
581162
|
+
parseStdout: stripAnsi2,
|
|
581163
|
+
homepage: "https://github.com/NousResearch/hermes-agent",
|
|
581164
|
+
install: {
|
|
581165
|
+
command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
|
|
581166
|
+
notes: "Hermes needs Python ≥ 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)."
|
|
581167
|
+
}
|
|
581168
|
+
},
|
|
581169
|
+
openclaw: {
|
|
581170
|
+
id: "openclaw",
|
|
581171
|
+
label: "OpenClaw",
|
|
581172
|
+
command: "openclaw",
|
|
581173
|
+
preferWindow: true,
|
|
581174
|
+
promptMode: "arg",
|
|
581175
|
+
args: ["run", "--headless"],
|
|
581176
|
+
timeoutMs: 120000,
|
|
581177
|
+
parseStdout: stripAnsi2,
|
|
581178
|
+
homepage: "https://github.com/openclaw/openclaw",
|
|
581179
|
+
install: {
|
|
581180
|
+
command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
|
|
581181
|
+
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.)"
|
|
581182
|
+
},
|
|
581183
|
+
requiresNodeVersion: "22.14.0"
|
|
581184
|
+
},
|
|
581185
|
+
pi: {
|
|
581186
|
+
preferWindow: true,
|
|
581187
|
+
id: "pi",
|
|
581188
|
+
label: "Pi (pi-mono)",
|
|
581189
|
+
command: "pi",
|
|
581190
|
+
promptMode: "flag",
|
|
581191
|
+
flagName: "-p",
|
|
581192
|
+
args: [],
|
|
581193
|
+
timeoutMs: 120000,
|
|
581194
|
+
parseStdout: stripAnsi2,
|
|
581195
|
+
homepage: "https://pi.dev",
|
|
581196
|
+
install: {
|
|
581197
|
+
command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
|
|
581198
|
+
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)."
|
|
581199
|
+
}
|
|
581200
|
+
},
|
|
581201
|
+
"8gent": {
|
|
581202
|
+
id: "8gent",
|
|
581203
|
+
label: "8gent (nested)",
|
|
581204
|
+
command: "8gent",
|
|
581205
|
+
promptMode: "arg",
|
|
581206
|
+
args: ["run"],
|
|
581207
|
+
timeoutMs: 180000,
|
|
581208
|
+
parseStdout: stripAnsi2,
|
|
581209
|
+
homepage: "https://8gent.dev",
|
|
581210
|
+
install: {
|
|
581211
|
+
command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
|
|
581212
|
+
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."
|
|
581213
|
+
}
|
|
581214
|
+
}
|
|
581215
|
+
};
|
|
581216
|
+
});
|
|
581217
|
+
|
|
581218
|
+
// packages/eight/welcome.ts
|
|
581219
|
+
import { existsSync as existsSync107 } from "node:fs";
|
|
581220
|
+
import { basename as basename51, delimiter as delimiter9, dirname as dirname75, isAbsolute as isAbsolute50, join as join159, relative as relative34, resolve as resolve72 } from "node:path";
|
|
581221
|
+
function pathOutsideFolder(path, cwd) {
|
|
581222
|
+
const root = resolve72(cwd);
|
|
581223
|
+
return path.split(delimiter9).filter((dir) => {
|
|
581224
|
+
if (!dir || !isAbsolute50(dir))
|
|
581225
|
+
return false;
|
|
581226
|
+
const rel = relative34(root, resolve72(dir));
|
|
581227
|
+
return rel.startsWith("..") || isAbsolute50(rel);
|
|
581228
|
+
}).join(delimiter9);
|
|
581229
|
+
}
|
|
581230
|
+
function safeModelLabel(model) {
|
|
581231
|
+
const m = model.trim();
|
|
581232
|
+
if (!m || m.length > 80 || /:\/\/|[@?\s]/.test(m))
|
|
581233
|
+
return "a custom model";
|
|
581234
|
+
return m;
|
|
581235
|
+
}
|
|
581236
|
+
function inGitRepo(dir) {
|
|
581237
|
+
let d = dir;
|
|
581238
|
+
for (let i = 0;i < 64; i++) {
|
|
581239
|
+
if (existsSync107(join159(d, ".git")))
|
|
581240
|
+
return true;
|
|
581241
|
+
const up = dirname75(d);
|
|
581242
|
+
if (up === d)
|
|
581243
|
+
return false;
|
|
581244
|
+
d = up;
|
|
581245
|
+
}
|
|
581246
|
+
return false;
|
|
581247
|
+
}
|
|
581248
|
+
function hostLabel(android, platform, arch) {
|
|
581249
|
+
if (android)
|
|
581250
|
+
return `Android (Termux, ${arch})`;
|
|
581251
|
+
const os = platform === "darwin" ? "macOS" : platform === "linux" ? "Linux" : platform === "win32" ? "Windows" : platform;
|
|
581252
|
+
return `${os} ${arch}`;
|
|
581253
|
+
}
|
|
581254
|
+
async function knownPresets() {
|
|
581255
|
+
const runner = await Promise.resolve().then(() => (init_external_agent_runner(), {}));
|
|
581256
|
+
const out = [];
|
|
581257
|
+
for (const id of listPresetIds()) {
|
|
581258
|
+
const p = getPreset(id);
|
|
581259
|
+
if (p)
|
|
581260
|
+
out.push({ id: p.id, command: p.command });
|
|
581261
|
+
}
|
|
581262
|
+
return out;
|
|
581263
|
+
}
|
|
581264
|
+
async function gatherWelcomeFacts(opts) {
|
|
581265
|
+
const env = opts.env ?? process.env;
|
|
581266
|
+
const android = isAndroidHost(opts.platform ?? process.platform, env);
|
|
581267
|
+
const cwd = resolve72(opts.cwd);
|
|
581268
|
+
const home = env.HOME ? resolve72(env.HOME) : null;
|
|
581269
|
+
const lookupEnv = { ...env, PATH: pathOutsideFolder(String(env.PATH ?? ""), cwd) };
|
|
581270
|
+
const presets = (opts.presets ?? await knownPresets()).filter((p) => p.id !== "8gent");
|
|
581271
|
+
return {
|
|
581272
|
+
version: String(import_package.default.version),
|
|
581273
|
+
host: hostLabel(android, opts.platform ?? process.platform, opts.arch ?? process.arch),
|
|
581274
|
+
android,
|
|
581275
|
+
model: safeModelLabel(opts.model),
|
|
581276
|
+
provider: opts.provider,
|
|
581277
|
+
presetIds: presets.map((p) => p.id),
|
|
581278
|
+
installed: presets.filter((p) => findOnPath(p.command, lookupEnv) !== null).map((p) => p.id),
|
|
581279
|
+
folder: cwd === home ? "~" : basename51(cwd) || "/",
|
|
581280
|
+
gitRepo: inGitRepo(cwd)
|
|
581281
|
+
};
|
|
581282
|
+
}
|
|
581283
|
+
function listWords(items) {
|
|
581284
|
+
if (items.length <= 1)
|
|
581285
|
+
return items.join("");
|
|
581286
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
581287
|
+
}
|
|
581288
|
+
function buildWelcome(f) {
|
|
581289
|
+
const where = f.android ? "phone" : "machine";
|
|
581290
|
+
const lines = [`Hi, I'm 8gent v${f.version} on ${f.host}, using ${f.model} via ${f.provider}.`];
|
|
581291
|
+
if (f.installed.length > 0) {
|
|
581292
|
+
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.`);
|
|
581293
|
+
} else {
|
|
581294
|
+
lines.push(`I checked PATH for ${listWords(f.presetIds)}: none installed, so it's just me here.`);
|
|
581295
|
+
}
|
|
581296
|
+
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.`);
|
|
581297
|
+
const next = [];
|
|
581298
|
+
if (f.installed.length > 0)
|
|
581299
|
+
next.push(`run ${f.installed[0]}`);
|
|
581300
|
+
next.push(f.gitRepo ? "what changed in the last commit" : "make a folder called demo with a hello web page");
|
|
581301
|
+
next.push("what can you do");
|
|
581302
|
+
lines.push("Try:", ...next.map((n) => ` "${n}"`));
|
|
581303
|
+
return lines.join(`
|
|
581304
|
+
`);
|
|
581305
|
+
}
|
|
581306
|
+
var import_package;
|
|
581307
|
+
var init_welcome = __esm(() => {
|
|
581308
|
+
init_termux();
|
|
581309
|
+
import_package = __toESM(require_package(), 1);
|
|
581310
|
+
});
|
|
581311
|
+
|
|
580460
581312
|
// packages/eight/failover-provider-config.ts
|
|
580461
581313
|
function providerConfigForStep(session, step) {
|
|
580462
581314
|
if (step.provider === session.name) {
|
|
@@ -580978,8 +581830,8 @@ var init_local_turn_error = __esm(() => {
|
|
|
580978
581830
|
});
|
|
580979
581831
|
|
|
580980
581832
|
// packages/eight/output-gate.ts
|
|
580981
|
-
import { existsSync as
|
|
580982
|
-
import { isAbsolute as
|
|
581833
|
+
import { existsSync as existsSync108 } from "node:fs";
|
|
581834
|
+
import { isAbsolute as isAbsolute51, relative as relative35, resolve as resolve73 } from "node:path";
|
|
580983
581835
|
function isOutputGateEnabled(env = process.env, option) {
|
|
580984
581836
|
if (option !== undefined)
|
|
580985
581837
|
return option;
|
|
@@ -581011,10 +581863,10 @@ class OutputGate {
|
|
|
581011
581863
|
events = [];
|
|
581012
581864
|
constructor(task, cwd, enabled) {
|
|
581013
581865
|
this.cwd = cwd;
|
|
581014
|
-
this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs:
|
|
581866
|
+
this.required = !enabled ? [] : namedOutputs(task).map((shown) => ({ shown, abs: resolve73(cwd, shown) })).filter(({ abs }) => !relative35(cwd, abs).startsWith("..") && !isAbsolute51(relative35(cwd, abs))).filter(({ abs }) => !existsSync108(abs));
|
|
581015
581867
|
}
|
|
581016
581868
|
missing() {
|
|
581017
|
-
return this.required.filter(({ abs }) => !
|
|
581869
|
+
return this.required.filter(({ abs }) => !existsSync108(abs)).map(({ shown }) => shown);
|
|
581018
581870
|
}
|
|
581019
581871
|
check(reply) {
|
|
581020
581872
|
const missing = this.missing();
|
|
@@ -581052,7 +581904,7 @@ var init_output_gate = __esm(() => {
|
|
|
581052
581904
|
function stripPunctuation(s) {
|
|
581053
581905
|
return s.replace(/[.,;:!?]+$/g, "").trim();
|
|
581054
581906
|
}
|
|
581055
|
-
function
|
|
581907
|
+
function isGreeting2(message) {
|
|
581056
581908
|
const stripped = stripPunctuation(message.toLowerCase()).trim();
|
|
581057
581909
|
if (stripped.length === 0)
|
|
581058
581910
|
return true;
|
|
@@ -581073,7 +581925,7 @@ class PreToolRouter {
|
|
|
581073
581925
|
classify(userMessage, _projectContext) {
|
|
581074
581926
|
const msg = userMessage ?? "";
|
|
581075
581927
|
const trimmed = msg.trim();
|
|
581076
|
-
if (trimmed.length === 0 ||
|
|
581928
|
+
if (trimmed.length === 0 || isGreeting2(trimmed)) {
|
|
581077
581929
|
return {
|
|
581078
581930
|
strategy: "none",
|
|
581079
581931
|
args: {},
|
|
@@ -581345,12 +582197,12 @@ __export(exports_system_prompt, {
|
|
|
581345
582197
|
styleHasGuide: () => styleHasGuide,
|
|
581346
582198
|
workingProjectNote: () => workingProjectNote
|
|
581347
582199
|
});
|
|
581348
|
-
import { readFileSync as
|
|
581349
|
-
import { basename as
|
|
582200
|
+
import { existsSync as existsSync109, readFileSync as readFileSync98 } from "node:fs";
|
|
582201
|
+
import { basename as basename52, join as join160, resolve as resolve74 } from "node:path";
|
|
581350
582202
|
function buildBoardContextSegment(path = BOARD_CONTEXT_PATH) {
|
|
581351
582203
|
let text;
|
|
581352
582204
|
try {
|
|
581353
|
-
text =
|
|
582205
|
+
text = readFileSync98(path, "utf-8").trim();
|
|
581354
582206
|
} catch {
|
|
581355
582207
|
return "";
|
|
581356
582208
|
}
|
|
@@ -581377,8 +582229,20 @@ function communicationStyleLine(style) {
|
|
|
581377
582229
|
function styleHasGuide(style) {
|
|
581378
582230
|
return isCommunicationStyle(style) && STYLE_GUIDE[style] !== "";
|
|
581379
582231
|
}
|
|
582232
|
+
function isPlainHome(dir, home = resolveHome()) {
|
|
582233
|
+
try {
|
|
582234
|
+
return home !== "" && resolve74(dir) === resolve74(home) && !existsSync109(join160(dir, ".git"));
|
|
582235
|
+
} catch {
|
|
582236
|
+
return false;
|
|
582237
|
+
}
|
|
582238
|
+
}
|
|
581380
582239
|
function workingProjectNote(dir) {
|
|
581381
|
-
const name =
|
|
582240
|
+
const name = basename52(dir) || dir;
|
|
582241
|
+
if (isPlainHome(dir)) {
|
|
582242
|
+
return `
|
|
582243
|
+
|
|
582244
|
+
**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.**`;
|
|
582245
|
+
}
|
|
581382
582246
|
if (name === "8gent-code") {
|
|
581383
582247
|
return `
|
|
581384
582248
|
|
|
@@ -581722,7 +582586,7 @@ var init_system_prompt = __esm(() => {
|
|
|
581722
582586
|
init_tool_registry();
|
|
581723
582587
|
init_soul_layers();
|
|
581724
582588
|
IDENTITY_SEGMENT = composeSoulPrompt("owner");
|
|
581725
|
-
BOARD_CONTEXT_PATH =
|
|
582589
|
+
BOARD_CONTEXT_PATH = join160(resolveHome(), ".8gent", "board-context.md");
|
|
581726
582590
|
ACTION_FIRST_STYLE = [
|
|
581727
582591
|
"Shape every reply so the reader can act without rereading:",
|
|
581728
582592
|
ACTION_FIRST_PRECEDENCE,
|
|
@@ -582076,11 +582940,11 @@ var init_toolshed_bridge = __esm(() => {
|
|
|
582076
582940
|
});
|
|
582077
582941
|
|
|
582078
582942
|
// packages/ai/embedding-cache.ts
|
|
582079
|
-
import { join as
|
|
582943
|
+
import { join as join161 } from "node:path";
|
|
582080
582944
|
var CACHE_DIR, CACHE_PATH;
|
|
582081
582945
|
var init_embedding_cache = __esm(() => {
|
|
582082
|
-
CACHE_DIR =
|
|
582083
|
-
CACHE_PATH =
|
|
582946
|
+
CACHE_DIR = join161(process.env.HOME || "~", ".8gent");
|
|
582947
|
+
CACHE_PATH = join161(CACHE_DIR, "embedding-cache.json");
|
|
582084
582948
|
});
|
|
582085
582949
|
|
|
582086
582950
|
// packages/ai/edge-inference.ts
|
|
@@ -582359,20 +583223,20 @@ var init_quick_answer = __esm(() => {
|
|
|
582359
583223
|
});
|
|
582360
583224
|
|
|
582361
583225
|
// packages/eight/session-scratch.ts
|
|
582362
|
-
import { lstatSync as lstatSync30, mkdirSync as
|
|
583226
|
+
import { lstatSync as lstatSync30, mkdirSync as mkdirSync75, rmSync as rmSync15 } from "node:fs";
|
|
582363
583227
|
import { tmpdir as tmpdir19 } from "node:os";
|
|
582364
|
-
import { join as
|
|
583228
|
+
import { join as join162 } from "node:path";
|
|
582365
583229
|
function removeAllAtExit() {
|
|
582366
583230
|
for (const dir of [...live2])
|
|
582367
583231
|
removeSessionScratch(dir);
|
|
582368
583232
|
}
|
|
582369
583233
|
function sessionScratchPath(sessionId) {
|
|
582370
|
-
return
|
|
583234
|
+
return join162(tmpdir19(), `8gent-${sessionId}`);
|
|
582371
583235
|
}
|
|
582372
583236
|
function createSessionScratch(sessionId) {
|
|
582373
583237
|
const dir = sessionScratchPath(sessionId);
|
|
582374
583238
|
try {
|
|
582375
|
-
|
|
583239
|
+
mkdirSync75(dir, { mode: 448 });
|
|
582376
583240
|
live2.add(dir);
|
|
582377
583241
|
if (!exitHandlerSet) {
|
|
582378
583242
|
exitHandlerSet = true;
|
|
@@ -582393,7 +583257,7 @@ function removeSessionScratch(dir) {
|
|
|
582393
583257
|
return;
|
|
582394
583258
|
if (typeof process.getuid === "function" && st.uid !== process.getuid())
|
|
582395
583259
|
return;
|
|
582396
|
-
|
|
583260
|
+
rmSync15(dir, { recursive: true, force: true });
|
|
582397
583261
|
} catch {}
|
|
582398
583262
|
}
|
|
582399
583263
|
function sessionScratchNote(dir) {
|
|
@@ -590272,19 +591136,19 @@ var init_opportunity_scanner = () => {};
|
|
|
590272
591136
|
var init_capability_matcher = () => {};
|
|
590273
591137
|
|
|
590274
591138
|
// packages/proactive/work-tracker.ts
|
|
590275
|
-
import { join as
|
|
591139
|
+
import { join as join165 } from "node:path";
|
|
590276
591140
|
var DATA_DIR3, STORE_PATH;
|
|
590277
591141
|
var init_work_tracker = __esm(() => {
|
|
590278
|
-
DATA_DIR3 =
|
|
590279
|
-
STORE_PATH =
|
|
591142
|
+
DATA_DIR3 = join165(process.env.HOME || "~", ".8gent");
|
|
591143
|
+
STORE_PATH = join165(DATA_DIR3, "opportunities.json");
|
|
590280
591144
|
});
|
|
590281
591145
|
|
|
590282
591146
|
// packages/proactive/revenue-engine.ts
|
|
590283
|
-
import { join as
|
|
591147
|
+
import { join as join166 } from "node:path";
|
|
590284
591148
|
var DATA_DIR4, STORE_PATH2;
|
|
590285
591149
|
var init_revenue_engine = __esm(() => {
|
|
590286
|
-
DATA_DIR4 =
|
|
590287
|
-
STORE_PATH2 =
|
|
591150
|
+
DATA_DIR4 = join166(process.env.HOME || "~", ".8gent");
|
|
591151
|
+
STORE_PATH2 = join166(DATA_DIR4, "revenue.json");
|
|
590288
591152
|
});
|
|
590289
591153
|
|
|
590290
591154
|
// packages/proactive/deliverable-generator.ts
|
|
@@ -590297,11 +591161,11 @@ var init_client_outreach = () => {};
|
|
|
590297
591161
|
var init_content_packaging = () => {};
|
|
590298
591162
|
|
|
590299
591163
|
// packages/tools/browser/cache.ts
|
|
590300
|
-
import { homedir as
|
|
590301
|
-
import { join as
|
|
591164
|
+
import { homedir as homedir81 } from "node:os";
|
|
591165
|
+
import { join as join167 } from "node:path";
|
|
590302
591166
|
var CACHE_DIR2, TTL_MS, MAX_CACHE_BYTES;
|
|
590303
591167
|
var init_cache2 = __esm(() => {
|
|
590304
|
-
CACHE_DIR2 =
|
|
591168
|
+
CACHE_DIR2 = join167(process.env.EIGHT_DATA_DIR || join167(homedir81(), ".8gent"), "browser-cache");
|
|
590305
591169
|
TTL_MS = 60 * 60 * 1000;
|
|
590306
591170
|
MAX_CACHE_BYTES = 100 * 1024 * 1024;
|
|
590307
591171
|
});
|
|
@@ -591044,7 +591908,7 @@ var init_voice3 = __esm(() => {
|
|
|
591044
591908
|
|
|
591045
591909
|
// packages/eight/observation-pack.ts
|
|
591046
591910
|
import { createHash as createHash21 } from "node:crypto";
|
|
591047
|
-
import { readFileSync as
|
|
591911
|
+
import { readFileSync as readFileSync100 } from "node:fs";
|
|
591048
591912
|
function observationPackEnabled(env = process.env) {
|
|
591049
591913
|
return env.EIGHT_OBSERVATION_PACK === "1";
|
|
591050
591914
|
}
|
|
@@ -591064,7 +591928,7 @@ class ObservationStore {
|
|
|
591064
591928
|
const path = this.paths.get(handle);
|
|
591065
591929
|
if (!path)
|
|
591066
591930
|
throw new Error(`no saved output with handle "${handle}" in this session`);
|
|
591067
|
-
return
|
|
591931
|
+
return readFileSync100(path, "utf8").slice(offset, offset + limit);
|
|
591068
591932
|
}
|
|
591069
591933
|
size(handle) {
|
|
591070
591934
|
return this.read(handle).length;
|
|
@@ -592073,6 +592937,7 @@ class Agent {
|
|
|
592073
592937
|
steerQueue = [];
|
|
592074
592938
|
activeTurn = null;
|
|
592075
592939
|
turnCounter = 0;
|
|
592940
|
+
welcomed = false;
|
|
592076
592941
|
stopRequested = false;
|
|
592077
592942
|
orchestratorBus;
|
|
592078
592943
|
toolRegistry;
|
|
@@ -592540,14 +593405,15 @@ ${LOCAL_LOGIN_NOTE}`;
|
|
|
592540
593405
|
instructions,
|
|
592541
593406
|
localCoreTools,
|
|
592542
593407
|
chatStartTime,
|
|
592543
|
-
textForAgent
|
|
593408
|
+
textForAgent,
|
|
593409
|
+
smallTalk = false
|
|
592544
593410
|
} = opts;
|
|
592545
593411
|
const signal = this.armController().signal;
|
|
592546
593412
|
const allow = new Set(localCoreTools);
|
|
592547
593413
|
const specs = toolDefsToSpecs(this.executor.getToolDefinitions(), allow);
|
|
592548
593414
|
let stepNumber = 0;
|
|
592549
593415
|
let breakerStop = null;
|
|
592550
|
-
if (this.extensionToolsAllowed()) {
|
|
593416
|
+
if (this.extensionToolsAllowed() && !smallTalk) {
|
|
592551
593417
|
for (const t of this.extensionHost.listTools()) {
|
|
592552
593418
|
if (this.modeAllows(t.name)) {
|
|
592553
593419
|
specs.push({ name: t.name, description: t.description, parameters: t.parameters });
|
|
@@ -593111,6 +593977,21 @@ ${LOCAL_LOGIN_NOTE}`;
|
|
|
593111
593977
|
console.log(`[turn-review] ${line}`);
|
|
593112
593978
|
}
|
|
593113
593979
|
}
|
|
593980
|
+
async greetingWelcome(text) {
|
|
593981
|
+
if (this.welcomed || this.config.headless || this.agentDepth > 0 || !isGreeting(text))
|
|
593982
|
+
return null;
|
|
593983
|
+
try {
|
|
593984
|
+
const facts = await gatherWelcomeFacts({
|
|
593985
|
+
model: String(this.config.model),
|
|
593986
|
+
provider: String(this.config.runtime),
|
|
593987
|
+
cwd: this.config.workingDirectory || process.cwd()
|
|
593988
|
+
});
|
|
593989
|
+
this.welcomed = true;
|
|
593990
|
+
return buildWelcome(facts);
|
|
593991
|
+
} catch {
|
|
593992
|
+
return null;
|
|
593993
|
+
}
|
|
593994
|
+
}
|
|
593114
593995
|
async runTurn(userMessage, imageBase64, imageMimeType, imageOriginal) {
|
|
593115
593996
|
await this.extensionsReady;
|
|
593116
593997
|
this.loopDetector.reset();
|
|
@@ -593125,6 +594006,17 @@ ${LOCAL_LOGIN_NOTE}`;
|
|
|
593125
594006
|
this.turnGitBaseline = asksForCommit(userMessage) ? gitSnapshot(this.config.workingDirectory || process.cwd()) : null;
|
|
593126
594007
|
this.executor.beginTurn(userMessage);
|
|
593127
594008
|
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);
|
|
594009
|
+
const smallTalkTurn = isSmallTalk(textForAgent) && !imageBase64 && this.config.agentScope !== "__table__";
|
|
594010
|
+
if (smallTalkTurn) {
|
|
594011
|
+
const welcome = await this.greetingWelcome(textForAgent);
|
|
594012
|
+
if (welcome) {
|
|
594013
|
+
this.messageHistory.push({ role: "user", content: textForAgent });
|
|
594014
|
+
this.messageHistory.push({ role: "assistant", content: welcome });
|
|
594015
|
+
this.sessionWriter.writeUserMessage(textForAgent);
|
|
594016
|
+
return welcome;
|
|
594017
|
+
}
|
|
594018
|
+
this.messageHistory.push({ role: "user", content: harnessNote(SMALL_TALK_NOTE) });
|
|
594019
|
+
}
|
|
593128
594020
|
let visionId = null;
|
|
593129
594021
|
let visionFailed = false;
|
|
593130
594022
|
if (imageBase64 && await this.promptImageSeen()) {
|
|
@@ -593195,7 +594087,7 @@ ${result.description.slice(0, 200)}${result.description.length > 200 ? "..." : "
|
|
|
593195
594087
|
}
|
|
593196
594088
|
}
|
|
593197
594089
|
const quickPrompt = quickLaneEnabled() && classifyPrompt(textForAgent) === "quick";
|
|
593198
|
-
if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !isNoToolScope(this.config.agentScope)) {
|
|
594090
|
+
if (needsClarification(textForAgent) && !imageBase64 && !quickPrompt && !smallTalkTurn && !isNoToolScope(this.config.agentScope)) {
|
|
593199
594091
|
this.proactiveGatherer = createGatherer(textForAgent);
|
|
593200
594092
|
const question = this.proactiveGatherer.getCurrentQuestion();
|
|
593201
594093
|
if (question) {
|
|
@@ -593217,7 +594109,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
593217
594109
|
this.kanban.moveTask(this.currentBmadTask.id, "ready");
|
|
593218
594110
|
this.kanban.moveTask(this.currentBmadTask.id, "in_progress");
|
|
593219
594111
|
}
|
|
593220
|
-
if (!this.proactiveGatherer && !quickPrompt) {
|
|
594112
|
+
if (!this.proactiveGatherer && !quickPrompt && !smallTalkTurn) {
|
|
593221
594113
|
await this.tryRunPreToolRouter(textForAgent);
|
|
593222
594114
|
}
|
|
593223
594115
|
const needsPlanningGate2 = !isVerbatimScope(this.config.agentScope) && needsPlanningGate(textForAgent);
|
|
@@ -593362,9 +594254,9 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
593362
594254
|
"search_symbols",
|
|
593363
594255
|
"recall"
|
|
593364
594256
|
]);
|
|
593365
|
-
const scopedTools = isNoToolScope(this.config.agentScope) ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
|
|
594257
|
+
const scopedTools = isNoToolScope(this.config.agentScope) || smallTalkTurn ? {} : this.config.agentScope === "__table__" ? Object.fromEntries(Object.entries(providerTools).filter(([k]) => TABLE_SESSION_TOOLS.has(k))) : providerTools;
|
|
593366
594258
|
const withExtensions = { ...scopedTools };
|
|
593367
|
-
if (this.extensionToolsAllowed()) {
|
|
594259
|
+
if (this.extensionToolsAllowed() && !smallTalkTurn) {
|
|
593368
594260
|
for (const t of this.extensionHost.listTools()) {
|
|
593369
594261
|
if (t.name in withExtensions)
|
|
593370
594262
|
continue;
|
|
@@ -593376,7 +594268,7 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
593376
594268
|
}
|
|
593377
594269
|
}
|
|
593378
594270
|
const effectiveTools = this.modeFilter(withExtensions);
|
|
593379
|
-
const textToolAllowlist = (isNoToolScope(this.config.agentScope) ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
|
|
594271
|
+
const textToolAllowlist = (isNoToolScope(this.config.agentScope) || smallTalkTurn ? [] : this.config.agentScope === "__table__" ? [...TABLE_SESSION_TOOLS] : localCoreTools).filter((name) => getModeManager().isToolAllowed(name));
|
|
593380
594272
|
const harness = this.harnessProfileFor(providerConfig.model, isLocalProvider);
|
|
593381
594273
|
Object.assign(this.runtimeParams, {
|
|
593382
594274
|
voiceChatActive: getRuntimeParams().voiceChatActive,
|
|
@@ -593401,7 +594293,8 @@ Ask the user naturally; don't mention this instruction. After they answer, proce
|
|
|
593401
594293
|
`),
|
|
593402
594294
|
localCoreTools: textToolAllowlist,
|
|
593403
594295
|
chatStartTime,
|
|
593404
|
-
textForAgent
|
|
594296
|
+
textForAgent,
|
|
594297
|
+
smallTalk: smallTalkTurn
|
|
593405
594298
|
});
|
|
593406
594299
|
await this.readServerContextWindow();
|
|
593407
594300
|
await this.compactIfNeeded(providerConfig);
|
|
@@ -594086,7 +594979,7 @@ ${summary || " (no provider errors recorded)"}`);
|
|
|
594086
594979
|
};
|
|
594087
594980
|
}
|
|
594088
594981
|
const blankNative = gatedNative.content.trim() === "";
|
|
594089
|
-
const content = blankNative ? emptyReplyNote(this.turnToolLedger.length) : gatedNative.content;
|
|
594982
|
+
const content = blankNative ? emptyReplyNote(this.turnToolLedger.length, this.turnToolLedger) : gatedNative.content;
|
|
594090
594983
|
const flavor = voice.getFlavor("complete");
|
|
594091
594984
|
const flavoredContent = fixCompletedLine(gatedNative.violated || isVerbatimScope(this.config.agentScope) ? content : flavorResponse(content, flavor)).text;
|
|
594092
594985
|
this.messageHistory.push({ role: "assistant", content: flavoredContent });
|
|
@@ -594801,7 +595694,9 @@ var init_agent2 = __esm(() => {
|
|
|
594801
595694
|
init_modes();
|
|
594802
595695
|
init_planning_gate();
|
|
594803
595696
|
init_registry();
|
|
595697
|
+
init_small_talk();
|
|
594804
595698
|
init_verify_gate();
|
|
595699
|
+
init_welcome();
|
|
594805
595700
|
init_local_tool_scope();
|
|
594806
595701
|
init_local_turn_error();
|
|
594807
595702
|
init_output_gate();
|
|
@@ -595295,9 +596190,9 @@ var init_install = __esm(() => {
|
|
|
595295
596190
|
});
|
|
595296
596191
|
|
|
595297
596192
|
// packages/eight/source-update.ts
|
|
595298
|
-
import { execFile as
|
|
595299
|
-
import { existsSync as
|
|
595300
|
-
import { homedir as
|
|
596193
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
596194
|
+
import { existsSync as existsSync114, realpathSync as realpathSync36, statSync as statSync37 } from "node:fs";
|
|
596195
|
+
import { homedir as homedir85 } from "node:os";
|
|
595301
596196
|
import * as nodePath from "node:path";
|
|
595302
596197
|
function scrubbedEnv(base) {
|
|
595303
596198
|
const out = {};
|
|
@@ -595395,7 +596290,7 @@ function modulePathToFs(modulePath) {
|
|
|
595395
596290
|
}
|
|
595396
596291
|
return s;
|
|
595397
596292
|
}
|
|
595398
|
-
function findCheckoutRoot(modulePath, platform, hasGit = (d) =>
|
|
596293
|
+
function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync114(lib(platform).join(d, ".git"))) {
|
|
595399
596294
|
const p = lib(platform);
|
|
595400
596295
|
const fsPath = modulePathToFs(modulePath);
|
|
595401
596296
|
let dir = p.dirname(platform === "win32" ? fsPath.replace(/\//g, "\\") : fsPath);
|
|
@@ -595411,7 +596306,7 @@ function findCheckoutRoot(modulePath, platform, hasGit = (d) => existsSync110(li
|
|
|
595411
596306
|
}
|
|
595412
596307
|
function findBrowserCheckout(o) {
|
|
595413
596308
|
const p = lib(o.platform);
|
|
595414
|
-
const hasGit = o.hasGit ?? ((d) =>
|
|
596309
|
+
const hasGit = o.hasGit ?? ((d) => existsSync114(p.join(d, ".git")));
|
|
595415
596310
|
const looked = [];
|
|
595416
596311
|
let note;
|
|
595417
596312
|
const cands = [];
|
|
@@ -595737,7 +596632,7 @@ async function runSourceUpdate(deps, opts, report) {
|
|
|
595737
596632
|
git,
|
|
595738
596633
|
bun: bun ?? "bun",
|
|
595739
596634
|
platform,
|
|
595740
|
-
fileExists: deps.fileExists ?? ((f) =>
|
|
596635
|
+
fileExists: deps.fileExists ?? ((f) => existsSync114(f)),
|
|
595741
596636
|
now: deps.now ?? (() => new Date),
|
|
595742
596637
|
baseEnv: env,
|
|
595743
596638
|
forgeHost: env.EIGHT_FORGE_HOST,
|
|
@@ -595761,7 +596656,7 @@ async function runSourceUpdate(deps, opts, report) {
|
|
|
595761
596656
|
report?.({ updated: true, to: short2(code.to ?? "") });
|
|
595762
596657
|
const found = findBrowserCheckout({
|
|
595763
596658
|
env,
|
|
595764
|
-
home: deps.home ??
|
|
596659
|
+
home: deps.home ?? homedir85(),
|
|
595765
596660
|
platform,
|
|
595766
596661
|
codeRoot: root,
|
|
595767
596662
|
hasGit: deps.hasGit
|
|
@@ -595787,7 +596682,7 @@ async function runSourceUpdate(deps, opts, report) {
|
|
|
595787
596682
|
return bad ? 1 : 0;
|
|
595788
596683
|
}
|
|
595789
596684
|
var T_LOCAL = 30000, T_FETCH = 120000, T_INSTALL = 600000, ENV_KEEP, defaultExec = (file, args, opts) => new Promise((resolve) => {
|
|
595790
|
-
|
|
596685
|
+
execFile9(file, args, {
|
|
595791
596686
|
cwd: opts.cwd,
|
|
595792
596687
|
timeout: opts.timeoutMs,
|
|
595793
596688
|
maxBuffer: 33554432,
|
|
@@ -596050,16 +596945,16 @@ var init_cli_maintenance = __esm(() => {
|
|
|
596050
596945
|
});
|
|
596051
596946
|
|
|
596052
596947
|
// packages/eight/update-resume.ts
|
|
596053
|
-
import { mkdirSync as
|
|
596054
|
-
import { join as
|
|
596948
|
+
import { mkdirSync as mkdirSync79, readFileSync as readFileSync104, rmSync as rmSync16, writeFileSync as writeFileSync61 } from "node:fs";
|
|
596949
|
+
import { join as join172 } from "node:path";
|
|
596055
596950
|
function dataDir4(env = process.env) {
|
|
596056
|
-
return
|
|
596951
|
+
return join172(resolveHome(env), ".8gent");
|
|
596057
596952
|
}
|
|
596058
596953
|
function writeResumeRequest(req, env = process.env) {
|
|
596059
|
-
|
|
596954
|
+
mkdirSync79(dataDir4(env), { recursive: true });
|
|
596060
596955
|
writeFileSync61(file(env), JSON.stringify(req), "utf8");
|
|
596061
596956
|
}
|
|
596062
|
-
var RELAUNCH_EXIT_CODE = 75, file = (env) =>
|
|
596957
|
+
var RELAUNCH_EXIT_CODE = 75, file = (env) => join172(dataDir4(env), "update-resume.json");
|
|
596063
596958
|
var init_update_resume = __esm(() => {
|
|
596064
596959
|
init_home();
|
|
596065
596960
|
});
|
|
@@ -596071,8 +596966,8 @@ __export(exports_update_notice, {
|
|
|
596071
596966
|
maybeUpdateNotice: () => maybeUpdateNotice,
|
|
596072
596967
|
realNoticeDeps: () => realNoticeDeps
|
|
596073
596968
|
});
|
|
596074
|
-
import { mkdirSync as
|
|
596075
|
-
import { join as
|
|
596969
|
+
import { mkdirSync as mkdirSync80, readFileSync as readFileSync105, writeFileSync as writeFileSync62 } from "node:fs";
|
|
596970
|
+
import { join as join173 } from "node:path";
|
|
596076
596971
|
function noticeText(from, to) {
|
|
596077
596972
|
return `Update available (${from} -> ${to}). Run 8gent update, or type /update.`;
|
|
596078
596973
|
}
|
|
@@ -596086,7 +596981,7 @@ function updateCheckDisabled(env, settingsFile) {
|
|
|
596086
596981
|
return true;
|
|
596087
596982
|
if (settingsFile) {
|
|
596088
596983
|
try {
|
|
596089
|
-
const s = JSON.parse(
|
|
596984
|
+
const s = JSON.parse(readFileSync105(settingsFile, "utf8"));
|
|
596090
596985
|
if (s.updateCheck === false)
|
|
596091
596986
|
return true;
|
|
596092
596987
|
} catch {}
|
|
@@ -596123,7 +597018,7 @@ async function maybeUpdateNotice(d) {
|
|
|
596123
597018
|
function realNoticeDeps(o) {
|
|
596124
597019
|
const env = o.env ?? process.env;
|
|
596125
597020
|
const platform = o.platform ?? process.platform;
|
|
596126
|
-
const stateFile =
|
|
597021
|
+
const stateFile = join173(dataDir4(env), "update-check.json");
|
|
596127
597022
|
const channel = detectChannel({ modulePath: o.modulePath, embedded: o.embedded });
|
|
596128
597023
|
const srcDeps = { modulePath: o.modulePath, env, platform, exec: o.exec };
|
|
596129
597024
|
return {
|
|
@@ -596131,7 +597026,7 @@ function realNoticeDeps(o) {
|
|
|
596131
597026
|
disabled: () => !isUpdateCheckEnabled(env) || updateCheckDisabled(env, o.settingsFile),
|
|
596132
597027
|
readState: () => {
|
|
596133
597028
|
try {
|
|
596134
|
-
const s = JSON.parse(
|
|
597029
|
+
const s = JSON.parse(readFileSync105(stateFile, "utf8"));
|
|
596135
597030
|
return typeof s.checkedAt === "number" ? s : null;
|
|
596136
597031
|
} catch {
|
|
596137
597032
|
return null;
|
|
@@ -596139,7 +597034,7 @@ function realNoticeDeps(o) {
|
|
|
596139
597034
|
},
|
|
596140
597035
|
writeState: (s) => {
|
|
596141
597036
|
try {
|
|
596142
|
-
|
|
597037
|
+
mkdirSync80(dataDir4(env), { recursive: true });
|
|
596143
597038
|
writeFileSync62(stateFile, JSON.stringify(s), "utf8");
|
|
596144
597039
|
} catch {}
|
|
596145
597040
|
},
|
|
@@ -596183,7 +597078,7 @@ var init_update_notice = __esm(() => {
|
|
|
596183
597078
|
});
|
|
596184
597079
|
|
|
596185
597080
|
// packages/voice/cloud-transcriber.ts
|
|
596186
|
-
import { existsSync as
|
|
597081
|
+
import { existsSync as existsSync115 } from "node:fs";
|
|
596187
597082
|
async function transcribeCloud(wavPath, options) {
|
|
596188
597083
|
const {
|
|
596189
597084
|
apiKey,
|
|
@@ -596195,7 +597090,7 @@ async function transcribeCloud(wavPath, options) {
|
|
|
596195
597090
|
if (!apiKey) {
|
|
596196
597091
|
throw new Error("OpenAI API key is required for cloud transcription. Set OPENAI_API_KEY environment variable.");
|
|
596197
597092
|
}
|
|
596198
|
-
if (!
|
|
597093
|
+
if (!existsSync115(wavPath)) {
|
|
596199
597094
|
throw new Error(`WAV file not found: ${wavPath}`);
|
|
596200
597095
|
}
|
|
596201
597096
|
const startTime = Date.now();
|
|
@@ -596299,11 +597194,11 @@ var init_types4 = __esm(() => {
|
|
|
596299
597194
|
|
|
596300
597195
|
// packages/voice/model-manager.ts
|
|
596301
597196
|
import { EventEmitter as EventEmitter15 } from "node:events";
|
|
596302
|
-
import { existsSync as
|
|
596303
|
-
import { homedir as
|
|
596304
|
-
import { join as
|
|
597197
|
+
import { existsSync as existsSync116, mkdirSync as mkdirSync81, realpathSync as realpathSync37, unlinkSync as unlinkSync4 } from "node:fs";
|
|
597198
|
+
import { homedir as homedir86 } from "node:os";
|
|
597199
|
+
import { join as join174, sep as sep30 } from "node:path";
|
|
596305
597200
|
function resolveWhisperModel(opts = {}) {
|
|
596306
|
-
const exists = opts.exists ??
|
|
597201
|
+
const exists = opts.exists ?? existsSync116;
|
|
596307
597202
|
const dirs = [
|
|
596308
597203
|
resolveModelsPath(opts.modelsDir ?? "~/.8gent/models/whisper"),
|
|
596309
597204
|
...opts.extraDirs ?? []
|
|
@@ -596313,7 +597208,7 @@ function resolveWhisperModel(opts = {}) {
|
|
|
596313
597208
|
for (const m of WHISPER_MODEL_RANK) {
|
|
596314
597209
|
if (!english && m.filename.endsWith(".en.bin"))
|
|
596315
597210
|
continue;
|
|
596316
|
-
const path =
|
|
597211
|
+
const path = join174(dir, m.filename);
|
|
596317
597212
|
if (!exists(path))
|
|
596318
597213
|
continue;
|
|
596319
597214
|
if (!opts.exists && !isInside2(dir, path))
|
|
@@ -596342,7 +597237,7 @@ function missingWhisperModelMessage(modelsDir = "~/.8gent/models/whisper") {
|
|
|
596342
597237
|
}
|
|
596343
597238
|
function resolveModelsPath(configPath) {
|
|
596344
597239
|
if (configPath.startsWith("~")) {
|
|
596345
|
-
return
|
|
597240
|
+
return join174(homedir86(), configPath.slice(1));
|
|
596346
597241
|
}
|
|
596347
597242
|
return configPath;
|
|
596348
597243
|
}
|
|
@@ -596364,8 +597259,8 @@ var init_model_manager = __esm(() => {
|
|
|
596364
597259
|
this.modelsDir = resolveModelsPath(modelsPath);
|
|
596365
597260
|
}
|
|
596366
597261
|
ensureModelsDir() {
|
|
596367
|
-
if (!
|
|
596368
|
-
|
|
597262
|
+
if (!existsSync116(this.modelsDir)) {
|
|
597263
|
+
mkdirSync81(this.modelsDir, { recursive: true });
|
|
596369
597264
|
}
|
|
596370
597265
|
}
|
|
596371
597266
|
getModelsDir() {
|
|
@@ -596375,10 +597270,10 @@ var init_model_manager = __esm(() => {
|
|
|
596375
597270
|
return WHISPER_MODELS[name];
|
|
596376
597271
|
}
|
|
596377
597272
|
getModelPath(name) {
|
|
596378
|
-
return
|
|
597273
|
+
return join174(this.modelsDir, WHISPER_MODELS[name].filename);
|
|
596379
597274
|
}
|
|
596380
597275
|
isModelDownloaded(name) {
|
|
596381
|
-
return
|
|
597276
|
+
return existsSync116(this.getModelPath(name));
|
|
596382
597277
|
}
|
|
596383
597278
|
listModels() {
|
|
596384
597279
|
return Object.keys(WHISPER_MODELS).map((name) => ({
|
|
@@ -596393,7 +597288,7 @@ var init_model_manager = __esm(() => {
|
|
|
596393
597288
|
async downloadModel(name) {
|
|
596394
597289
|
const info = WHISPER_MODELS[name];
|
|
596395
597290
|
const destPath = this.getModelPath(name);
|
|
596396
|
-
if (
|
|
597291
|
+
if (existsSync116(destPath)) {
|
|
596397
597292
|
return destPath;
|
|
596398
597293
|
}
|
|
596399
597294
|
this.ensureModelsDir();
|
|
@@ -596444,9 +597339,9 @@ var init_model_manager = __esm(() => {
|
|
|
596444
597339
|
this.emit("download-complete", { model: name, path: destPath });
|
|
596445
597340
|
return destPath;
|
|
596446
597341
|
} catch (err) {
|
|
596447
|
-
if (
|
|
597342
|
+
if (existsSync116(destPath)) {
|
|
596448
597343
|
try {
|
|
596449
|
-
|
|
597344
|
+
unlinkSync4(destPath);
|
|
596450
597345
|
} catch {}
|
|
596451
597346
|
}
|
|
596452
597347
|
const message = err instanceof Error ? err.message : "Download failed";
|
|
@@ -596456,8 +597351,8 @@ var init_model_manager = __esm(() => {
|
|
|
596456
597351
|
}
|
|
596457
597352
|
deleteModel(name) {
|
|
596458
597353
|
const path = this.getModelPath(name);
|
|
596459
|
-
if (
|
|
596460
|
-
|
|
597354
|
+
if (existsSync116(path)) {
|
|
597355
|
+
unlinkSync4(path);
|
|
596461
597356
|
return true;
|
|
596462
597357
|
}
|
|
596463
597358
|
return false;
|
|
@@ -596467,7 +597362,7 @@ var init_model_manager = __esm(() => {
|
|
|
596467
597362
|
let totalBytes = 0;
|
|
596468
597363
|
for (const name of Object.keys(WHISPER_MODELS)) {
|
|
596469
597364
|
const path = this.getModelPath(name);
|
|
596470
|
-
if (
|
|
597365
|
+
if (existsSync116(path)) {
|
|
596471
597366
|
try {
|
|
596472
597367
|
const stat = Bun.file(path);
|
|
596473
597368
|
models[name] = stat.size;
|
|
@@ -596480,61 +597375,11 @@ var init_model_manager = __esm(() => {
|
|
|
596480
597375
|
};
|
|
596481
597376
|
});
|
|
596482
597377
|
|
|
596483
|
-
// packages/voice/termux.ts
|
|
596484
|
-
import { constants as constants15, accessSync as accessSync5, readFileSync as readFileSync105 } from "node:fs";
|
|
596485
|
-
import { delimiter as delimiter8, join as join170 } from "node:path";
|
|
596486
|
-
function isAndroidHost(platform = process.platform, env = process.env) {
|
|
596487
|
-
return platform === "android" || !!env.TERMUX_VERSION || String(env.PREFIX ?? "").includes("/com.termux/");
|
|
596488
|
-
}
|
|
596489
|
-
function findOnPath(name, env = process.env) {
|
|
596490
|
-
for (const dir of String(env.PATH ?? "").split(delimiter8)) {
|
|
596491
|
-
if (!dir)
|
|
596492
|
-
continue;
|
|
596493
|
-
const candidate = join170(dir, name);
|
|
596494
|
-
try {
|
|
596495
|
-
accessSync5(candidate, constants15.X_OK);
|
|
596496
|
-
return candidate;
|
|
596497
|
-
} catch {}
|
|
596498
|
-
}
|
|
596499
|
-
return null;
|
|
596500
|
-
}
|
|
596501
|
-
function voiceOutputOn(env = process.env, readSettings = () => {
|
|
596502
|
-
const home = env.EIGHT_HOME || join170(env.HOME ?? "", ".8gent");
|
|
596503
|
-
return readFileSync105(join170(home, "settings.json"), "utf8");
|
|
596504
|
-
}) {
|
|
596505
|
-
if (env.EIGHT_VOICE === "1")
|
|
596506
|
-
return true;
|
|
596507
|
-
try {
|
|
596508
|
-
return JSON.parse(readSettings())?.voice?.outputEnabled === true;
|
|
596509
|
-
} catch {
|
|
596510
|
-
return false;
|
|
596511
|
-
}
|
|
596512
|
-
}
|
|
596513
|
-
function ctrlRAction(key, input, android = isAndroidHost()) {
|
|
596514
|
-
if (!key.ctrl || input !== "r")
|
|
596515
|
-
return "ignore";
|
|
596516
|
-
return android ? "android-line" : "toggle";
|
|
596517
|
-
}
|
|
596518
|
-
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;
|
|
596519
|
-
var init_termux = __esm(() => {
|
|
596520
|
-
ANDROID_VOICE_LINE_SUBS = [
|
|
596521
|
-
"",
|
|
596522
|
-
"chat",
|
|
596523
|
-
"conversation",
|
|
596524
|
-
"talk",
|
|
596525
|
-
"record",
|
|
596526
|
-
"listen",
|
|
596527
|
-
"stt",
|
|
596528
|
-
"status",
|
|
596529
|
-
"stop"
|
|
596530
|
-
];
|
|
596531
|
-
});
|
|
596532
|
-
|
|
596533
597378
|
// packages/voice/recorder.ts
|
|
596534
597379
|
import { EventEmitter as EventEmitter16 } from "node:events";
|
|
596535
|
-
import { closeSync as closeSync21, existsSync as
|
|
597380
|
+
import { closeSync as closeSync21, existsSync as existsSync117, openSync as openSync21, readSync as readSync13, statSync as statSync38, unlinkSync as unlinkSync5 } from "node:fs";
|
|
596536
597381
|
import { tmpdir as tmpdir20 } from "node:os";
|
|
596537
|
-
import { join as
|
|
597382
|
+
import { join as join175 } from "node:path";
|
|
596538
597383
|
async function findSoxPath() {
|
|
596539
597384
|
try {
|
|
596540
597385
|
const proc = spawn(["which", "rec"], {
|
|
@@ -596614,7 +597459,7 @@ var init_recorder = __esm(() => {
|
|
|
596614
597459
|
channels: opts.channels ?? 1,
|
|
596615
597460
|
bitDepth: opts.bitDepth ?? 16,
|
|
596616
597461
|
maxDurationSeconds: opts.maxDurationSeconds ?? 30,
|
|
596617
|
-
outputPath: opts.outputPath ??
|
|
597462
|
+
outputPath: opts.outputPath ?? join175(tmpdir20(), `8gent-voice-${Date.now()}.wav`)
|
|
596618
597463
|
};
|
|
596619
597464
|
this.outputPath = this.options.outputPath;
|
|
596620
597465
|
}
|
|
@@ -596630,7 +597475,7 @@ var init_recorder = __esm(() => {
|
|
|
596630
597475
|
throw new Error(`sox not installed. ${soxCheck.installHint}`);
|
|
596631
597476
|
}
|
|
596632
597477
|
this.device = null;
|
|
596633
|
-
this.outputPath = this.options.outputPath.includes("8gent-voice-") ?
|
|
597478
|
+
this.outputPath = this.options.outputPath.includes("8gent-voice-") ? join175(tmpdir20(), `8gent-voice-${Date.now()}.wav`) : this.options.outputPath;
|
|
596634
597479
|
const args = [
|
|
596635
597480
|
"-q",
|
|
596636
597481
|
"-r",
|
|
@@ -596734,8 +597579,8 @@ var init_recorder = __esm(() => {
|
|
|
596734
597579
|
}
|
|
596735
597580
|
static cleanupFile(path) {
|
|
596736
597581
|
try {
|
|
596737
|
-
if (
|
|
596738
|
-
|
|
597582
|
+
if (existsSync117(path)) {
|
|
597583
|
+
unlinkSync5(path);
|
|
596739
597584
|
}
|
|
596740
597585
|
} catch {}
|
|
596741
597586
|
}
|
|
@@ -596754,15 +597599,15 @@ var init_recorder = __esm(() => {
|
|
|
596754
597599
|
});
|
|
596755
597600
|
|
|
596756
597601
|
// packages/voice/transcriber.ts
|
|
596757
|
-
import { existsSync as
|
|
596758
|
-
import { arch as arch2, homedir as
|
|
596759
|
-
import { join as
|
|
597602
|
+
import { existsSync as existsSync118 } from "node:fs";
|
|
597603
|
+
import { arch as arch2, homedir as homedir87, platform as platform9 } from "node:os";
|
|
597604
|
+
import { join as join176 } from "node:path";
|
|
596760
597605
|
function getWhisperBinaryPath() {
|
|
596761
|
-
return
|
|
597606
|
+
return join176(WHISPER_BIN_DIR, WHISPER_BIN_NAME);
|
|
596762
597607
|
}
|
|
596763
597608
|
async function findWhisperBinary() {
|
|
596764
597609
|
const managedPath = getWhisperBinaryPath();
|
|
596765
|
-
if (
|
|
597610
|
+
if (existsSync118(managedPath)) {
|
|
596766
597611
|
return managedPath;
|
|
596767
597612
|
}
|
|
596768
597613
|
const names = ["whisper-cpp", "whisper-cli", "whisper", "main"];
|
|
@@ -596777,7 +597622,7 @@ async function findWhisperBinary() {
|
|
|
596777
597622
|
} catch {}
|
|
596778
597623
|
}
|
|
596779
597624
|
for (const brewName of ["/opt/homebrew/bin/whisper-cpp", "/opt/homebrew/bin/whisper-cli"]) {
|
|
596780
|
-
if (
|
|
597625
|
+
if (existsSync118(brewName)) {
|
|
596781
597626
|
return brewName;
|
|
596782
597627
|
}
|
|
596783
597628
|
}
|
|
@@ -596785,13 +597630,13 @@ async function findWhisperBinary() {
|
|
|
596785
597630
|
}
|
|
596786
597631
|
async function transcribeLocal(wavPath, options) {
|
|
596787
597632
|
const { binaryPath, modelPath, language = "en", timeoutMs = 30000, threads } = options;
|
|
596788
|
-
if (!
|
|
597633
|
+
if (!existsSync118(wavPath)) {
|
|
596789
597634
|
throw new Error(`WAV file not found: ${wavPath}`);
|
|
596790
597635
|
}
|
|
596791
|
-
if (!
|
|
597636
|
+
if (!existsSync118(binaryPath)) {
|
|
596792
597637
|
throw new Error(`Whisper binary not found: ${binaryPath}`);
|
|
596793
597638
|
}
|
|
596794
|
-
if (!
|
|
597639
|
+
if (!existsSync118(modelPath)) {
|
|
596795
597640
|
throw new Error(`Model file not found: ${modelPath}`);
|
|
596796
597641
|
}
|
|
596797
597642
|
const startTime = Date.now();
|
|
@@ -596879,13 +597724,13 @@ function extractModelName(modelPath) {
|
|
|
596879
597724
|
var WHISPER_BIN_DIR, WHISPER_BIN_NAME = "whisper-cpp";
|
|
596880
597725
|
var init_transcriber = __esm(() => {
|
|
596881
597726
|
init_bun_shim();
|
|
596882
|
-
WHISPER_BIN_DIR =
|
|
597727
|
+
WHISPER_BIN_DIR = join176(homedir87(), ".8gent", "bin");
|
|
596883
597728
|
});
|
|
596884
597729
|
|
|
596885
597730
|
// packages/decide/backends/neudecide.ts
|
|
596886
|
-
import { mkdtempSync as
|
|
597731
|
+
import { mkdtempSync as mkdtempSync12, rmSync as rmSync17, writeFileSync as writeFileSync63 } from "node:fs";
|
|
596887
597732
|
import { tmpdir as tmpdir22 } from "node:os";
|
|
596888
|
-
import { dirname as
|
|
597733
|
+
import { dirname as dirname79, join as join179 } from "node:path";
|
|
596889
597734
|
function wavDurationMs(buf) {
|
|
596890
597735
|
if (buf.length < 12)
|
|
596891
597736
|
return null;
|
|
@@ -596942,7 +597787,7 @@ function pythonRunner(env = process.env, spawn = Bun.spawn) {
|
|
|
596942
597787
|
const proc = spawn([python, "-I", "-c", PY, wavPath, toolsJson], {
|
|
596943
597788
|
stdout: "pipe",
|
|
596944
597789
|
stderr: "pipe",
|
|
596945
|
-
cwd:
|
|
597790
|
+
cwd: dirname79(wavPath),
|
|
596946
597791
|
env: { ...env, HF_HUB_OFFLINE: "1" }
|
|
596947
597792
|
});
|
|
596948
597793
|
const kill = () => {
|
|
@@ -596980,15 +597825,15 @@ class NeuDecideBackend {
|
|
|
596980
597825
|
description: c.description,
|
|
596981
597826
|
parameters: { type: "object", properties: {} }
|
|
596982
597827
|
}));
|
|
596983
|
-
const dir =
|
|
596984
|
-
const wavPath =
|
|
597828
|
+
const dir = mkdtempSync12(join179(tmpdir22(), "8gent-neudecide-"));
|
|
597829
|
+
const wavPath = join179(dir, "in.wav");
|
|
596985
597830
|
const t0 = performance.now();
|
|
596986
597831
|
let out;
|
|
596987
597832
|
try {
|
|
596988
597833
|
writeFileSync63(wavPath, request.audio);
|
|
596989
597834
|
out = await this.run(wavPath, JSON.stringify(tools), request.signal);
|
|
596990
597835
|
} finally {
|
|
596991
|
-
|
|
597836
|
+
rmSync17(dir, { recursive: true, force: true });
|
|
596992
597837
|
}
|
|
596993
597838
|
const latencyMs = performance.now() - t0;
|
|
596994
597839
|
let calls;
|
|
@@ -597066,289 +597911,6 @@ var init_neudecide = __esm(() => {
|
|
|
597066
597911
|
];
|
|
597067
597912
|
});
|
|
597068
597913
|
|
|
597069
|
-
// packages/runtime/node-runtime.ts
|
|
597070
|
-
import { execFile as execFile8 } from "node:child_process";
|
|
597071
|
-
import { existsSync as existsSync119 } from "node:fs";
|
|
597072
|
-
import { homedir as homedir88 } from "node:os";
|
|
597073
|
-
import { join as join179 } from "node:path";
|
|
597074
|
-
import { promisify as promisify6 } from "node:util";
|
|
597075
|
-
function parseNodeVersion(raw) {
|
|
597076
|
-
const trimmed = raw.trim();
|
|
597077
|
-
const match = trimmed.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
597078
|
-
if (!match)
|
|
597079
|
-
return null;
|
|
597080
|
-
return {
|
|
597081
|
-
major: Number.parseInt(match[1], 10),
|
|
597082
|
-
minor: Number.parseInt(match[2], 10),
|
|
597083
|
-
patch: Number.parseInt(match[3], 10)
|
|
597084
|
-
};
|
|
597085
|
-
}
|
|
597086
|
-
function satisfiesMinVersion(v, min) {
|
|
597087
|
-
const minParsed = parseNodeVersion(min);
|
|
597088
|
-
if (!minParsed)
|
|
597089
|
-
return true;
|
|
597090
|
-
if (v.major !== minParsed.major)
|
|
597091
|
-
return v.major > minParsed.major;
|
|
597092
|
-
if (v.minor !== minParsed.minor)
|
|
597093
|
-
return v.minor > minParsed.minor;
|
|
597094
|
-
return v.patch >= minParsed.patch;
|
|
597095
|
-
}
|
|
597096
|
-
function pickPlatformAsset(input) {
|
|
597097
|
-
const byArch = SUPPORTED[input.platform];
|
|
597098
|
-
if (!byArch) {
|
|
597099
|
-
throw new Error(`unsupported platform: ${input.platform}`);
|
|
597100
|
-
}
|
|
597101
|
-
const asset = byArch[input.arch];
|
|
597102
|
-
if (!asset) {
|
|
597103
|
-
throw new Error(`unsupported arch: ${input.arch} on ${input.platform}`);
|
|
597104
|
-
}
|
|
597105
|
-
return asset;
|
|
597106
|
-
}
|
|
597107
|
-
function buildDownloadUrl(opts) {
|
|
597108
|
-
const cleanVersion = opts.version.startsWith("v") ? opts.version.slice(1) : opts.version;
|
|
597109
|
-
const v = `v${cleanVersion}`;
|
|
597110
|
-
const fileBase = `node-${v}-${opts.asset.os}-${opts.asset.arch}`;
|
|
597111
|
-
return `https://nodejs.org/dist/${v}/${fileBase}.${opts.asset.ext}`;
|
|
597112
|
-
}
|
|
597113
|
-
function defaultRoot() {
|
|
597114
|
-
return join179(homedir88(), ".8gent", "runtime");
|
|
597115
|
-
}
|
|
597116
|
-
function getRuntimeDir(loc) {
|
|
597117
|
-
const root = loc.root ?? defaultRoot();
|
|
597118
|
-
return join179(root, `node-${loc.version}`);
|
|
597119
|
-
}
|
|
597120
|
-
function resolvedNodeBinPath(opts) {
|
|
597121
|
-
const dir = getRuntimeDir(opts);
|
|
597122
|
-
if (opts.platform === "win32") {
|
|
597123
|
-
return join179(dir, "node.exe");
|
|
597124
|
-
}
|
|
597125
|
-
return join179(dir, "bin", "node");
|
|
597126
|
-
}
|
|
597127
|
-
async function isRuntimeReady(opts) {
|
|
597128
|
-
const platform = opts.platform ?? process.platform;
|
|
597129
|
-
const bin = resolvedNodeBinPath({
|
|
597130
|
-
root: opts.root,
|
|
597131
|
-
version: opts.version,
|
|
597132
|
-
platform
|
|
597133
|
-
});
|
|
597134
|
-
if (!existsSync119(bin))
|
|
597135
|
-
return false;
|
|
597136
|
-
const min = opts.minVersion ?? opts.version;
|
|
597137
|
-
try {
|
|
597138
|
-
const { stdout } = await execFileAsync4(bin, ["--version"], {
|
|
597139
|
-
timeout: 3000
|
|
597140
|
-
});
|
|
597141
|
-
const parsed = parseNodeVersion(stdout);
|
|
597142
|
-
if (!parsed)
|
|
597143
|
-
return false;
|
|
597144
|
-
return satisfiesMinVersion(parsed, min);
|
|
597145
|
-
} catch {
|
|
597146
|
-
return false;
|
|
597147
|
-
}
|
|
597148
|
-
}
|
|
597149
|
-
var execFileAsync4, SUPPORTED;
|
|
597150
|
-
var init_node_runtime = __esm(() => {
|
|
597151
|
-
execFileAsync4 = promisify6(execFile8);
|
|
597152
|
-
SUPPORTED = {
|
|
597153
|
-
darwin: {
|
|
597154
|
-
arm64: { os: "darwin", arch: "arm64", ext: "tar.gz" },
|
|
597155
|
-
x64: { os: "darwin", arch: "x64", ext: "tar.gz" }
|
|
597156
|
-
},
|
|
597157
|
-
linux: {
|
|
597158
|
-
arm64: { os: "linux", arch: "arm64", ext: "tar.xz" },
|
|
597159
|
-
x64: { os: "linux", arch: "x64", ext: "tar.xz" }
|
|
597160
|
-
},
|
|
597161
|
-
win32: {
|
|
597162
|
-
x64: { os: "win", arch: "x64", ext: "zip" },
|
|
597163
|
-
arm64: { os: "win", arch: "arm64", ext: "zip" }
|
|
597164
|
-
}
|
|
597165
|
-
};
|
|
597166
|
-
});
|
|
597167
|
-
|
|
597168
|
-
// packages/runtime/installer.ts
|
|
597169
|
-
import { spawn as spawn23 } from "node:child_process";
|
|
597170
|
-
import {
|
|
597171
|
-
createWriteStream,
|
|
597172
|
-
existsSync as existsSync120,
|
|
597173
|
-
mkdirSync as mkdirSync83,
|
|
597174
|
-
mkdtempSync as mkdtempSync12,
|
|
597175
|
-
readdirSync as readdirSync27,
|
|
597176
|
-
renameSync as renameSync17,
|
|
597177
|
-
rmSync as rmSync17
|
|
597178
|
-
} from "node:fs";
|
|
597179
|
-
import { join as join180 } from "node:path";
|
|
597180
|
-
import { Readable as Readable2 } from "node:stream";
|
|
597181
|
-
import { pipeline } from "node:stream/promises";
|
|
597182
|
-
function planInstall(input) {
|
|
597183
|
-
const platform = input.platform ?? process.platform;
|
|
597184
|
-
const arch = input.arch ?? process.arch;
|
|
597185
|
-
const asset = pickPlatformAsset({ platform, arch });
|
|
597186
|
-
const url = buildDownloadUrl({ version: input.version, asset });
|
|
597187
|
-
const runtimeDir = getRuntimeDir({ root: input.root, version: input.version });
|
|
597188
|
-
const binPath = resolvedNodeBinPath({
|
|
597189
|
-
root: input.root,
|
|
597190
|
-
version: input.version,
|
|
597191
|
-
platform
|
|
597192
|
-
});
|
|
597193
|
-
return {
|
|
597194
|
-
version: input.version,
|
|
597195
|
-
url,
|
|
597196
|
-
asset,
|
|
597197
|
-
runtimeDir,
|
|
597198
|
-
binPath,
|
|
597199
|
-
archiveExt: asset.ext
|
|
597200
|
-
};
|
|
597201
|
-
}
|
|
597202
|
-
async function installRuntime(input) {
|
|
597203
|
-
const plan = planInstall(input);
|
|
597204
|
-
const platform = input.platform ?? process.platform;
|
|
597205
|
-
const minVersion = input.minVersion ?? input.version;
|
|
597206
|
-
const ready = await isRuntimeReady({
|
|
597207
|
-
root: input.root,
|
|
597208
|
-
version: input.version,
|
|
597209
|
-
platform,
|
|
597210
|
-
minVersion
|
|
597211
|
-
});
|
|
597212
|
-
if (ready || input.dryRun) {
|
|
597213
|
-
return {
|
|
597214
|
-
...plan,
|
|
597215
|
-
action: ready ? "already-ready" : "dry-run"
|
|
597216
|
-
};
|
|
597217
|
-
}
|
|
597218
|
-
const runtimeRoot = plan.runtimeDir.replace(/\/node-[^/]+$/, "");
|
|
597219
|
-
mkdirSync83(runtimeRoot, { recursive: true });
|
|
597220
|
-
const stagingDir = mkdtempSync12(join180(runtimeRoot, ".dl-"));
|
|
597221
|
-
const archivePath = join180(stagingDir, `node.${plan.archiveExt}`);
|
|
597222
|
-
try {
|
|
597223
|
-
await downloadFile(plan.url, archivePath);
|
|
597224
|
-
const extractRoot = join180(stagingDir, "extract");
|
|
597225
|
-
mkdirSync83(extractRoot, { recursive: true });
|
|
597226
|
-
await extractArchive(archivePath, extractRoot, plan.archiveExt);
|
|
597227
|
-
const children = readdirSync27(extractRoot);
|
|
597228
|
-
const nodeDir = children.find((n) => n.startsWith("node-"));
|
|
597229
|
-
if (!nodeDir) {
|
|
597230
|
-
throw new Error(`could not find node-* dir inside ${extractRoot}`);
|
|
597231
|
-
}
|
|
597232
|
-
const extractedPath = join180(extractRoot, nodeDir);
|
|
597233
|
-
if (existsSync120(plan.runtimeDir)) {
|
|
597234
|
-
rmSync17(plan.runtimeDir, { recursive: true, force: true });
|
|
597235
|
-
}
|
|
597236
|
-
renameSync17(extractedPath, plan.runtimeDir);
|
|
597237
|
-
} catch (err) {
|
|
597238
|
-
return {
|
|
597239
|
-
...plan,
|
|
597240
|
-
action: "failed",
|
|
597241
|
-
error: err instanceof Error ? err.message : String(err)
|
|
597242
|
-
};
|
|
597243
|
-
} finally {
|
|
597244
|
-
try {
|
|
597245
|
-
rmSync17(stagingDir, { recursive: true, force: true });
|
|
597246
|
-
} catch {}
|
|
597247
|
-
}
|
|
597248
|
-
const reReady = await isRuntimeReady({
|
|
597249
|
-
root: input.root,
|
|
597250
|
-
version: input.version,
|
|
597251
|
-
platform,
|
|
597252
|
-
minVersion
|
|
597253
|
-
});
|
|
597254
|
-
if (!reReady) {
|
|
597255
|
-
return {
|
|
597256
|
-
...plan,
|
|
597257
|
-
action: "failed",
|
|
597258
|
-
error: `installed runtime at ${plan.binPath} but it does not satisfy minVersion ${minVersion}`
|
|
597259
|
-
};
|
|
597260
|
-
}
|
|
597261
|
-
return {
|
|
597262
|
-
...plan,
|
|
597263
|
-
action: "installed"
|
|
597264
|
-
};
|
|
597265
|
-
}
|
|
597266
|
-
async function downloadFile(url, dest) {
|
|
597267
|
-
const res = await fetch(url, { redirect: "follow" });
|
|
597268
|
-
if (!res.ok || !res.body) {
|
|
597269
|
-
throw new Error(`download failed: HTTP ${res.status} ${res.statusText} for ${url}`);
|
|
597270
|
-
}
|
|
597271
|
-
const out = createWriteStream(dest);
|
|
597272
|
-
await pipeline(Readable2.fromWeb(res.body), out);
|
|
597273
|
-
}
|
|
597274
|
-
async function extractArchive(archivePath, destDir, ext) {
|
|
597275
|
-
if (ext === "tar.gz" || ext === "tar.xz") {
|
|
597276
|
-
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
597277
|
-
} else if (ext === "zip") {
|
|
597278
|
-
try {
|
|
597279
|
-
await runCmd("tar", ["-xf", archivePath, "-C", destDir]);
|
|
597280
|
-
} catch {
|
|
597281
|
-
await runCmd("powershell", [
|
|
597282
|
-
"-Command",
|
|
597283
|
-
`Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force`
|
|
597284
|
-
]);
|
|
597285
|
-
}
|
|
597286
|
-
} else {
|
|
597287
|
-
throw new Error(`unsupported archive ext: ${ext}`);
|
|
597288
|
-
}
|
|
597289
|
-
}
|
|
597290
|
-
function runCmd(command, args) {
|
|
597291
|
-
return new Promise((resolve, reject) => {
|
|
597292
|
-
const proc = spawn23(command, args, { stdio: "ignore" });
|
|
597293
|
-
proc.on("error", (err) => reject(err));
|
|
597294
|
-
proc.on("close", (code) => {
|
|
597295
|
-
if (code === 0)
|
|
597296
|
-
resolve();
|
|
597297
|
-
else
|
|
597298
|
-
reject(new Error(`${command} ${args.join(" ")} exited ${code}`));
|
|
597299
|
-
});
|
|
597300
|
-
});
|
|
597301
|
-
}
|
|
597302
|
-
var init_installer = __esm(() => {
|
|
597303
|
-
init_node_runtime();
|
|
597304
|
-
});
|
|
597305
|
-
|
|
597306
|
-
// packages/runtime/contract-validator.ts
|
|
597307
|
-
var init_contract_validator = __esm(() => {
|
|
597308
|
-
init_types3();
|
|
597309
|
-
});
|
|
597310
|
-
|
|
597311
|
-
// packages/runtime/index.ts
|
|
597312
|
-
import { join as join181 } from "node:path";
|
|
597313
|
-
import { execFile as execFile9 } from "node:child_process";
|
|
597314
|
-
import { promisify as promisify7 } from "node:util";
|
|
597315
|
-
async function ensureNodeFor(minVersion) {
|
|
597316
|
-
try {
|
|
597317
|
-
const { stdout } = await execFileAsync5("node", ["--version"], {
|
|
597318
|
-
timeout: 3000
|
|
597319
|
-
});
|
|
597320
|
-
const parsed = parseNodeVersion(stdout);
|
|
597321
|
-
if (parsed && satisfiesMinVersion(parsed, minVersion)) {
|
|
597322
|
-
return null;
|
|
597323
|
-
}
|
|
597324
|
-
} catch {}
|
|
597325
|
-
const ready = await isRuntimeReady({
|
|
597326
|
-
version: MANAGED_NODE_VERSION,
|
|
597327
|
-
minVersion
|
|
597328
|
-
});
|
|
597329
|
-
const dir = getRuntimeDir({ version: MANAGED_NODE_VERSION });
|
|
597330
|
-
const binDir = process.platform === "win32" ? dir : join181(dir, "bin");
|
|
597331
|
-
if (ready)
|
|
597332
|
-
return binDir;
|
|
597333
|
-
const result = await installRuntime({
|
|
597334
|
-
version: MANAGED_NODE_VERSION,
|
|
597335
|
-
minVersion
|
|
597336
|
-
});
|
|
597337
|
-
if (result.action === "failed") {
|
|
597338
|
-
throw new Error(`failed to install Node ${MANAGED_NODE_VERSION}: ${result.error ?? "unknown"}`);
|
|
597339
|
-
}
|
|
597340
|
-
return binDir;
|
|
597341
|
-
}
|
|
597342
|
-
var execFileAsync5, MANAGED_NODE_VERSION = "22.14.0";
|
|
597343
|
-
var init_runtime = __esm(() => {
|
|
597344
|
-
init_installer();
|
|
597345
|
-
init_node_runtime();
|
|
597346
|
-
init_node_runtime();
|
|
597347
|
-
init_installer();
|
|
597348
|
-
init_contract_validator();
|
|
597349
|
-
execFileAsync5 = promisify7(execFile9);
|
|
597350
|
-
});
|
|
597351
|
-
|
|
597352
597914
|
// packages/goal/types.ts
|
|
597353
597915
|
var DEFAULT_BUDGET, SATISFIED_CONFIDENCE_FLOOR = 0.75;
|
|
597354
597916
|
var init_types5 = __esm(() => {
|
|
@@ -599212,7 +599774,7 @@ Nothing was changed. Type /update again to apply.`);
|
|
|
599212
599774
|
// apps/tui/src/lib/telegram-setup.ts
|
|
599213
599775
|
import {
|
|
599214
599776
|
chmodSync as chmodSync6,
|
|
599215
|
-
existsSync as
|
|
599777
|
+
existsSync as existsSync137,
|
|
599216
599778
|
lstatSync as lstatSync31,
|
|
599217
599779
|
mkdirSync as mkdirSync96,
|
|
599218
599780
|
readFileSync as readFileSync121,
|
|
@@ -599221,7 +599783,7 @@ import {
|
|
|
599221
599783
|
writeFileSync as writeFileSync76
|
|
599222
599784
|
} from "node:fs";
|
|
599223
599785
|
import { homedir as homedir95 } from "node:os";
|
|
599224
|
-
import { dirname as
|
|
599786
|
+
import { dirname as dirname84, join as join202 } from "node:path";
|
|
599225
599787
|
function redact3(text, key) {
|
|
599226
599788
|
let out = text;
|
|
599227
599789
|
if (key) {
|
|
@@ -599238,7 +599800,7 @@ function cleanLabel(raw, max = 40) {
|
|
|
599238
599800
|
}
|
|
599239
599801
|
function ensureEnvFile(file) {
|
|
599240
599802
|
const path = expand4(file);
|
|
599241
|
-
const dir =
|
|
599803
|
+
const dir = dirname84(path);
|
|
599242
599804
|
const notes = [];
|
|
599243
599805
|
const kind = (p) => {
|
|
599244
599806
|
try {
|
|
@@ -599332,9 +599894,9 @@ async function getSeenChats(key) {
|
|
|
599332
599894
|
return { chats: [...seen.values()] };
|
|
599333
599895
|
}
|
|
599334
599896
|
function mergeSettings(chatIds, envFile, tokenVar) {
|
|
599335
|
-
const path =
|
|
599897
|
+
const path = join202(homeDir4(), ".8gent", "settings.json");
|
|
599336
599898
|
let settings = {};
|
|
599337
|
-
if (
|
|
599899
|
+
if (existsSync137(path)) {
|
|
599338
599900
|
try {
|
|
599339
599901
|
const parsed = JSON.parse(readFileSync121(path, "utf8"));
|
|
599340
599902
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -599357,7 +599919,7 @@ function mergeSettings(chatIds, envFile, tokenVar) {
|
|
|
599357
599919
|
botEnvFile: envFile,
|
|
599358
599920
|
botTokenVar: tokenVar
|
|
599359
599921
|
};
|
|
599360
|
-
mkdirSync96(
|
|
599922
|
+
mkdirSync96(dirname84(path), { recursive: true });
|
|
599361
599923
|
const tmp = `${path}.tmp-${process.pid}`;
|
|
599362
599924
|
rmSync18(tmp, { force: true });
|
|
599363
599925
|
writeFileSync76(tmp, `${JSON.stringify(settings, null, 2)}
|
|
@@ -599367,7 +599929,7 @@ function mergeSettings(chatIds, envFile, tokenVar) {
|
|
|
599367
599929
|
}
|
|
599368
599930
|
function configured() {
|
|
599369
599931
|
try {
|
|
599370
|
-
const pm = JSON.parse(readFileSync121(
|
|
599932
|
+
const pm = JSON.parse(readFileSync121(join202(homeDir4(), ".8gent", "settings.json"), "utf8"))?.postMessage;
|
|
599371
599933
|
const file = typeof pm?.botEnvFile === "string" ? pm.botEnvFile : DEFAULT_ENV_FILE;
|
|
599372
599934
|
const name = typeof pm?.botTokenVar === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(pm.botTokenVar) ? pm.botTokenVar : DEFAULT_TOKEN_VAR;
|
|
599373
599935
|
return { file, name };
|
|
@@ -599442,7 +600004,7 @@ async function runTelegramSetup2(args) {
|
|
|
599442
600004
|
].join(`
|
|
599443
600005
|
`));
|
|
599444
600006
|
}
|
|
599445
|
-
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("~/") ?
|
|
600007
|
+
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("~/") ? join202(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.";
|
|
599446
600008
|
var init_telegram_setup = __esm(() => {
|
|
599447
600009
|
init_post_message();
|
|
599448
600010
|
BOT_TOKEN_RE2 = /(?:bot)?\d{6,}:[A-Za-z0-9_-]{20,}/g;
|
|
@@ -599701,11 +600263,11 @@ Personal 8gent mini-app. Iteration is driven by \`SKILL.md\`. Run tests with \`b
|
|
|
599701
600263
|
}
|
|
599702
600264
|
|
|
599703
600265
|
// packages/app-creator/creator.ts
|
|
599704
|
-
import { existsSync as
|
|
600266
|
+
import { existsSync as existsSync138, mkdirSync as mkdirSync98, writeFileSync as writeFileSync78 } from "node:fs";
|
|
599705
600267
|
import { homedir as homedir96 } from "node:os";
|
|
599706
|
-
import { dirname as
|
|
600268
|
+
import { dirname as dirname85, join as join204 } from "node:path";
|
|
599707
600269
|
function defaultAppsRoot() {
|
|
599708
|
-
return
|
|
600270
|
+
return join204(homedir96(), ".8gent", "apps");
|
|
599709
600271
|
}
|
|
599710
600272
|
function buildManifest2(input) {
|
|
599711
600273
|
const slug = slugify3(input.name);
|
|
@@ -599739,7 +600301,7 @@ function draftApp(input) {
|
|
|
599739
600301
|
};
|
|
599740
600302
|
}
|
|
599741
600303
|
const m = built.manifest;
|
|
599742
|
-
const dir =
|
|
600304
|
+
const dir = join204(root, m.name);
|
|
599743
600305
|
const files = {
|
|
599744
600306
|
"manifest.json": `${JSON.stringify(m, null, 2)}
|
|
599745
600307
|
`,
|
|
@@ -599759,7 +600321,7 @@ function createApp(input) {
|
|
|
599759
600321
|
return { ...draft, persisted: false, written: [] };
|
|
599760
600322
|
}
|
|
599761
600323
|
const dir = draft.dir;
|
|
599762
|
-
const targetExists =
|
|
600324
|
+
const targetExists = existsSync138(dir);
|
|
599763
600325
|
if (targetExists && !input.allowOverwrite) {
|
|
599764
600326
|
return {
|
|
599765
600327
|
...draft,
|
|
@@ -599770,11 +600332,11 @@ function createApp(input) {
|
|
|
599770
600332
|
]
|
|
599771
600333
|
};
|
|
599772
600334
|
}
|
|
599773
|
-
mkdirSync98(
|
|
600335
|
+
mkdirSync98(join204(dir, "tests"), { recursive: true });
|
|
599774
600336
|
const written = [];
|
|
599775
600337
|
for (const [rel, contents] of Object.entries(draft.files)) {
|
|
599776
|
-
const full =
|
|
599777
|
-
mkdirSync98(
|
|
600338
|
+
const full = join204(dir, rel);
|
|
600339
|
+
mkdirSync98(dirname85(full), { recursive: true });
|
|
599778
600340
|
writeFileSync78(full, contents);
|
|
599779
600341
|
written.push(full);
|
|
599780
600342
|
}
|
|
@@ -600606,8 +601168,8 @@ var init_producer = __esm(() => {
|
|
|
600606
601168
|
});
|
|
600607
601169
|
|
|
600608
601170
|
// packages/pet/companion.ts
|
|
600609
|
-
import { existsSync as
|
|
600610
|
-
import { join as
|
|
601171
|
+
import { existsSync as existsSync142, mkdirSync as mkdirSync104, readFileSync as readFileSync123, writeFileSync as writeFileSync80 } from "node:fs";
|
|
601172
|
+
import { join as join206 } from "node:path";
|
|
600611
601173
|
function seedRng(seed) {
|
|
600612
601174
|
let h = 0;
|
|
600613
601175
|
for (let i = 0;i < seed.length; i++) {
|
|
@@ -600745,12 +601307,12 @@ function generateCompanion(sessionId) {
|
|
|
600745
601307
|
}
|
|
600746
601308
|
function getDeckPath() {
|
|
600747
601309
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
600748
|
-
return
|
|
601310
|
+
return join206(home, ".8gent", "companion-deck.json");
|
|
600749
601311
|
}
|
|
600750
601312
|
function loadDeck() {
|
|
600751
601313
|
const deckPath = getDeckPath();
|
|
600752
601314
|
try {
|
|
600753
|
-
if (
|
|
601315
|
+
if (existsSync142(deckPath)) {
|
|
600754
601316
|
return JSON.parse(readFileSync123(deckPath, "utf-8"));
|
|
600755
601317
|
}
|
|
600756
601318
|
} catch {}
|
|
@@ -601194,7 +601756,7 @@ var init_companion = __esm(() => {
|
|
|
601194
601756
|
// packages/orchestration/adaptive-pipeline.ts
|
|
601195
601757
|
import { spawn as spawn26 } from "node:child_process";
|
|
601196
601758
|
import { homedir as homedir97 } from "node:os";
|
|
601197
|
-
import { join as
|
|
601759
|
+
import { join as join207 } from "node:path";
|
|
601198
601760
|
|
|
601199
601761
|
class Obstacle {
|
|
601200
601762
|
type;
|
|
@@ -601683,7 +602245,7 @@ var init_adaptive_pipeline = __esm(() => {
|
|
|
601683
602245
|
init_role_config();
|
|
601684
602246
|
OLLAMA_URL2 = process.env.OLLAMA_BASE_URL || "http://localhost:11434";
|
|
601685
602247
|
LMSTUDIO_URL2 = process.env.LMSTUDIO_BASE_URL || "http://localhost:1234/v1";
|
|
601686
|
-
BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE ||
|
|
602248
|
+
BRIDGE_PATH2 = process.env.APPLE_FOUNDATION_BRIDGE || join207(homedir97(), ".8gent", "bin", "apple-foundation-bridge");
|
|
601687
602249
|
((Severity) => {
|
|
601688
602250
|
Severity[Severity["Trivial"] = 1] = "Trivial";
|
|
601689
602251
|
Severity[Severity["Moderate"] = 2] = "Moderate";
|
|
@@ -611562,7 +612124,7 @@ init_local_model_server();
|
|
|
611562
612124
|
init_sequential_pipeline();
|
|
611563
612125
|
init_speak();
|
|
611564
612126
|
var import_react104 = __toESM(require_react(), 1);
|
|
611565
|
-
var
|
|
612127
|
+
var import_package2 = __toESM(require_package(), 1);
|
|
611566
612128
|
|
|
611567
612129
|
// apps/tui/src/components/ActivityMonitor.tsx
|
|
611568
612130
|
var import_react31 = __toESM(require_react(), 1);
|
|
@@ -622006,234 +622568,6 @@ function useImageInput(options = {}) {
|
|
|
622006
622568
|
// apps/tui/src/components/message-list.tsx
|
|
622007
622569
|
var import_react63 = __toESM(require_react(), 1);
|
|
622008
622570
|
|
|
622009
|
-
// apps/tui/src/lib/chat-layout.ts
|
|
622010
|
-
var SHELL_CHROME = 4;
|
|
622011
|
-
var COLUMN_GAP = 1;
|
|
622012
|
-
var ACTIVITY_RAIL_WIDTH = 34;
|
|
622013
|
-
function chatColumnWidth(cols, shell, min = 24) {
|
|
622014
|
-
let width = cols - SHELL_CHROME;
|
|
622015
|
-
if (shell.planWidth && shell.planWidth > 0)
|
|
622016
|
-
width -= shell.planWidth + COLUMN_GAP;
|
|
622017
|
-
if (shell.activity)
|
|
622018
|
-
width -= ACTIVITY_RAIL_WIDTH + COLUMN_GAP;
|
|
622019
|
-
return Math.max(min, width);
|
|
622020
|
-
}
|
|
622021
|
-
var USER_BUBBLE_SHARE = 0.78;
|
|
622022
|
-
function bubbleWidths(contentWidth, role) {
|
|
622023
|
-
const inner = Math.max(16, contentWidth - 2);
|
|
622024
|
-
const bubble = role === "user" ? Math.max(16, Math.floor(inner * USER_BUBBLE_SHARE)) : inner;
|
|
622025
|
-
return { bubble, wrap: Math.max(8, bubble - 2) };
|
|
622026
|
-
}
|
|
622027
|
-
|
|
622028
|
-
// apps/tui/src/lib/tool-trail.ts
|
|
622029
|
-
var COLLAPSE_THRESHOLD = 8;
|
|
622030
|
-
var MAX_TRAIL_ROWS = 12;
|
|
622031
|
-
var PATH_KEYS = ["path", "file_path", "filePath", "file", "directory", "dir"];
|
|
622032
|
-
var COMMAND_KEYS = ["command", "cmd"];
|
|
622033
|
-
var QUERY_KEYS = ["query", "pattern", "q", "search", "url"];
|
|
622034
|
-
function oneLine(s) {
|
|
622035
|
-
return s.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
622036
|
-
}
|
|
622037
|
-
function pick3(args, keys) {
|
|
622038
|
-
for (const k of keys) {
|
|
622039
|
-
const v = args[k];
|
|
622040
|
-
if (typeof v === "string" && v.trim())
|
|
622041
|
-
return oneLine(v);
|
|
622042
|
-
}
|
|
622043
|
-
return null;
|
|
622044
|
-
}
|
|
622045
|
-
function summarizeToolArgs(tool, args) {
|
|
622046
|
-
if (!args || typeof args !== "object")
|
|
622047
|
-
return "";
|
|
622048
|
-
const isCommand = /command|shell|exec|bash/.test(tool);
|
|
622049
|
-
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];
|
|
622050
|
-
for (const keys of order) {
|
|
622051
|
-
const hit = pick3(args, keys);
|
|
622052
|
-
if (hit)
|
|
622053
|
-
return hit;
|
|
622054
|
-
}
|
|
622055
|
-
for (const v of Object.values(args)) {
|
|
622056
|
-
if (typeof v === "string" && v.trim())
|
|
622057
|
-
return oneLine(v);
|
|
622058
|
-
}
|
|
622059
|
-
return "";
|
|
622060
|
-
}
|
|
622061
|
-
var GATE_PREFIX = /^\s*\[([A-Z0-9_ -]*\b(?:BLOCKED|DENIED)\b[A-Z0-9_ -]*)\]/;
|
|
622062
|
-
var OTHER_BLOCK = /^\s*(?:Path blocked by path-guard|Path traversal blocked)|Hook blocked tool/;
|
|
622063
|
-
var RULE_NAME = /\[([a-z0-9]+(?:-[a-z0-9]+)+)\]/;
|
|
622064
|
-
function classifyToolResult(success, preview) {
|
|
622065
|
-
const text = preview ?? "";
|
|
622066
|
-
const gate = text.match(GATE_PREFIX);
|
|
622067
|
-
if (gate || OTHER_BLOCK.test(text)) {
|
|
622068
|
-
if (gate && /DENIED/.test(gate[1]))
|
|
622069
|
-
return { status: "blocked", reason: "denied" };
|
|
622070
|
-
const rule = text.match(RULE_NAME);
|
|
622071
|
-
return { status: "blocked", reason: rule ? `blocked: [${rule[1]}]` : "blocked" };
|
|
622072
|
-
}
|
|
622073
|
-
const exit = text.match(/^\s*Exit code (-?\d+)/);
|
|
622074
|
-
if (exit && exit[1] !== "0")
|
|
622075
|
-
return { status: "fail", reason: `exit ${exit[1]}` };
|
|
622076
|
-
if (!success || /^\s*(?:Error\b|Unknown tool:)/.test(text)) {
|
|
622077
|
-
const first = (text.split(`
|
|
622078
|
-
`).find((l) => l.trim()) ?? "").replace(/^\s*Error(?: running tool "[^"]*")?:?\s*/, "").trim();
|
|
622079
|
-
if (!first)
|
|
622080
|
-
return { status: "fail", reason: "error" };
|
|
622081
|
-
return { status: "fail", reason: first.length > 40 ? `${first.slice(0, 39)}…` : first };
|
|
622082
|
-
}
|
|
622083
|
-
return { status: "ok" };
|
|
622084
|
-
}
|
|
622085
|
-
function toTrailEntry(event) {
|
|
622086
|
-
const { status, reason } = classifyToolResult(event.success !== false, event.resultPreview);
|
|
622087
|
-
const entry = {
|
|
622088
|
-
tool: event.toolName,
|
|
622089
|
-
summary: summarizeToolArgs(event.toolName, event.args),
|
|
622090
|
-
status
|
|
622091
|
-
};
|
|
622092
|
-
if (reason)
|
|
622093
|
-
entry.reason = reason;
|
|
622094
|
-
if (event.toolName === "update_plan") {
|
|
622095
|
-
const items = event.args?.plan;
|
|
622096
|
-
if (Array.isArray(items)) {
|
|
622097
|
-
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" }));
|
|
622098
|
-
if (plan.length > 0)
|
|
622099
|
-
entry.plan = plan;
|
|
622100
|
-
}
|
|
622101
|
-
}
|
|
622102
|
-
return entry;
|
|
622103
|
-
}
|
|
622104
|
-
function isReadTool(tool) {
|
|
622105
|
-
return /^(?:read_|list_|get_|search|grep|glob|find|view|web_search|web_fetch)/.test(tool);
|
|
622106
|
-
}
|
|
622107
|
-
function commonDir(paths) {
|
|
622108
|
-
const split = paths.map((p) => p.split("/").slice(0, -1));
|
|
622109
|
-
const first = split[0] ?? [];
|
|
622110
|
-
let n = 0;
|
|
622111
|
-
while (n < first.length && split.every((s) => s[n] === first[n]))
|
|
622112
|
-
n++;
|
|
622113
|
-
return n > 0 ? `${first.slice(0, n).join("/")}/` : "";
|
|
622114
|
-
}
|
|
622115
|
-
function collapseTrail(entries, maxRows = MAX_TRAIL_ROWS) {
|
|
622116
|
-
let rows = entries.map((e) => ({ ...e, count: 1 }));
|
|
622117
|
-
if (entries.length > COLLAPSE_THRESHOLD) {
|
|
622118
|
-
const out = [];
|
|
622119
|
-
for (let i = 0;i < entries.length; ) {
|
|
622120
|
-
const e = entries[i];
|
|
622121
|
-
let j = i + 1;
|
|
622122
|
-
if (e.status === "ok" && isReadTool(e.tool)) {
|
|
622123
|
-
while (j < entries.length && entries[j].tool === e.tool && entries[j].status === "ok")
|
|
622124
|
-
j++;
|
|
622125
|
-
}
|
|
622126
|
-
if (j - i > 1) {
|
|
622127
|
-
const run = entries.slice(i, j);
|
|
622128
|
-
out.push({
|
|
622129
|
-
tool: e.tool,
|
|
622130
|
-
status: "ok",
|
|
622131
|
-
count: run.length,
|
|
622132
|
-
summary: commonDir(run.map((r) => r.summary))
|
|
622133
|
-
});
|
|
622134
|
-
} else {
|
|
622135
|
-
out.push({ ...e, count: 1 });
|
|
622136
|
-
}
|
|
622137
|
-
i = j;
|
|
622138
|
-
}
|
|
622139
|
-
rows = out;
|
|
622140
|
-
}
|
|
622141
|
-
const cap = Math.max(1, Math.floor(maxRows));
|
|
622142
|
-
if (rows.length > cap) {
|
|
622143
|
-
let toFold = rows.length - cap + 1;
|
|
622144
|
-
const fold = new Set;
|
|
622145
|
-
for (const wantOk of [true, false]) {
|
|
622146
|
-
for (let i = 0;i < rows.length && toFold > 0; i++) {
|
|
622147
|
-
if (fold.has(i) || wantOk && rows[i].status !== "ok")
|
|
622148
|
-
continue;
|
|
622149
|
-
fold.add(i);
|
|
622150
|
-
toFold--;
|
|
622151
|
-
}
|
|
622152
|
-
}
|
|
622153
|
-
const folded = rows.filter((_, i) => fold.has(i));
|
|
622154
|
-
const count = (s) => folded.filter((r) => r.status === s).reduce((n, r) => n + r.count, 0);
|
|
622155
|
-
const failed = count("fail");
|
|
622156
|
-
const blocked = count("blocked");
|
|
622157
|
-
const summary = {
|
|
622158
|
-
tool: "",
|
|
622159
|
-
summary: "",
|
|
622160
|
-
status: failed > 0 ? "fail" : blocked > 0 ? "blocked" : "ok",
|
|
622161
|
-
count: folded.reduce((n, r) => n + r.count, 0),
|
|
622162
|
-
folded: true,
|
|
622163
|
-
all: fold.size === rows.length
|
|
622164
|
-
};
|
|
622165
|
-
if (failed > 0)
|
|
622166
|
-
summary.failed = failed;
|
|
622167
|
-
if (blocked > 0)
|
|
622168
|
-
summary.blocked = blocked;
|
|
622169
|
-
rows = [summary, ...rows.filter((_, i) => !fold.has(i))];
|
|
622170
|
-
}
|
|
622171
|
-
return rows;
|
|
622172
|
-
}
|
|
622173
|
-
var ICONS = { ok: "✓", fail: "✗", blocked: "⊘" };
|
|
622174
|
-
function formatTrailRow(row, width) {
|
|
622175
|
-
const icon = ICONS[row.status];
|
|
622176
|
-
const budget = Math.max(1, width - icon.length - 1);
|
|
622177
|
-
if (row.folded) {
|
|
622178
|
-
const parts = [`${row.count} ${row.all ? "calls" : "earlier calls"}`];
|
|
622179
|
-
if (row.failed)
|
|
622180
|
-
parts.push(`${row.failed} failed`);
|
|
622181
|
-
if (row.blocked)
|
|
622182
|
-
parts.push(`${row.blocked} blocked`);
|
|
622183
|
-
return { icon, text: clip(parts.join(", "), budget) };
|
|
622184
|
-
}
|
|
622185
|
-
const head = row.count > 1 ? `${row.tool} ×${row.count}` : row.tool;
|
|
622186
|
-
const tail = row.reason ? ` (${row.reason})` : "";
|
|
622187
|
-
let summary = row.count > 1 ? row.summary ? `(${row.summary}…)` : "" : row.summary;
|
|
622188
|
-
if (!summary)
|
|
622189
|
-
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
622190
|
-
const room = budget - head.length - 1 - tail.length;
|
|
622191
|
-
if (room < 4)
|
|
622192
|
-
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
622193
|
-
if (summary.length > room)
|
|
622194
|
-
summary = `${summary.slice(0, room - 1)}…`;
|
|
622195
|
-
return { icon, text: `${head} ${summary}${tail}` };
|
|
622196
|
-
}
|
|
622197
|
-
function clip(s, width) {
|
|
622198
|
-
return s.length <= width ? s : `${s.slice(0, Math.max(0, width - 1))}…`;
|
|
622199
|
-
}
|
|
622200
|
-
function buildChatItems(messages) {
|
|
622201
|
-
const items = [];
|
|
622202
|
-
let pending = [];
|
|
622203
|
-
let pendingFirst = null;
|
|
622204
|
-
const flush = () => {
|
|
622205
|
-
if (pending.length > 0 && pendingFirst) {
|
|
622206
|
-
items.push({
|
|
622207
|
-
message: { ...pendingFirst, id: `trail-${pendingFirst.id}`, role: "tool", content: "" },
|
|
622208
|
-
trail: pending
|
|
622209
|
-
});
|
|
622210
|
-
}
|
|
622211
|
-
pending = [];
|
|
622212
|
-
pendingFirst = null;
|
|
622213
|
-
};
|
|
622214
|
-
for (const m of messages) {
|
|
622215
|
-
if (m.role === "tool") {
|
|
622216
|
-
if (m.toolTrail) {
|
|
622217
|
-
if (!pendingFirst)
|
|
622218
|
-
pendingFirst = m;
|
|
622219
|
-
pending.push(m.toolTrail);
|
|
622220
|
-
}
|
|
622221
|
-
continue;
|
|
622222
|
-
}
|
|
622223
|
-
if (m.role === "assistant") {
|
|
622224
|
-
items.push({ message: m, trail: pending });
|
|
622225
|
-
pending = [];
|
|
622226
|
-
pendingFirst = null;
|
|
622227
|
-
continue;
|
|
622228
|
-
}
|
|
622229
|
-
if (m.role === "user")
|
|
622230
|
-
flush();
|
|
622231
|
-
items.push({ message: m, trail: [] });
|
|
622232
|
-
}
|
|
622233
|
-
flush();
|
|
622234
|
-
return items;
|
|
622235
|
-
}
|
|
622236
|
-
|
|
622237
622571
|
// apps/tui/src/hooks/useMouseScroll.ts
|
|
622238
622572
|
var import_react57 = __toESM(require_react(), 1);
|
|
622239
622573
|
function useMouseScroll({
|
|
@@ -622259,111 +622593,25 @@ function useMouseScroll({
|
|
|
622259
622593
|
}, [enabled, step]);
|
|
622260
622594
|
}
|
|
622261
622595
|
|
|
622262
|
-
// apps/tui/src/
|
|
622263
|
-
var
|
|
622264
|
-
var
|
|
622265
|
-
|
|
622266
|
-
|
|
622267
|
-
|
|
622268
|
-
|
|
622269
|
-
|
|
622270
|
-
|
|
622271
|
-
|
|
622272
|
-
|
|
622273
|
-
import_react58.useEffect(() => {
|
|
622274
|
-
if (!started)
|
|
622275
|
-
return;
|
|
622276
|
-
const timeout = setTimeout(() => {
|
|
622277
|
-
onComplete?.();
|
|
622278
|
-
}, duration);
|
|
622279
|
-
return () => clearTimeout(timeout);
|
|
622280
|
-
}, [started, duration, onComplete]);
|
|
622281
|
-
if (!started)
|
|
622282
|
-
return null;
|
|
622283
|
-
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
|
|
622284
|
-
children
|
|
622285
|
-
}, undefined, false, undefined, this);
|
|
622286
|
-
}
|
|
622287
|
-
|
|
622288
|
-
// apps/tui/src/components/ToolTrail.tsx
|
|
622289
|
-
var import_react59 = __toESM(require_react(), 1);
|
|
622290
|
-
var jsx_dev_runtime31 = __toESM(require_jsx_dev_runtime(), 1);
|
|
622291
|
-
function iconColor(status) {
|
|
622292
|
-
return status === "ok" ? t.green : status === "fail" ? t.red : t.orange;
|
|
622293
|
-
}
|
|
622294
|
-
function useLandingRows(total, animate) {
|
|
622295
|
-
const [shown, setShown] = import_react59.useState(total);
|
|
622296
|
-
const shownRef = import_react59.useRef(total);
|
|
622297
|
-
shownRef.current = shown;
|
|
622298
|
-
const landingRef = import_react59.useRef(null);
|
|
622299
|
-
import_react59.useEffect(() => {
|
|
622300
|
-
const from = shownRef.current;
|
|
622301
|
-
if (total <= from + 1 || !motionEnabled(animate)) {
|
|
622302
|
-
landingRef.current = null;
|
|
622303
|
-
setShown(total);
|
|
622304
|
-
return;
|
|
622305
|
-
}
|
|
622306
|
-
landingRef.current = total;
|
|
622307
|
-
const step = staggerFor(total - from);
|
|
622308
|
-
let n = from + 1;
|
|
622309
|
-
setShown(n);
|
|
622310
|
-
const id = setInterval(() => {
|
|
622311
|
-
n += 1;
|
|
622312
|
-
setShown(Math.min(total, n));
|
|
622313
|
-
if (n >= total) {
|
|
622314
|
-
landingRef.current = null;
|
|
622315
|
-
clearInterval(id);
|
|
622316
|
-
}
|
|
622317
|
-
}, step);
|
|
622318
|
-
return () => clearInterval(id);
|
|
622319
|
-
}, [total, animate]);
|
|
622320
|
-
if (landingRef.current === total)
|
|
622321
|
-
return Math.min(shown, total);
|
|
622322
|
-
if (total <= shown + 1)
|
|
622323
|
-
return total;
|
|
622324
|
-
return shown;
|
|
622325
|
-
}
|
|
622326
|
-
function ToolTrail({
|
|
622327
|
-
entries,
|
|
622328
|
-
width,
|
|
622329
|
-
maxRows,
|
|
622330
|
-
animate = true
|
|
622331
|
-
}) {
|
|
622332
|
-
const rows = collapseTrail(entries, maxRows);
|
|
622333
|
-
const visible = useLandingRows(rows.length, animate);
|
|
622334
|
-
if (rows.length === 0)
|
|
622335
|
-
return null;
|
|
622336
|
-
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
622337
|
-
flexDirection: "column",
|
|
622338
|
-
flexShrink: 0,
|
|
622339
|
-
children: rows.slice(0, visible).map((row, i) => {
|
|
622340
|
-
const { text } = formatTrailRow(row, width);
|
|
622341
|
-
const g = glyphs();
|
|
622342
|
-
const icon = row.status === "ok" ? g.ok : row.status === "fail" ? g.fail : g.blocked;
|
|
622343
|
-
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
622344
|
-
width,
|
|
622345
|
-
children: [
|
|
622346
|
-
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
622347
|
-
color: iconColor(row.status),
|
|
622348
|
-
children: icon
|
|
622349
|
-
}, undefined, false, undefined, this),
|
|
622350
|
-
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
622351
|
-
color: row.status === "ok" ? t.muted : t.textPrimary,
|
|
622352
|
-
wrap: "truncate-end",
|
|
622353
|
-
children: ` ${text}`
|
|
622354
|
-
}, undefined, false, undefined, this)
|
|
622355
|
-
]
|
|
622356
|
-
}, i, true, undefined, this);
|
|
622357
|
-
})
|
|
622358
|
-
}, undefined, false, undefined, this);
|
|
622596
|
+
// apps/tui/src/lib/chat-layout.ts
|
|
622597
|
+
var SHELL_CHROME = 4;
|
|
622598
|
+
var COLUMN_GAP = 1;
|
|
622599
|
+
var ACTIVITY_RAIL_WIDTH = 34;
|
|
622600
|
+
function chatColumnWidth(cols, shell, min = 24) {
|
|
622601
|
+
let width = cols - SHELL_CHROME;
|
|
622602
|
+
if (shell.planWidth && shell.planWidth > 0)
|
|
622603
|
+
width -= shell.planWidth + COLUMN_GAP;
|
|
622604
|
+
if (shell.activity)
|
|
622605
|
+
width -= ACTIVITY_RAIL_WIDTH + COLUMN_GAP;
|
|
622606
|
+
return Math.max(min, width);
|
|
622359
622607
|
}
|
|
622360
|
-
|
|
622361
|
-
|
|
622608
|
+
var USER_BUBBLE_SHARE = 0.78;
|
|
622609
|
+
function bubbleWidths(contentWidth, role) {
|
|
622610
|
+
const inner = Math.max(16, contentWidth - 2);
|
|
622611
|
+
const bubble = role === "user" ? Math.max(16, Math.floor(inner * USER_BUBBLE_SHARE)) : inner;
|
|
622612
|
+
return { bubble, wrap: Math.max(8, bubble - 2) };
|
|
622362
622613
|
}
|
|
622363
622614
|
|
|
622364
|
-
// apps/tui/src/components/TurnResults.tsx
|
|
622365
|
-
var import_react60 = __toESM(require_react(), 1);
|
|
622366
|
-
|
|
622367
622615
|
// apps/tui/src/lib/inline-markdown.ts
|
|
622368
622616
|
var MAX_DEPTH3 = 3;
|
|
622369
622617
|
var INDENT_STEP = 2;
|
|
@@ -622678,6 +622926,215 @@ function blockRows(block, width) {
|
|
|
622678
622926
|
}
|
|
622679
622927
|
}
|
|
622680
622928
|
|
|
622929
|
+
// apps/tui/src/lib/tool-trail.ts
|
|
622930
|
+
var COLLAPSE_THRESHOLD = 8;
|
|
622931
|
+
var MAX_TRAIL_ROWS = 12;
|
|
622932
|
+
var PATH_KEYS = ["path", "file_path", "filePath", "file", "directory", "dir"];
|
|
622933
|
+
var COMMAND_KEYS = ["command", "cmd"];
|
|
622934
|
+
var QUERY_KEYS = ["query", "pattern", "q", "search", "url"];
|
|
622935
|
+
function oneLine(s) {
|
|
622936
|
+
return s.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
622937
|
+
}
|
|
622938
|
+
function pick3(args, keys) {
|
|
622939
|
+
for (const k of keys) {
|
|
622940
|
+
const v = args[k];
|
|
622941
|
+
if (typeof v === "string" && v.trim())
|
|
622942
|
+
return oneLine(v);
|
|
622943
|
+
}
|
|
622944
|
+
return null;
|
|
622945
|
+
}
|
|
622946
|
+
function summarizeToolArgs(tool, args) {
|
|
622947
|
+
if (!args || typeof args !== "object")
|
|
622948
|
+
return "";
|
|
622949
|
+
const isCommand = /command|shell|exec|bash/.test(tool);
|
|
622950
|
+
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];
|
|
622951
|
+
for (const keys of order) {
|
|
622952
|
+
const hit = pick3(args, keys);
|
|
622953
|
+
if (hit)
|
|
622954
|
+
return hit;
|
|
622955
|
+
}
|
|
622956
|
+
for (const v of Object.values(args)) {
|
|
622957
|
+
if (typeof v === "string" && v.trim())
|
|
622958
|
+
return oneLine(v);
|
|
622959
|
+
}
|
|
622960
|
+
return "";
|
|
622961
|
+
}
|
|
622962
|
+
var GATE_PREFIX = /^\s*\[([A-Z0-9_ -]*\b(?:BLOCKED|DENIED)\b[A-Z0-9_ -]*)\]/;
|
|
622963
|
+
var OTHER_BLOCK = /^\s*(?:Path blocked by path-guard|Path traversal blocked)|Hook blocked tool/;
|
|
622964
|
+
var RULE_NAME = /\[([a-z0-9]+(?:-[a-z0-9]+)+)\]/;
|
|
622965
|
+
function classifyToolResult(success, preview) {
|
|
622966
|
+
const text = preview ?? "";
|
|
622967
|
+
const gate = text.match(GATE_PREFIX);
|
|
622968
|
+
if (gate || OTHER_BLOCK.test(text)) {
|
|
622969
|
+
if (gate && /DENIED/.test(gate[1]))
|
|
622970
|
+
return { status: "blocked", reason: "denied" };
|
|
622971
|
+
const rule = text.match(RULE_NAME);
|
|
622972
|
+
return { status: "blocked", reason: rule ? `blocked: [${rule[1]}]` : "blocked" };
|
|
622973
|
+
}
|
|
622974
|
+
const exit = text.match(/^\s*Exit code (-?\d+)/);
|
|
622975
|
+
if (exit && exit[1] !== "0")
|
|
622976
|
+
return { status: "fail", reason: `exit ${exit[1]}` };
|
|
622977
|
+
if (!success || /^\s*(?:Error\b|Unknown tool:)/.test(text)) {
|
|
622978
|
+
const first = (text.split(`
|
|
622979
|
+
`).find((l) => l.trim()) ?? "").replace(/^\s*Error(?: running tool "[^"]*")?:?\s*/, "").trim();
|
|
622980
|
+
if (!first)
|
|
622981
|
+
return { status: "fail", reason: "error" };
|
|
622982
|
+
return { status: "fail", reason: first.length > 40 ? `${first.slice(0, 39)}…` : first };
|
|
622983
|
+
}
|
|
622984
|
+
return { status: "ok" };
|
|
622985
|
+
}
|
|
622986
|
+
function toTrailEntry(event) {
|
|
622987
|
+
const { status, reason } = classifyToolResult(event.success !== false, event.resultPreview);
|
|
622988
|
+
const entry = {
|
|
622989
|
+
tool: event.toolName,
|
|
622990
|
+
summary: summarizeToolArgs(event.toolName, event.args),
|
|
622991
|
+
status
|
|
622992
|
+
};
|
|
622993
|
+
if (reason)
|
|
622994
|
+
entry.reason = reason;
|
|
622995
|
+
if (event.toolName === "update_plan") {
|
|
622996
|
+
const items = event.args?.plan;
|
|
622997
|
+
if (Array.isArray(items)) {
|
|
622998
|
+
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" }));
|
|
622999
|
+
if (plan.length > 0)
|
|
623000
|
+
entry.plan = plan;
|
|
623001
|
+
}
|
|
623002
|
+
}
|
|
623003
|
+
return entry;
|
|
623004
|
+
}
|
|
623005
|
+
function isReadTool(tool) {
|
|
623006
|
+
return /^(?:read_|list_|get_|search|grep|glob|find|view|web_search|web_fetch)/.test(tool);
|
|
623007
|
+
}
|
|
623008
|
+
function commonDir(paths) {
|
|
623009
|
+
const split = paths.map((p) => p.split("/").slice(0, -1));
|
|
623010
|
+
const first = split[0] ?? [];
|
|
623011
|
+
let n = 0;
|
|
623012
|
+
while (n < first.length && split.every((s) => s[n] === first[n]))
|
|
623013
|
+
n++;
|
|
623014
|
+
return n > 0 ? `${first.slice(0, n).join("/")}/` : "";
|
|
623015
|
+
}
|
|
623016
|
+
function collapseTrail(entries, maxRows = MAX_TRAIL_ROWS) {
|
|
623017
|
+
let rows = entries.map((e) => ({ ...e, count: 1 }));
|
|
623018
|
+
if (entries.length > COLLAPSE_THRESHOLD) {
|
|
623019
|
+
const out = [];
|
|
623020
|
+
for (let i = 0;i < entries.length; ) {
|
|
623021
|
+
const e = entries[i];
|
|
623022
|
+
let j = i + 1;
|
|
623023
|
+
if (e.status === "ok" && isReadTool(e.tool)) {
|
|
623024
|
+
while (j < entries.length && entries[j].tool === e.tool && entries[j].status === "ok")
|
|
623025
|
+
j++;
|
|
623026
|
+
}
|
|
623027
|
+
if (j - i > 1) {
|
|
623028
|
+
const run = entries.slice(i, j);
|
|
623029
|
+
out.push({
|
|
623030
|
+
tool: e.tool,
|
|
623031
|
+
status: "ok",
|
|
623032
|
+
count: run.length,
|
|
623033
|
+
summary: commonDir(run.map((r) => r.summary))
|
|
623034
|
+
});
|
|
623035
|
+
} else {
|
|
623036
|
+
out.push({ ...e, count: 1 });
|
|
623037
|
+
}
|
|
623038
|
+
i = j;
|
|
623039
|
+
}
|
|
623040
|
+
rows = out;
|
|
623041
|
+
}
|
|
623042
|
+
const cap = Math.max(1, Math.floor(maxRows));
|
|
623043
|
+
if (rows.length > cap) {
|
|
623044
|
+
let toFold = rows.length - cap + 1;
|
|
623045
|
+
const fold = new Set;
|
|
623046
|
+
for (const wantOk of [true, false]) {
|
|
623047
|
+
for (let i = 0;i < rows.length && toFold > 0; i++) {
|
|
623048
|
+
if (fold.has(i) || wantOk && rows[i].status !== "ok")
|
|
623049
|
+
continue;
|
|
623050
|
+
fold.add(i);
|
|
623051
|
+
toFold--;
|
|
623052
|
+
}
|
|
623053
|
+
}
|
|
623054
|
+
const folded = rows.filter((_, i) => fold.has(i));
|
|
623055
|
+
const count = (s) => folded.filter((r) => r.status === s).reduce((n, r) => n + r.count, 0);
|
|
623056
|
+
const failed = count("fail");
|
|
623057
|
+
const blocked = count("blocked");
|
|
623058
|
+
const summary = {
|
|
623059
|
+
tool: "",
|
|
623060
|
+
summary: "",
|
|
623061
|
+
status: failed > 0 ? "fail" : blocked > 0 ? "blocked" : "ok",
|
|
623062
|
+
count: folded.reduce((n, r) => n + r.count, 0),
|
|
623063
|
+
folded: true,
|
|
623064
|
+
all: fold.size === rows.length
|
|
623065
|
+
};
|
|
623066
|
+
if (failed > 0)
|
|
623067
|
+
summary.failed = failed;
|
|
623068
|
+
if (blocked > 0)
|
|
623069
|
+
summary.blocked = blocked;
|
|
623070
|
+
rows = [summary, ...rows.filter((_, i) => !fold.has(i))];
|
|
623071
|
+
}
|
|
623072
|
+
return rows;
|
|
623073
|
+
}
|
|
623074
|
+
var ICONS = { ok: "✓", fail: "✗", blocked: "⊘" };
|
|
623075
|
+
function formatTrailRow(row, width) {
|
|
623076
|
+
const icon = ICONS[row.status];
|
|
623077
|
+
const budget = Math.max(1, width - icon.length - 1);
|
|
623078
|
+
if (row.folded) {
|
|
623079
|
+
const parts = [`${row.count} ${row.all ? "calls" : "earlier calls"}`];
|
|
623080
|
+
if (row.failed)
|
|
623081
|
+
parts.push(`${row.failed} failed`);
|
|
623082
|
+
if (row.blocked)
|
|
623083
|
+
parts.push(`${row.blocked} blocked`);
|
|
623084
|
+
return { icon, text: clip(parts.join(", "), budget) };
|
|
623085
|
+
}
|
|
623086
|
+
const head = row.count > 1 ? `${row.tool} ×${row.count}` : row.tool;
|
|
623087
|
+
const tail = row.reason ? ` (${row.reason})` : "";
|
|
623088
|
+
let summary = row.count > 1 ? row.summary ? `(${row.summary}…)` : "" : row.summary;
|
|
623089
|
+
if (!summary)
|
|
623090
|
+
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
623091
|
+
const room = budget - head.length - 1 - tail.length;
|
|
623092
|
+
if (room < 4)
|
|
623093
|
+
return { icon, text: clip(`${head}${tail}`, budget) };
|
|
623094
|
+
if (summary.length > room)
|
|
623095
|
+
summary = `${summary.slice(0, room - 1)}…`;
|
|
623096
|
+
return { icon, text: `${head} ${summary}${tail}` };
|
|
623097
|
+
}
|
|
623098
|
+
function clip(s, width) {
|
|
623099
|
+
return s.length <= width ? s : `${s.slice(0, Math.max(0, width - 1))}…`;
|
|
623100
|
+
}
|
|
623101
|
+
function buildChatItems(messages) {
|
|
623102
|
+
const items = [];
|
|
623103
|
+
let pending = [];
|
|
623104
|
+
let pendingFirst = null;
|
|
623105
|
+
const flush = () => {
|
|
623106
|
+
if (pending.length > 0 && pendingFirst) {
|
|
623107
|
+
items.push({
|
|
623108
|
+
message: { ...pendingFirst, id: `trail-${pendingFirst.id}`, role: "tool", content: "" },
|
|
623109
|
+
trail: pending
|
|
623110
|
+
});
|
|
623111
|
+
}
|
|
623112
|
+
pending = [];
|
|
623113
|
+
pendingFirst = null;
|
|
623114
|
+
};
|
|
623115
|
+
for (const m of messages) {
|
|
623116
|
+
if (m.role === "tool") {
|
|
623117
|
+
if (m.toolTrail) {
|
|
623118
|
+
if (!pendingFirst)
|
|
623119
|
+
pendingFirst = m;
|
|
623120
|
+
pending.push(m.toolTrail);
|
|
623121
|
+
}
|
|
623122
|
+
continue;
|
|
623123
|
+
}
|
|
623124
|
+
if (m.role === "assistant") {
|
|
623125
|
+
items.push({ message: m, trail: pending });
|
|
623126
|
+
pending = [];
|
|
623127
|
+
pendingFirst = null;
|
|
623128
|
+
continue;
|
|
623129
|
+
}
|
|
623130
|
+
if (m.role === "user")
|
|
623131
|
+
flush();
|
|
623132
|
+
items.push({ message: m, trail: [] });
|
|
623133
|
+
}
|
|
623134
|
+
flush();
|
|
623135
|
+
return items;
|
|
623136
|
+
}
|
|
623137
|
+
|
|
622681
623138
|
// apps/tui/src/lib/activity-rail-derivation.ts
|
|
622682
623139
|
function deriveTools(messages, isProcessing, limit = 5) {
|
|
622683
623140
|
const ended = new Map;
|
|
@@ -623149,8 +623606,85 @@ function turnResultRows(trail, maxRows, plan) {
|
|
|
623149
623606
|
return buildTurnResults(trail, maxRows, plan).length;
|
|
623150
623607
|
}
|
|
623151
623608
|
|
|
623609
|
+
// apps/tui/src/components/ToolTrail.tsx
|
|
623610
|
+
var import_react58 = __toESM(require_react(), 1);
|
|
623611
|
+
var jsx_dev_runtime30 = __toESM(require_jsx_dev_runtime(), 1);
|
|
623612
|
+
function iconColor(status) {
|
|
623613
|
+
return status === "ok" ? t.green : status === "fail" ? t.red : t.orange;
|
|
623614
|
+
}
|
|
623615
|
+
function useLandingRows(total, animate) {
|
|
623616
|
+
const [shown, setShown] = import_react58.useState(total);
|
|
623617
|
+
const shownRef = import_react58.useRef(total);
|
|
623618
|
+
shownRef.current = shown;
|
|
623619
|
+
const landingRef = import_react58.useRef(null);
|
|
623620
|
+
import_react58.useEffect(() => {
|
|
623621
|
+
const from = shownRef.current;
|
|
623622
|
+
if (total <= from + 1 || !motionEnabled(animate)) {
|
|
623623
|
+
landingRef.current = null;
|
|
623624
|
+
setShown(total);
|
|
623625
|
+
return;
|
|
623626
|
+
}
|
|
623627
|
+
landingRef.current = total;
|
|
623628
|
+
const step = staggerFor(total - from);
|
|
623629
|
+
let n = from + 1;
|
|
623630
|
+
setShown(n);
|
|
623631
|
+
const id = setInterval(() => {
|
|
623632
|
+
n += 1;
|
|
623633
|
+
setShown(Math.min(total, n));
|
|
623634
|
+
if (n >= total) {
|
|
623635
|
+
landingRef.current = null;
|
|
623636
|
+
clearInterval(id);
|
|
623637
|
+
}
|
|
623638
|
+
}, step);
|
|
623639
|
+
return () => clearInterval(id);
|
|
623640
|
+
}, [total, animate]);
|
|
623641
|
+
if (landingRef.current === total)
|
|
623642
|
+
return Math.min(shown, total);
|
|
623643
|
+
if (total <= shown + 1)
|
|
623644
|
+
return total;
|
|
623645
|
+
return shown;
|
|
623646
|
+
}
|
|
623647
|
+
function ToolTrail({
|
|
623648
|
+
entries,
|
|
623649
|
+
width,
|
|
623650
|
+
maxRows,
|
|
623651
|
+
animate = true
|
|
623652
|
+
}) {
|
|
623653
|
+
const rows = collapseTrail(entries, maxRows);
|
|
623654
|
+
const visible = useLandingRows(rows.length, animate);
|
|
623655
|
+
if (rows.length === 0)
|
|
623656
|
+
return null;
|
|
623657
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
|
|
623658
|
+
flexDirection: "column",
|
|
623659
|
+
flexShrink: 0,
|
|
623660
|
+
children: rows.slice(0, visible).map((row, i) => {
|
|
623661
|
+
const { text } = formatTrailRow(row, width);
|
|
623662
|
+
const g = glyphs();
|
|
623663
|
+
const icon = row.status === "ok" ? g.ok : row.status === "fail" ? g.fail : g.blocked;
|
|
623664
|
+
return /* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Box_default, {
|
|
623665
|
+
width,
|
|
623666
|
+
children: [
|
|
623667
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Text, {
|
|
623668
|
+
color: iconColor(row.status),
|
|
623669
|
+
children: icon
|
|
623670
|
+
}, undefined, false, undefined, this),
|
|
623671
|
+
/* @__PURE__ */ jsx_dev_runtime30.jsxDEV(Text, {
|
|
623672
|
+
color: row.status === "ok" ? t.muted : t.textPrimary,
|
|
623673
|
+
wrap: "truncate-end",
|
|
623674
|
+
children: ` ${text}`
|
|
623675
|
+
}, undefined, false, undefined, this)
|
|
623676
|
+
]
|
|
623677
|
+
}, i, true, undefined, this);
|
|
623678
|
+
})
|
|
623679
|
+
}, undefined, false, undefined, this);
|
|
623680
|
+
}
|
|
623681
|
+
function toolTrailRows(entries, maxRows) {
|
|
623682
|
+
return entries.length === 0 ? 0 : collapseTrail(entries, maxRows).length;
|
|
623683
|
+
}
|
|
623684
|
+
|
|
623152
623685
|
// apps/tui/src/components/TurnResults.tsx
|
|
623153
|
-
var
|
|
623686
|
+
var import_react59 = __toESM(require_react(), 1);
|
|
623687
|
+
var jsx_dev_runtime31 = __toESM(require_jsx_dev_runtime(), 1);
|
|
623154
623688
|
function iconFor(status) {
|
|
623155
623689
|
const g = glyphs();
|
|
623156
623690
|
if (status === "ok")
|
|
@@ -623162,8 +623696,8 @@ function iconFor(status) {
|
|
|
623162
623696
|
return { icon: g.pending, color: t.muted };
|
|
623163
623697
|
}
|
|
623164
623698
|
function useResultLanding(total, land) {
|
|
623165
|
-
const [shown, setShown] =
|
|
623166
|
-
|
|
623699
|
+
const [shown, setShown] = import_react59.useState(land ? 0 : total);
|
|
623700
|
+
import_react59.useEffect(() => {
|
|
623167
623701
|
if (!land) {
|
|
623168
623702
|
setShown(total);
|
|
623169
623703
|
return;
|
|
@@ -623203,12 +623737,12 @@ function TurnResults({
|
|
|
623203
623737
|
const visible = useResultLanding(rows.length, land && motionEnabled(animate));
|
|
623204
623738
|
if (rows.length === 0)
|
|
623205
623739
|
return null;
|
|
623206
|
-
return /* @__PURE__ */
|
|
623740
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
623207
623741
|
flexDirection: "column",
|
|
623208
623742
|
flexShrink: 0,
|
|
623209
623743
|
children: rows.map((row, i) => {
|
|
623210
623744
|
if (i >= visible) {
|
|
623211
|
-
return /* @__PURE__ */
|
|
623745
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
623212
623746
|
height: 1,
|
|
623213
623747
|
width
|
|
623214
623748
|
}, i, false, undefined, this);
|
|
@@ -623216,55 +623750,55 @@ function TurnResults({
|
|
|
623216
623750
|
const { icon, color } = iconFor(row.status);
|
|
623217
623751
|
const fit = fitResultRow(row, width);
|
|
623218
623752
|
const quiet = row.status === "pending" || row.kind === "fold";
|
|
623219
|
-
return /* @__PURE__ */
|
|
623753
|
+
return /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Box_default, {
|
|
623220
623754
|
width,
|
|
623221
623755
|
height: 1,
|
|
623222
|
-
children: /* @__PURE__ */
|
|
623756
|
+
children: /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623223
623757
|
wrap: "truncate-end",
|
|
623224
623758
|
children: [
|
|
623225
|
-
/* @__PURE__ */
|
|
623759
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623226
623760
|
color,
|
|
623227
623761
|
children: icon
|
|
623228
623762
|
}, undefined, false, undefined, this),
|
|
623229
|
-
/* @__PURE__ */
|
|
623763
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623230
623764
|
children: " "
|
|
623231
623765
|
}, undefined, false, undefined, this),
|
|
623232
|
-
/* @__PURE__ */
|
|
623766
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623233
623767
|
bold: !quiet,
|
|
623234
623768
|
color: quiet ? t.muted : t.textPrimary,
|
|
623235
623769
|
children: fit.verb
|
|
623236
623770
|
}, undefined, false, undefined, this),
|
|
623237
|
-
fit.spans ? /* @__PURE__ */
|
|
623771
|
+
fit.spans ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(jsx_dev_runtime31.Fragment, {
|
|
623238
623772
|
children: [
|
|
623239
|
-
fit.verb ? /* @__PURE__ */
|
|
623773
|
+
fit.verb ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623240
623774
|
children: " "
|
|
623241
623775
|
}, undefined, false, undefined, this) : null,
|
|
623242
|
-
fit.spans.map((s, j) => s.code ? /* @__PURE__ */
|
|
623776
|
+
fit.spans.map((s, j) => s.code ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623243
623777
|
color: t.textPrimary,
|
|
623244
623778
|
backgroundColor: t.border,
|
|
623245
623779
|
children: s.text
|
|
623246
|
-
}, j, false, undefined, this) : /* @__PURE__ */
|
|
623780
|
+
}, j, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623247
623781
|
color: quiet ? t.muted : t.textSecondary,
|
|
623248
623782
|
children: s.text
|
|
623249
623783
|
}, j, false, undefined, this))
|
|
623250
623784
|
]
|
|
623251
|
-
}, undefined, true, undefined, this) : fit.text ? /* @__PURE__ */
|
|
623785
|
+
}, undefined, true, undefined, this) : fit.text ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623252
623786
|
color: quiet ? t.muted : t.textSecondary,
|
|
623253
623787
|
children: ` ${fit.text}`
|
|
623254
623788
|
}, undefined, false, undefined, this) : null,
|
|
623255
|
-
fit.chip ? /* @__PURE__ */
|
|
623789
|
+
fit.chip ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(jsx_dev_runtime31.Fragment, {
|
|
623256
623790
|
children: [
|
|
623257
|
-
/* @__PURE__ */
|
|
623791
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623258
623792
|
children: " "
|
|
623259
623793
|
}, undefined, false, undefined, this),
|
|
623260
|
-
/* @__PURE__ */
|
|
623794
|
+
/* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623261
623795
|
color: t.textPrimary,
|
|
623262
623796
|
backgroundColor: t.border,
|
|
623263
623797
|
children: ` ${fit.chip} `
|
|
623264
623798
|
}, undefined, false, undefined, this)
|
|
623265
623799
|
]
|
|
623266
623800
|
}, undefined, true, undefined, this) : null,
|
|
623267
|
-
fit.note ? /* @__PURE__ */
|
|
623801
|
+
fit.note ? /* @__PURE__ */ jsx_dev_runtime31.jsxDEV(Text, {
|
|
623268
623802
|
color: row.status === "fail" ? t.red : t.muted,
|
|
623269
623803
|
children: `${" ".repeat(fit.noteGap ?? 2)}${fit.note}`
|
|
623270
623804
|
}, undefined, false, undefined, this) : null
|
|
@@ -623275,6 +623809,32 @@ function TurnResults({
|
|
|
623275
623809
|
}, undefined, false, undefined, this);
|
|
623276
623810
|
}
|
|
623277
623811
|
|
|
623812
|
+
// apps/tui/src/components/fade-transition.tsx
|
|
623813
|
+
var import_react60 = __toESM(require_react(), 1);
|
|
623814
|
+
var jsx_dev_runtime32 = __toESM(require_jsx_dev_runtime(), 1);
|
|
623815
|
+
function FadeIn({ children, duration = 300, delay = 0, onComplete }) {
|
|
623816
|
+
const [started, setStarted] = import_react60.useState(false);
|
|
623817
|
+
import_react60.useEffect(() => {
|
|
623818
|
+
const timeout = setTimeout(() => {
|
|
623819
|
+
setStarted(true);
|
|
623820
|
+
}, delay);
|
|
623821
|
+
return () => clearTimeout(timeout);
|
|
623822
|
+
}, [delay]);
|
|
623823
|
+
import_react60.useEffect(() => {
|
|
623824
|
+
if (!started)
|
|
623825
|
+
return;
|
|
623826
|
+
const timeout = setTimeout(() => {
|
|
623827
|
+
onComplete?.();
|
|
623828
|
+
}, duration);
|
|
623829
|
+
return () => clearTimeout(timeout);
|
|
623830
|
+
}, [started, duration, onComplete]);
|
|
623831
|
+
if (!started)
|
|
623832
|
+
return null;
|
|
623833
|
+
return /* @__PURE__ */ jsx_dev_runtime32.jsxDEV(Box_default, {
|
|
623834
|
+
children
|
|
623835
|
+
}, undefined, false, undefined, this);
|
|
623836
|
+
}
|
|
623837
|
+
|
|
623278
623838
|
// apps/tui/src/components/sound-effects.tsx
|
|
623279
623839
|
var import_react61 = __toESM(require_react(), 1);
|
|
623280
623840
|
var BELL = "\x07";
|
|
@@ -623687,6 +624247,7 @@ function MessageList({
|
|
|
623687
624247
|
showAnimations,
|
|
623688
624248
|
isLatestAssistant: message.id === lastAssistantId,
|
|
623689
624249
|
trail: trailById.get(message.id) ?? [],
|
|
624250
|
+
turnRunning,
|
|
623690
624251
|
trailMaxRows: trailCaps.get(message.id),
|
|
623691
624252
|
onAnimationStart: (id) => {
|
|
623692
624253
|
animatedIdsRef.current.add(id);
|
|
@@ -623718,6 +624279,7 @@ function MessageItem({
|
|
|
623718
624279
|
showAnimations,
|
|
623719
624280
|
isLatestAssistant = false,
|
|
623720
624281
|
trail = [],
|
|
624282
|
+
turnRunning = false,
|
|
623721
624283
|
trailMaxRows,
|
|
623722
624284
|
onAnimationStart
|
|
623723
624285
|
}) {
|
|
@@ -623903,7 +624465,7 @@ function MessageItem({
|
|
|
623903
624465
|
animate: showAnimations
|
|
623904
624466
|
}, undefined, false, undefined, this)
|
|
623905
624467
|
}, undefined, false, undefined, this),
|
|
623906
|
-
!isUser && !message.content.trim() && trail.length > 0 ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(MutedText, {
|
|
624468
|
+
!isUser && !turnRunning && !message.content.trim() && trail.length > 0 ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(MutedText, {
|
|
623907
624469
|
children: "No reply."
|
|
623908
624470
|
}, undefined, false, undefined, this) : null,
|
|
623909
624471
|
message.content.trim() || trail.length === 0 ? /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Box_default, {
|
|
@@ -624065,7 +624627,11 @@ function MarkdownBody({
|
|
|
624065
624627
|
})
|
|
624066
624628
|
}, undefined, false, undefined, this);
|
|
624067
624629
|
}
|
|
624068
|
-
function InlineSpans({
|
|
624630
|
+
function InlineSpans({
|
|
624631
|
+
spans,
|
|
624632
|
+
color,
|
|
624633
|
+
adhdMode
|
|
624634
|
+
}) {
|
|
624069
624635
|
return /* @__PURE__ */ jsx_dev_runtime34.jsxDEV(Text, {
|
|
624070
624636
|
color,
|
|
624071
624637
|
wrap: "wrap",
|
|
@@ -626476,9 +627042,9 @@ init_cloud_transcriber();
|
|
|
626476
627042
|
init_types4();
|
|
626477
627043
|
|
|
626478
627044
|
// packages/voice/voice-chat.ts
|
|
626479
|
-
import { existsSync as
|
|
627045
|
+
import { existsSync as existsSync119, unlinkSync as unlinkSync6 } from "node:fs";
|
|
626480
627046
|
import { tmpdir as tmpdir21 } from "node:os";
|
|
626481
|
-
import { join as
|
|
627047
|
+
import { join as join177 } from "node:path";
|
|
626482
627048
|
|
|
626483
627049
|
// packages/voice/tts-engine.ts
|
|
626484
627050
|
init_termux();
|
|
@@ -626886,7 +627452,7 @@ class VoiceChatLoop {
|
|
|
626886
627452
|
await this.speakText(response);
|
|
626887
627453
|
}
|
|
626888
627454
|
async listenForSpeech() {
|
|
626889
|
-
const wavPath =
|
|
627455
|
+
const wavPath = join177(tmpdir21(), `8gent-voicechat-${Date.now()}.wav`);
|
|
626890
627456
|
const silenceSec = (this.silenceMs / 1000).toFixed(1);
|
|
626891
627457
|
try {
|
|
626892
627458
|
const recProc = Bun.spawn([
|
|
@@ -626935,7 +627501,7 @@ class VoiceChatLoop {
|
|
|
626935
627501
|
cleanupFile(wavPath);
|
|
626936
627502
|
throw new VoiceChatFatalError(describeRecFailure(exitCode, why));
|
|
626937
627503
|
}
|
|
626938
|
-
if (!
|
|
627504
|
+
if (!existsSync119(wavPath)) {
|
|
626939
627505
|
this.reportError("No audio was recorded. Check that your microphone is the system input.");
|
|
626940
627506
|
return null;
|
|
626941
627507
|
}
|
|
@@ -627059,8 +627625,8 @@ function sleep2(ms) {
|
|
|
627059
627625
|
}
|
|
627060
627626
|
function cleanupFile(path) {
|
|
627061
627627
|
try {
|
|
627062
|
-
if (
|
|
627063
|
-
|
|
627628
|
+
if (existsSync119(path))
|
|
627629
|
+
unlinkSync6(path);
|
|
627064
627630
|
} catch {}
|
|
627065
627631
|
}
|
|
627066
627632
|
var HEARD_ONLY_MARK = "[interrupted]";
|
|
@@ -627118,14 +627684,14 @@ function splitIntoSentences(text) {
|
|
|
627118
627684
|
return chunks.length ? chunks : [text];
|
|
627119
627685
|
}
|
|
627120
627686
|
// packages/voice/full-duplex-provider.ts
|
|
627121
|
-
import { execSync as
|
|
627122
|
-
import { existsSync as
|
|
627123
|
-
import { homedir as
|
|
627124
|
-
import { join as
|
|
627125
|
-
var MOSHI_HF_CACHE_PATH =
|
|
627687
|
+
import { execSync as execSync7 } from "node:child_process";
|
|
627688
|
+
import { existsSync as existsSync120 } from "node:fs";
|
|
627689
|
+
import { homedir as homedir88 } from "node:os";
|
|
627690
|
+
import { join as join178 } from "node:path";
|
|
627691
|
+
var MOSHI_HF_CACHE_PATH = join178(homedir88(), ".cache", "huggingface", "hub", "models--kyutai--moshiko-pytorch-bf16", "snapshots");
|
|
627126
627692
|
function tryExec(cmd) {
|
|
627127
627693
|
try {
|
|
627128
|
-
|
|
627694
|
+
execSync7(cmd, { stdio: "ignore", timeout: 5000 });
|
|
627129
627695
|
return true;
|
|
627130
627696
|
} catch {
|
|
627131
627697
|
return false;
|
|
@@ -627137,7 +627703,7 @@ async function detectCapabilities() {
|
|
|
627137
627703
|
const hasAppleSilicon = platform === "darwin" && arch === "arm64";
|
|
627138
627704
|
const hasMLX = hasAppleSilicon && tryExec('python3 -c "import mlx"');
|
|
627139
627705
|
const hasMoshiInstalled = tryExec('python3 -c "import moshi"');
|
|
627140
|
-
const hasMoshiModel =
|
|
627706
|
+
const hasMoshiModel = existsSync120(MOSHI_HF_CACHE_PATH);
|
|
627141
627707
|
const hasCUDA = tryExec("nvidia-smi");
|
|
627142
627708
|
const hasNIMKey = !!process.env.NVIDIA_NIM_KEY;
|
|
627143
627709
|
return {
|
|
@@ -628169,8 +628735,8 @@ function useWorkspaceTabs() {
|
|
|
628169
628735
|
|
|
628170
628736
|
// apps/tui/src/lib/adhd-audio.ts
|
|
628171
628737
|
init_bun_shim();
|
|
628172
|
-
import { existsSync as
|
|
628173
|
-
import { join as
|
|
628738
|
+
import { existsSync as existsSync122, mkdirSync as mkdirSync83 } from "node:fs";
|
|
628739
|
+
import { join as join181 } from "node:path";
|
|
628174
628740
|
var DEFAULT_CONFIG4 = {
|
|
628175
628741
|
duration: 180,
|
|
628176
628742
|
bpm: null,
|
|
@@ -628209,11 +628775,11 @@ var SOUNDSCAPES = {
|
|
|
628209
628775
|
bpm: 70
|
|
628210
628776
|
}
|
|
628211
628777
|
};
|
|
628212
|
-
var CACHE_DIR3 =
|
|
628213
|
-
var CONFIG_PATH =
|
|
628778
|
+
var CACHE_DIR3 = join181(process.env.HOME || "~", ".8gent", "adhd-audio");
|
|
628779
|
+
var CONFIG_PATH = join181(CACHE_DIR3, "config.json");
|
|
628214
628780
|
function loadConfig2() {
|
|
628215
628781
|
try {
|
|
628216
|
-
if (
|
|
628782
|
+
if (existsSync122(CONFIG_PATH)) {
|
|
628217
628783
|
const raw = JSON.parse(__require("node:fs").readFileSync(CONFIG_PATH, "utf-8"));
|
|
628218
628784
|
return { ...DEFAULT_CONFIG4, ...raw };
|
|
628219
628785
|
}
|
|
@@ -628222,8 +628788,8 @@ function loadConfig2() {
|
|
|
628222
628788
|
}
|
|
628223
628789
|
function saveConfig2(config) {
|
|
628224
628790
|
try {
|
|
628225
|
-
if (!
|
|
628226
|
-
|
|
628791
|
+
if (!existsSync122(CACHE_DIR3))
|
|
628792
|
+
mkdirSync83(CACHE_DIR3, { recursive: true });
|
|
628227
628793
|
__require("node:fs").writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
628228
628794
|
} catch {}
|
|
628229
628795
|
}
|
|
@@ -628234,8 +628800,8 @@ class ADHDAudio {
|
|
|
628234
628800
|
generating = false;
|
|
628235
628801
|
_config;
|
|
628236
628802
|
constructor() {
|
|
628237
|
-
if (!
|
|
628238
|
-
|
|
628803
|
+
if (!existsSync122(CACHE_DIR3)) {
|
|
628804
|
+
mkdirSync83(CACHE_DIR3, { recursive: true });
|
|
628239
628805
|
}
|
|
628240
628806
|
this._config = loadConfig2();
|
|
628241
628807
|
}
|
|
@@ -628261,7 +628827,7 @@ class ADHDAudio {
|
|
|
628261
628827
|
for (const soundscape of Object.keys(SOUNDSCAPES)) {
|
|
628262
628828
|
const path = this.getCachePath(soundscape);
|
|
628263
628829
|
try {
|
|
628264
|
-
if (
|
|
628830
|
+
if (existsSync122(path))
|
|
628265
628831
|
__require("node:fs").unlinkSync(path);
|
|
628266
628832
|
} catch {}
|
|
628267
628833
|
}
|
|
@@ -628277,10 +628843,10 @@ class ADHDAudio {
|
|
|
628277
628843
|
}
|
|
628278
628844
|
}
|
|
628279
628845
|
getCachePath(soundscape) {
|
|
628280
|
-
return
|
|
628846
|
+
return join181(CACHE_DIR3, `${soundscape}.mp3`);
|
|
628281
628847
|
}
|
|
628282
628848
|
hasCached(soundscape) {
|
|
628283
|
-
return
|
|
628849
|
+
return existsSync122(this.getCachePath(soundscape));
|
|
628284
628850
|
}
|
|
628285
628851
|
async generate(soundscape) {
|
|
628286
628852
|
const preset = SOUNDSCAPES[soundscape];
|
|
@@ -628689,325 +629255,8 @@ class DaemonSessionClient {
|
|
|
628689
629255
|
}
|
|
628690
629256
|
}
|
|
628691
629257
|
|
|
628692
|
-
// apps/tui/src/
|
|
628693
|
-
|
|
628694
|
-
import { execSync as execSync7, spawn as spawn24 } from "node:child_process";
|
|
628695
|
-
var stripAnsi2 = (s) => s.replace(/\[[0-9;?]*[a-zA-Z]/g, "").replace(/\][^]*/g, "");
|
|
628696
|
-
var EXTERNAL_AGENT_PRESETS = {
|
|
628697
|
-
claude: {
|
|
628698
|
-
id: "claude",
|
|
628699
|
-
label: "Sparring",
|
|
628700
|
-
command: "claude",
|
|
628701
|
-
promptMode: "flag",
|
|
628702
|
-
flagName: "-p",
|
|
628703
|
-
args: [],
|
|
628704
|
-
timeoutMs: 120000,
|
|
628705
|
-
parseStdout: stripAnsi2,
|
|
628706
|
-
homepage: "https://docs.claude.com/en/docs/claude-code",
|
|
628707
|
-
preferWindow: true,
|
|
628708
|
-
install: {
|
|
628709
|
-
command: "npm install -g --prefix=$HOME/.npm-global @anthropic-ai/claude-code",
|
|
628710
|
-
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.'
|
|
628711
|
-
}
|
|
628712
|
-
},
|
|
628713
|
-
codex: {
|
|
628714
|
-
id: "codex",
|
|
628715
|
-
label: "OpenAI Codex",
|
|
628716
|
-
command: "codex",
|
|
628717
|
-
promptMode: "arg",
|
|
628718
|
-
args: ["exec"],
|
|
628719
|
-
timeoutMs: 120000,
|
|
628720
|
-
parseStdout: stripAnsi2,
|
|
628721
|
-
homepage: "https://github.com/openai/codex",
|
|
628722
|
-
preferWindow: true,
|
|
628723
|
-
install: {
|
|
628724
|
-
command: "npm install -g --prefix=$HOME/.npm-global @openai/codex",
|
|
628725
|
-
notes: "Binary at ~/.npm-global/bin/codex. Add `~/.npm-global/bin` to PATH if needed. Requires `export OPENAI_API_KEY=sk-...` before /spawn."
|
|
628726
|
-
}
|
|
628727
|
-
},
|
|
628728
|
-
hermes: {
|
|
628729
|
-
id: "hermes",
|
|
628730
|
-
label: "Hermes Agent",
|
|
628731
|
-
command: "hermes",
|
|
628732
|
-
preferWindow: true,
|
|
628733
|
-
promptMode: "flag",
|
|
628734
|
-
flagName: "-z",
|
|
628735
|
-
args: [],
|
|
628736
|
-
timeoutMs: 120000,
|
|
628737
|
-
parseStdout: stripAnsi2,
|
|
628738
|
-
homepage: "https://github.com/NousResearch/hermes-agent",
|
|
628739
|
-
install: {
|
|
628740
|
-
command: "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash -s -- --skip-setup --no-venv",
|
|
628741
|
-
notes: "Hermes needs Python ≥ 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)."
|
|
628742
|
-
}
|
|
628743
|
-
},
|
|
628744
|
-
openclaw: {
|
|
628745
|
-
id: "openclaw",
|
|
628746
|
-
label: "OpenClaw",
|
|
628747
|
-
command: "openclaw",
|
|
628748
|
-
preferWindow: true,
|
|
628749
|
-
promptMode: "arg",
|
|
628750
|
-
args: ["run", "--headless"],
|
|
628751
|
-
timeoutMs: 120000,
|
|
628752
|
-
parseStdout: stripAnsi2,
|
|
628753
|
-
homepage: "https://github.com/openclaw/openclaw",
|
|
628754
|
-
install: {
|
|
628755
|
-
command: "npm install -g --prefix=$HOME/.npm-global openclaw@latest",
|
|
628756
|
-
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.)"
|
|
628757
|
-
},
|
|
628758
|
-
requiresNodeVersion: "22.14.0"
|
|
628759
|
-
},
|
|
628760
|
-
pi: {
|
|
628761
|
-
preferWindow: true,
|
|
628762
|
-
id: "pi",
|
|
628763
|
-
label: "Pi (pi-mono)",
|
|
628764
|
-
command: "pi",
|
|
628765
|
-
promptMode: "flag",
|
|
628766
|
-
flagName: "-p",
|
|
628767
|
-
args: [],
|
|
628768
|
-
timeoutMs: 120000,
|
|
628769
|
-
parseStdout: stripAnsi2,
|
|
628770
|
-
homepage: "https://pi.dev",
|
|
628771
|
-
install: {
|
|
628772
|
-
command: "npm install -g --prefix=$HOME/.npm-global @mariozechner/pi-coding-agent",
|
|
628773
|
-
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)."
|
|
628774
|
-
}
|
|
628775
|
-
},
|
|
628776
|
-
"8gent": {
|
|
628777
|
-
id: "8gent",
|
|
628778
|
-
label: "8gent (nested)",
|
|
628779
|
-
command: "8gent",
|
|
628780
|
-
promptMode: "arg",
|
|
628781
|
-
args: ["run"],
|
|
628782
|
-
timeoutMs: 180000,
|
|
628783
|
-
parseStdout: stripAnsi2,
|
|
628784
|
-
homepage: "https://8gent.dev",
|
|
628785
|
-
install: {
|
|
628786
|
-
command: "npm install -g --prefix=$HOME/.npm-global @8gi-foundation/8gent-code --force",
|
|
628787
|
-
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."
|
|
628788
|
-
}
|
|
628789
|
-
}
|
|
628790
|
-
};
|
|
628791
|
-
function getPreset(id) {
|
|
628792
|
-
return EXTERNAL_AGENT_PRESETS[id.toLowerCase()] ?? null;
|
|
628793
|
-
}
|
|
628794
|
-
function listPresetIds() {
|
|
628795
|
-
return Object.keys(EXTERNAL_AGENT_PRESETS);
|
|
628796
|
-
}
|
|
628797
|
-
function isInstalled(preset) {
|
|
628798
|
-
try {
|
|
628799
|
-
execSync7(`command -v "${preset.command}"`, {
|
|
628800
|
-
stdio: "ignore",
|
|
628801
|
-
timeout: 1500
|
|
628802
|
-
});
|
|
628803
|
-
return true;
|
|
628804
|
-
} catch {
|
|
628805
|
-
return false;
|
|
628806
|
-
}
|
|
628807
|
-
}
|
|
628808
|
-
async function installAgent(preset, onLine) {
|
|
628809
|
-
const start = performance.now();
|
|
628810
|
-
if (!preset.install) {
|
|
628811
|
-
return {
|
|
628812
|
-
ok: false,
|
|
628813
|
-
stdout: "",
|
|
628814
|
-
stderr: "",
|
|
628815
|
-
durationMs: 0,
|
|
628816
|
-
command: "",
|
|
628817
|
-
error: `No install recipe for ${preset.id}. Install ${preset.command} manually and try again.`
|
|
628818
|
-
};
|
|
628819
|
-
}
|
|
628820
|
-
const command = preset.install.command;
|
|
628821
|
-
return new Promise((resolve) => {
|
|
628822
|
-
let stdout = "";
|
|
628823
|
-
let stderr = "";
|
|
628824
|
-
let exited = false;
|
|
628825
|
-
const proc = spawnShell(command, {
|
|
628826
|
-
posix: ["bash", "-lc"],
|
|
628827
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
628828
|
-
env: { ...process.env, NO_COLOR: "1", FORCE_COLOR: "0" }
|
|
628829
|
-
});
|
|
628830
|
-
const finish = (result) => {
|
|
628831
|
-
if (exited)
|
|
628832
|
-
return;
|
|
628833
|
-
exited = true;
|
|
628834
|
-
clearTimeout(timer);
|
|
628835
|
-
resolve({
|
|
628836
|
-
...result,
|
|
628837
|
-
durationMs: Math.round(performance.now() - start),
|
|
628838
|
-
command
|
|
628839
|
-
});
|
|
628840
|
-
};
|
|
628841
|
-
const pipeLines = (chunk, source) => {
|
|
628842
|
-
const text = chunk.toString();
|
|
628843
|
-
if (source === "stdout")
|
|
628844
|
-
stdout += text;
|
|
628845
|
-
else
|
|
628846
|
-
stderr += text;
|
|
628847
|
-
if (onLine) {
|
|
628848
|
-
for (const line of text.split(/\r?\n/)) {
|
|
628849
|
-
if (line.trim().length > 0)
|
|
628850
|
-
onLine(line, source);
|
|
628851
|
-
}
|
|
628852
|
-
}
|
|
628853
|
-
};
|
|
628854
|
-
proc.stdout?.on("data", (c) => pipeLines(c, "stdout"));
|
|
628855
|
-
proc.stderr?.on("data", (c) => pipeLines(c, "stderr"));
|
|
628856
|
-
proc.on("error", (err) => {
|
|
628857
|
-
finish({ ok: false, stdout, stderr, error: err.message });
|
|
628858
|
-
});
|
|
628859
|
-
proc.on("close", (code) => {
|
|
628860
|
-
finish({
|
|
628861
|
-
ok: code === 0,
|
|
628862
|
-
stdout,
|
|
628863
|
-
stderr,
|
|
628864
|
-
error: code === 0 ? undefined : stderr.trim().slice(0, 800) || `installer exited with code ${code}`
|
|
628865
|
-
});
|
|
628866
|
-
});
|
|
628867
|
-
const timer = setTimeout(() => {
|
|
628868
|
-
proc.kill("SIGTERM");
|
|
628869
|
-
finish({ ok: false, stdout, stderr, error: "install timed out after 5 minutes" });
|
|
628870
|
-
}, 5 * 60 * 1000);
|
|
628871
|
-
});
|
|
628872
|
-
}
|
|
628873
|
-
async function ensureInstalled(preset, onLine) {
|
|
628874
|
-
if (isInstalled(preset))
|
|
628875
|
-
return true;
|
|
628876
|
-
if (!preset.install) {
|
|
628877
|
-
onLine?.(`${preset.command}: not installed and no auto-install recipe is configured.`, "info");
|
|
628878
|
-
return false;
|
|
628879
|
-
}
|
|
628880
|
-
onLine?.(`${preset.command}: not installed, running ${preset.install.command}`, "info");
|
|
628881
|
-
const result = await installAgent(preset, (line, source) => onLine?.(line, source));
|
|
628882
|
-
if (!result.ok) {
|
|
628883
|
-
onLine?.(`Install failed: ${result.error ?? "unknown error"}`, "info");
|
|
628884
|
-
return false;
|
|
628885
|
-
}
|
|
628886
|
-
const stillThere = isInstalled(preset);
|
|
628887
|
-
if (!stillThere) {
|
|
628888
|
-
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");
|
|
628889
|
-
}
|
|
628890
|
-
return stillThere;
|
|
628891
|
-
}
|
|
628892
|
-
function composePrompt(history, prompt) {
|
|
628893
|
-
const lines = [];
|
|
628894
|
-
for (const m of history) {
|
|
628895
|
-
const tag = m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : m.role;
|
|
628896
|
-
lines.push(`${tag}: ${m.content}`);
|
|
628897
|
-
}
|
|
628898
|
-
lines.push(`User: ${prompt}`);
|
|
628899
|
-
lines.push("Assistant:");
|
|
628900
|
-
return lines.join(`
|
|
628901
|
-
|
|
628902
|
-
`);
|
|
628903
|
-
}
|
|
628904
|
-
async function runExternalAgent(preset, prompt, signal) {
|
|
628905
|
-
const start = performance.now();
|
|
628906
|
-
const argv = [...preset.args];
|
|
628907
|
-
if (preset.promptMode === "flag") {
|
|
628908
|
-
argv.push(preset.flagName ?? "-p", prompt);
|
|
628909
|
-
} else if (preset.promptMode === "arg") {
|
|
628910
|
-
argv.push(prompt);
|
|
628911
|
-
}
|
|
628912
|
-
let pathPrefix = "";
|
|
628913
|
-
if (preset.requiresNodeVersion) {
|
|
628914
|
-
try {
|
|
628915
|
-
await Promise.resolve().then(() => init_runtime());
|
|
628916
|
-
const binDir = await ensureNodeFor(preset.requiresNodeVersion);
|
|
628917
|
-
if (binDir)
|
|
628918
|
-
pathPrefix = `${binDir}:`;
|
|
628919
|
-
} catch (err) {
|
|
628920
|
-
return {
|
|
628921
|
-
ok: false,
|
|
628922
|
-
text: "",
|
|
628923
|
-
durationMs: Math.round(performance.now() - start),
|
|
628924
|
-
command: `${preset.command} ${argv.join(" ")}`,
|
|
628925
|
-
error: `managed Node runtime install failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
628926
|
-
exitCode: null
|
|
628927
|
-
};
|
|
628928
|
-
}
|
|
628929
|
-
}
|
|
628930
|
-
return new Promise((resolve) => {
|
|
628931
|
-
let stdout = "";
|
|
628932
|
-
let stderr = "";
|
|
628933
|
-
let exited = false;
|
|
628934
|
-
const proc = spawn24(preset.command, argv, {
|
|
628935
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
628936
|
-
env: {
|
|
628937
|
-
...process.env,
|
|
628938
|
-
PATH: `${pathPrefix}${process.env.PATH ?? ""}`,
|
|
628939
|
-
NO_COLOR: "1",
|
|
628940
|
-
FORCE_COLOR: "0",
|
|
628941
|
-
"8GENT_NO_INTRO": "1",
|
|
628942
|
-
AI_SDK_LOG_WARNINGS: "false"
|
|
628943
|
-
}
|
|
628944
|
-
});
|
|
628945
|
-
const finish = (result) => {
|
|
628946
|
-
if (exited)
|
|
628947
|
-
return;
|
|
628948
|
-
exited = true;
|
|
628949
|
-
clearTimeout(timer);
|
|
628950
|
-
signal?.removeEventListener("abort", onAbort);
|
|
628951
|
-
resolve({
|
|
628952
|
-
...result,
|
|
628953
|
-
durationMs: Math.round(performance.now() - start),
|
|
628954
|
-
command: `${preset.command} ${argv.map((a) => a.includes(" ") ? `"${a}"` : a).join(" ")}`
|
|
628955
|
-
});
|
|
628956
|
-
};
|
|
628957
|
-
proc.on("error", (err) => {
|
|
628958
|
-
finish({
|
|
628959
|
-
ok: false,
|
|
628960
|
-
text: "",
|
|
628961
|
-
error: err.code === "ENOENT" ? `${preset.command}: not installed (no binary on $PATH)` : err.message,
|
|
628962
|
-
exitCode: null
|
|
628963
|
-
});
|
|
628964
|
-
});
|
|
628965
|
-
proc.stdout?.on("data", (chunk) => {
|
|
628966
|
-
stdout += chunk.toString();
|
|
628967
|
-
});
|
|
628968
|
-
proc.stderr?.on("data", (chunk) => {
|
|
628969
|
-
stderr += chunk.toString();
|
|
628970
|
-
});
|
|
628971
|
-
proc.on("close", (code) => {
|
|
628972
|
-
let text = preset.parseStdout ? preset.parseStdout(stdout).trim() : stdout.trim();
|
|
628973
|
-
try {
|
|
628974
|
-
init_keys();
|
|
628975
|
-
if (text)
|
|
628976
|
-
text = redactAndWarn(text);
|
|
628977
|
-
} catch {}
|
|
628978
|
-
if (code === 0 || code !== null && text.length > 0) {
|
|
628979
|
-
finish({ ok: code === 0, text, exitCode: code, error: code === 0 ? undefined : stderr.trim().slice(0, 400) });
|
|
628980
|
-
} else {
|
|
628981
|
-
finish({
|
|
628982
|
-
ok: false,
|
|
628983
|
-
text,
|
|
628984
|
-
exitCode: code,
|
|
628985
|
-
error: stderr.trim().slice(0, 400) || `exited with code ${code}`
|
|
628986
|
-
});
|
|
628987
|
-
}
|
|
628988
|
-
});
|
|
628989
|
-
if (preset.promptMode === "stdin" && proc.stdin) {
|
|
628990
|
-
proc.stdin.write(prompt);
|
|
628991
|
-
proc.stdin.end();
|
|
628992
|
-
} else if (proc.stdin) {
|
|
628993
|
-
proc.stdin.end();
|
|
628994
|
-
}
|
|
628995
|
-
const timer = setTimeout(() => {
|
|
628996
|
-
proc.kill("SIGTERM");
|
|
628997
|
-
finish({
|
|
628998
|
-
ok: false,
|
|
628999
|
-
text: stdout,
|
|
629000
|
-
error: `timeout after ${preset.timeoutMs ?? 90000}ms`,
|
|
629001
|
-
exitCode: null
|
|
629002
|
-
});
|
|
629003
|
-
}, preset.timeoutMs ?? 90000);
|
|
629004
|
-
const onAbort = () => {
|
|
629005
|
-
proc.kill("SIGTERM");
|
|
629006
|
-
finish({ ok: false, text: stdout, error: "aborted", exitCode: null });
|
|
629007
|
-
};
|
|
629008
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
629009
|
-
});
|
|
629010
|
-
}
|
|
629258
|
+
// apps/tui/src/app.tsx
|
|
629259
|
+
init_external_agent_runner();
|
|
629011
629260
|
|
|
629012
629261
|
// packages/daemon/goal-rpc.ts
|
|
629013
629262
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
@@ -630290,7 +630539,7 @@ class InProcessGoalTransport {
|
|
|
630290
630539
|
// apps/tui/src/lib/intro-gate.ts
|
|
630291
630540
|
init_home();
|
|
630292
630541
|
import { mkdirSync as mkdirSync85, readFileSync as readFileSync109, writeFileSync as writeFileSync65 } from "node:fs";
|
|
630293
|
-
import { join as
|
|
630542
|
+
import { join as join185 } from "node:path";
|
|
630294
630543
|
function shouldShowIntro({ setting, env, seenVersion, version }) {
|
|
630295
630544
|
if (setting === "off")
|
|
630296
630545
|
return false;
|
|
@@ -630301,7 +630550,7 @@ function shouldShowIntro({ setting, env, seenVersion, version }) {
|
|
|
630301
630550
|
return seenVersion !== version;
|
|
630302
630551
|
}
|
|
630303
630552
|
function seenPath(home) {
|
|
630304
|
-
return
|
|
630553
|
+
return join185(home, ".8gent", "intro-seen");
|
|
630305
630554
|
}
|
|
630306
630555
|
function readSeenVersion(home = resolveHome()) {
|
|
630307
630556
|
try {
|
|
@@ -630313,7 +630562,7 @@ function readSeenVersion(home = resolveHome()) {
|
|
|
630313
630562
|
}
|
|
630314
630563
|
function markIntroSeen(version, home = resolveHome()) {
|
|
630315
630564
|
try {
|
|
630316
|
-
mkdirSync85(
|
|
630565
|
+
mkdirSync85(join185(home, ".8gent"), { recursive: true });
|
|
630317
630566
|
writeFileSync65(seenPath(home), `${version}
|
|
630318
630567
|
`);
|
|
630319
630568
|
} catch {}
|
|
@@ -632006,12 +632255,12 @@ function sanitizeFreeText(value) {
|
|
|
632006
632255
|
// packages/voice/audio-gate.ts
|
|
632007
632256
|
init_home();
|
|
632008
632257
|
import { readFileSync as readFileSync111 } from "node:fs";
|
|
632009
|
-
import { join as
|
|
632258
|
+
import { join as join188 } from "node:path";
|
|
632010
632259
|
function audioOutputAllowed(env = process.env) {
|
|
632011
632260
|
if (env.EIGHT_VOICE === "1")
|
|
632012
632261
|
return true;
|
|
632013
632262
|
try {
|
|
632014
|
-
const raw = JSON.parse(readFileSync111(
|
|
632263
|
+
const raw = JSON.parse(readFileSync111(join188(resolveHome(env), ".8gent", "settings.json"), "utf8"));
|
|
632015
632264
|
return raw?.voice?.outputEnabled === true;
|
|
632016
632265
|
} catch {
|
|
632017
632266
|
return false;
|
|
@@ -633185,10 +633434,10 @@ function snapshot(manager) {
|
|
|
633185
633434
|
|
|
633186
633435
|
// apps/tui/src/hooks/useBodyParts.ts
|
|
633187
633436
|
var import_react83 = __toESM(require_react(), 1);
|
|
633188
|
-
import { existsSync as
|
|
633437
|
+
import { existsSync as existsSync125 } from "node:fs";
|
|
633189
633438
|
import { execSync as execSync8 } from "node:child_process";
|
|
633190
633439
|
import { homedir as homedir90 } from "node:os";
|
|
633191
|
-
import { join as
|
|
633440
|
+
import { join as join189 } from "node:path";
|
|
633192
633441
|
var PULSE_FLASH_MS = 150;
|
|
633193
633442
|
function hasCliclick() {
|
|
633194
633443
|
try {
|
|
@@ -633199,7 +633448,7 @@ function hasCliclick() {
|
|
|
633199
633448
|
}
|
|
633200
633449
|
}
|
|
633201
633450
|
function hasAxBridge() {
|
|
633202
|
-
return
|
|
633451
|
+
return existsSync125(join189(homedir90(), ".8gent", "bin", "8gent-ax-bridge"));
|
|
633203
633452
|
}
|
|
633204
633453
|
function detectDefaultBodyPartsState() {
|
|
633205
633454
|
const handsOk = hasCliclick();
|
|
@@ -633487,6 +633736,7 @@ function onChange(fn) {
|
|
|
633487
633736
|
init_shell();
|
|
633488
633737
|
init_secret_scanner();
|
|
633489
633738
|
init_path_guard();
|
|
633739
|
+
init_permission_mode();
|
|
633490
633740
|
init_eight_browser();
|
|
633491
633741
|
|
|
633492
633742
|
// apps/tui/src/lib/consult-command.ts
|
|
@@ -633527,8 +633777,16 @@ function sendRefusal(command) {
|
|
|
633527
633777
|
return null;
|
|
633528
633778
|
}
|
|
633529
633779
|
function planModeRefusal2(mode) {
|
|
633530
|
-
return mode === "plan" ? "Plan mode runs nothing, shell lines included. Shift+Tab to change mode, then run it again." : null;
|
|
633780
|
+
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;
|
|
633781
|
+
}
|
|
633782
|
+
function parseModeArgs(args) {
|
|
633783
|
+
const words = args.flatMap((a) => a.trim().split(/\s+/)).filter(Boolean);
|
|
633784
|
+
if (words.length !== 1)
|
|
633785
|
+
return null;
|
|
633786
|
+
const name = words[0].toLowerCase();
|
|
633787
|
+
return isPermissionMode(name) ? name : null;
|
|
633531
633788
|
}
|
|
633789
|
+
var MODE_USAGE = "Usage: /mode plan | ask | guarded | infinite (this tab's permission mode).";
|
|
633532
633790
|
var ANSI2 = /\x1b\[[0-?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[ -/]*[0-~]/g;
|
|
633533
633791
|
var CONTROL4 = /[\x00-\x08\x0b-\x1f\x7f]/g;
|
|
633534
633792
|
function cleanOutput(raw) {
|
|
@@ -634787,6 +635045,24 @@ ${r.message}`;
|
|
|
634787
635045
|
// apps/tui/src/app.tsx
|
|
634788
635046
|
init_slash_commands();
|
|
634789
635047
|
|
|
635048
|
+
// apps/tui/src/lib/term-intent.ts
|
|
635049
|
+
var VERBS2 = "run|open|start|launch|fire up|spin up|boot";
|
|
635050
|
+
var POLITE = "(?:please\\s+|can you\\s+|could you\\s+)?";
|
|
635051
|
+
var WHERE = "(?:\\s+in\\s+(?:a\\s+)?(?:new\\s+)?(?:tab|terminal(?:\\s+tab)?))?";
|
|
635052
|
+
var PRESET_INTENT = new RegExp(`^${POLITE}(?:${VERBS2})\\s+(?:up\\s+)?([a-z0-9][a-z0-9_-]*)(${WHERE})(?:\\s+please)?$`);
|
|
635053
|
+
function detectTermPresetIntent(input, presetIds) {
|
|
635054
|
+
const text = input.trim().toLowerCase().replace(/[.!?]+$/, "").replace(/\s+/g, " ");
|
|
635055
|
+
if (!text || text.length > 60)
|
|
635056
|
+
return null;
|
|
635057
|
+
const m = PRESET_INTENT.exec(text);
|
|
635058
|
+
if (!m)
|
|
635059
|
+
return null;
|
|
635060
|
+
const id = presetIds.find((p) => p.toLowerCase() === m[1]);
|
|
635061
|
+
if (!id)
|
|
635062
|
+
return null;
|
|
635063
|
+
return m[2] ? [id, "--in-tab"] : [id];
|
|
635064
|
+
}
|
|
635065
|
+
|
|
634790
635066
|
// apps/tui/src/lib/turn-outcome.ts
|
|
634791
635067
|
init_local_turn_error();
|
|
634792
635068
|
function turnEndedInError(messages) {
|
|
@@ -634804,8 +635080,8 @@ function turnEndedInError(messages) {
|
|
|
634804
635080
|
}
|
|
634805
635081
|
|
|
634806
635082
|
// apps/tui/src/screens/BTWView.tsx
|
|
634807
|
-
import { existsSync as
|
|
634808
|
-
import { join as
|
|
635083
|
+
import { existsSync as existsSync127, mkdirSync as mkdirSync89, readFileSync as readFileSync113, writeFileSync as writeFileSync69 } from "node:fs";
|
|
635084
|
+
import { join as join191 } from "node:path";
|
|
634809
635085
|
var import_react85 = __toESM(require_react(), 1);
|
|
634810
635086
|
|
|
634811
635087
|
// apps/tui/src/components/primitives/Divider.tsx
|
|
@@ -634817,13 +635093,13 @@ var Divider = ({ width = 60, character = "─" }) => /* @__PURE__ */ jsx_dev_run
|
|
|
634817
635093
|
|
|
634818
635094
|
// apps/tui/src/screens/BTWView.tsx
|
|
634819
635095
|
var jsx_dev_runtime50 = __toESM(require_jsx_dev_runtime(), 1);
|
|
634820
|
-
var DATA_DIR5 =
|
|
635096
|
+
var DATA_DIR5 = join191(process.env.HOME || "~", ".8gent", "tabs");
|
|
634821
635097
|
function loadBTW() {
|
|
634822
635098
|
try {
|
|
634823
|
-
if (!
|
|
635099
|
+
if (!existsSync127(DATA_DIR5))
|
|
634824
635100
|
mkdirSync89(DATA_DIR5, { recursive: true });
|
|
634825
|
-
const filepath =
|
|
634826
|
-
if (
|
|
635101
|
+
const filepath = join191(DATA_DIR5, "btw.json");
|
|
635102
|
+
if (existsSync127(filepath)) {
|
|
634827
635103
|
const raw = JSON.parse(readFileSync113(filepath, "utf-8"));
|
|
634828
635104
|
return raw.items || [];
|
|
634829
635105
|
}
|
|
@@ -634832,9 +635108,9 @@ function loadBTW() {
|
|
|
634832
635108
|
}
|
|
634833
635109
|
function saveBTW(items) {
|
|
634834
635110
|
try {
|
|
634835
|
-
if (!
|
|
635111
|
+
if (!existsSync127(DATA_DIR5))
|
|
634836
635112
|
mkdirSync89(DATA_DIR5, { recursive: true });
|
|
634837
|
-
writeFileSync69(
|
|
635113
|
+
writeFileSync69(join191(DATA_DIR5, "btw.json"), JSON.stringify({ items }, null, 2));
|
|
634838
635114
|
} catch {}
|
|
634839
635115
|
}
|
|
634840
635116
|
function sortItems(items) {
|
|
@@ -635167,17 +635443,17 @@ function HistoryScreen({ conversations, onSelect, onBack }) {
|
|
|
635167
635443
|
}
|
|
635168
635444
|
|
|
635169
635445
|
// apps/tui/src/screens/IdeasView.tsx
|
|
635170
|
-
import { existsSync as
|
|
635171
|
-
import { join as
|
|
635446
|
+
import { existsSync as existsSync128, mkdirSync as mkdirSync90, readFileSync as readFileSync114, writeFileSync as writeFileSync70 } from "node:fs";
|
|
635447
|
+
import { join as join192 } from "node:path";
|
|
635172
635448
|
var import_react87 = __toESM(require_react(), 1);
|
|
635173
635449
|
var jsx_dev_runtime52 = __toESM(require_jsx_dev_runtime(), 1);
|
|
635174
|
-
var DATA_DIR6 =
|
|
635450
|
+
var DATA_DIR6 = join192(process.env.HOME || "~", ".8gent", "tabs");
|
|
635175
635451
|
function loadIdeas() {
|
|
635176
635452
|
try {
|
|
635177
|
-
if (!
|
|
635453
|
+
if (!existsSync128(DATA_DIR6))
|
|
635178
635454
|
mkdirSync90(DATA_DIR6, { recursive: true });
|
|
635179
|
-
const filepath =
|
|
635180
|
-
if (
|
|
635455
|
+
const filepath = join192(DATA_DIR6, "ideas.json");
|
|
635456
|
+
if (existsSync128(filepath)) {
|
|
635181
635457
|
const raw = JSON.parse(readFileSync114(filepath, "utf-8"));
|
|
635182
635458
|
return raw.ideas || [];
|
|
635183
635459
|
}
|
|
@@ -635186,9 +635462,9 @@ function loadIdeas() {
|
|
|
635186
635462
|
}
|
|
635187
635463
|
function saveIdeas(ideas) {
|
|
635188
635464
|
try {
|
|
635189
|
-
if (!
|
|
635465
|
+
if (!existsSync128(DATA_DIR6))
|
|
635190
635466
|
mkdirSync90(DATA_DIR6, { recursive: true });
|
|
635191
|
-
writeFileSync70(
|
|
635467
|
+
writeFileSync70(join192(DATA_DIR6, "ideas.json"), JSON.stringify({ ideas }, null, 2));
|
|
635192
635468
|
} catch {}
|
|
635193
635469
|
}
|
|
635194
635470
|
function extractTags2(text) {
|
|
@@ -635649,11 +635925,11 @@ function KeyVaultScreen({
|
|
|
635649
635925
|
}
|
|
635650
635926
|
|
|
635651
635927
|
// apps/tui/src/screens/MusicPlayerView.tsx
|
|
635652
|
-
import { existsSync as
|
|
635653
|
-
import { basename as
|
|
635928
|
+
import { existsSync as existsSync129, readdirSync as readdirSync28, statSync as statSync39 } from "node:fs";
|
|
635929
|
+
import { basename as basename54, join as join193 } from "node:path";
|
|
635654
635930
|
var import_react89 = __toESM(require_react(), 1);
|
|
635655
635931
|
var jsx_dev_runtime54 = __toESM(require_jsx_dev_runtime(), 1);
|
|
635656
|
-
var CACHE_DIR4 =
|
|
635932
|
+
var CACHE_DIR4 = join193(process.env.HOME || "~", ".8gent", "adhd-audio");
|
|
635657
635933
|
function formatBytes(bytes) {
|
|
635658
635934
|
if (bytes < 1024)
|
|
635659
635935
|
return `${bytes}B`;
|
|
@@ -635671,20 +635947,20 @@ function formatDate(date) {
|
|
|
635671
635947
|
}
|
|
635672
635948
|
function loadTracks(currentTrack) {
|
|
635673
635949
|
const tracks = [];
|
|
635674
|
-
if (!
|
|
635950
|
+
if (!existsSync129(CACHE_DIR4))
|
|
635675
635951
|
return tracks;
|
|
635676
635952
|
try {
|
|
635677
635953
|
const files = readdirSync28(CACHE_DIR4).filter((f) => f.endsWith(".mp3") || f.endsWith(".wav"));
|
|
635678
635954
|
for (const file of files) {
|
|
635679
|
-
const filePath =
|
|
635955
|
+
const filePath = join193(CACHE_DIR4, file);
|
|
635680
635956
|
const stat = statSync39(filePath);
|
|
635681
|
-
const name =
|
|
635957
|
+
const name = basename54(file, ".mp3").replace(/-/g, " ");
|
|
635682
635958
|
tracks.push({
|
|
635683
635959
|
name: name.charAt(0).toUpperCase() + name.slice(1),
|
|
635684
635960
|
path: filePath,
|
|
635685
635961
|
size: formatBytes(stat.size),
|
|
635686
635962
|
modified: formatDate(stat.mtime),
|
|
635687
|
-
playing: currentTrack === name.toLowerCase() || currentTrack ===
|
|
635963
|
+
playing: currentTrack === name.toLowerCase() || currentTrack === basename54(file, ".mp3")
|
|
635688
635964
|
});
|
|
635689
635965
|
}
|
|
635690
635966
|
} catch {}
|
|
@@ -636180,18 +636456,18 @@ function NarratorView({ tasks, narratorText, maxHeight }) {
|
|
|
636180
636456
|
}
|
|
636181
636457
|
|
|
636182
636458
|
// apps/tui/src/screens/NotesView.tsx
|
|
636183
|
-
import { existsSync as
|
|
636184
|
-
import { join as
|
|
636459
|
+
import { existsSync as existsSync130, mkdirSync as mkdirSync91, readFileSync as readFileSync115, writeFileSync as writeFileSync71 } from "node:fs";
|
|
636460
|
+
import { join as join194 } from "node:path";
|
|
636185
636461
|
var import_react91 = __toESM(require_react(), 1);
|
|
636186
636462
|
var jsx_dev_runtime59 = __toESM(require_jsx_dev_runtime(), 1);
|
|
636187
|
-
var DATA_DIR7 =
|
|
636463
|
+
var DATA_DIR7 = join194(process.env.HOME || "~", ".8gent", "tabs");
|
|
636188
636464
|
var EMPTY_TAB_NAMES = [];
|
|
636189
636465
|
function loadNotes() {
|
|
636190
636466
|
try {
|
|
636191
|
-
if (!
|
|
636467
|
+
if (!existsSync130(DATA_DIR7))
|
|
636192
636468
|
mkdirSync91(DATA_DIR7, { recursive: true });
|
|
636193
|
-
const filepath =
|
|
636194
|
-
if (
|
|
636469
|
+
const filepath = join194(DATA_DIR7, "notes.json");
|
|
636470
|
+
if (existsSync130(filepath)) {
|
|
636195
636471
|
const raw = JSON.parse(readFileSync115(filepath, "utf-8"));
|
|
636196
636472
|
return raw.notes || [];
|
|
636197
636473
|
}
|
|
@@ -636200,9 +636476,9 @@ function loadNotes() {
|
|
|
636200
636476
|
}
|
|
636201
636477
|
function saveNotes(notes) {
|
|
636202
636478
|
try {
|
|
636203
|
-
if (!
|
|
636479
|
+
if (!existsSync130(DATA_DIR7))
|
|
636204
636480
|
mkdirSync91(DATA_DIR7, { recursive: true });
|
|
636205
|
-
writeFileSync71(
|
|
636481
|
+
writeFileSync71(join194(DATA_DIR7, "notes.json"), JSON.stringify({ notes }, null, 2));
|
|
636206
636482
|
} catch {}
|
|
636207
636483
|
}
|
|
636208
636484
|
function NotesView({
|
|
@@ -637395,40 +637671,40 @@ function OnboardingScreen({
|
|
|
637395
637671
|
|
|
637396
637672
|
// apps/tui/src/screens/ProjectsView.tsx
|
|
637397
637673
|
import { execSync as execSync9 } from "node:child_process";
|
|
637398
|
-
import { existsSync as
|
|
637674
|
+
import { existsSync as existsSync131, mkdirSync as mkdirSync92, readFileSync as readFileSync116, readdirSync as readdirSync29, statSync as statSync40, writeFileSync as writeFileSync72 } from "node:fs";
|
|
637399
637675
|
import { homedir as homedir91 } from "node:os";
|
|
637400
|
-
import { basename as
|
|
637676
|
+
import { basename as basename55, join as join195 } from "node:path";
|
|
637401
637677
|
var import_react96 = __toESM(require_react(), 1);
|
|
637402
637678
|
var jsx_dev_runtime61 = __toESM(require_jsx_dev_runtime(), 1);
|
|
637403
|
-
var SAVED_PROJECTS_PATH =
|
|
637679
|
+
var SAVED_PROJECTS_PATH = join195(homedir91(), ".8gent", "tabs", "projects.json");
|
|
637404
637680
|
var SCAN_DIRS = [
|
|
637405
637681
|
homedir91(),
|
|
637406
|
-
|
|
637407
|
-
|
|
637408
|
-
|
|
637682
|
+
join195(homedir91(), "Documents"),
|
|
637683
|
+
join195(homedir91(), "Projects"),
|
|
637684
|
+
join195(homedir91(), "Code")
|
|
637409
637685
|
];
|
|
637410
637686
|
var PROJECT_MARKERS = ["package.json", ".git", "CLAUDE.md", ".8gent"];
|
|
637411
637687
|
function isProjectDir(dirPath) {
|
|
637412
637688
|
try {
|
|
637413
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
637689
|
+
return PROJECT_MARKERS.some((marker) => existsSync131(join195(dirPath, marker)));
|
|
637414
637690
|
} catch {
|
|
637415
637691
|
return false;
|
|
637416
637692
|
}
|
|
637417
637693
|
}
|
|
637418
637694
|
function getProjectName(dirPath) {
|
|
637419
637695
|
try {
|
|
637420
|
-
const pkgPath =
|
|
637421
|
-
if (
|
|
637696
|
+
const pkgPath = join195(dirPath, "package.json");
|
|
637697
|
+
if (existsSync131(pkgPath)) {
|
|
637422
637698
|
const pkg = JSON.parse(readFileSync116(pkgPath, "utf8"));
|
|
637423
637699
|
if (pkg.name)
|
|
637424
637700
|
return pkg.name;
|
|
637425
637701
|
}
|
|
637426
637702
|
} catch {}
|
|
637427
|
-
return
|
|
637703
|
+
return basename55(dirPath);
|
|
637428
637704
|
}
|
|
637429
637705
|
function getGitBranch2(dirPath) {
|
|
637430
637706
|
try {
|
|
637431
|
-
if (!
|
|
637707
|
+
if (!existsSync131(join195(dirPath, ".git")))
|
|
637432
637708
|
return;
|
|
637433
637709
|
const result = execSync9(`git -C "${dirPath}" branch --show-current 2>/dev/null`, {
|
|
637434
637710
|
encoding: "utf8",
|
|
@@ -637448,7 +637724,7 @@ function getLastModified(dirPath) {
|
|
|
637448
637724
|
}
|
|
637449
637725
|
}
|
|
637450
637726
|
function has8gent(dirPath) {
|
|
637451
|
-
return
|
|
637727
|
+
return existsSync131(join195(dirPath, ".8gent"));
|
|
637452
637728
|
}
|
|
637453
637729
|
function buildProjectEntry(dirPath) {
|
|
637454
637730
|
return {
|
|
@@ -637465,7 +637741,7 @@ function scanForProjects(currentPath) {
|
|
|
637465
637741
|
found.add(currentPath);
|
|
637466
637742
|
results.push(buildProjectEntry(currentPath));
|
|
637467
637743
|
for (const scanDir of SCAN_DIRS) {
|
|
637468
|
-
if (!
|
|
637744
|
+
if (!existsSync131(scanDir))
|
|
637469
637745
|
continue;
|
|
637470
637746
|
try {
|
|
637471
637747
|
const entries = readdirSync29(scanDir, { withFileTypes: true });
|
|
@@ -637474,7 +637750,7 @@ function scanForProjects(currentPath) {
|
|
|
637474
637750
|
continue;
|
|
637475
637751
|
if (entry.name.startsWith("."))
|
|
637476
637752
|
continue;
|
|
637477
|
-
const fullPath =
|
|
637753
|
+
const fullPath = join195(scanDir, entry.name);
|
|
637478
637754
|
if (found.has(fullPath))
|
|
637479
637755
|
continue;
|
|
637480
637756
|
if (isProjectDir(fullPath)) {
|
|
@@ -637497,7 +637773,7 @@ function scanForProjects(currentPath) {
|
|
|
637497
637773
|
}
|
|
637498
637774
|
function loadSavedProjects() {
|
|
637499
637775
|
try {
|
|
637500
|
-
if (!
|
|
637776
|
+
if (!existsSync131(SAVED_PROJECTS_PATH))
|
|
637501
637777
|
return [];
|
|
637502
637778
|
const raw = readFileSync116(SAVED_PROJECTS_PATH, "utf8");
|
|
637503
637779
|
const data = JSON.parse(raw);
|
|
@@ -637508,7 +637784,7 @@ function loadSavedProjects() {
|
|
|
637508
637784
|
}
|
|
637509
637785
|
function saveSavedProjects(projects) {
|
|
637510
637786
|
try {
|
|
637511
|
-
const dir =
|
|
637787
|
+
const dir = join195(homedir91(), ".8gent", "tabs");
|
|
637512
637788
|
mkdirSync92(dir, { recursive: true });
|
|
637513
637789
|
const data = { projects };
|
|
637514
637790
|
writeFileSync72(SAVED_PROJECTS_PATH, JSON.stringify(data, null, 2), "utf8");
|
|
@@ -637520,7 +637796,7 @@ function mergeProjects(scanned, saved) {
|
|
|
637520
637796
|
for (const s of saved) {
|
|
637521
637797
|
if (paths.has(s.path))
|
|
637522
637798
|
continue;
|
|
637523
|
-
if (!
|
|
637799
|
+
if (!existsSync131(s.path))
|
|
637524
637800
|
continue;
|
|
637525
637801
|
paths.add(s.path);
|
|
637526
637802
|
extra.push(buildProjectEntry(s.path));
|
|
@@ -637588,7 +637864,7 @@ function ProjectsView({
|
|
|
637588
637864
|
if (addMode) {
|
|
637589
637865
|
if (key.return) {
|
|
637590
637866
|
const trimmed = addInput.trim();
|
|
637591
|
-
if (trimmed &&
|
|
637867
|
+
if (trimmed && existsSync131(trimmed)) {
|
|
637592
637868
|
const newEntry = {
|
|
637593
637869
|
...buildProjectEntry(trimmed),
|
|
637594
637870
|
addedAt: new Date().toISOString()
|
|
@@ -637775,17 +638051,17 @@ function ProjectsView({
|
|
|
637775
638051
|
}
|
|
637776
638052
|
|
|
637777
638053
|
// apps/tui/src/screens/QuestionsView.tsx
|
|
637778
|
-
import { existsSync as
|
|
637779
|
-
import { join as
|
|
638054
|
+
import { existsSync as existsSync132, mkdirSync as mkdirSync93, readFileSync as readFileSync117, writeFileSync as writeFileSync73 } from "node:fs";
|
|
638055
|
+
import { join as join196 } from "node:path";
|
|
637780
638056
|
var import_react97 = __toESM(require_react(), 1);
|
|
637781
638057
|
var jsx_dev_runtime62 = __toESM(require_jsx_dev_runtime(), 1);
|
|
637782
|
-
var DATA_DIR8 =
|
|
638058
|
+
var DATA_DIR8 = join196(process.env.HOME || "~", ".8gent", "tabs");
|
|
637783
638059
|
function loadQuestions() {
|
|
637784
638060
|
try {
|
|
637785
|
-
if (!
|
|
638061
|
+
if (!existsSync132(DATA_DIR8))
|
|
637786
638062
|
mkdirSync93(DATA_DIR8, { recursive: true });
|
|
637787
|
-
const filepath =
|
|
637788
|
-
if (
|
|
638063
|
+
const filepath = join196(DATA_DIR8, "questions.json");
|
|
638064
|
+
if (existsSync132(filepath)) {
|
|
637789
638065
|
const raw = JSON.parse(readFileSync117(filepath, "utf-8"));
|
|
637790
638066
|
return raw.questions || [];
|
|
637791
638067
|
}
|
|
@@ -637794,9 +638070,9 @@ function loadQuestions() {
|
|
|
637794
638070
|
}
|
|
637795
638071
|
function saveQuestions(questions) {
|
|
637796
638072
|
try {
|
|
637797
|
-
if (!
|
|
638073
|
+
if (!existsSync132(DATA_DIR8))
|
|
637798
638074
|
mkdirSync93(DATA_DIR8, { recursive: true });
|
|
637799
|
-
writeFileSync73(
|
|
638075
|
+
writeFileSync73(join196(DATA_DIR8, "questions.json"), JSON.stringify({ questions }, null, 2));
|
|
637800
638076
|
} catch {}
|
|
637801
638077
|
}
|
|
637802
638078
|
function QuestionsView({ visible, data, onUpdateData, onClose }) {
|
|
@@ -639082,13 +639358,13 @@ import * as fs104 from "node:fs";
|
|
|
639082
639358
|
import * as pathMod from "node:path";
|
|
639083
639359
|
|
|
639084
639360
|
// apps/tui/src/lib/package-scripts.ts
|
|
639085
|
-
import { existsSync as
|
|
639086
|
-
import { join as
|
|
639361
|
+
import { existsSync as existsSync133 } from "node:fs";
|
|
639362
|
+
import { join as join197, resolve as resolve75 } from "node:path";
|
|
639087
639363
|
var __dirname = (import.meta.dirname + "/../../apps/tui/src/lib");
|
|
639088
|
-
var PACKAGE_ROOT =
|
|
639364
|
+
var PACKAGE_ROOT = resolve75(__dirname, "../../../..");
|
|
639089
639365
|
function packageBinScript(name, root = PACKAGE_ROOT) {
|
|
639090
|
-
const candidate =
|
|
639091
|
-
return
|
|
639366
|
+
const candidate = join197(root, "bin", name);
|
|
639367
|
+
return existsSync133(candidate) ? candidate : null;
|
|
639092
639368
|
}
|
|
639093
639369
|
|
|
639094
639370
|
// apps/tui/src/app.tsx
|
|
@@ -639693,10 +639969,10 @@ function App2({
|
|
|
639693
639969
|
setting,
|
|
639694
639970
|
env: process.env,
|
|
639695
639971
|
seenVersion: readSeenVersion(),
|
|
639696
|
-
version:
|
|
639972
|
+
version: import_package2.default.version
|
|
639697
639973
|
});
|
|
639698
639974
|
if (show)
|
|
639699
|
-
markIntroSeen(
|
|
639975
|
+
markIntroSeen(import_package2.default.version);
|
|
639700
639976
|
return show;
|
|
639701
639977
|
});
|
|
639702
639978
|
const [processingStage, setProcessingStage] = import_react104.useState("planning");
|
|
@@ -641595,7 +641871,7 @@ Keyboard shortcuts:
|
|
|
641595
641871
|
setViewMode((prev) => prev === "kanban" ? "chat" : "kanban");
|
|
641596
641872
|
break;
|
|
641597
641873
|
case "bug":
|
|
641598
|
-
addSystemMessage(runBugCommand(args, { version:
|
|
641874
|
+
addSystemMessage(runBugCommand(args, { version: import_package2.default.version }).text);
|
|
641599
641875
|
break;
|
|
641600
641876
|
case "allow-read":
|
|
641601
641877
|
addSystemMessage(runAllowReadCommand(args, process.cwd(), (d) => agent?.allowReadDir(d) ?? null));
|
|
@@ -641928,6 +642204,19 @@ ${lines.join(`
|
|
|
641928
642204
|
agent.cleanup().catch(() => {});
|
|
641929
642205
|
exit();
|
|
641930
642206
|
break;
|
|
642207
|
+
case "mode": {
|
|
642208
|
+
const next = parseModeArgs(args);
|
|
642209
|
+
if (!next) {
|
|
642210
|
+
addSystemMessage(`${permSwitchLine(activePermMode)}
|
|
642211
|
+
${MODE_USAGE}`);
|
|
642212
|
+
break;
|
|
642213
|
+
}
|
|
642214
|
+
setTabPermMode(activeTabId, next);
|
|
642215
|
+
const shown = permView(permHolderFor(activeTabId));
|
|
642216
|
+
addSystemMessage(permSwitchLine(shown.mode, shown.held));
|
|
642217
|
+
showPermToast({ tabId: activeTabId, ...shown });
|
|
642218
|
+
break;
|
|
642219
|
+
}
|
|
641931
642220
|
case "infinite": {
|
|
641932
642221
|
const next = infiniteModeActive ? "ask" : "infinite";
|
|
641933
642222
|
setTabPermMode(activeTabId, next);
|
|
@@ -644012,6 +644301,26 @@ ${found.slice(0, 40).map((k) => ` ${k.name} ${k.description}`).join(`
|
|
|
644012
644301
|
}
|
|
644013
644302
|
return;
|
|
644014
644303
|
}
|
|
644304
|
+
if (input && !attached) {
|
|
644305
|
+
const termArgs = detectTermPresetIntent(input, listPresetIds());
|
|
644306
|
+
if (termArgs) {
|
|
644307
|
+
appendToTab(tabId, {
|
|
644308
|
+
id: `user-${Date.now()}`,
|
|
644309
|
+
role: "user",
|
|
644310
|
+
content: bubbleContent,
|
|
644311
|
+
timestamp: new Date
|
|
644312
|
+
});
|
|
644313
|
+
setRecentCommands((prev) => [bubbleContent, ...prev].slice(0, 20));
|
|
644314
|
+
const refused = planModeRefusal2(permView(permHolderFor(tabId)).mode);
|
|
644315
|
+
if (refused) {
|
|
644316
|
+
addSystemMessage(refused);
|
|
644317
|
+
return;
|
|
644318
|
+
}
|
|
644319
|
+
addSystemMessage(`Opening ${termArgs[0]} (same as /term ${termArgs.join(" ")}).`);
|
|
644320
|
+
handleSlashCommand("term", termArgs);
|
|
644321
|
+
return;
|
|
644322
|
+
}
|
|
644323
|
+
}
|
|
644015
644324
|
if (input && !attached) {
|
|
644016
644325
|
const buildTask = detectBuildIntent(input);
|
|
644017
644326
|
if (buildTask) {
|
|
@@ -644761,7 +645070,7 @@ ${result.commands.map((c) => ` $ ${c}`).join(`
|
|
|
644761
645070
|
value: { enabled: adhdMode, ratio: 0.5 },
|
|
644762
645071
|
children: /* @__PURE__ */ jsx_dev_runtime67.jsxDEV(FixedFrame, {
|
|
644763
645072
|
children: /* @__PURE__ */ jsx_dev_runtime67.jsxDEV(IntroBanner, {
|
|
644764
|
-
version:
|
|
645073
|
+
version: import_package2.default.version,
|
|
644765
645074
|
animate: showAnimations,
|
|
644766
645075
|
onDone: (carried) => {
|
|
644767
645076
|
bootTrace("intro-done", carried ? "by-key" : "timeout");
|
|
@@ -644835,7 +645144,7 @@ ${result.commands.map((c) => ` $ ${c}`).join(`
|
|
|
644835
645144
|
flexShrink: 0,
|
|
644836
645145
|
children: /* @__PURE__ */ jsx_dev_runtime67.jsxDEV(HeaderBar, {
|
|
644837
645146
|
updateAvailable: updateInfo,
|
|
644838
|
-
version:
|
|
645147
|
+
version: import_package2.default.version,
|
|
644839
645148
|
workspacePath: process.cwd(),
|
|
644840
645149
|
branch: git.branch,
|
|
644841
645150
|
syncStatus: git.noRepo ? "no repo" : git.sync,
|