@prestyj/boss 4.3.160 → 4.3.164
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/README.md +3 -3
- package/dist/{chunk-P2JWHLOI.js → chunk-7QDS2KEP.js} +3 -3
- package/dist/{chunk-YNWFCUMR.js → chunk-DZO3FVYX.js} +3 -3
- package/dist/chunk-DZO3FVYX.js.map +1 -0
- package/dist/{chunk-7QT7YZKN.js → chunk-RVAJYH5L.js} +2 -2
- package/dist/{chunk-PGC5XQTC.js → chunk-STUHLGRN.js} +28536 -13365
- package/dist/{chunk-PGC5XQTC.js.map → chunk-STUHLGRN.js.map} +1 -1
- package/dist/cli.js +1705 -1000
- package/dist/cli.js.map +1 -1
- package/dist/{devtools-4TI4D7F2.js → devtools-ASTBUBZC.js} +11 -33
- package/dist/{devtools-4TI4D7F2.js.map → devtools-ASTBUBZC.js.map} +1 -1
- package/dist/{dist-VXOVSHZ5.js → dist-IGN2W3JX.js} +2 -2
- package/dist/{chunk-EZYGVECW.js → ignore-3XU7YNRW.js} +3 -6
- package/dist/index.js +4 -6
- package/dist/index.js.map +1 -1
- package/dist/{chunk-RMSZMSH5.js → out-NHVJUVVH.js} +3 -6
- package/dist/{pixel-55DE4AGI.js → pixel-ALJG63HU.js} +4 -4
- package/dist/{pixel-fix-4LGSDR3J.js → pixel-fix-6NKZMYMY.js} +3 -3
- package/package.json +5 -5
- package/dist/chunk-YNWFCUMR.js.map +0 -1
- package/dist/ignore-AXNNXJD4.js +0 -7
- package/dist/out-NH6HQBFM.js +0 -7
- package/dist/out-NH6HQBFM.js.map +0 -1
- package/dist/pixel-55DE4AGI.js.map +0 -1
- /package/dist/{chunk-P2JWHLOI.js.map → chunk-7QDS2KEP.js.map} +0 -0
- /package/dist/{chunk-7QT7YZKN.js.map → chunk-RVAJYH5L.js.map} +0 -0
- /package/dist/{dist-VXOVSHZ5.js.map → dist-IGN2W3JX.js.map} +0 -0
- /package/dist/{chunk-EZYGVECW.js.map → ignore-3XU7YNRW.js.map} +0 -0
- /package/dist/{chunk-RMSZMSH5.js.map → out-NHVJUVVH.js.map} +0 -0
- /package/dist/{ignore-AXNNXJD4.js.map → pixel-ALJG63HU.js.map} +0 -0
- /package/dist/{pixel-fix-4LGSDR3J.js.map → pixel-fix-6NKZMYMY.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --max-old-space-size=8192 --expose-gc
|
|
2
2
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
-
ActivityIndicator,
|
|
5
4
|
AnimationProvider,
|
|
6
5
|
AssistantMessage,
|
|
7
6
|
Box_default,
|
|
7
|
+
ChatControls,
|
|
8
|
+
ChatInputStack,
|
|
9
|
+
ChatLayout,
|
|
10
|
+
ChatLivePane,
|
|
8
11
|
CompactionDone,
|
|
9
12
|
CompactionSpinner,
|
|
10
13
|
GGBoss,
|
|
11
14
|
InputArea,
|
|
12
15
|
MODELS,
|
|
13
16
|
MessageResponse,
|
|
14
|
-
|
|
15
|
-
SelectList,
|
|
16
|
-
Static,
|
|
17
|
-
StreamingArea,
|
|
17
|
+
RESPONSE_LEFT_PADDING,
|
|
18
18
|
TerminalSizeProvider,
|
|
19
19
|
Text,
|
|
20
20
|
ThemeContext,
|
|
21
21
|
ToolExecution,
|
|
22
|
+
ToolGroupExecution,
|
|
22
23
|
ToolUseLoader,
|
|
24
|
+
TranscriptItemFrame,
|
|
23
25
|
UserMessage,
|
|
24
26
|
bossStore,
|
|
27
|
+
bossToolGroupRenderers,
|
|
28
|
+
buildToolGroupSummary,
|
|
25
29
|
closeLogger,
|
|
30
|
+
color,
|
|
31
|
+
dim,
|
|
32
|
+
formatHistoryWrite,
|
|
26
33
|
getAppPaths,
|
|
27
34
|
getBossState,
|
|
28
35
|
getContextWindow,
|
|
36
|
+
getNextThinkingLevel,
|
|
29
37
|
getSplashAudioDurationMs,
|
|
38
|
+
getTranscriptItemMarginTop,
|
|
39
|
+
gradientLine,
|
|
40
|
+
indent,
|
|
30
41
|
initLogger,
|
|
31
42
|
loadSettings,
|
|
32
43
|
loadTheme,
|
|
@@ -36,9 +47,16 @@ import {
|
|
|
36
47
|
require_jsx_runtime,
|
|
37
48
|
require_react,
|
|
38
49
|
saveSettings,
|
|
50
|
+
serializeCompletedItemToTerminalHistory,
|
|
39
51
|
setStreamDiagnostic,
|
|
52
|
+
shouldSeparateTranscriptItemKinds,
|
|
53
|
+
shouldTopSpaceStreamingAssistant,
|
|
54
|
+
stripAnsi,
|
|
55
|
+
stripTerminalFocusSequences,
|
|
40
56
|
subscribeToBossStore,
|
|
41
57
|
tasksStore,
|
|
58
|
+
toolTonePalette,
|
|
59
|
+
truncatePlain,
|
|
42
60
|
useAnimationActive,
|
|
43
61
|
useAnimationTick,
|
|
44
62
|
useBossState,
|
|
@@ -48,18 +66,17 @@ import {
|
|
|
48
66
|
useTheme,
|
|
49
67
|
use_app_default,
|
|
50
68
|
use_input_default,
|
|
51
|
-
use_stdout_default
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
import "./chunk-
|
|
55
|
-
import "./chunk-P2JWHLOI.js";
|
|
69
|
+
use_stdout_default,
|
|
70
|
+
wrapPlain
|
|
71
|
+
} from "./chunk-STUHLGRN.js";
|
|
72
|
+
import "./chunk-7QDS2KEP.js";
|
|
56
73
|
import {
|
|
57
74
|
source_default
|
|
58
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-RVAJYH5L.js";
|
|
59
76
|
import {
|
|
60
77
|
__toESM,
|
|
61
78
|
init_esm_shims
|
|
62
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-DZO3FVYX.js";
|
|
63
80
|
|
|
64
81
|
// src/cli.ts
|
|
65
82
|
init_esm_shims();
|
|
@@ -344,7 +361,7 @@ init_esm_shims();
|
|
|
344
361
|
// package.json
|
|
345
362
|
var package_default = {
|
|
346
363
|
name: "@prestyj/boss",
|
|
347
|
-
version: "4.3.
|
|
364
|
+
version: "4.3.164",
|
|
348
365
|
type: "module",
|
|
349
366
|
description: "Orchestrator agent that drives multiple ezcoder sessions across projects from a single chat",
|
|
350
367
|
license: "MIT",
|
|
@@ -374,7 +391,7 @@ var package_default = {
|
|
|
374
391
|
"@types/node": "^25.6.0",
|
|
375
392
|
"@types/react": "^19.2.14",
|
|
376
393
|
chalk: "^5.6.2",
|
|
377
|
-
ink: "
|
|
394
|
+
ink: "6.8.0",
|
|
378
395
|
react: "^19.2.5",
|
|
379
396
|
tsup: "^8.5.1",
|
|
380
397
|
typescript: "^6.0.3",
|
|
@@ -422,24 +439,6 @@ var GRADIENT = [
|
|
|
422
439
|
"#b91c1c"
|
|
423
440
|
// red-700 (slight darker tail)
|
|
424
441
|
];
|
|
425
|
-
var PULSE_COLORS = [
|
|
426
|
-
"#dc2626",
|
|
427
|
-
// crimson
|
|
428
|
-
"#e11d48",
|
|
429
|
-
// rose
|
|
430
|
-
"#be185d",
|
|
431
|
-
// wine
|
|
432
|
-
"#a21caf",
|
|
433
|
-
// magenta
|
|
434
|
-
"#c026d3",
|
|
435
|
-
// fuchsia
|
|
436
|
-
"#a21caf",
|
|
437
|
-
// back
|
|
438
|
-
"#be185d",
|
|
439
|
-
// back
|
|
440
|
-
"#e11d48"
|
|
441
|
-
// back
|
|
442
|
-
];
|
|
443
442
|
var COLORS = {
|
|
444
443
|
primary: "#e11d48",
|
|
445
444
|
// crimson-rose — main brand color
|
|
@@ -452,7 +451,7 @@ var COLORS = {
|
|
|
452
451
|
error: "#f87171"
|
|
453
452
|
};
|
|
454
453
|
function clearScreen() {
|
|
455
|
-
process.stdout.write("\x1B[2J\x1B[
|
|
454
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
456
455
|
}
|
|
457
456
|
|
|
458
457
|
// src/banner.tsx
|
|
@@ -502,9 +501,9 @@ function GradientText({ text }) {
|
|
|
502
501
|
if (ch === " ") {
|
|
503
502
|
chars.push(ch);
|
|
504
503
|
} else {
|
|
505
|
-
const
|
|
504
|
+
const color2 = GRADIENT[colorIdx % GRADIENT.length];
|
|
506
505
|
chars.push(
|
|
507
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color, children: ch }, i)
|
|
506
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: color2, children: ch }, i)
|
|
508
507
|
);
|
|
509
508
|
colorIdx++;
|
|
510
509
|
}
|
|
@@ -1001,8 +1000,14 @@ async function saveBossTelegramConfig(config) {
|
|
|
1001
1000
|
}
|
|
1002
1001
|
function formatItemForTelegram(item) {
|
|
1003
1002
|
switch (item.kind) {
|
|
1003
|
+
case "banner":
|
|
1004
1004
|
case "user":
|
|
1005
|
-
case "
|
|
1005
|
+
case "tool_start":
|
|
1006
|
+
case "tool_done":
|
|
1007
|
+
case "tool_group":
|
|
1008
|
+
case "compacting":
|
|
1009
|
+
case "compacted":
|
|
1010
|
+
case "stopped":
|
|
1006
1011
|
case "worker_event":
|
|
1007
1012
|
return null;
|
|
1008
1013
|
case "assistant": {
|
|
@@ -1341,7 +1346,7 @@ ${lines.join("\n")}`);
|
|
|
1341
1346
|
await bot.send(chatId, `_Voice transcription failed: ${message}_${hint}`);
|
|
1342
1347
|
}
|
|
1343
1348
|
});
|
|
1344
|
-
process.stdout.write("\x1B[2J\x1B[
|
|
1349
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
1345
1350
|
printBanner({
|
|
1346
1351
|
bossModel: options.bossModel,
|
|
1347
1352
|
workerModel: options.workerModel,
|
|
@@ -1445,7 +1450,7 @@ function printBanner(opts) {
|
|
|
1445
1450
|
init_esm_shims();
|
|
1446
1451
|
import readline2 from "readline/promises";
|
|
1447
1452
|
async function runBossTelegramSetup() {
|
|
1448
|
-
process.stdout.write("\x1B[2J\x1B[
|
|
1453
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
1449
1454
|
printSetupBanner();
|
|
1450
1455
|
const existing = await loadBossTelegramConfig();
|
|
1451
1456
|
if (existing) {
|
|
@@ -1533,7 +1538,7 @@ function printSetupBanner() {
|
|
|
1533
1538
|
|
|
1534
1539
|
// src/orchestrator-app.tsx
|
|
1535
1540
|
init_esm_shims();
|
|
1536
|
-
var
|
|
1541
|
+
var import_react15 = __toESM(require_react(), 1);
|
|
1537
1542
|
|
|
1538
1543
|
// ../cli/dist/ui/components/index.js
|
|
1539
1544
|
init_esm_shims();
|
|
@@ -1543,29 +1548,100 @@ init_esm_shims();
|
|
|
1543
1548
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
1544
1549
|
var import_react3 = __toESM(require_react(), 1);
|
|
1545
1550
|
|
|
1546
|
-
// ../cli/dist/ui/components/
|
|
1551
|
+
// ../cli/dist/ui/components/SelectList.js
|
|
1547
1552
|
init_esm_shims();
|
|
1548
1553
|
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
1549
1554
|
var import_react4 = __toESM(require_react(), 1);
|
|
1555
|
+
function SelectList({ items, onSelect, onCancel, initialIndex = 0, windowSize }) {
|
|
1556
|
+
const theme = useTheme();
|
|
1557
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react4.useState)(initialIndex);
|
|
1558
|
+
const [filter, setFilter] = (0, import_react4.useState)("");
|
|
1559
|
+
const filtered = (0, import_react4.useMemo)(() => {
|
|
1560
|
+
if (!filter)
|
|
1561
|
+
return items;
|
|
1562
|
+
const lower = filter.toLowerCase();
|
|
1563
|
+
return items.filter((item) => item.label.toLowerCase().includes(lower) || item.value.toLowerCase().includes(lower));
|
|
1564
|
+
}, [items, filter]);
|
|
1565
|
+
use_input_default((input, key) => {
|
|
1566
|
+
const inputWithoutFocusReports = stripTerminalFocusSequences(input);
|
|
1567
|
+
if (!inputWithoutFocusReports && input)
|
|
1568
|
+
return;
|
|
1569
|
+
input = inputWithoutFocusReports;
|
|
1570
|
+
if (key.escape) {
|
|
1571
|
+
onCancel();
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
if (key.return) {
|
|
1575
|
+
if (filtered.length > 0) {
|
|
1576
|
+
onSelect(filtered[selectedIndex].value);
|
|
1577
|
+
}
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
if (key.upArrow) {
|
|
1581
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
if (key.downArrow) {
|
|
1585
|
+
setSelectedIndex((i) => Math.min(filtered.length - 1, i + 1));
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
if (key.backspace || key.delete) {
|
|
1589
|
+
setFilter((f) => f.slice(0, -1));
|
|
1590
|
+
setSelectedIndex(0);
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1593
|
+
if (input && !key.ctrl && !key.meta) {
|
|
1594
|
+
setFilter((f) => f + input);
|
|
1595
|
+
setSelectedIndex(0);
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
const total = filtered.length;
|
|
1599
|
+
const clampedIndex = Math.min(Math.max(selectedIndex, 0), Math.max(0, total - 1));
|
|
1600
|
+
const useWindow = windowSize !== void 0 && windowSize > 0 && total > windowSize;
|
|
1601
|
+
const start = useWindow ? Math.max(0, Math.min(clampedIndex - Math.floor(windowSize / 2), total - windowSize)) : 0;
|
|
1602
|
+
const end = useWindow ? Math.min(start + windowSize, total) : total;
|
|
1603
|
+
const visible = useWindow ? filtered.slice(start, end) : filtered;
|
|
1604
|
+
const hasAbove = useWindow && start > 0;
|
|
1605
|
+
const hasBelow = useWindow && end < total;
|
|
1606
|
+
return (0, import_jsx_runtime4.jsxs)(Box_default, { flexDirection: "column", children: [filter && (0, import_jsx_runtime4.jsx)(Box_default, { marginBottom: 1, children: (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: ["Filter: ", filter] }) }), hasAbove && (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: [" \u2191 ", start, " more"] }), visible.map((item, i) => {
|
|
1607
|
+
const index = useWindow ? start + i : i;
|
|
1608
|
+
return (0, import_jsx_runtime4.jsxs)(Box_default, { children: [(0, import_jsx_runtime4.jsxs)(Text, { color: index === clampedIndex ? theme.primary : theme.text, children: [index === clampedIndex ? "\u276F " : " ", item.label] }), item.description && (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: [" \u2014 ", item.description] })] }, item.value);
|
|
1609
|
+
}), hasBelow && (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: [" \u2193 ", total - end, " more"] }), filtered.length === 0 && (0, import_jsx_runtime4.jsx)(Text, { color: theme.textDim, children: "No matches" }), (0, import_jsx_runtime4.jsx)(Box_default, { marginTop: 1, children: (0, import_jsx_runtime4.jsx)(Text, { color: theme.textDim, children: "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc cancel" }) })] });
|
|
1610
|
+
}
|
|
1550
1611
|
|
|
1551
|
-
// ../cli/dist/ui/components/
|
|
1612
|
+
// ../cli/dist/ui/components/TaskOverlay.js
|
|
1552
1613
|
init_esm_shims();
|
|
1553
1614
|
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
|
|
1554
1615
|
var import_react5 = __toESM(require_react(), 1);
|
|
1616
|
+
import { randomUUID } from "crypto";
|
|
1617
|
+
import { homedir } from "os";
|
|
1618
|
+
var GAP = " ";
|
|
1619
|
+
var LOGO_WIDTH = 9;
|
|
1620
|
+
var SIDE_BY_SIDE_MIN = LOGO_WIDTH + GAP.length + 20;
|
|
1555
1621
|
|
|
1556
|
-
// ../cli/dist/ui/components/
|
|
1622
|
+
// ../cli/dist/ui/components/SessionSelector.js
|
|
1557
1623
|
init_esm_shims();
|
|
1558
1624
|
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
|
|
1559
1625
|
var import_react6 = __toESM(require_react(), 1);
|
|
1560
1626
|
|
|
1561
|
-
//
|
|
1627
|
+
// ../cli/dist/ui/components/SettingsSelector.js
|
|
1562
1628
|
init_esm_shims();
|
|
1563
|
-
var import_react7 = __toESM(require_react(), 1);
|
|
1564
1629
|
var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
1630
|
+
var import_react7 = __toESM(require_react(), 1);
|
|
1631
|
+
|
|
1632
|
+
// src/boss-chat-screen.tsx
|
|
1633
|
+
init_esm_shims();
|
|
1634
|
+
var import_react13 = __toESM(require_react(), 1);
|
|
1635
|
+
|
|
1636
|
+
// src/boss-footer.tsx
|
|
1637
|
+
init_esm_shims();
|
|
1638
|
+
var import_react8 = __toESM(require_react(), 1);
|
|
1639
|
+
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
1565
1640
|
var PARTIAL_BLOCKS = [" ", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589", "\u2588"];
|
|
1566
1641
|
var LIGHT_SHADE = "\u2591";
|
|
1642
|
+
var BAR_WIDTH = 8;
|
|
1567
1643
|
var SHORT_MODELS = {
|
|
1568
|
-
"claude-opus-4-
|
|
1644
|
+
"claude-opus-4-8": "Opus",
|
|
1569
1645
|
"claude-sonnet-4-6": "Sonnet",
|
|
1570
1646
|
"claude-haiku-4-5": "Haiku",
|
|
1571
1647
|
"claude-haiku-4-5-20251001": "Haiku",
|
|
@@ -1577,17 +1653,51 @@ var SHORT_MODELS = {
|
|
|
1577
1653
|
function shortModel(model) {
|
|
1578
1654
|
return SHORT_MODELS[model] ?? model;
|
|
1579
1655
|
}
|
|
1580
|
-
function
|
|
1656
|
+
function getBossFooterContextPercent(model, tokensIn) {
|
|
1581
1657
|
const limit = getContextWindow(model);
|
|
1582
1658
|
if (!limit || tokensIn === 0) return 0;
|
|
1583
1659
|
return Math.round(tokensIn / limit * 100);
|
|
1584
1660
|
}
|
|
1661
|
+
function getContextColor(pct, theme) {
|
|
1662
|
+
if (pct >= 80) return theme.error;
|
|
1663
|
+
if (pct >= 50) return theme.warning;
|
|
1664
|
+
return theme.success;
|
|
1665
|
+
}
|
|
1666
|
+
function getThinkingColor(level, theme) {
|
|
1667
|
+
if (!level) return theme.textDim;
|
|
1668
|
+
if (level === "low") return theme.textMuted;
|
|
1669
|
+
if (level === "medium") return theme.accent;
|
|
1670
|
+
if (level === "high") return theme.warning;
|
|
1671
|
+
return COLORS.accent;
|
|
1672
|
+
}
|
|
1673
|
+
function getBossFooterThinkingLabel(level) {
|
|
1674
|
+
return level ? `Thinking ${level}` : "Thinking off";
|
|
1675
|
+
}
|
|
1585
1676
|
var SHORT_RADIO = {
|
|
1586
1677
|
"somafm-groove-salad": "Groove Salad",
|
|
1587
1678
|
"somafm-drone-zone": "Drone Zone",
|
|
1588
1679
|
"radio-paradise": "Radio Paradise",
|
|
1589
1680
|
"george-fm": "George FM"
|
|
1590
1681
|
};
|
|
1682
|
+
function renderContextBar({
|
|
1683
|
+
contextPct,
|
|
1684
|
+
contextColor,
|
|
1685
|
+
dimColor
|
|
1686
|
+
}) {
|
|
1687
|
+
const fillFloat = Math.min(contextPct / 100 * BAR_WIDTH, BAR_WIDTH);
|
|
1688
|
+
const barChars = [];
|
|
1689
|
+
for (let i = 0; i < BAR_WIDTH; i++) {
|
|
1690
|
+
const cellFill = Math.max(0, Math.min(1, fillFloat - i));
|
|
1691
|
+
const eighths = Math.round(cellFill * 8);
|
|
1692
|
+
barChars.push(
|
|
1693
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: eighths > 0 ? contextColor : dimColor, children: eighths > 0 ? PARTIAL_BLOCKS[eighths] : LIGHT_SHADE }, i)
|
|
1694
|
+
);
|
|
1695
|
+
}
|
|
1696
|
+
return barChars;
|
|
1697
|
+
}
|
|
1698
|
+
function getBossFooterScopeLabel(scope) {
|
|
1699
|
+
return scope === "all" ? "all projects" : scope;
|
|
1700
|
+
}
|
|
1591
1701
|
function BossFooter({
|
|
1592
1702
|
bossModel,
|
|
1593
1703
|
workerModel,
|
|
@@ -1595,149 +1705,231 @@ function BossFooter({
|
|
|
1595
1705
|
exitPending,
|
|
1596
1706
|
bossThinkingLevel,
|
|
1597
1707
|
updatePending,
|
|
1598
|
-
currentRadioStationId
|
|
1708
|
+
currentRadioStationId,
|
|
1709
|
+
scope
|
|
1599
1710
|
}) {
|
|
1600
1711
|
const theme = useTheme();
|
|
1601
1712
|
const { columns } = useTerminalSize();
|
|
1602
1713
|
if (exitPending) {
|
|
1603
|
-
return /* @__PURE__ */ (0,
|
|
1604
|
-
}
|
|
1605
|
-
const contextPct = getContextPercent(bossModel, tokensIn);
|
|
1606
|
-
const contextColor = contextPct >= 80 ? theme.error : contextPct >= 50 ? theme.warning : theme.success;
|
|
1607
|
-
const sep = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.border, children: " \u2502 " });
|
|
1608
|
-
const barWidth = 8;
|
|
1609
|
-
const fillFloat = Math.min(contextPct / 100 * barWidth, barWidth);
|
|
1610
|
-
const barChars = [];
|
|
1611
|
-
for (let i = 0; i < barWidth; i++) {
|
|
1612
|
-
const cellFill = Math.max(0, Math.min(1, fillFloat - i));
|
|
1613
|
-
const eighths = Math.round(cellFill * 8);
|
|
1614
|
-
if (eighths === 8) {
|
|
1615
|
-
barChars.push(
|
|
1616
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: contextColor, children: PARTIAL_BLOCKS[8] }, i)
|
|
1617
|
-
);
|
|
1618
|
-
} else if (eighths > 0) {
|
|
1619
|
-
barChars.push(
|
|
1620
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: contextColor, children: PARTIAL_BLOCKS[eighths] }, i)
|
|
1621
|
-
);
|
|
1622
|
-
} else {
|
|
1623
|
-
barChars.push(
|
|
1624
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.textDim, children: LIGHT_SHADE }, i)
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1714
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { paddingLeft: 1, paddingRight: 1, width: columns, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.warning, children: "Press Ctrl+C again to exit" }) });
|
|
1627
1715
|
}
|
|
1716
|
+
const contextPct = getBossFooterContextPercent(bossModel, tokensIn);
|
|
1717
|
+
const contextColor = getContextColor(contextPct, theme);
|
|
1718
|
+
const sep = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.border, children: " \u2502 " });
|
|
1719
|
+
const bossName = shortModel(bossModel);
|
|
1720
|
+
const workerName = shortModel(workerModel);
|
|
1721
|
+
const thinkingText = getBossFooterThinkingLabel(bossThinkingLevel);
|
|
1628
1722
|
const radioName = currentRadioStationId ? SHORT_RADIO[currentRadioStationId] ?? currentRadioStationId : null;
|
|
1629
|
-
const
|
|
1630
|
-
const
|
|
1631
|
-
const
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
(
|
|
1637
|
-
const
|
|
1638
|
-
const
|
|
1639
|
-
const
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
/* @__PURE__ */ (0,
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1723
|
+
const updateText = updatePending ? "Update ready. Restart EZ Boss." : null;
|
|
1724
|
+
const leftText = getBossFooterScopeLabel(scope);
|
|
1725
|
+
const barChars = renderContextBar({
|
|
1726
|
+
contextPct,
|
|
1727
|
+
contextColor,
|
|
1728
|
+
dimColor: theme.textDim
|
|
1729
|
+
});
|
|
1730
|
+
const rightLen = BAR_WIDTH + 1 + String(contextPct).length + 3 + bossName.length + 3 + "workers ".length + workerName.length + 3 + thinkingText.length + (radioName ? 3 + 2 + radioName.length : 0) + (updateText ? 3 + updateText.length : 0);
|
|
1731
|
+
const availableWidth = columns - 2;
|
|
1732
|
+
const fitsOnOneLine = leftText.length + rightLen <= availableWidth;
|
|
1733
|
+
const hideRadio = !!radioName && leftText.length + rightLen > availableWidth + 8;
|
|
1734
|
+
const compactUpdate = !!updateText && leftText.length + rightLen > availableWidth + 12;
|
|
1735
|
+
const rightContent = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: barChars }),
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: contextColor, children: [
|
|
1738
|
+
" ",
|
|
1739
|
+
contextPct,
|
|
1740
|
+
"%"
|
|
1741
|
+
] }),
|
|
1742
|
+
sep,
|
|
1743
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.primary, bold: true, children: bossName }),
|
|
1744
|
+
sep,
|
|
1745
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.textDim, children: "workers " }),
|
|
1746
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: COLORS.accent, bold: true, children: workerName }),
|
|
1747
|
+
sep,
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: getThinkingColor(bossThinkingLevel, theme), bold: bossThinkingLevel === "high", children: thinkingText }),
|
|
1749
|
+
radioName && !hideRadio && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1652
1750
|
sep,
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
sep,
|
|
1657
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: bossThinkingLevel ? theme.accent : theme.textDim, children: bossThinkingLevel ? "Thinking on" : "Thinking off" })
|
|
1658
|
-
] }),
|
|
1659
|
-
radioName && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1660
|
-
sep,
|
|
1661
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: theme.secondary ?? theme.accent, children: [
|
|
1662
|
-
"\u266A ",
|
|
1663
|
-
radioName
|
|
1664
|
-
] })
|
|
1665
|
-
] }),
|
|
1666
|
-
updatePending && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1667
|
-
sep,
|
|
1668
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.success, bold: true, wrap: "truncate", children: useShortUpdate ? "Update ready" : "Update ready. Restart EZ Boss." })
|
|
1751
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: theme.secondary, children: [
|
|
1752
|
+
"\u266A ",
|
|
1753
|
+
radioName
|
|
1669
1754
|
] })
|
|
1755
|
+
] }),
|
|
1756
|
+
updateText && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1757
|
+
sep,
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.success, bold: true, wrap: "truncate", children: compactUpdate ? "Update ready" : updateText })
|
|
1670
1759
|
] })
|
|
1671
1760
|
] });
|
|
1761
|
+
if (fitsOnOneLine) {
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { paddingLeft: 1, paddingRight: 1, width: columns, children: [
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.textDim, wrap: "truncate", children: leftText }) }),
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexShrink: 0, children: rightContent })
|
|
1765
|
+
] });
|
|
1766
|
+
}
|
|
1767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, width: columns, children: [
|
|
1768
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.textDim, wrap: "truncate", children: leftText }) }),
|
|
1769
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { children: rightContent })
|
|
1770
|
+
] });
|
|
1672
1771
|
}
|
|
1673
1772
|
|
|
1674
|
-
// src/
|
|
1773
|
+
// src/boss-model-selector.tsx
|
|
1675
1774
|
init_esm_shims();
|
|
1676
|
-
var
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
if (
|
|
1775
|
+
var import_react9 = __toESM(require_react(), 1);
|
|
1776
|
+
var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
|
|
1777
|
+
var MAX_MODELS_TO_SHOW = 8;
|
|
1778
|
+
var PROVIDER_LABEL = {
|
|
1779
|
+
anthropic: "Anthropic",
|
|
1780
|
+
openai: "OpenAI",
|
|
1781
|
+
gemini: "Gemini",
|
|
1782
|
+
glm: "Z.AI",
|
|
1783
|
+
moonshot: "Moonshot",
|
|
1784
|
+
xiaomi: "Xiaomi",
|
|
1785
|
+
minimax: "MiniMax",
|
|
1786
|
+
deepseek: "DeepSeek",
|
|
1787
|
+
openrouter: "OpenRouter"
|
|
1788
|
+
};
|
|
1789
|
+
var ESC = String.fromCharCode(27);
|
|
1790
|
+
var ESC_FOCUS_GAINED = `${ESC}[I`;
|
|
1791
|
+
var ESC_FOCUS_LOST = `${ESC}[O`;
|
|
1792
|
+
var ESC_LESS_FOCUS_GAINED = "[I";
|
|
1793
|
+
var ESC_LESS_FOCUS_LOST = "[O";
|
|
1794
|
+
function stripTerminalFocusSequences2(input) {
|
|
1795
|
+
const withoutEscFocusReports = input.replaceAll(ESC_FOCUS_GAINED, "").replaceAll(ESC_FOCUS_LOST, "");
|
|
1796
|
+
let remaining = withoutEscFocusReports;
|
|
1797
|
+
while (remaining.length > 0) {
|
|
1798
|
+
if (remaining.startsWith(ESC_LESS_FOCUS_GAINED) || remaining.startsWith(ESC_LESS_FOCUS_LOST)) {
|
|
1799
|
+
remaining = remaining.slice(2);
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
return withoutEscFocusReports;
|
|
1700
1803
|
}
|
|
1701
|
-
return
|
|
1804
|
+
return "";
|
|
1702
1805
|
}
|
|
1703
|
-
function
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1806
|
+
function BossModelSelectList({
|
|
1807
|
+
items,
|
|
1808
|
+
onSelect,
|
|
1809
|
+
onCancel,
|
|
1810
|
+
initialIndex
|
|
1811
|
+
}) {
|
|
1812
|
+
const theme = useTheme();
|
|
1813
|
+
const { columns } = useTerminalSize();
|
|
1814
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react9.useState)(initialIndex);
|
|
1815
|
+
const [filter, setFilter] = (0, import_react9.useState)("");
|
|
1816
|
+
const filtered = (0, import_react9.useMemo)(() => {
|
|
1817
|
+
if (!filter) return items;
|
|
1818
|
+
const lower = filter.toLowerCase();
|
|
1819
|
+
return items.filter(
|
|
1820
|
+
(item) => item.label.toLowerCase().includes(lower) || item.value.toLowerCase().includes(lower) || item.description.toLowerCase().includes(lower)
|
|
1821
|
+
);
|
|
1822
|
+
}, [items, filter]);
|
|
1823
|
+
use_input_default((input, key) => {
|
|
1824
|
+
const inputWithoutFocusReports = stripTerminalFocusSequences2(input);
|
|
1825
|
+
if (!inputWithoutFocusReports && input) return;
|
|
1826
|
+
input = inputWithoutFocusReports;
|
|
1827
|
+
if (key.escape) {
|
|
1828
|
+
onCancel();
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
if (key.return) {
|
|
1832
|
+
const selected = filtered[selectedIndex];
|
|
1833
|
+
if (selected) onSelect(selected.value);
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
if (key.upArrow) {
|
|
1837
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
if (key.downArrow) {
|
|
1841
|
+
setSelectedIndex((i) => filtered.length === 0 ? 0 : Math.min(filtered.length - 1, i + 1));
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
if (key.backspace || key.delete) {
|
|
1845
|
+
setFilter((current) => current.slice(0, -1));
|
|
1846
|
+
setSelectedIndex(0);
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
if (input && !key.ctrl && !key.meta) {
|
|
1850
|
+
setFilter((current) => current + input);
|
|
1851
|
+
setSelectedIndex(0);
|
|
1852
|
+
}
|
|
1853
|
+
});
|
|
1854
|
+
const total = filtered.length;
|
|
1855
|
+
const idx = Math.min(Math.max(selectedIndex, 0), Math.max(0, total - 1));
|
|
1856
|
+
const start = total <= MAX_MODELS_TO_SHOW ? 0 : Math.max(0, Math.min(idx - Math.floor(MAX_MODELS_TO_SHOW / 2), total - MAX_MODELS_TO_SHOW));
|
|
1857
|
+
const end = Math.min(start + MAX_MODELS_TO_SHOW, total);
|
|
1858
|
+
const visible = filtered.slice(start, end);
|
|
1859
|
+
const width = Math.max(20, columns);
|
|
1860
|
+
const maxLabelLength = Math.max(0, ...filtered.map((item) => item.label.length));
|
|
1861
|
+
const labelColumnWidth = Math.min(maxLabelLength, Math.floor(width * 0.5));
|
|
1862
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, width, children: [
|
|
1863
|
+
filter && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.textDim, children: [
|
|
1864
|
+
"Filter: ",
|
|
1865
|
+
filter
|
|
1866
|
+
] }),
|
|
1867
|
+
start > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.text, children: "\u25B2" }),
|
|
1868
|
+
visible.map((item, i) => {
|
|
1869
|
+
const actualIndex = start + i;
|
|
1870
|
+
const isSelected = actualIndex === idx;
|
|
1871
|
+
const textColor = isSelected ? theme.commandColor : theme.textDim;
|
|
1872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1873
|
+
Box_default,
|
|
1874
|
+
{
|
|
1875
|
+
flexDirection: "row",
|
|
1876
|
+
backgroundColor: isSelected ? theme.border : void 0,
|
|
1877
|
+
children: [
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { width: labelColumnWidth, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: textColor, children: item.label }) }),
|
|
1879
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { flexGrow: 1, paddingLeft: 3, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: textColor, wrap: "truncate", children: item.description.slice(0, 100) }) })
|
|
1880
|
+
]
|
|
1881
|
+
},
|
|
1882
|
+
item.value
|
|
1883
|
+
);
|
|
1884
|
+
}),
|
|
1885
|
+
end < total && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: "\u25BC" }),
|
|
1886
|
+
total > MAX_MODELS_TO_SHOW && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.textDim, children: [
|
|
1887
|
+
"(",
|
|
1888
|
+
idx + 1,
|
|
1889
|
+
"/",
|
|
1890
|
+
total,
|
|
1891
|
+
")"
|
|
1892
|
+
] }),
|
|
1893
|
+
total === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: "No matches" })
|
|
1894
|
+
] });
|
|
1895
|
+
}
|
|
1896
|
+
function BossModelSelector({
|
|
1897
|
+
onSelect,
|
|
1898
|
+
onCancel,
|
|
1899
|
+
currentModel,
|
|
1900
|
+
currentProvider
|
|
1901
|
+
}) {
|
|
1902
|
+
const currentValue = `${currentProvider}:${currentModel}`;
|
|
1903
|
+
const items = (0, import_react9.useMemo)(
|
|
1904
|
+
() => MODELS.map((model) => {
|
|
1905
|
+
const value = `${model.provider}:${model.id}`;
|
|
1906
|
+
const isCurrent = value === currentValue;
|
|
1907
|
+
return {
|
|
1908
|
+
label: `${isCurrent ? "* " : " "}${model.name}`,
|
|
1909
|
+
value,
|
|
1910
|
+
description: `${PROVIDER_LABEL[model.provider] ?? model.provider} \xB7 ${model.id}`
|
|
1911
|
+
};
|
|
1912
|
+
}),
|
|
1913
|
+
[currentValue]
|
|
1914
|
+
);
|
|
1915
|
+
const initialIndex = Math.max(
|
|
1916
|
+
0,
|
|
1917
|
+
items.findIndex((item) => item.value === currentValue)
|
|
1918
|
+
);
|
|
1919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1920
|
+
BossModelSelectList,
|
|
1921
|
+
{
|
|
1922
|
+
items,
|
|
1923
|
+
onSelect,
|
|
1924
|
+
onCancel,
|
|
1925
|
+
initialIndex
|
|
1926
|
+
}
|
|
1927
|
+
);
|
|
1737
1928
|
}
|
|
1738
1929
|
|
|
1739
|
-
// src/
|
|
1930
|
+
// src/boss-tasks-overlay.tsx
|
|
1740
1931
|
init_esm_shims();
|
|
1932
|
+
var import_react10 = __toESM(require_react(), 1);
|
|
1741
1933
|
|
|
1742
1934
|
// src/colors.ts
|
|
1743
1935
|
init_esm_shims();
|
|
@@ -1770,206 +1962,48 @@ function projectColor(name) {
|
|
|
1770
1962
|
return PROJECT_COLORS[stableHash(name) % PROJECT_COLORS.length];
|
|
1771
1963
|
}
|
|
1772
1964
|
|
|
1773
|
-
// src/
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1965
|
+
// src/boss-tasks-overlay.tsx
|
|
1966
|
+
var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
|
|
1967
|
+
function statusGlyph(status) {
|
|
1968
|
+
switch (status) {
|
|
1969
|
+
case "done":
|
|
1970
|
+
return "\u2713";
|
|
1971
|
+
case "in_progress":
|
|
1972
|
+
return "~";
|
|
1973
|
+
case "blocked":
|
|
1974
|
+
return "\u2717";
|
|
1975
|
+
case "skipped":
|
|
1976
|
+
return "\u2014";
|
|
1977
|
+
default:
|
|
1978
|
+
return " ";
|
|
1979
|
+
}
|
|
1782
1980
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
const maxMsg = promptWorkerDetailLen(project) - (fresh ? 8 : 0);
|
|
1810
|
-
const truncMsg = truncate2(message, Math.max(15, maxMsg));
|
|
1811
|
-
const head = fresh ? "fresh \xB7 " : "";
|
|
1812
|
-
return project ? `${head}${project} \xB7 ${truncMsg}` : `${head}${truncMsg}`;
|
|
1813
|
-
}
|
|
1814
|
-
default:
|
|
1815
|
-
return void 0;
|
|
1816
|
-
}
|
|
1817
|
-
},
|
|
1818
|
-
formatInline(name, result, isError) {
|
|
1819
|
-
if (isError) return void 0;
|
|
1820
|
-
switch (name) {
|
|
1821
|
-
case "list_workers": {
|
|
1822
|
-
const lines = result.split("\n").filter((l) => l.startsWith("-"));
|
|
1823
|
-
return `${lines.length} worker${lines.length === 1 ? "" : "s"}`;
|
|
1824
|
-
}
|
|
1825
|
-
case "prompt_worker": {
|
|
1826
|
-
if (result.includes("currently working")) {
|
|
1827
|
-
return { text: "busy \u2014 skipped", color: "#fbbf24" };
|
|
1828
|
-
}
|
|
1829
|
-
if (result.includes("Unknown project")) {
|
|
1830
|
-
return { text: "unknown project", color: "#f87171" };
|
|
1831
|
-
}
|
|
1832
|
-
const project = String(result.match(/"([^"]+)"/)?.[1] ?? "");
|
|
1833
|
-
const color = project ? projectColor(project) : "#e11d48";
|
|
1834
|
-
return { text: "dispatched", color };
|
|
1835
|
-
}
|
|
1836
|
-
case "get_worker_status": {
|
|
1837
|
-
const parts = result.split(":");
|
|
1838
|
-
if (parts.length < 2) return void 0;
|
|
1839
|
-
const status = parts.slice(1).join(":").trim();
|
|
1840
|
-
const project = parts[0].trim();
|
|
1841
|
-
return { text: status, color: projectColor(project) };
|
|
1842
|
-
}
|
|
1843
|
-
case "get_worker_summary": {
|
|
1844
|
-
const turnMatch = result.match(/Turn:\s*(\d+)/);
|
|
1845
|
-
const projectMatch = result.match(/Project:\s*(.+)/);
|
|
1846
|
-
const toolsMatch = result.match(/Tools used:\s*(.+)/);
|
|
1847
|
-
const tools = toolsMatch ? toolsMatch[1] : "";
|
|
1848
|
-
const toolCount = tools && tools !== "(no tools used)" ? tools.split(",").length : 0;
|
|
1849
|
-
const turn = turnMatch ? `turn ${turnMatch[1]}` : void 0;
|
|
1850
|
-
const tCount = toolCount > 0 ? `${toolCount} tool${toolCount === 1 ? "" : "s"}` : void 0;
|
|
1851
|
-
const summary = [turn, tCount].filter(Boolean).join(" \xB7 ");
|
|
1852
|
-
if (!summary) return void 0;
|
|
1853
|
-
const project = projectMatch ? projectMatch[1].trim() : "";
|
|
1854
|
-
return project ? { text: summary, color: projectColor(project) } : { text: summary, color: "#9ca3af" };
|
|
1855
|
-
}
|
|
1856
|
-
default:
|
|
1857
|
-
return void 0;
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
};
|
|
1861
|
-
|
|
1862
|
-
// src/boss-phrases.ts
|
|
1863
|
-
init_esm_shims();
|
|
1864
|
-
var BOSS_PHRASES = {
|
|
1865
|
-
// Generic between-states fallback. Probably never shown but keep for safety.
|
|
1866
|
-
idle: ["Standing by", "Waiting for orders", "On call"],
|
|
1867
|
-
// Boss has issued a request, waiting for the LLM to begin streaming.
|
|
1868
|
-
waiting: [
|
|
1869
|
-
"Briefing",
|
|
1870
|
-
"Reviewing the room",
|
|
1871
|
-
"Triaging",
|
|
1872
|
-
"Lining up the brief",
|
|
1873
|
-
"Surveying projects",
|
|
1874
|
-
"Reading the room",
|
|
1875
|
-
"Picking the right hand",
|
|
1876
|
-
"Marshalling thoughts",
|
|
1877
|
-
"Checking the board",
|
|
1878
|
-
"Sizing up the work"
|
|
1879
|
-
],
|
|
1880
|
-
// LLM is mid-thinking-block (extended reasoning).
|
|
1881
|
-
thinking: [
|
|
1882
|
-
"Strategising",
|
|
1883
|
-
"Plotting next move",
|
|
1884
|
-
"Weighing options",
|
|
1885
|
-
"Reasoning",
|
|
1886
|
-
"Deliberating",
|
|
1887
|
-
"Thinking it through",
|
|
1888
|
-
"Mapping the play",
|
|
1889
|
-
"Considering angles",
|
|
1890
|
-
"Calculating odds",
|
|
1891
|
-
"Drafting the call"
|
|
1892
|
-
],
|
|
1893
|
-
// LLM is streaming text — boss is forming its dispatch / response.
|
|
1894
|
-
generating: [
|
|
1895
|
-
"Drafting",
|
|
1896
|
-
"Composing dispatch",
|
|
1897
|
-
"Writing the brief",
|
|
1898
|
-
"Penning instructions",
|
|
1899
|
-
"Wording it up",
|
|
1900
|
-
"Putting it on paper",
|
|
1901
|
-
"Phrasing the ask",
|
|
1902
|
-
"Forming the directive",
|
|
1903
|
-
"Scripting the plan"
|
|
1904
|
-
],
|
|
1905
|
-
// Boss is invoking a tool — most often prompt_worker.
|
|
1906
|
-
tools: [
|
|
1907
|
-
"Coordinating",
|
|
1908
|
-
"Dispatching",
|
|
1909
|
-
"Routing",
|
|
1910
|
-
"Delegating",
|
|
1911
|
-
"Issuing orders",
|
|
1912
|
-
"Handing off",
|
|
1913
|
-
"Aligning workers",
|
|
1914
|
-
"Conducting",
|
|
1915
|
-
"Calling the team",
|
|
1916
|
-
"Steering",
|
|
1917
|
-
"Pulling levers"
|
|
1918
|
-
],
|
|
1919
|
-
// Provider retry (overloaded / rate-limited / etc.).
|
|
1920
|
-
retrying: [
|
|
1921
|
-
"Reattempting",
|
|
1922
|
-
"Course correcting",
|
|
1923
|
-
"Trying again",
|
|
1924
|
-
"Pushing through",
|
|
1925
|
-
"Holding the line"
|
|
1926
|
-
]
|
|
1927
|
-
};
|
|
1928
|
-
|
|
1929
|
-
// src/boss-tasks-overlay.tsx
|
|
1930
|
-
init_esm_shims();
|
|
1931
|
-
var import_react8 = __toESM(require_react(), 1);
|
|
1932
|
-
var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
1933
|
-
function statusGlyph(status) {
|
|
1934
|
-
switch (status) {
|
|
1935
|
-
case "done":
|
|
1936
|
-
return "\u2713";
|
|
1937
|
-
case "in_progress":
|
|
1938
|
-
return "~";
|
|
1939
|
-
case "blocked":
|
|
1940
|
-
return "\u2717";
|
|
1941
|
-
case "skipped":
|
|
1942
|
-
return "\u2014";
|
|
1943
|
-
default:
|
|
1944
|
-
return " ";
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
function BossTasksOverlay({
|
|
1948
|
-
boss,
|
|
1949
|
-
workers,
|
|
1950
|
-
onClose
|
|
1951
|
-
}) {
|
|
1952
|
-
const theme = useTheme();
|
|
1953
|
-
const tasksState = useTasksState();
|
|
1954
|
-
const tasks = tasksState.tasks;
|
|
1955
|
-
const [selectedIndex, setSelectedIndex] = (0, import_react8.useState)(0);
|
|
1956
|
-
const [status, setStatusMsg] = (0, import_react8.useState)("");
|
|
1957
|
-
const statusTimer = (0, import_react8.useRef)(null);
|
|
1958
|
-
const showStatus = (0, import_react8.useCallback)((msg) => {
|
|
1959
|
-
setStatusMsg(msg);
|
|
1960
|
-
if (statusTimer.current) clearTimeout(statusTimer.current);
|
|
1961
|
-
statusTimer.current = setTimeout(() => setStatusMsg(""), 2500);
|
|
1962
|
-
}, []);
|
|
1963
|
-
const groupedTasks = workers.map((w) => ({
|
|
1964
|
-
project: w.name,
|
|
1965
|
-
tasks: tasks.filter((t) => t.project === w.name).sort((a, b) => a.createdAt.localeCompare(b.createdAt))
|
|
1966
|
-
}));
|
|
1967
|
-
const flatTasks = groupedTasks.flatMap((g) => g.tasks);
|
|
1968
|
-
(0, import_react8.useEffect)(() => {
|
|
1969
|
-
if (flatTasks.length === 0) {
|
|
1970
|
-
setSelectedIndex(0);
|
|
1971
|
-
} else if (selectedIndex >= flatTasks.length) {
|
|
1972
|
-
setSelectedIndex(flatTasks.length - 1);
|
|
1981
|
+
function BossTasksOverlay({
|
|
1982
|
+
boss,
|
|
1983
|
+
workers,
|
|
1984
|
+
onClose
|
|
1985
|
+
}) {
|
|
1986
|
+
const theme = useTheme();
|
|
1987
|
+
const tasksState = useTasksState();
|
|
1988
|
+
const tasks = tasksState.tasks;
|
|
1989
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react10.useState)(0);
|
|
1990
|
+
const [status, setStatusMsg] = (0, import_react10.useState)("");
|
|
1991
|
+
const statusTimer = (0, import_react10.useRef)(null);
|
|
1992
|
+
const showStatus = (0, import_react10.useCallback)((msg) => {
|
|
1993
|
+
setStatusMsg(msg);
|
|
1994
|
+
if (statusTimer.current) clearTimeout(statusTimer.current);
|
|
1995
|
+
statusTimer.current = setTimeout(() => setStatusMsg(""), 2500);
|
|
1996
|
+
}, []);
|
|
1997
|
+
const groupedTasks = workers.map((w) => ({
|
|
1998
|
+
project: w.name,
|
|
1999
|
+
tasks: tasks.filter((t) => t.project === w.name).sort((a, b) => a.createdAt.localeCompare(b.createdAt))
|
|
2000
|
+
}));
|
|
2001
|
+
const flatTasks = groupedTasks.flatMap((g) => g.tasks);
|
|
2002
|
+
(0, import_react10.useEffect)(() => {
|
|
2003
|
+
if (flatTasks.length === 0) {
|
|
2004
|
+
setSelectedIndex(0);
|
|
2005
|
+
} else if (selectedIndex >= flatTasks.length) {
|
|
2006
|
+
setSelectedIndex(flatTasks.length - 1);
|
|
1973
2007
|
}
|
|
1974
2008
|
}, [flatTasks.length, selectedIndex]);
|
|
1975
2009
|
const selected = flatTasks[selectedIndex];
|
|
@@ -2025,11 +2059,11 @@ function BossTasksOverlay({
|
|
|
2025
2059
|
const inProgressCount = tasks.filter((t) => t.status === "in_progress").length;
|
|
2026
2060
|
const pendingCount = tasks.filter((t) => t.status === "pending").length;
|
|
2027
2061
|
const blockedCount = tasks.filter((t) => t.status === "blocked").length;
|
|
2028
|
-
return /* @__PURE__ */ (0,
|
|
2029
|
-
/* @__PURE__ */ (0,
|
|
2030
|
-
/* @__PURE__ */ (0,
|
|
2031
|
-
/* @__PURE__ */ (0,
|
|
2032
|
-
/* @__PURE__ */ (0,
|
|
2062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, paddingX: 1, children: [
|
|
2063
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { children: [
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: COLORS.primary, bold: true, children: "Tasks" }),
|
|
2065
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ` \xB7 ${tasks.length} total \xB7 ` }),
|
|
2066
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2033
2067
|
CountsRow,
|
|
2034
2068
|
{
|
|
2035
2069
|
theme,
|
|
@@ -2040,28 +2074,28 @@ function BossTasksOverlay({
|
|
|
2040
2074
|
}
|
|
2041
2075
|
)
|
|
2042
2076
|
] }),
|
|
2043
|
-
flatTasks.length === 0 && /* @__PURE__ */ (0,
|
|
2077
|
+
flatTasks.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.textDim, children: [
|
|
2044
2078
|
" No tasks yet. Ask the boss to plan some \u2014 e.g. ",
|
|
2045
|
-
/* @__PURE__ */ (0,
|
|
2079
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.text, children: '"plan some work"' }),
|
|
2046
2080
|
"."
|
|
2047
2081
|
] }) }),
|
|
2048
|
-
showingTop && /* @__PURE__ */ (0,
|
|
2082
|
+
showingTop && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ` \u2191 ${startIdx} more above` }),
|
|
2049
2083
|
groupedTasks.map((group, gIdx) => {
|
|
2050
2084
|
const startInFlat = groupedTasks.slice(0, gIdx).reduce((acc, g) => acc + g.tasks.length, 0);
|
|
2051
2085
|
const visibleInSection = group.tasks.filter((t) => visibleIdSet.has(t.id));
|
|
2052
2086
|
if (visibleInSection.length === 0) return null;
|
|
2053
|
-
return /* @__PURE__ */ (0,
|
|
2054
|
-
/* @__PURE__ */ (0,
|
|
2055
|
-
/* @__PURE__ */ (0,
|
|
2056
|
-
/* @__PURE__ */ (0,
|
|
2087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
2088
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
|
|
2089
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: projectColor(group.project), bold: true, children: group.project }),
|
|
2090
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ` \xB7 ${group.tasks.length}` })
|
|
2057
2091
|
] }),
|
|
2058
2092
|
visibleInSection.map((task) => {
|
|
2059
2093
|
const realIdx = startInFlat + group.tasks.indexOf(task);
|
|
2060
2094
|
const isSelected = realIdx === selectedIndex;
|
|
2061
2095
|
const prefix = isSelected ? "\u276F " : " ";
|
|
2062
2096
|
const glyph = statusGlyph(task.status);
|
|
2063
|
-
const
|
|
2064
|
-
return /* @__PURE__ */ (0,
|
|
2097
|
+
const color2 = isSelected ? theme.primary : task.status === "done" ? theme.success : task.status === "in_progress" ? theme.warning : task.status === "blocked" ? theme.error : theme.text;
|
|
2098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: color2, bold: isSelected, children: [
|
|
2065
2099
|
prefix,
|
|
2066
2100
|
"[",
|
|
2067
2101
|
glyph,
|
|
@@ -2071,16 +2105,16 @@ function BossTasksOverlay({
|
|
|
2071
2105
|
})
|
|
2072
2106
|
] }, group.project);
|
|
2073
2107
|
}),
|
|
2074
|
-
showingBottom && /* @__PURE__ */ (0,
|
|
2075
|
-
status && /* @__PURE__ */ (0,
|
|
2076
|
-
/* @__PURE__ */ (0,
|
|
2077
|
-
/* @__PURE__ */ (0,
|
|
2108
|
+
showingBottom && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ` \u2193 ${flatTasks.length - endIdx} more below` }),
|
|
2109
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.success, children: " " + status }) }),
|
|
2110
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.textDim, children: [
|
|
2111
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "\u2191\u2193" }),
|
|
2078
2112
|
" move \xB7 (",
|
|
2079
|
-
/* @__PURE__ */ (0,
|
|
2113
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "d" }),
|
|
2080
2114
|
")elete \xB7 (",
|
|
2081
|
-
/* @__PURE__ */ (0,
|
|
2115
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "r" }),
|
|
2082
2116
|
")un pending \xB7 ",
|
|
2083
|
-
/* @__PURE__ */ (0,
|
|
2117
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "ESC" }),
|
|
2084
2118
|
" close"
|
|
2085
2119
|
] }) })
|
|
2086
2120
|
] });
|
|
@@ -2092,24 +2126,24 @@ function CountsRow({
|
|
|
2092
2126
|
pending,
|
|
2093
2127
|
blocked
|
|
2094
2128
|
}) {
|
|
2095
|
-
return /* @__PURE__ */ (0,
|
|
2096
|
-
/* @__PURE__ */ (0,
|
|
2129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.success, children: [
|
|
2097
2131
|
done,
|
|
2098
2132
|
" done"
|
|
2099
2133
|
] }),
|
|
2100
|
-
/* @__PURE__ */ (0,
|
|
2101
|
-
/* @__PURE__ */ (0,
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.warning, children: [
|
|
2102
2136
|
active,
|
|
2103
2137
|
" active"
|
|
2104
2138
|
] }),
|
|
2105
|
-
/* @__PURE__ */ (0,
|
|
2106
|
-
/* @__PURE__ */ (0,
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
|
|
2140
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.text, children: [
|
|
2107
2141
|
pending,
|
|
2108
2142
|
" pending"
|
|
2109
2143
|
] }),
|
|
2110
|
-
blocked > 0 && /* @__PURE__ */ (0,
|
|
2111
|
-
/* @__PURE__ */ (0,
|
|
2112
|
-
/* @__PURE__ */ (0,
|
|
2144
|
+
blocked > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2145
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
|
|
2146
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.error, children: [
|
|
2113
2147
|
blocked,
|
|
2114
2148
|
" blocked"
|
|
2115
2149
|
] })
|
|
@@ -2117,9 +2151,100 @@ function CountsRow({
|
|
|
2117
2151
|
] });
|
|
2118
2152
|
}
|
|
2119
2153
|
|
|
2154
|
+
// src/boss-worker-status-row.tsx
|
|
2155
|
+
init_esm_shims();
|
|
2156
|
+
var import_react11 = __toESM(require_react(), 1);
|
|
2157
|
+
var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
|
|
2158
|
+
var SHIMMER_WIDTH = 3;
|
|
2159
|
+
function formatWorkerElapsed(ms) {
|
|
2160
|
+
const total = Math.floor(ms / 1e3);
|
|
2161
|
+
const m = Math.floor(total / 60);
|
|
2162
|
+
const s = total % 60;
|
|
2163
|
+
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
2164
|
+
}
|
|
2165
|
+
function AnimationActiveSentinel() {
|
|
2166
|
+
useAnimationActive();
|
|
2167
|
+
return null;
|
|
2168
|
+
}
|
|
2169
|
+
function ShimmerName({
|
|
2170
|
+
name,
|
|
2171
|
+
color: color2,
|
|
2172
|
+
tick
|
|
2173
|
+
}) {
|
|
2174
|
+
const cycle = name.length + SHIMMER_WIDTH * 2;
|
|
2175
|
+
const shimmerPos = tick % cycle - SHIMMER_WIDTH;
|
|
2176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: name.split("").map((ch, i) => {
|
|
2177
|
+
const isBright = Math.abs(i - shimmerPos) <= SHIMMER_WIDTH;
|
|
2178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { color: color2, bold: isBright, dimColor: !isBright, children: ch }, i);
|
|
2179
|
+
}) });
|
|
2180
|
+
}
|
|
2181
|
+
function BossWorkerStatusRow({
|
|
2182
|
+
workers,
|
|
2183
|
+
pendingMessages
|
|
2184
|
+
}) {
|
|
2185
|
+
const theme = useTheme();
|
|
2186
|
+
const { columns } = useTerminalSize();
|
|
2187
|
+
const working = workers.filter((w) => w.status === "working");
|
|
2188
|
+
const errored = workers.filter((w) => w.status === "error");
|
|
2189
|
+
const idleCount = workers.length - working.length - errored.length;
|
|
2190
|
+
const anyWorking = working.length > 0;
|
|
2191
|
+
const tick = useAnimationTick();
|
|
2192
|
+
const now = Date.now();
|
|
2193
|
+
if (workers.length === 0) return null;
|
|
2194
|
+
const slots = [];
|
|
2195
|
+
for (const w of working) {
|
|
2196
|
+
const projectHue = projectColor(w.name);
|
|
2197
|
+
const elapsed = w.workStartedAt ? formatWorkerElapsed(now - w.workStartedAt) : null;
|
|
2198
|
+
slots.push(
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react11.default.Fragment, { children: [
|
|
2200
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ShimmerName, { name: w.name, color: projectHue, tick }),
|
|
2201
|
+
elapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { color: theme.textDim, children: [
|
|
2202
|
+
" ",
|
|
2203
|
+
elapsed
|
|
2204
|
+
] })
|
|
2205
|
+
] }, `w-${w.name}`)
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
for (const w of errored) {
|
|
2209
|
+
slots.push(
|
|
2210
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react11.default.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { color: theme.error, children: [
|
|
2211
|
+
"\u2717 ",
|
|
2212
|
+
w.name
|
|
2213
|
+
] }) }, `e-${w.name}`)
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
2216
|
+
if (idleCount > 0) {
|
|
2217
|
+
slots.push(
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react11.default.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { color: theme.textDim, children: [
|
|
2219
|
+
"\u25CB ",
|
|
2220
|
+
idleCount,
|
|
2221
|
+
" idle"
|
|
2222
|
+
] }) }, "idle")
|
|
2223
|
+
);
|
|
2224
|
+
}
|
|
2225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { paddingX: 1, width: columns, flexShrink: 1, children: [
|
|
2226
|
+
anyWorking && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AnimationActiveSentinel, {}),
|
|
2227
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { wrap: "truncate", children: [
|
|
2228
|
+
slots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react11.default.Fragment, { children: [
|
|
2229
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { color: theme.border, children: " \u2502 " }),
|
|
2230
|
+
slot
|
|
2231
|
+
] }, i)),
|
|
2232
|
+
pendingMessages > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
2233
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { color: theme.textDim, children: " " }),
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { color: theme.warning, children: [
|
|
2235
|
+
pendingMessages,
|
|
2236
|
+
" message",
|
|
2237
|
+
pendingMessages === 1 ? "" : "s",
|
|
2238
|
+
" queued"
|
|
2239
|
+
] })
|
|
2240
|
+
] })
|
|
2241
|
+
] })
|
|
2242
|
+
] });
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2120
2245
|
// src/radio-picker.tsx
|
|
2121
2246
|
init_esm_shims();
|
|
2122
|
-
var
|
|
2247
|
+
var import_react12 = __toESM(require_react(), 1);
|
|
2123
2248
|
|
|
2124
2249
|
// src/radio.ts
|
|
2125
2250
|
init_esm_shims();
|
|
@@ -2287,7 +2412,7 @@ function buildInstallHint() {
|
|
|
2287
2412
|
}
|
|
2288
2413
|
|
|
2289
2414
|
// src/radio-picker.tsx
|
|
2290
|
-
var
|
|
2415
|
+
var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
|
|
2291
2416
|
function RadioPicker({
|
|
2292
2417
|
currentStationId: currentStationId2,
|
|
2293
2418
|
onSelect,
|
|
@@ -2309,7 +2434,7 @@ function RadioPicker({
|
|
|
2309
2434
|
0,
|
|
2310
2435
|
items.findIndex((i) => i.value === (currentStationId2 ?? "off"))
|
|
2311
2436
|
);
|
|
2312
|
-
return /* @__PURE__ */ (0,
|
|
2437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2313
2438
|
SelectList,
|
|
2314
2439
|
{
|
|
2315
2440
|
items,
|
|
@@ -2321,42 +2446,905 @@ function RadioPicker({
|
|
|
2321
2446
|
);
|
|
2322
2447
|
}
|
|
2323
2448
|
|
|
2324
|
-
// src/
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2449
|
+
// src/boss-chat-screen.tsx
|
|
2450
|
+
var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
|
|
2451
|
+
function BossChatScreen({
|
|
2452
|
+
boss,
|
|
2453
|
+
columns,
|
|
2454
|
+
state,
|
|
2455
|
+
overlay,
|
|
2456
|
+
controlsRef = () => {
|
|
2457
|
+
},
|
|
2458
|
+
livePane,
|
|
2459
|
+
theme,
|
|
2460
|
+
statusSlotVisible,
|
|
2461
|
+
activityVisible,
|
|
2462
|
+
stallStatusVisible,
|
|
2463
|
+
doneStatus,
|
|
2464
|
+
elapsedMs,
|
|
2465
|
+
runStartRef,
|
|
2466
|
+
charCountRef,
|
|
2467
|
+
realTokensAccumRef,
|
|
2468
|
+
lastUserMessage,
|
|
2469
|
+
activeToolNames,
|
|
2470
|
+
inputActive,
|
|
2471
|
+
isRunning,
|
|
2472
|
+
onSubmit,
|
|
2473
|
+
onAbort,
|
|
2474
|
+
onTab,
|
|
2475
|
+
onShiftTab,
|
|
2476
|
+
commands,
|
|
2477
|
+
scopeBadge,
|
|
2478
|
+
onCloseOverlay,
|
|
2479
|
+
onModelSelect,
|
|
2480
|
+
currentRadio,
|
|
2481
|
+
onRadioSelect,
|
|
2482
|
+
bossModel,
|
|
2483
|
+
workerModel,
|
|
2484
|
+
updatePending,
|
|
2485
|
+
currentRadioStationId,
|
|
2486
|
+
workers,
|
|
2487
|
+
pendingMessages,
|
|
2488
|
+
formatDuration
|
|
2489
|
+
}) {
|
|
2490
|
+
if (overlay === "tasks") {
|
|
2491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChatLayout, { columns, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BossTasksOverlay, { boss, workers, onClose: onCloseOverlay }) });
|
|
2351
2492
|
}
|
|
2493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ChatLayout, { columns, children: [
|
|
2494
|
+
livePane,
|
|
2495
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ChatControls, { controlsRef, children: [
|
|
2496
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2497
|
+
ChatInputStack,
|
|
2498
|
+
{
|
|
2499
|
+
columns,
|
|
2500
|
+
theme,
|
|
2501
|
+
statusSlotVisible,
|
|
2502
|
+
activityVisible,
|
|
2503
|
+
stallStatusVisible,
|
|
2504
|
+
liveToolFeed: [],
|
|
2505
|
+
doneStatus,
|
|
2506
|
+
activityPhase: state.activityPhase,
|
|
2507
|
+
elapsedMs,
|
|
2508
|
+
runStartRef,
|
|
2509
|
+
thinkingMs: state.streaming?.thinkingMs ?? 0,
|
|
2510
|
+
isThinking: state.activityPhase === "thinking",
|
|
2511
|
+
thinkingLevel: state.bossThinkingLevel,
|
|
2512
|
+
tokenEstimate: state.bossInputTokens,
|
|
2513
|
+
charCountRef,
|
|
2514
|
+
realTokensAccumRef,
|
|
2515
|
+
lastUserMessage,
|
|
2516
|
+
activeToolNames,
|
|
2517
|
+
retryInfo: state.retryInfo,
|
|
2518
|
+
planDone: 0,
|
|
2519
|
+
planTotal: 0,
|
|
2520
|
+
renderMarkdown: true,
|
|
2521
|
+
formatDuration
|
|
2522
|
+
}
|
|
2523
|
+
),
|
|
2524
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2525
|
+
InputArea,
|
|
2526
|
+
{
|
|
2527
|
+
onSubmit,
|
|
2528
|
+
onAbort,
|
|
2529
|
+
disabled: isRunning,
|
|
2530
|
+
isActive: inputActive,
|
|
2531
|
+
cwd: process.cwd(),
|
|
2532
|
+
commands,
|
|
2533
|
+
scopeBadge,
|
|
2534
|
+
disableMouseTracking: true,
|
|
2535
|
+
onTab,
|
|
2536
|
+
onShiftTab
|
|
2537
|
+
}
|
|
2538
|
+
),
|
|
2539
|
+
overlay === "model-boss" || overlay === "model-workers" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2540
|
+
BossModelSelector,
|
|
2541
|
+
{
|
|
2542
|
+
onSelect: onModelSelect,
|
|
2543
|
+
onCancel: onCloseOverlay,
|
|
2544
|
+
currentModel: overlay === "model-boss" ? state.bossModel : state.workerModel,
|
|
2545
|
+
currentProvider: overlay === "model-boss" ? state.bossProvider : state.workerProvider
|
|
2546
|
+
}
|
|
2547
|
+
) : overlay === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2548
|
+
RadioPicker,
|
|
2549
|
+
{
|
|
2550
|
+
currentStationId: currentRadio,
|
|
2551
|
+
onCancel: onCloseOverlay,
|
|
2552
|
+
onSelect: onRadioSelect
|
|
2553
|
+
}
|
|
2554
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
2555
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2556
|
+
BossFooter,
|
|
2557
|
+
{
|
|
2558
|
+
bossModel,
|
|
2559
|
+
workerModel,
|
|
2560
|
+
tokensIn: state.bossInputTokens,
|
|
2561
|
+
exitPending: state.exitPending,
|
|
2562
|
+
bossThinkingLevel: state.bossThinkingLevel,
|
|
2563
|
+
updatePending,
|
|
2564
|
+
currentRadioStationId,
|
|
2565
|
+
scope: state.scope
|
|
2566
|
+
}
|
|
2567
|
+
),
|
|
2568
|
+
!state.exitPending && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BossWorkerStatusRow, { workers, pendingMessages })
|
|
2569
|
+
] })
|
|
2570
|
+
] })
|
|
2571
|
+
] });
|
|
2352
2572
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2573
|
+
|
|
2574
|
+
// src/slash-commands.ts
|
|
2575
|
+
init_esm_shims();
|
|
2576
|
+
var BOSS_SLASH_COMMANDS = [
|
|
2577
|
+
{ name: "help", aliases: ["?"], description: "Show available commands" },
|
|
2578
|
+
{
|
|
2579
|
+
name: "model-boss",
|
|
2580
|
+
aliases: ["m", "model", "models"],
|
|
2581
|
+
description: "Switch the orchestrator's model"
|
|
2582
|
+
},
|
|
2583
|
+
{ name: "model-workers", aliases: [], description: "Switch every worker's model" },
|
|
2584
|
+
{ name: "compact", aliases: [], description: "Compact the boss's context now" },
|
|
2585
|
+
{ name: "clear", aliases: [], description: "Clear chat history and terminal" },
|
|
2586
|
+
{ name: "radio", aliases: [], description: "Stream a free internet radio station" },
|
|
2587
|
+
{ name: "quit", aliases: ["q", "exit"], description: "Exit ezboss" }
|
|
2588
|
+
];
|
|
2589
|
+
function isSlashCommand(value) {
|
|
2590
|
+
return value.startsWith("/") && !value.startsWith("//");
|
|
2591
|
+
}
|
|
2592
|
+
function parseSlash(value) {
|
|
2593
|
+
if (!isSlashCommand(value)) return null;
|
|
2594
|
+
const rest = value.slice(1).trim();
|
|
2595
|
+
if (!rest) return null;
|
|
2596
|
+
const space = rest.indexOf(" ");
|
|
2597
|
+
if (space === -1) return { name: rest.toLowerCase(), args: "" };
|
|
2598
|
+
return { name: rest.slice(0, space).toLowerCase(), args: rest.slice(space + 1).trim() };
|
|
2599
|
+
}
|
|
2600
|
+
function canonicalName(name) {
|
|
2601
|
+
for (const cmd of BOSS_SLASH_COMMANDS) {
|
|
2602
|
+
if (cmd.name === name) return cmd.name;
|
|
2603
|
+
if (cmd.aliases.includes(name)) return cmd.name;
|
|
2604
|
+
}
|
|
2605
|
+
return null;
|
|
2606
|
+
}
|
|
2607
|
+
function buildHelpText() {
|
|
2608
|
+
const lines = ["**ezboss commands**", ""];
|
|
2609
|
+
for (const cmd of BOSS_SLASH_COMMANDS) {
|
|
2610
|
+
const aliases = cmd.aliases.length > 0 ? ` (${cmd.aliases.map((a) => "/" + a).join(", ")})` : "";
|
|
2611
|
+
lines.push(`- \`/${cmd.name}\`${aliases} \u2014 ${cmd.description}`);
|
|
2612
|
+
}
|
|
2613
|
+
lines.push("");
|
|
2614
|
+
lines.push("**Global keybindings**");
|
|
2615
|
+
lines.push("- `Ctrl+T` \u2014 open the Tasks pane");
|
|
2616
|
+
lines.push("- `Tab` \u2014 switch project scope (All / per-project pill in the input)");
|
|
2617
|
+
lines.push("- `Shift+Tab` \u2014 cycle the boss's thinking level, then off");
|
|
2618
|
+
lines.push("- `Esc` \u2014 interrupt the boss while it's running");
|
|
2619
|
+
lines.push("- `Ctrl+C` (twice) \u2014 exit");
|
|
2620
|
+
lines.push("");
|
|
2621
|
+
lines.push("**Inside the Tasks pane (Ctrl+T)**");
|
|
2622
|
+
lines.push("- `\u2191` / `\u2193` (or `k` / `j`) \u2014 navigate tasks");
|
|
2623
|
+
lines.push("- `r` \u2014 run all pending and blocked tasks across idle workers");
|
|
2624
|
+
lines.push("- `d` \u2014 delete the selected task");
|
|
2625
|
+
lines.push("- `Esc` \u2014 close the Tasks pane");
|
|
2626
|
+
lines.push("");
|
|
2627
|
+
lines.push("**Inside model pickers (`/model`, `/models`, `/model-boss`, `/model-workers`)**");
|
|
2628
|
+
lines.push("- `\u2191` / `\u2193` \u2014 navigate models");
|
|
2629
|
+
lines.push("- `Enter` \u2014 select");
|
|
2630
|
+
lines.push("- `Esc` \u2014 cancel");
|
|
2631
|
+
lines.push("");
|
|
2632
|
+
lines.push("**Radio** (`/radio`)");
|
|
2633
|
+
lines.push("- Pick a station to stream while you work, or select `Off` to stop.");
|
|
2634
|
+
lines.push("- Requires `mpv` (recommended), `ffplay`, `mpg123`, or `vlc/cvlc` installed.");
|
|
2635
|
+
lines.push("");
|
|
2636
|
+
lines.push("**Input area**");
|
|
2637
|
+
lines.push("- `\u2191` / `\u2193` \u2014 recall previous prompts (when input is empty)");
|
|
2638
|
+
lines.push("- `Enter` \u2014 send \xB7 `Shift+Enter` \u2014 newline");
|
|
2639
|
+
lines.push("- `/` \u2014 open the slash-command menu (Tab / arrows to pick, Enter to insert)");
|
|
2640
|
+
return lines.join("\n");
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
// src/boss-transcript-rows.tsx
|
|
2644
|
+
init_esm_shims();
|
|
2645
|
+
var import_react14 = __toESM(require_react(), 1);
|
|
2646
|
+
|
|
2647
|
+
// src/boss-spacing.ts
|
|
2648
|
+
init_esm_shims();
|
|
2649
|
+
var BOSS_SPACING_KINDS = /* @__PURE__ */ new Set([
|
|
2650
|
+
"user",
|
|
2651
|
+
"assistant",
|
|
2652
|
+
"tool_start",
|
|
2653
|
+
"tool_done",
|
|
2654
|
+
"tool_group",
|
|
2655
|
+
"worker_event",
|
|
2656
|
+
"worker_error",
|
|
2657
|
+
"task_dispatch",
|
|
2658
|
+
"info",
|
|
2659
|
+
"update_notice",
|
|
2660
|
+
"compacting",
|
|
2661
|
+
"compacted",
|
|
2662
|
+
"stopped"
|
|
2663
|
+
]);
|
|
2664
|
+
var BOSS_COMPACT_BOUNDARIES = /* @__PURE__ */ new Set([
|
|
2665
|
+
"user\u2192assistant",
|
|
2666
|
+
"assistant\u2192user",
|
|
2667
|
+
"user\u2192queued"
|
|
2668
|
+
]);
|
|
2669
|
+
|
|
2670
|
+
// src/tool-formatters.ts
|
|
2671
|
+
init_esm_shims();
|
|
2672
|
+
function truncate2(s, max) {
|
|
2673
|
+
if (max <= 1) return "\u2026";
|
|
2674
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
2675
|
+
}
|
|
2676
|
+
function promptWorkerDetailLen(project) {
|
|
2677
|
+
const cols = process.stdout.columns ?? 80;
|
|
2678
|
+
const fixed = 2 + 13 + 1 + project.length + 3 + 1 + 1 + 11 + 6;
|
|
2679
|
+
return Math.max(20, cols - fixed);
|
|
2680
|
+
}
|
|
2681
|
+
var bossToolFormatters = {
|
|
2682
|
+
formatLabel(name) {
|
|
2683
|
+
switch (name) {
|
|
2684
|
+
case "list_workers":
|
|
2685
|
+
return "List Workers";
|
|
2686
|
+
case "get_worker_status":
|
|
2687
|
+
return "Worker Status";
|
|
2688
|
+
case "prompt_worker":
|
|
2689
|
+
return "Prompt Worker";
|
|
2690
|
+
case "get_worker_summary":
|
|
2691
|
+
return "Worker Summary";
|
|
2692
|
+
default:
|
|
2693
|
+
return void 0;
|
|
2694
|
+
}
|
|
2695
|
+
},
|
|
2696
|
+
formatDetail(name, args) {
|
|
2697
|
+
switch (name) {
|
|
2698
|
+
case "list_workers":
|
|
2699
|
+
return "";
|
|
2700
|
+
case "get_worker_status":
|
|
2701
|
+
case "get_worker_summary":
|
|
2702
|
+
return truncate2(String(args.project ?? ""), 40);
|
|
2703
|
+
case "prompt_worker": {
|
|
2704
|
+
const project = String(args.project ?? "");
|
|
2705
|
+
const message = String(args.message ?? "").replace(/\s+/g, " ");
|
|
2706
|
+
const fresh = args.fresh === true;
|
|
2707
|
+
const maxMsg = promptWorkerDetailLen(project) - (fresh ? 8 : 0);
|
|
2708
|
+
const truncMsg = truncate2(message, Math.max(15, maxMsg));
|
|
2709
|
+
const head = fresh ? "fresh \xB7 " : "";
|
|
2710
|
+
return project ? `${head}${project} \xB7 ${truncMsg}` : `${head}${truncMsg}`;
|
|
2711
|
+
}
|
|
2712
|
+
default:
|
|
2713
|
+
return void 0;
|
|
2714
|
+
}
|
|
2715
|
+
},
|
|
2716
|
+
formatInline(name, result, isError) {
|
|
2717
|
+
if (isError) return void 0;
|
|
2718
|
+
switch (name) {
|
|
2719
|
+
case "list_workers": {
|
|
2720
|
+
const lines = result.split("\n").filter((l) => l.startsWith("-"));
|
|
2721
|
+
return `${lines.length} worker${lines.length === 1 ? "" : "s"}`;
|
|
2722
|
+
}
|
|
2723
|
+
case "prompt_worker": {
|
|
2724
|
+
if (result.includes("currently working")) {
|
|
2725
|
+
return { text: "busy \u2014 skipped", color: "#fbbf24" };
|
|
2726
|
+
}
|
|
2727
|
+
if (result.includes("Unknown project")) {
|
|
2728
|
+
return { text: "unknown project", color: "#f87171" };
|
|
2729
|
+
}
|
|
2730
|
+
const project = String(result.match(/"([^"]+)"/)?.[1] ?? "");
|
|
2731
|
+
const color2 = project ? projectColor(project) : "#e11d48";
|
|
2732
|
+
return { text: "dispatched", color: color2 };
|
|
2733
|
+
}
|
|
2734
|
+
case "get_worker_status": {
|
|
2735
|
+
const parts = result.split(":");
|
|
2736
|
+
if (parts.length < 2) return void 0;
|
|
2737
|
+
const status = parts.slice(1).join(":").trim();
|
|
2738
|
+
const project = parts[0].trim();
|
|
2739
|
+
return { text: status, color: projectColor(project) };
|
|
2740
|
+
}
|
|
2741
|
+
case "get_worker_summary": {
|
|
2742
|
+
const turnMatch = result.match(/Turn:\s*(\d+)/);
|
|
2743
|
+
const projectMatch = result.match(/Project:\s*(.+)/);
|
|
2744
|
+
const toolsMatch = result.match(/Tools used:\s*(.+)/);
|
|
2745
|
+
const tools = toolsMatch ? toolsMatch[1] : "";
|
|
2746
|
+
const toolCount = tools && tools !== "(no tools used)" ? tools.split(",").length : 0;
|
|
2747
|
+
const turn = turnMatch ? `turn ${turnMatch[1]}` : void 0;
|
|
2748
|
+
const tCount = toolCount > 0 ? `${toolCount} tool${toolCount === 1 ? "" : "s"}` : void 0;
|
|
2749
|
+
const summary = [turn, tCount].filter(Boolean).join(" \xB7 ");
|
|
2750
|
+
if (!summary) return void 0;
|
|
2751
|
+
const project = projectMatch ? projectMatch[1].trim() : "";
|
|
2752
|
+
return project ? { text: summary, color: projectColor(project) } : { text: summary, color: "#9ca3af" };
|
|
2753
|
+
}
|
|
2754
|
+
default:
|
|
2755
|
+
return void 0;
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
};
|
|
2759
|
+
|
|
2760
|
+
// src/boss-transcript-rows.tsx
|
|
2761
|
+
var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
|
|
2762
|
+
function getBossTranscriptMarginTop({
|
|
2763
|
+
row,
|
|
2764
|
+
previousRow
|
|
2765
|
+
}) {
|
|
2766
|
+
if (row.kind === "banner" || previousRow?.kind === "banner") return 0;
|
|
2767
|
+
if (!BOSS_SPACING_KINDS.has(row.kind)) return 0;
|
|
2768
|
+
return getTranscriptItemMarginTop({
|
|
2769
|
+
item: row,
|
|
2770
|
+
previousLiveItem: previousRow,
|
|
2771
|
+
spacingKinds: BOSS_SPACING_KINDS,
|
|
2772
|
+
compactBoundaries: BOSS_COMPACT_BOUNDARIES
|
|
2773
|
+
});
|
|
2774
|
+
}
|
|
2775
|
+
function BossTranscriptRow({
|
|
2776
|
+
row,
|
|
2777
|
+
previousRow
|
|
2778
|
+
}) {
|
|
2779
|
+
if (row.kind === "banner") {
|
|
2780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Box_default, { paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(BossBanner, { subtitle: "Orchestrator", showShortcuts: true }) });
|
|
2781
|
+
}
|
|
2782
|
+
const marginTop = getBossTranscriptMarginTop({ row, previousRow });
|
|
2783
|
+
const renderWithSpacing = (node) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TranscriptItemFrame, { marginTop, children: node });
|
|
2784
|
+
if (row.kind === "user") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UserMessage, { text: row.text }));
|
|
2785
|
+
if (row.kind === "assistant") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AssistantRow, { item: row }));
|
|
2786
|
+
if (row.kind === "tool_start") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolStartHistoryRow, { item: row }));
|
|
2787
|
+
if (row.kind === "tool_done") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolHistoryRow, { item: row }));
|
|
2788
|
+
if (row.kind === "tool_group") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolGroupRow, { item: row }));
|
|
2789
|
+
if (row.kind === "worker_event") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(WorkerEventRow, { item: row }));
|
|
2790
|
+
if (row.kind === "worker_error") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(WorkerErrorRow, { item: row }));
|
|
2791
|
+
if (row.kind === "info") {
|
|
2792
|
+
return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(InfoRow, { text: row.text, level: row.level ?? "info" }));
|
|
2793
|
+
}
|
|
2794
|
+
if (row.kind === "task_dispatch") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TaskDispatchRow, { tasks: row.tasks }));
|
|
2795
|
+
if (row.kind === "update_notice") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UpdateNoticeRow, { text: row.text }));
|
|
2796
|
+
if (row.kind === "compacting") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CompactionSpinner, { staticDisplay: true }));
|
|
2797
|
+
if (row.kind === "compacted") {
|
|
2798
|
+
return renderWithSpacing(
|
|
2799
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2800
|
+
CompactionDone,
|
|
2801
|
+
{
|
|
2802
|
+
originalCount: row.originalCount,
|
|
2803
|
+
newCount: row.newCount,
|
|
2804
|
+
tokensBefore: row.tokensBefore,
|
|
2805
|
+
tokensAfter: row.tokensAfter
|
|
2806
|
+
}
|
|
2807
|
+
)
|
|
2808
|
+
);
|
|
2809
|
+
}
|
|
2810
|
+
if (row.kind === "stopped") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(InfoRow, { text: row.text, level: "warning" }));
|
|
2811
|
+
return null;
|
|
2812
|
+
}
|
|
2813
|
+
function UpdateNoticeRow({ text }) {
|
|
2814
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Box_default, { flexShrink: 1, borderStyle: "round", borderColor: COLORS.accent, paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { wrap: "wrap", children: [
|
|
2815
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: COLORS.accent, bold: true, children: "\u2728 " }),
|
|
2816
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: COLORS.primary, bold: true, children: text })
|
|
2817
|
+
] }) });
|
|
2818
|
+
}
|
|
2819
|
+
function TaskDispatchRow({
|
|
2820
|
+
tasks
|
|
2821
|
+
}) {
|
|
2822
|
+
const theme = useTheme();
|
|
2823
|
+
const count = tasks.length;
|
|
2824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, children: [
|
|
2825
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { children: [
|
|
2826
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: COLORS.primary, bold: true, children: "\u23FA " }),
|
|
2827
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { color: theme.text, bold: true, children: [
|
|
2828
|
+
"Running ",
|
|
2829
|
+
count,
|
|
2830
|
+
" task",
|
|
2831
|
+
count === 1 ? "" : "s",
|
|
2832
|
+
":"
|
|
2833
|
+
] })
|
|
2834
|
+
] }),
|
|
2835
|
+
tasks.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { children: [
|
|
2836
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.textDim, children: " \u2022 " }),
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: projectColor(t.project), bold: true, children: t.project }),
|
|
2838
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.textDim, children: ": " }),
|
|
2839
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.text, children: t.title })
|
|
2840
|
+
] }, `${t.project}-${i}`))
|
|
2841
|
+
] });
|
|
2842
|
+
}
|
|
2843
|
+
var SHORTCUT_PATTERNS = [
|
|
2844
|
+
// Modifier+Key combos: Ctrl+T, Shift+Tab, Cmd+K, Ctrl+Shift+P, Ctrl+C
|
|
2845
|
+
/\b(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super)(?:\s*\+\s*(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super))*\s*\+\s*(?:Tab|Enter|Esc|Escape|Space|Backspace|Delete|Del|Home|End|PageUp|PageDown|Up|Down|Left|Right|F[1-9]|F1[0-2]|[A-Z0-9]|\/|\?|\.|,|;|=|-)\b/g,
|
|
2846
|
+
// Bare named keys (only when surrounded by clear key context)
|
|
2847
|
+
/\b(?:Ctrl-[A-Z]|F[1-9]|F1[0-2])\b/g
|
|
2848
|
+
];
|
|
2849
|
+
function highlightShortcuts(text) {
|
|
2850
|
+
if (!text) return text;
|
|
2851
|
+
const SENTINEL = "\uE000";
|
|
2852
|
+
const masks = [];
|
|
2853
|
+
let masked = text.replace(/```[\s\S]*?```|`[^`]+`/g, (m) => {
|
|
2854
|
+
const idx = masks.push(m) - 1;
|
|
2855
|
+
return `${SENTINEL}${idx}${SENTINEL}`;
|
|
2856
|
+
});
|
|
2857
|
+
for (const re of SHORTCUT_PATTERNS) {
|
|
2858
|
+
masked = masked.replace(re, (m) => `\`${m}\``);
|
|
2859
|
+
}
|
|
2860
|
+
return masked.replace(
|
|
2861
|
+
new RegExp(`${SENTINEL}(\\d+)${SENTINEL}`, "g"),
|
|
2862
|
+
(_, i) => masks[Number(i)]
|
|
2863
|
+
);
|
|
2864
|
+
}
|
|
2865
|
+
function AssistantRow({ item }) {
|
|
2866
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AssistantMessage, { text: highlightShortcuts(item.text), renderMarkdown: true });
|
|
2867
|
+
}
|
|
2868
|
+
function ToolStartHistoryRow({
|
|
2869
|
+
item
|
|
2870
|
+
}) {
|
|
2871
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2872
|
+
ToolExecution,
|
|
2873
|
+
{
|
|
2874
|
+
status: "running",
|
|
2875
|
+
name: item.name,
|
|
2876
|
+
args: item.args,
|
|
2877
|
+
formatters: bossToolFormatters
|
|
2878
|
+
}
|
|
2879
|
+
);
|
|
2880
|
+
}
|
|
2881
|
+
function ToolGroupRow({ item }) {
|
|
2882
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolGroupExecution, { tools: item.tools, summaryRenderers: bossToolGroupRenderers });
|
|
2883
|
+
}
|
|
2884
|
+
function ToolHistoryRow({ item }) {
|
|
2885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2886
|
+
ToolExecution,
|
|
2887
|
+
{
|
|
2888
|
+
status: "done",
|
|
2889
|
+
name: item.name,
|
|
2890
|
+
args: item.args,
|
|
2891
|
+
result: item.result,
|
|
2892
|
+
isError: item.isError,
|
|
2893
|
+
details: item.details,
|
|
2894
|
+
formatters: bossToolFormatters
|
|
2895
|
+
}
|
|
2896
|
+
);
|
|
2897
|
+
}
|
|
2898
|
+
function parseStatusGrade(text) {
|
|
2899
|
+
const matches = [
|
|
2900
|
+
...text.matchAll(/(?:^|\b)Status:\s*(DONE|UNVERIFIED|PARTIAL|BLOCKED|INFO)\b/gim)
|
|
2901
|
+
];
|
|
2902
|
+
const last = matches[matches.length - 1];
|
|
2903
|
+
if (!last) return null;
|
|
2904
|
+
return last[1].toUpperCase();
|
|
2905
|
+
}
|
|
2906
|
+
function statusGradeColor(grade, theme) {
|
|
2907
|
+
switch (grade) {
|
|
2908
|
+
case "DONE":
|
|
2909
|
+
return theme.success;
|
|
2910
|
+
case "UNVERIFIED":
|
|
2911
|
+
case "PARTIAL":
|
|
2912
|
+
return theme.warning;
|
|
2913
|
+
case "BLOCKED":
|
|
2914
|
+
return theme.error;
|
|
2915
|
+
case "INFO":
|
|
2916
|
+
return theme.textDim;
|
|
2917
|
+
default:
|
|
2918
|
+
return theme.textDim;
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
function WorkerEventRow({ item }) {
|
|
2922
|
+
const theme = useTheme();
|
|
2923
|
+
const failedCount = item.toolsUsed.filter((t) => !t.ok).length;
|
|
2924
|
+
const grade = parseStatusGrade(item.finalText);
|
|
2925
|
+
const loaderStatus = grade === "BLOCKED" || failedCount > 0 ? "error" : grade === "UNVERIFIED" || grade === "PARTIAL" ? "queued" : "done";
|
|
2926
|
+
const headerColor = loaderStatus === "error" ? theme.toolError : projectColor(item.project);
|
|
2927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
2928
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolUseLoader, { status: loaderStatus }),
|
|
2929
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { wrap: "wrap", children: [
|
|
2930
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: headerColor, bold: true, children: item.project }),
|
|
2931
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.text, children: ` turn ${item.turnIndex}` }),
|
|
2932
|
+
grade && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
2933
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
|
|
2934
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: statusGradeColor(grade, theme), bold: true, children: grade })
|
|
2935
|
+
] })
|
|
2936
|
+
] }) })
|
|
2937
|
+
] });
|
|
2938
|
+
}
|
|
2939
|
+
function WorkerErrorRow({ item }) {
|
|
2940
|
+
const theme = useTheme();
|
|
2941
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
2942
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
2943
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolUseLoader, { status: "error" }),
|
|
2944
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { wrap: "wrap", children: [
|
|
2945
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.toolError, bold: true, children: item.project }),
|
|
2946
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.textDim, children: " worker error" })
|
|
2947
|
+
] }) })
|
|
2948
|
+
] }),
|
|
2949
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.error, wrap: "wrap", children: item.message }) })
|
|
2950
|
+
] });
|
|
2951
|
+
}
|
|
2952
|
+
function InfoRow({
|
|
2953
|
+
text,
|
|
2954
|
+
level
|
|
2955
|
+
}) {
|
|
2956
|
+
if (level === "info") return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AssistantMessage, { text });
|
|
2957
|
+
const theme = useTheme();
|
|
2958
|
+
const color2 = level === "error" ? theme.error : theme.warning;
|
|
2959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
2960
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolUseLoader, { status: level === "error" ? "error" : "queued" }),
|
|
2961
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: color2, wrap: "wrap", children: text }) })
|
|
2962
|
+
] });
|
|
2963
|
+
}
|
|
2964
|
+
function BossStreamingTurnView({
|
|
2965
|
+
turn,
|
|
2966
|
+
isRunning,
|
|
2967
|
+
liveItems = [],
|
|
2968
|
+
lastPendingHistoryItem,
|
|
2969
|
+
lastHistoryItem,
|
|
2970
|
+
availableTerminalHeight = 20
|
|
2971
|
+
}) {
|
|
2972
|
+
const visibleLiveItems = liveItems.filter(
|
|
2973
|
+
(item) => item.kind === "user" || item.kind === "tool_start" || item.kind === "tool_done" || item.kind === "tool_group" || item.kind === "compacting" || item.kind === "compacted"
|
|
2974
|
+
);
|
|
2975
|
+
const lastLiveItem = visibleLiveItems[visibleLiveItems.length - 1];
|
|
2976
|
+
const visibleStreamingText = turn?.text ?? "";
|
|
2977
|
+
const previousTranscriptItem = lastPendingHistoryItem ?? lastHistoryItem;
|
|
2978
|
+
const isAwaitingAssistantAfterUser = isRunning && visibleStreamingText.trim().length === 0 && (lastLiveItem?.kind === "user" || !lastLiveItem && previousTranscriptItem?.kind === "user");
|
|
2979
|
+
const shouldReserveStreamingSpacing = isRunning && (visibleStreamingText.trim().length > 0 || visibleLiveItems.some((item) => BOSS_SPACING_KINDS.has(item.kind)) || isAwaitingAssistantAfterUser);
|
|
2980
|
+
const assistantMarginTop = shouldTopSpaceStreamingAssistant({
|
|
2981
|
+
visibleStreamingText,
|
|
2982
|
+
lastLiveItem,
|
|
2983
|
+
lastPendingHistoryItem,
|
|
2984
|
+
lastHistoryItem,
|
|
2985
|
+
spacingKinds: BOSS_SPACING_KINDS,
|
|
2986
|
+
compactBoundaries: BOSS_COMPACT_BOUNDARIES
|
|
2987
|
+
}) ? 1 : 0;
|
|
2988
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2989
|
+
ChatLivePane,
|
|
2990
|
+
{
|
|
2991
|
+
liveItems: visibleLiveItems,
|
|
2992
|
+
renderItem: (_item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2993
|
+
BossTranscriptRow,
|
|
2994
|
+
{
|
|
2995
|
+
row: visibleLiveItems[index],
|
|
2996
|
+
previousRow: index > 0 ? visibleLiveItems[index - 1] : previousTranscriptItem
|
|
2997
|
+
}
|
|
2998
|
+
),
|
|
2999
|
+
isRunning,
|
|
3000
|
+
visibleStreamingText,
|
|
3001
|
+
streamingThinking: "",
|
|
3002
|
+
thinkingMs: turn?.thinkingMs ?? 0,
|
|
3003
|
+
reserveStreamingSpacing: shouldReserveStreamingSpacing,
|
|
3004
|
+
renderMarkdown: true,
|
|
3005
|
+
measuredLiveAreaRows: availableTerminalHeight,
|
|
3006
|
+
assistantMarginTop,
|
|
3007
|
+
streamingContinuation: false
|
|
3008
|
+
}
|
|
3009
|
+
);
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
// src/boss-terminal-history.tsx
|
|
3013
|
+
init_esm_shims();
|
|
3014
|
+
function createBossTerminalHistoryPrinter({
|
|
3015
|
+
stream = process.stdout
|
|
3016
|
+
} = {}) {
|
|
3017
|
+
const printed = /* @__PURE__ */ new Set();
|
|
3018
|
+
let previousPrintedKind = null;
|
|
3019
|
+
return {
|
|
3020
|
+
print(items, context, options) {
|
|
3021
|
+
const writeOutput = options?.write ?? ((data) => void stream.write(data));
|
|
3022
|
+
for (const item of items) {
|
|
3023
|
+
if (!options?.force && printed.has(item.id)) continue;
|
|
3024
|
+
const output = serializeBossItemToTerminalHistory(item, context);
|
|
3025
|
+
const formatted = formatHistoryWrite(output, {
|
|
3026
|
+
leadingSeparator: item.kind === "banner" ? false : shouldSeparateTranscriptItemKinds({
|
|
3027
|
+
previousKind: previousPrintedKind ?? void 0,
|
|
3028
|
+
currentKind: item.kind,
|
|
3029
|
+
spacingKinds: BOSS_SPACING_KINDS,
|
|
3030
|
+
compactBoundaries: BOSS_COMPACT_BOUNDARIES
|
|
3031
|
+
}),
|
|
3032
|
+
trailingBlankLine: item.kind === "banner",
|
|
3033
|
+
trailingNewlines: item.kind === "user" ? 1 : void 0
|
|
3034
|
+
});
|
|
3035
|
+
if (formatted.length === 0) continue;
|
|
3036
|
+
printed.add(item.id);
|
|
3037
|
+
writeOutput(formatted);
|
|
3038
|
+
previousPrintedKind = item.kind;
|
|
3039
|
+
}
|
|
3040
|
+
},
|
|
3041
|
+
clear() {
|
|
3042
|
+
printed.clear();
|
|
3043
|
+
previousPrintedKind = null;
|
|
3044
|
+
},
|
|
3045
|
+
resetPrinted() {
|
|
3046
|
+
printed.clear();
|
|
3047
|
+
previousPrintedKind = null;
|
|
3048
|
+
},
|
|
3049
|
+
get printedIds() {
|
|
3050
|
+
return printed;
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
function serializeBossItemToTerminalHistory(item, context) {
|
|
3055
|
+
switch (item.kind) {
|
|
3056
|
+
case "banner":
|
|
3057
|
+
return renderBanner(context);
|
|
3058
|
+
case "worker_event":
|
|
3059
|
+
return renderWorkerEvent(item, context);
|
|
3060
|
+
case "worker_error":
|
|
3061
|
+
return renderWorkerError(item, context);
|
|
3062
|
+
case "task_dispatch":
|
|
3063
|
+
return renderTaskDispatch(item, context);
|
|
3064
|
+
case "tool_group":
|
|
3065
|
+
return renderToolGroup(item, context);
|
|
3066
|
+
case "update_notice":
|
|
3067
|
+
return renderUpdateNotice(item, context);
|
|
3068
|
+
default:
|
|
3069
|
+
return serializeCompletedItemToTerminalHistory(toGGCoderCompletedItem(item), context);
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
function renderBanner(context) {
|
|
3073
|
+
const logo = LOGO_LINES.map((lineText) => gradientLine(lineText, GRADIENT));
|
|
3074
|
+
const shortcuts = `${color(COLORS.primary, "^T")} ${dim(context, "tasks ")}${color(
|
|
3075
|
+
COLORS.primary,
|
|
3076
|
+
"Tab"
|
|
3077
|
+
)} ${dim(context, "scope ")}${color(COLORS.primary, "\u21E7Tab")} ${dim(
|
|
3078
|
+
context,
|
|
3079
|
+
"thinking "
|
|
3080
|
+
)}${color(COLORS.primary, "ESC")} ${dim(context, "interrupt")}`;
|
|
3081
|
+
return [
|
|
3082
|
+
"",
|
|
3083
|
+
`${logo[0]}${LOGO_GAP}${color(COLORS.primary, BRAND, true)}${dim(
|
|
3084
|
+
context,
|
|
3085
|
+
` v${VERSION} \xB7 By `
|
|
3086
|
+
)}${color(COLORS.text, AUTHOR, true)}`,
|
|
3087
|
+
`${logo[1]}${LOGO_GAP}${color(COLORS.accent, "Orchestrator")}`,
|
|
3088
|
+
`${logo[2]}${LOGO_GAP}${shortcuts}`,
|
|
3089
|
+
""
|
|
3090
|
+
].join("\n");
|
|
3091
|
+
}
|
|
3092
|
+
function renderUpdateNotice(item, context) {
|
|
3093
|
+
return renderRoundNoticeBox(
|
|
3094
|
+
[`${color(COLORS.accent, "\u2728 ", true)}${color(COLORS.primary, item.text, true)}`],
|
|
3095
|
+
context,
|
|
3096
|
+
COLORS.accent
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
function renderToolGroup(item, context) {
|
|
3100
|
+
const tools = item.tools;
|
|
3101
|
+
const allDone = tools.every((tool) => tool.status === "done");
|
|
3102
|
+
const hasError = tools.some((tool) => tool.isError);
|
|
3103
|
+
const status = allDone ? hasError ? "error" : "done" : "running";
|
|
3104
|
+
const label = buildToolGroupSummary(tools, allDone, bossToolGroupRenderers).map((seg) => {
|
|
3105
|
+
const hex = seg.tone ? toolTonePalette(context.theme, seg.tone).primary : context.theme.toolName;
|
|
3106
|
+
return color(hex, seg.text, seg.bold);
|
|
3107
|
+
}).join("");
|
|
3108
|
+
return toolStatusHeader({ status, label, context, labelAlreadyStyled: true });
|
|
3109
|
+
}
|
|
3110
|
+
function renderWorkerEvent(item, context) {
|
|
3111
|
+
const theme = context.theme;
|
|
3112
|
+
const failedCount = item.toolsUsed.filter((tool) => !tool.ok).length;
|
|
3113
|
+
const grade = parseStatusGrade(item.finalText);
|
|
3114
|
+
const isError = grade === "BLOCKED" || failedCount > 0;
|
|
3115
|
+
const isWarning = grade === "UNVERIFIED" || grade === "PARTIAL";
|
|
3116
|
+
const statusColor = isError ? theme.error : isWarning ? theme.warning : theme.success;
|
|
3117
|
+
const headerColor = isError ? theme.error : projectColor(item.project);
|
|
3118
|
+
return toolStatusHeader({
|
|
3119
|
+
status: isError ? "error" : isWarning ? "queued" : "done",
|
|
3120
|
+
label: color(headerColor, item.project, true),
|
|
3121
|
+
suffix: `${color(theme.text, ` turn ${item.turnIndex}`)}${grade ? `${dim(context, " \xB7 ")}${color(statusColor, grade, true)}` : ""}`,
|
|
3122
|
+
context,
|
|
3123
|
+
labelAlreadyStyled: true
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
3126
|
+
function renderWorkerError(item, context) {
|
|
3127
|
+
return [
|
|
3128
|
+
toolStatusHeader({
|
|
3129
|
+
status: "error",
|
|
3130
|
+
label: color(context.theme.error, item.project, true),
|
|
3131
|
+
suffix: dim(context, " worker error"),
|
|
3132
|
+
context,
|
|
3133
|
+
labelAlreadyStyled: true
|
|
3134
|
+
}),
|
|
3135
|
+
messageResponseText(color(context.theme.error, item.message), context)
|
|
3136
|
+
].join("\n");
|
|
3137
|
+
}
|
|
3138
|
+
function renderTaskDispatch(item, context) {
|
|
3139
|
+
const count = item.tasks.length;
|
|
3140
|
+
const lines = [
|
|
3141
|
+
toolStatusHeader({
|
|
3142
|
+
status: "done",
|
|
3143
|
+
label: color(context.theme.text, `Running ${count} task${count === 1 ? "" : "s"}:`, true),
|
|
3144
|
+
context,
|
|
3145
|
+
dotColor: COLORS.primary,
|
|
3146
|
+
labelAlreadyStyled: true
|
|
3147
|
+
})
|
|
3148
|
+
];
|
|
3149
|
+
for (const task of item.tasks) {
|
|
3150
|
+
lines.push(
|
|
3151
|
+
` \u2022 ${color(projectColor(task.project), task.project, true)}${dim(context, ": ")}${color(context.theme.text, task.title)}`
|
|
3152
|
+
);
|
|
3153
|
+
}
|
|
3154
|
+
return lines.join("\n");
|
|
3155
|
+
}
|
|
3156
|
+
function toGGCoderCompletedItem(item) {
|
|
3157
|
+
switch (item.kind) {
|
|
3158
|
+
case "user":
|
|
3159
|
+
return { kind: "user", id: item.id, text: item.text };
|
|
3160
|
+
case "assistant":
|
|
3161
|
+
return {
|
|
3162
|
+
kind: "assistant",
|
|
3163
|
+
id: item.id,
|
|
3164
|
+
text: item.text,
|
|
3165
|
+
thinking: item.thinking,
|
|
3166
|
+
thinkingMs: item.thinkingMs,
|
|
3167
|
+
continuation: item.continuation
|
|
3168
|
+
};
|
|
3169
|
+
case "tool_start":
|
|
3170
|
+
return {
|
|
3171
|
+
kind: "tool_start",
|
|
3172
|
+
id: item.id,
|
|
3173
|
+
toolCallId: item.toolCallId,
|
|
3174
|
+
name: item.name,
|
|
3175
|
+
args: formatBossToolArgsForHistory(item.name, item.args),
|
|
3176
|
+
startedAt: item.startedAt,
|
|
3177
|
+
animateUntil: item.animateUntil,
|
|
3178
|
+
progressOutput: item.progressOutput
|
|
3179
|
+
};
|
|
3180
|
+
case "tool_done":
|
|
3181
|
+
return {
|
|
3182
|
+
kind: "tool_done",
|
|
3183
|
+
id: item.id,
|
|
3184
|
+
name: item.name,
|
|
3185
|
+
args: formatBossToolArgsForHistory(item.name, item.args),
|
|
3186
|
+
result: formatBossToolResultForHistory(item.name, item.result, item.isError),
|
|
3187
|
+
isError: item.isError,
|
|
3188
|
+
durationMs: item.durationMs,
|
|
3189
|
+
details: item.details
|
|
3190
|
+
};
|
|
3191
|
+
case "info":
|
|
3192
|
+
return { kind: "info", id: item.id, text: item.text };
|
|
3193
|
+
case "compacting":
|
|
3194
|
+
return { kind: "compacting", id: item.id };
|
|
3195
|
+
case "compacted":
|
|
3196
|
+
return {
|
|
3197
|
+
kind: "compacted",
|
|
3198
|
+
id: item.id,
|
|
3199
|
+
originalCount: item.originalCount,
|
|
3200
|
+
newCount: item.newCount,
|
|
3201
|
+
tokensBefore: item.tokensBefore,
|
|
3202
|
+
tokensAfter: item.tokensAfter
|
|
3203
|
+
};
|
|
3204
|
+
case "stopped":
|
|
3205
|
+
return { kind: "stopped", id: item.id, text: item.text };
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
function formatBossToolArgsForHistory(name, args) {
|
|
3209
|
+
switch (name) {
|
|
3210
|
+
case "list_workers":
|
|
3211
|
+
return { action: "workers" };
|
|
3212
|
+
case "get_worker_status":
|
|
3213
|
+
case "get_worker_summary":
|
|
3214
|
+
return { action: String(args.project ?? "") };
|
|
3215
|
+
case "prompt_worker": {
|
|
3216
|
+
const project = String(args.project ?? "");
|
|
3217
|
+
const message = String(args.message ?? "").replace(/\s+/gu, " ");
|
|
3218
|
+
const fresh = args.fresh === true ? "fresh \xB7 " : "";
|
|
3219
|
+
const detail = project ? `${fresh}${project} \xB7 ${message}` : `${fresh}${message}`;
|
|
3220
|
+
return {
|
|
3221
|
+
action: truncatePlain(detail, Math.max(20, contextlessPromptWorkerDetailLen(project)))
|
|
3222
|
+
};
|
|
3223
|
+
}
|
|
3224
|
+
default:
|
|
3225
|
+
return args;
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
function formatBossToolResultForHistory(name, result, isError) {
|
|
3229
|
+
if (isError) return result;
|
|
3230
|
+
const inline = formatBossToolInlineForHistory(name, result);
|
|
3231
|
+
if (!inline) return result;
|
|
3232
|
+
return typeof inline === "string" ? inline : inline.text;
|
|
3233
|
+
}
|
|
3234
|
+
function formatBossToolInlineForHistory(name, result) {
|
|
3235
|
+
switch (name) {
|
|
3236
|
+
case "list_workers": {
|
|
3237
|
+
const lines = result.split("\n").filter((lineText) => lineText.startsWith("-"));
|
|
3238
|
+
return `${lines.length} worker${lines.length === 1 ? "" : "s"}`;
|
|
3239
|
+
}
|
|
3240
|
+
case "prompt_worker": {
|
|
3241
|
+
if (result.includes("currently working")) return "busy \u2014 skipped";
|
|
3242
|
+
if (result.includes("Unknown project")) return "unknown project";
|
|
3243
|
+
return "dispatched";
|
|
3244
|
+
}
|
|
3245
|
+
case "get_worker_status": {
|
|
3246
|
+
const parts = result.split(":");
|
|
3247
|
+
if (parts.length < 2) return void 0;
|
|
3248
|
+
return parts.slice(1).join(":").trim();
|
|
3249
|
+
}
|
|
3250
|
+
case "get_worker_summary": {
|
|
3251
|
+
const turnMatch = result.match(/Turn:\s*(\d+)/u);
|
|
3252
|
+
const toolsMatch = result.match(/Tools used:\s*(.+)/u);
|
|
3253
|
+
const tools = toolsMatch ? toolsMatch[1] : "";
|
|
3254
|
+
const toolCount = tools && tools !== "(no tools used)" ? tools.split(",").length : 0;
|
|
3255
|
+
const turn = turnMatch ? `turn ${turnMatch[1]}` : void 0;
|
|
3256
|
+
const toolSummary = toolCount > 0 ? `${toolCount} tool${toolCount === 1 ? "" : "s"}` : void 0;
|
|
3257
|
+
return [turn, toolSummary].filter(Boolean).join(" \xB7 ") || void 0;
|
|
3258
|
+
}
|
|
3259
|
+
default:
|
|
3260
|
+
return void 0;
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
function contextlessPromptWorkerDetailLen(project) {
|
|
3264
|
+
const cols = process.stdout.columns ?? 80;
|
|
3265
|
+
const fixed = 2 + 13 + 1 + project.length + 3 + 1 + 1 + 11 + 6;
|
|
3266
|
+
return Math.max(20, cols - fixed);
|
|
3267
|
+
}
|
|
3268
|
+
function toolStatusHeader({
|
|
3269
|
+
status,
|
|
3270
|
+
label,
|
|
3271
|
+
suffix = "",
|
|
3272
|
+
context,
|
|
3273
|
+
dotColor,
|
|
3274
|
+
labelAlreadyStyled = false
|
|
3275
|
+
}) {
|
|
3276
|
+
const resolvedDotColor = dotColor ?? (status === "error" ? context.theme.error : status === "done" ? context.theme.success : status === "queued" ? context.theme.warning : context.theme.spinnerColor);
|
|
3277
|
+
const indicator = status === "running" ? "\u280B" : "\u23FA";
|
|
3278
|
+
const labelText = labelAlreadyStyled ? label : color(context.theme.toolName, label, true);
|
|
3279
|
+
return `${RESPONSE_LEFT_PADDING}${color(resolvedDotColor, indicator)} ${labelText}${suffix}`;
|
|
3280
|
+
}
|
|
3281
|
+
function messageResponseText(text, context) {
|
|
3282
|
+
const [first, ...rest] = wrapPlain(text, Math.max(10, context.columns - 8)).split("\n");
|
|
3283
|
+
return [
|
|
3284
|
+
`${RESPONSE_LEFT_PADDING}${dim(context, " \u23BF ")}${first ?? ""}`,
|
|
3285
|
+
...rest.map((lineText) => `${RESPONSE_LEFT_PADDING}${dim(context, " ")}${lineText}`)
|
|
3286
|
+
].join("\n");
|
|
3287
|
+
}
|
|
3288
|
+
function renderRoundNoticeBox(lines, context, borderColor) {
|
|
3289
|
+
const width = Math.max(
|
|
3290
|
+
4,
|
|
3291
|
+
Math.min(
|
|
3292
|
+
context.columns - RESPONSE_LEFT_PADDING.length,
|
|
3293
|
+
Math.max(...lines.map((lineText) => stripAnsi(lineText).length)) + 4
|
|
3294
|
+
)
|
|
3295
|
+
);
|
|
3296
|
+
const contentWidth = Math.max(1, width - 4);
|
|
3297
|
+
const top = `${color(borderColor, "\u256D")}${color(borderColor, "\u2500".repeat(width - 2))}${color(
|
|
3298
|
+
borderColor,
|
|
3299
|
+
"\u256E"
|
|
3300
|
+
)}`;
|
|
3301
|
+
const bottom = `${color(borderColor, "\u2570")}${color(borderColor, "\u2500".repeat(width - 2))}${color(
|
|
3302
|
+
borderColor,
|
|
3303
|
+
"\u256F"
|
|
3304
|
+
)}`;
|
|
3305
|
+
const body = lines.flatMap((lineText) => wrapPlain(lineText, contentWidth).split("\n")).map((lineText) => {
|
|
3306
|
+
const plainLength = stripAnsi(lineText).length;
|
|
3307
|
+
return `${color(borderColor, "\u2502")} ${lineText}${" ".repeat(Math.max(0, contentWidth - plainLength))} ${color(borderColor, "\u2502")}`;
|
|
3308
|
+
});
|
|
3309
|
+
return indent([top, ...body, bottom].join("\n"), RESPONSE_LEFT_PADDING);
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
// src/auto-update.ts
|
|
3313
|
+
init_esm_shims();
|
|
3314
|
+
import { spawn as spawn2 } from "child_process";
|
|
3315
|
+
import fs4 from "fs";
|
|
3316
|
+
import path4 from "path";
|
|
3317
|
+
import os2 from "os";
|
|
3318
|
+
var PACKAGE_NAME = "@prestyj/boss";
|
|
3319
|
+
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
3320
|
+
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
3321
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
3322
|
+
function getStateFilePath() {
|
|
3323
|
+
return path4.join(os2.homedir(), ".ezcoder", "boss", "update-state.json");
|
|
3324
|
+
}
|
|
3325
|
+
function readState() {
|
|
3326
|
+
try {
|
|
3327
|
+
const raw = fs4.readFileSync(getStateFilePath(), "utf-8");
|
|
3328
|
+
return JSON.parse(raw);
|
|
3329
|
+
} catch {
|
|
3330
|
+
return null;
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
function writeState(state) {
|
|
3334
|
+
try {
|
|
3335
|
+
const dir = path4.dirname(getStateFilePath());
|
|
3336
|
+
fs4.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3337
|
+
fs4.writeFileSync(getStateFilePath(), JSON.stringify(state));
|
|
3338
|
+
} catch {
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
function compareVersions(a, b) {
|
|
3342
|
+
const pa = a.split(".").map(Number);
|
|
3343
|
+
const pb = b.split(".").map(Number);
|
|
3344
|
+
for (let i = 0; i < 3; i++) {
|
|
3345
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
3346
|
+
if (diff !== 0) return diff;
|
|
3347
|
+
}
|
|
2360
3348
|
return 0;
|
|
2361
3349
|
}
|
|
2362
3350
|
function detectInstallInfo() {
|
|
@@ -2489,29 +3477,30 @@ function stopPeriodicUpdateCheck() {
|
|
|
2489
3477
|
}
|
|
2490
3478
|
|
|
2491
3479
|
// src/orchestrator-app.tsx
|
|
2492
|
-
var
|
|
3480
|
+
var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
|
|
2493
3481
|
function BossApp(props) {
|
|
2494
3482
|
const theme = loadTheme("dark");
|
|
2495
|
-
return /* @__PURE__ */ (0,
|
|
3483
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TerminalSizeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AnimationProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BossAppInner, { ...props }) }) }) });
|
|
2496
3484
|
}
|
|
2497
|
-
function BossAppInner({ boss, resetUI }) {
|
|
3485
|
+
function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
|
|
2498
3486
|
const state = useBossState();
|
|
3487
|
+
const theme = useTheme();
|
|
2499
3488
|
const { exit } = use_app_default();
|
|
2500
|
-
const { stdout } = use_stdout_default();
|
|
2501
|
-
const {
|
|
2502
|
-
const runStartRef = (0,
|
|
3489
|
+
const { stdout, write: writeStdout } = use_stdout_default();
|
|
3490
|
+
const { columns, rows } = useTerminalSize();
|
|
3491
|
+
const runStartRef = (0, import_react15.useRef)(null);
|
|
2503
3492
|
runStartRef.current = state.runStartMs;
|
|
2504
|
-
const charCountRef = (0,
|
|
3493
|
+
const charCountRef = (0, import_react15.useRef)(0);
|
|
2505
3494
|
charCountRef.current = state.streaming?.text.length ?? 0;
|
|
2506
|
-
const realTokensAccumRef = (0,
|
|
3495
|
+
const realTokensAccumRef = (0, import_react15.useRef)(0);
|
|
2507
3496
|
realTokensAccumRef.current = state.bossInputTokens;
|
|
2508
|
-
const [lastUserMessage, setLastUserMessage] = (0,
|
|
3497
|
+
const [lastUserMessage, setLastUserMessage] = (0, import_react15.useState)("");
|
|
2509
3498
|
const overlay = state.overlay;
|
|
2510
|
-
const [currentRadio, setCurrentRadio] = (0,
|
|
2511
|
-
const [updatePending, setUpdatePending] = (0,
|
|
3499
|
+
const [currentRadio, setCurrentRadio] = (0, import_react15.useState)(() => getCurrentStation());
|
|
3500
|
+
const [updatePending, setUpdatePending] = (0, import_react15.useState)(
|
|
2512
3501
|
() => getPendingUpdate(VERSION) !== null
|
|
2513
3502
|
);
|
|
2514
|
-
(0,
|
|
3503
|
+
(0, import_react15.useEffect)(() => {
|
|
2515
3504
|
startPeriodicUpdateCheck(VERSION, (msg) => {
|
|
2516
3505
|
bossStore.appendUpdateNotice(msg);
|
|
2517
3506
|
setUpdatePending(true);
|
|
@@ -2519,8 +3508,8 @@ function BossAppInner({ boss, resetUI }) {
|
|
|
2519
3508
|
return () => stopPeriodicUpdateCheck();
|
|
2520
3509
|
}, []);
|
|
2521
3510
|
const workersRunning = state.workers.filter((w) => w.status === "working").length;
|
|
2522
|
-
const titlePrevRef = (0,
|
|
2523
|
-
(0,
|
|
3511
|
+
const titlePrevRef = (0, import_react15.useRef)("");
|
|
3512
|
+
(0, import_react15.useEffect)(() => {
|
|
2524
3513
|
if (!stdout) return;
|
|
2525
3514
|
let title;
|
|
2526
3515
|
if (workersRunning > 0) {
|
|
@@ -2536,45 +3525,83 @@ function BossAppInner({ boss, resetUI }) {
|
|
|
2536
3525
|
stdout.write(`\x1B]0;${title}\x1B\\`);
|
|
2537
3526
|
}
|
|
2538
3527
|
}, [stdout, workersRunning, state.phase]);
|
|
2539
|
-
(0,
|
|
3528
|
+
(0, import_react15.useEffect)(() => {
|
|
2540
3529
|
return () => {
|
|
2541
3530
|
stdout?.write(`\x1B]0;EZ Boss\x1B\\`);
|
|
2542
3531
|
};
|
|
2543
3532
|
}, [stdout]);
|
|
2544
|
-
const
|
|
2545
|
-
|
|
2546
|
-
|
|
3533
|
+
const liveItems = state.liveItems;
|
|
3534
|
+
const terminalHistoryPrinterRef = (0, import_react15.useRef)(
|
|
3535
|
+
terminalHistoryPrinter ?? createBossTerminalHistoryPrinter({ stream: stdout })
|
|
2547
3536
|
);
|
|
2548
|
-
const
|
|
3537
|
+
const terminalHistoryContext = {
|
|
3538
|
+
theme,
|
|
3539
|
+
columns,
|
|
3540
|
+
version: VERSION,
|
|
3541
|
+
model: state.bossModel,
|
|
3542
|
+
provider: state.bossProvider,
|
|
3543
|
+
cwd: process.cwd()
|
|
3544
|
+
};
|
|
3545
|
+
const printedHistoryIdsRef = (0, import_react15.useRef)(/* @__PURE__ */ new Set());
|
|
3546
|
+
(0, import_react15.useEffect)(() => {
|
|
3547
|
+
const printer = terminalHistoryPrinterRef.current;
|
|
3548
|
+
const pending = state.history.filter((item) => !printedHistoryIdsRef.current.has(item.id));
|
|
3549
|
+
if (pending.length === 0) return;
|
|
3550
|
+
printer.print(pending, terminalHistoryContext, { write: writeStdout });
|
|
3551
|
+
for (const item of pending) printedHistoryIdsRef.current.add(item.id);
|
|
3552
|
+
}, [columns, state.bossModel, state.bossProvider, state.history, theme, writeStdout]);
|
|
3553
|
+
const overlayResetTimerRef = (0, import_react15.useRef)(null);
|
|
3554
|
+
(0, import_react15.useEffect)(() => {
|
|
3555
|
+
return () => {
|
|
3556
|
+
if (overlayResetTimerRef.current) clearTimeout(overlayResetTimerRef.current);
|
|
3557
|
+
};
|
|
3558
|
+
}, []);
|
|
3559
|
+
const scheduleOverlayReset = (0, import_react15.useCallback)(() => {
|
|
3560
|
+
if (!resetUI) return;
|
|
3561
|
+
if (overlayResetTimerRef.current) clearTimeout(overlayResetTimerRef.current);
|
|
3562
|
+
overlayResetTimerRef.current = setTimeout(() => {
|
|
3563
|
+
overlayResetTimerRef.current = null;
|
|
3564
|
+
resetUI();
|
|
3565
|
+
}, 0);
|
|
3566
|
+
}, [resetUI]);
|
|
3567
|
+
const openOverlay = (0, import_react15.useCallback)(
|
|
2549
3568
|
(next) => {
|
|
2550
3569
|
bossStore.setOverlay(next);
|
|
2551
|
-
|
|
3570
|
+
scheduleOverlayReset();
|
|
2552
3571
|
},
|
|
2553
|
-
[
|
|
3572
|
+
[scheduleOverlayReset]
|
|
2554
3573
|
);
|
|
2555
|
-
const closeOverlay = (0,
|
|
3574
|
+
const closeOverlay = (0, import_react15.useCallback)(() => {
|
|
2556
3575
|
bossStore.setOverlay(null);
|
|
2557
|
-
|
|
2558
|
-
}, [
|
|
3576
|
+
scheduleOverlayReset();
|
|
3577
|
+
}, [scheduleOverlayReset]);
|
|
2559
3578
|
void stdout;
|
|
2560
3579
|
const handleDoubleExit = useDoublePress(
|
|
2561
3580
|
(pending) => bossStore.setExitPending(pending),
|
|
2562
3581
|
() => exit()
|
|
2563
3582
|
);
|
|
2564
|
-
(0,
|
|
3583
|
+
(0, import_react15.useEffect)(() => {
|
|
2565
3584
|
if (state.pendingFlush.length > 0) {
|
|
2566
3585
|
bossStore.commitPendingFlush();
|
|
2567
3586
|
}
|
|
2568
3587
|
}, [state.flushGeneration, state.pendingFlush.length]);
|
|
3588
|
+
const handleAbort = (0, import_react15.useCallback)(() => {
|
|
3589
|
+
if (state.phase === "working") {
|
|
3590
|
+
boss.abort();
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
handleDoubleExit();
|
|
3594
|
+
}, [boss, handleDoubleExit, state.phase]);
|
|
2569
3595
|
use_input_default((input, key) => {
|
|
3596
|
+
if (key.ctrl && input === "c" && overlay) {
|
|
3597
|
+
handleAbort();
|
|
3598
|
+
return;
|
|
3599
|
+
}
|
|
2570
3600
|
if (key.ctrl && input === "t") {
|
|
2571
3601
|
if (overlay === "tasks") closeOverlay();
|
|
2572
3602
|
else openOverlay("tasks");
|
|
2573
3603
|
return;
|
|
2574
3604
|
}
|
|
2575
|
-
if (key.escape && state.phase === "working") {
|
|
2576
|
-
boss.abort();
|
|
2577
|
-
}
|
|
2578
3605
|
});
|
|
2579
3606
|
const handleSlashCommand = async (value) => {
|
|
2580
3607
|
const parsed = parseSlash(value);
|
|
@@ -2591,7 +3618,7 @@ function BossAppInner({ boss, resetUI }) {
|
|
|
2591
3618
|
return true;
|
|
2592
3619
|
case "clear":
|
|
2593
3620
|
bossStore.clearHistory();
|
|
2594
|
-
resetUI?.();
|
|
3621
|
+
resetUI?.("session-clear");
|
|
2595
3622
|
await boss.resetConversation();
|
|
2596
3623
|
bossStore.appendInfo("Session cleared.", "info");
|
|
2597
3624
|
return true;
|
|
@@ -2622,11 +3649,11 @@ function BossAppInner({ boss, resetUI }) {
|
|
|
2622
3649
|
}
|
|
2623
3650
|
const provider = value.slice(0, colon);
|
|
2624
3651
|
const model = value.slice(colon + 1);
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
}
|
|
3652
|
+
const switchPromise = overlay === "model-boss" ? boss.switchBossModel(provider, model) : overlay === "model-workers" ? boss.switchWorkerModel(provider, model) : Promise.resolve();
|
|
3653
|
+
void switchPromise.catch((err) => {
|
|
3654
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3655
|
+
bossStore.appendInfo(`Model switch failed: ${message}`, "error");
|
|
3656
|
+
});
|
|
2630
3657
|
closeOverlay();
|
|
2631
3658
|
};
|
|
2632
3659
|
const handleSubmit = (value) => {
|
|
@@ -2636,141 +3663,117 @@ function BossAppInner({ boss, resetUI }) {
|
|
|
2636
3663
|
void handleSlashCommand(trimmed);
|
|
2637
3664
|
return;
|
|
2638
3665
|
}
|
|
2639
|
-
bossStore.
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
state
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
setCurrentRadio(null);
|
|
2725
|
-
bossStore.appendInfo("Radio off.", "info");
|
|
2726
|
-
} else {
|
|
2727
|
-
const result = playRadio(value);
|
|
2728
|
-
if (result.ok) {
|
|
2729
|
-
setCurrentRadio(value);
|
|
2730
|
-
const station = RADIO_STATIONS.find((s) => s.id === value);
|
|
2731
|
-
bossStore.appendInfo(`Now playing: ${station?.name ?? value}`, "info");
|
|
2732
|
-
} else {
|
|
2733
|
-
bossStore.appendInfo(result.error ?? "Radio failed to start.", "warning");
|
|
2734
|
-
}
|
|
2735
|
-
}
|
|
2736
|
-
closeOverlay();
|
|
3666
|
+
const userItem = bossStore.createUserItem(trimmed);
|
|
3667
|
+
terminalHistoryPrinterRef.current.print([userItem], terminalHistoryContext, {
|
|
3668
|
+
write: writeStdout
|
|
3669
|
+
});
|
|
3670
|
+
printedHistoryIdsRef.current.add(userItem.id);
|
|
3671
|
+
bossStore.queueSubmittedUserItem(userItem);
|
|
3672
|
+
setLastUserMessage(trimmed);
|
|
3673
|
+
const scoped = scopePrefix2(state.scope) + trimmed;
|
|
3674
|
+
boss.enqueueUserMessage(scoped);
|
|
3675
|
+
};
|
|
3676
|
+
const activityVisible = state.phase === "working" && state.activityPhase !== "idle";
|
|
3677
|
+
const stallStatusVisible = false;
|
|
3678
|
+
const doneStatus = null;
|
|
3679
|
+
const statusSlotVisible = activityVisible || stallStatusVisible || !!doneStatus;
|
|
3680
|
+
const controlsRows = 7 + (statusSlotVisible ? 1 : 0) + (state.exitPending ? 0 : 1);
|
|
3681
|
+
const availableLiveRows = Math.max(1, rows - controlsRows);
|
|
3682
|
+
if (rows < 14) {
|
|
3683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", width: columns, paddingX: 1, marginTop: 1, children: [
|
|
3684
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { bold: true, color: COLORS.accent, children: "Terminal too small" }),
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: COLORS.primary, children: `Resize to at least 14 rows to use EZ Boss (currently ${rows}).` })
|
|
3686
|
+
] });
|
|
3687
|
+
}
|
|
3688
|
+
const lastPendingHistoryItem = state.pendingFlush[state.pendingFlush.length - 1];
|
|
3689
|
+
const lastHistoryItem = state.history[state.history.length - 1];
|
|
3690
|
+
const livePane = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3691
|
+
BossStreamingTurnView,
|
|
3692
|
+
{
|
|
3693
|
+
turn: state.streaming,
|
|
3694
|
+
isRunning: state.phase === "working",
|
|
3695
|
+
liveItems,
|
|
3696
|
+
lastPendingHistoryItem,
|
|
3697
|
+
lastHistoryItem,
|
|
3698
|
+
availableTerminalHeight: availableLiveRows
|
|
3699
|
+
}
|
|
3700
|
+
);
|
|
3701
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3702
|
+
BossChatScreen,
|
|
3703
|
+
{
|
|
3704
|
+
boss,
|
|
3705
|
+
columns,
|
|
3706
|
+
state,
|
|
3707
|
+
overlay,
|
|
3708
|
+
livePane,
|
|
3709
|
+
theme,
|
|
3710
|
+
statusSlotVisible,
|
|
3711
|
+
activityVisible,
|
|
3712
|
+
stallStatusVisible,
|
|
3713
|
+
doneStatus,
|
|
3714
|
+
elapsedMs: state.runStartMs ? Date.now() - state.runStartMs : 0,
|
|
3715
|
+
runStartRef,
|
|
3716
|
+
charCountRef,
|
|
3717
|
+
realTokensAccumRef,
|
|
3718
|
+
lastUserMessage,
|
|
3719
|
+
activeToolNames: (state.streaming?.tools ?? []).filter((tool) => tool.status === "running").map((tool) => tool.name),
|
|
3720
|
+
inputActive: !overlay,
|
|
3721
|
+
isRunning: state.phase === "working",
|
|
3722
|
+
onSubmit: handleSubmit,
|
|
3723
|
+
onAbort: handleAbort,
|
|
3724
|
+
onTab: () => bossStore.cycleScope(),
|
|
3725
|
+
onShiftTab: () => {
|
|
3726
|
+
const next = getNextThinkingLevel(
|
|
3727
|
+
state.bossProvider,
|
|
3728
|
+
state.bossModel,
|
|
3729
|
+
state.bossThinkingLevel
|
|
3730
|
+
);
|
|
3731
|
+
void boss.setBossThinking(next);
|
|
3732
|
+
},
|
|
3733
|
+
commands: BOSS_SLASH_COMMANDS,
|
|
3734
|
+
scopeBadge: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ScopePill, { scope: state.scope }),
|
|
3735
|
+
onCloseOverlay: closeOverlay,
|
|
3736
|
+
onModelSelect: handleModelSelect,
|
|
3737
|
+
currentRadio,
|
|
3738
|
+
onRadioSelect: (value) => {
|
|
3739
|
+
if (value === "off") {
|
|
3740
|
+
stopRadio();
|
|
3741
|
+
setCurrentRadio(null);
|
|
3742
|
+
bossStore.appendInfo("Radio off.", "info");
|
|
3743
|
+
} else {
|
|
3744
|
+
const result = playRadio(value);
|
|
3745
|
+
if (result.ok) {
|
|
3746
|
+
setCurrentRadio(value);
|
|
3747
|
+
const station = RADIO_STATIONS.find((stationInfo) => stationInfo.id === value);
|
|
3748
|
+
bossStore.appendInfo(`Now playing: ${station?.name ?? value}`, "info");
|
|
3749
|
+
} else {
|
|
3750
|
+
bossStore.appendInfo(result.error ?? "Radio failed to start.", "warning");
|
|
2737
3751
|
}
|
|
2738
3752
|
}
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
),
|
|
2752
|
-
!state.exitPending && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2753
|
-
WorkerStatusBar,
|
|
2754
|
-
{
|
|
2755
|
-
workers: state.workers,
|
|
2756
|
-
pendingMessages: state.pendingUserMessages
|
|
2757
|
-
}
|
|
2758
|
-
)
|
|
2759
|
-
] })
|
|
2760
|
-
] })
|
|
2761
|
-
] });
|
|
3753
|
+
closeOverlay();
|
|
3754
|
+
},
|
|
3755
|
+
bossModel: state.bossModel,
|
|
3756
|
+
workerModel: state.workerModel,
|
|
3757
|
+
updatePending,
|
|
3758
|
+
currentRadioStationId: currentRadio,
|
|
3759
|
+
radioStations: RADIO_STATIONS,
|
|
3760
|
+
workers: state.workers,
|
|
3761
|
+
pendingMessages: state.pendingUserMessages,
|
|
3762
|
+
formatDuration: formatBossDuration
|
|
3763
|
+
}
|
|
3764
|
+
);
|
|
2762
3765
|
}
|
|
2763
3766
|
function ScopePill({ scope }) {
|
|
2764
3767
|
const theme = useTheme();
|
|
2765
3768
|
const isAll = scope === "all";
|
|
2766
3769
|
const bg = isAll ? COLORS.accent : projectColor(scope);
|
|
2767
3770
|
const label = isAll ? "All" : scope;
|
|
2768
|
-
return /* @__PURE__ */ (0,
|
|
2769
|
-
/* @__PURE__ */ (0,
|
|
2770
|
-
/* @__PURE__ */ (0,
|
|
2771
|
-
/* @__PURE__ */ (0,
|
|
3771
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Text, { children: [
|
|
3772
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: theme.textDim, children: "Project " }),
|
|
3773
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: "black", backgroundColor: bg, bold: true, children: ` ${label} ` }),
|
|
3774
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Text, { color: theme.textDim, children: [
|
|
2772
3775
|
" ",
|
|
2773
|
-
/* @__PURE__ */ (0,
|
|
3776
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: theme.primary, children: "Tab" }),
|
|
2774
3777
|
" to switch"
|
|
2775
3778
|
] })
|
|
2776
3779
|
] });
|
|
@@ -2779,396 +3782,89 @@ function scopePrefix2(scope) {
|
|
|
2779
3782
|
if (scope === "all") return "[scope:all] ";
|
|
2780
3783
|
return `[scope:${scope}] `;
|
|
2781
3784
|
}
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
const
|
|
2785
|
-
const
|
|
2786
|
-
|
|
2787
|
-
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
2788
|
-
}
|
|
2789
|
-
function AnimationActiveSentinel() {
|
|
2790
|
-
useAnimationActive();
|
|
2791
|
-
return null;
|
|
2792
|
-
}
|
|
2793
|
-
function ShimmerName({
|
|
2794
|
-
name,
|
|
2795
|
-
color,
|
|
2796
|
-
tick
|
|
2797
|
-
}) {
|
|
2798
|
-
const cycle = name.length + SHIMMER_WIDTH * 2;
|
|
2799
|
-
const shimmerPos = tick % cycle - SHIMMER_WIDTH;
|
|
2800
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: name.split("").map((ch, i) => {
|
|
2801
|
-
const isBright = Math.abs(i - shimmerPos) <= SHIMMER_WIDTH;
|
|
2802
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color, bold: isBright, dimColor: !isBright, children: ch }, i);
|
|
2803
|
-
}) });
|
|
2804
|
-
}
|
|
2805
|
-
function WorkerStatusBar({
|
|
2806
|
-
workers,
|
|
2807
|
-
pendingMessages
|
|
2808
|
-
}) {
|
|
2809
|
-
const theme = useTheme();
|
|
2810
|
-
const { columns } = useTerminalSize();
|
|
2811
|
-
const working = workers.filter((w) => w.status === "working");
|
|
2812
|
-
const errored = workers.filter((w) => w.status === "error");
|
|
2813
|
-
const idleCount = workers.length - working.length - errored.length;
|
|
2814
|
-
const anyWorking = working.length > 0;
|
|
2815
|
-
const tick = useAnimationTick();
|
|
2816
|
-
const now = Date.now();
|
|
2817
|
-
if (workers.length === 0) return null;
|
|
2818
|
-
const slots = [];
|
|
2819
|
-
for (const w of working) {
|
|
2820
|
-
const projectHue = projectColor(w.name);
|
|
2821
|
-
const elapsed = w.workStartedAt ? formatElapsed(now - w.workStartedAt) : null;
|
|
2822
|
-
slots.push(
|
|
2823
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react10.default.Fragment, { children: [
|
|
2824
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ShimmerName, { name: w.name, color: projectHue, tick }),
|
|
2825
|
-
elapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.textDim, children: [
|
|
2826
|
-
" ",
|
|
2827
|
-
elapsed
|
|
2828
|
-
] })
|
|
2829
|
-
] }, `w-${w.name}`)
|
|
2830
|
-
);
|
|
2831
|
-
}
|
|
2832
|
-
for (const w of errored) {
|
|
2833
|
-
slots.push(
|
|
2834
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.default.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.error, children: [
|
|
2835
|
-
"\u2717 ",
|
|
2836
|
-
w.name
|
|
2837
|
-
] }) }, `e-${w.name}`)
|
|
2838
|
-
);
|
|
2839
|
-
}
|
|
2840
|
-
if (idleCount > 0) {
|
|
2841
|
-
slots.push(
|
|
2842
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.default.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.textDim, children: [
|
|
2843
|
-
"\u25CB ",
|
|
2844
|
-
idleCount,
|
|
2845
|
-
" idle"
|
|
2846
|
-
] }) }, "idle")
|
|
2847
|
-
);
|
|
2848
|
-
}
|
|
2849
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { paddingX: 1, width: columns, flexShrink: 1, children: [
|
|
2850
|
-
anyWorking && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AnimationActiveSentinel, {}),
|
|
2851
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { wrap: "truncate", children: [
|
|
2852
|
-
slots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react10.default.Fragment, { children: [
|
|
2853
|
-
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.border, children: " \u2502 " }),
|
|
2854
|
-
slot
|
|
2855
|
-
] }, i)),
|
|
2856
|
-
pendingMessages > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2857
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " " }),
|
|
2858
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.warning, children: [
|
|
2859
|
-
pendingMessages,
|
|
2860
|
-
" message",
|
|
2861
|
-
pendingMessages === 1 ? "" : "s",
|
|
2862
|
-
" queued"
|
|
2863
|
-
] })
|
|
2864
|
-
] })
|
|
2865
|
-
] })
|
|
2866
|
-
] });
|
|
2867
|
-
}
|
|
2868
|
-
function StaticRowView({ row }) {
|
|
2869
|
-
if (row.kind === "banner") {
|
|
2870
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BossBanner, { subtitle: "Orchestrator", showShortcuts: true }) });
|
|
2871
|
-
}
|
|
2872
|
-
if (row.kind === "user") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(UserMessage, { text: row.text });
|
|
2873
|
-
if (row.kind === "assistant") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AssistantRow, { item: row });
|
|
2874
|
-
if (row.kind === "tool") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolHistoryRow, { item: row });
|
|
2875
|
-
if (row.kind === "worker_event") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WorkerEventRow, { item: row });
|
|
2876
|
-
if (row.kind === "worker_error") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WorkerErrorRow, { item: row });
|
|
2877
|
-
if (row.kind === "info") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(InfoRow, { text: row.text, level: row.level ?? "info" });
|
|
2878
|
-
if (row.kind === "task_dispatch") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TaskDispatchRow, { tasks: row.tasks });
|
|
2879
|
-
if (row.kind === "update_notice") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(UpdateNoticeRow, { text: row.text });
|
|
2880
|
-
return null;
|
|
2881
|
-
}
|
|
2882
|
-
function UpdateNoticeRow({ text }) {
|
|
2883
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, flexShrink: 1, borderStyle: "round", borderColor: COLORS.accent, paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { wrap: "wrap", children: [
|
|
2884
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: COLORS.accent, bold: true, children: "\u2728 " }),
|
|
2885
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: COLORS.primary, bold: true, children: text })
|
|
2886
|
-
] }) });
|
|
2887
|
-
}
|
|
2888
|
-
function TaskDispatchRow({
|
|
2889
|
-
tasks
|
|
2890
|
-
}) {
|
|
2891
|
-
const theme = useTheme();
|
|
2892
|
-
const count = tasks.length;
|
|
2893
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
2894
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
|
|
2895
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: COLORS.primary, bold: true, children: "\u23FA " }),
|
|
2896
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.text, bold: true, children: [
|
|
2897
|
-
"Running ",
|
|
2898
|
-
count,
|
|
2899
|
-
" task",
|
|
2900
|
-
count === 1 ? "" : "s",
|
|
2901
|
-
":"
|
|
2902
|
-
] })
|
|
2903
|
-
] }),
|
|
2904
|
-
tasks.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
|
|
2905
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " \u2022 " }),
|
|
2906
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: projectColor(t.project), bold: true, children: t.project }),
|
|
2907
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ": " }),
|
|
2908
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.text, children: t.title })
|
|
2909
|
-
] }, `${t.project}-${i}`))
|
|
2910
|
-
] });
|
|
2911
|
-
}
|
|
2912
|
-
var SHORTCUT_PATTERNS = [
|
|
2913
|
-
// Modifier+Key combos: Ctrl+T, Shift+Tab, Cmd+K, Ctrl+Shift+P, Ctrl+C
|
|
2914
|
-
/\b(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super)(?:\s*\+\s*(?:Ctrl|Cmd|Alt|Option|Opt|Shift|Meta|Win|Super))*\s*\+\s*(?:Tab|Enter|Esc|Escape|Space|Backspace|Delete|Del|Home|End|PageUp|PageDown|Up|Down|Left|Right|F[1-9]|F1[0-2]|[A-Z0-9]|\/|\?|\.|,|;|=|-)\b/g,
|
|
2915
|
-
// Bare named keys (only when surrounded by clear key context)
|
|
2916
|
-
/\b(?:Ctrl-[A-Z]|F[1-9]|F1[0-2])\b/g
|
|
2917
|
-
];
|
|
2918
|
-
function highlightShortcuts(text) {
|
|
2919
|
-
if (!text) return text;
|
|
2920
|
-
const SENTINEL = "\uE000";
|
|
2921
|
-
const masks = [];
|
|
2922
|
-
let masked = text.replace(/```[\s\S]*?```|`[^`]+`/g, (m) => {
|
|
2923
|
-
const idx = masks.push(m) - 1;
|
|
2924
|
-
return `${SENTINEL}${idx}${SENTINEL}`;
|
|
2925
|
-
});
|
|
2926
|
-
for (const re of SHORTCUT_PATTERNS) {
|
|
2927
|
-
masked = masked.replace(re, (m) => `\`${m}\``);
|
|
2928
|
-
}
|
|
2929
|
-
return masked.replace(
|
|
2930
|
-
new RegExp(`${SENTINEL}(\\d+)${SENTINEL}`, "g"),
|
|
2931
|
-
(_, i) => masks[Number(i)]
|
|
2932
|
-
);
|
|
2933
|
-
}
|
|
2934
|
-
function AssistantRow({ item }) {
|
|
2935
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2936
|
-
AssistantMessage,
|
|
2937
|
-
{
|
|
2938
|
-
text: highlightShortcuts(item.text),
|
|
2939
|
-
thinking: item.thinking,
|
|
2940
|
-
thinkingMs: item.thinkingMs
|
|
2941
|
-
}
|
|
2942
|
-
);
|
|
3785
|
+
function formatBossDuration(durationMs) {
|
|
3786
|
+
const total = Math.max(0, Math.floor(durationMs / 1e3));
|
|
3787
|
+
const minutes = Math.floor(total / 60);
|
|
3788
|
+
const seconds = total % 60;
|
|
3789
|
+
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
2943
3790
|
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
3791
|
+
var INK_OPTIONS = {
|
|
3792
|
+
// Match ezcoder's keyboard setup: enable kitty keyboard so Ink can decode
|
|
3793
|
+
// enhanced key events, but keep exitOnCtrlC false so our handlers receive it.
|
|
3794
|
+
kittyKeyboard: {
|
|
3795
|
+
mode: "enabled",
|
|
3796
|
+
flags: ["disambiguateEscapeCodes"]
|
|
3797
|
+
},
|
|
3798
|
+
exitOnCtrlC: false
|
|
3799
|
+
};
|
|
3800
|
+
var DISABLE_MODIFY_OTHER_KEYS = "\x1B[>4;0m";
|
|
3801
|
+
var DISABLE_FOCUS_REPORTING = "\x1B[?1004l";
|
|
3802
|
+
var SCREEN_CLEAR = DISABLE_MODIFY_OTHER_KEYS + "\x1B[2J\x1B[3J\x1B[H";
|
|
3803
|
+
var VIEWPORT_CLEAR = DISABLE_MODIFY_OTHER_KEYS + "\x1B[2J\x1B[H";
|
|
3804
|
+
function renderBossApp(opts) {
|
|
3805
|
+
const terminalHistoryPrinter = createBossTerminalHistoryPrinter({ stream: process.stdout });
|
|
3806
|
+
process.stdout.write(SCREEN_CLEAR);
|
|
3807
|
+
const onProcessExit = () => {
|
|
3808
|
+
try {
|
|
3809
|
+
process.stdout.write(DISABLE_MODIFY_OTHER_KEYS + DISABLE_FOCUS_REPORTING);
|
|
3810
|
+
} catch {
|
|
2955
3811
|
}
|
|
2956
|
-
);
|
|
2957
|
-
}
|
|
2958
|
-
function parseStatusGrade(text) {
|
|
2959
|
-
const matches = [...text.matchAll(/^\s*Status:\s*(DONE|UNVERIFIED|PARTIAL|BLOCKED|INFO)\b/gim)];
|
|
2960
|
-
const last = matches[matches.length - 1];
|
|
2961
|
-
if (!last) return null;
|
|
2962
|
-
return last[1].toUpperCase();
|
|
2963
|
-
}
|
|
2964
|
-
function parseWorkerTrailer(text) {
|
|
2965
|
-
const out = {};
|
|
2966
|
-
const grab = (label) => {
|
|
2967
|
-
const re = new RegExp(
|
|
2968
|
-
`^\\s*${label}:\\s*([\\s\\S]*?)(?=^\\s*(?:Changed|Skipped|Verified|Notes|Status):|$)`,
|
|
2969
|
-
"im"
|
|
2970
|
-
);
|
|
2971
|
-
const m = re.exec(text);
|
|
2972
|
-
if (!m) return void 0;
|
|
2973
|
-
const v = m[1].replace(/```[\s\S]*?```/g, "[code]").replace(/`([^`]+)`/g, "$1").replace(/\s+/g, " ").trim();
|
|
2974
|
-
return v.length > 0 ? v : void 0;
|
|
2975
3812
|
};
|
|
2976
|
-
|
|
2977
|
-
out.skipped = grab("Skipped");
|
|
2978
|
-
out.verified = grab("Verified");
|
|
2979
|
-
out.notes = grab("Notes");
|
|
2980
|
-
return out;
|
|
2981
|
-
}
|
|
2982
|
-
function clip(text, maxLen) {
|
|
2983
|
-
return text.length <= maxLen ? text : text.slice(0, Math.max(1, maxLen - 1)) + "\u2026";
|
|
2984
|
-
}
|
|
2985
|
-
function summarizeFinalText(text, maxLen) {
|
|
2986
|
-
if (!text) return "";
|
|
2987
|
-
const trailer = parseWorkerTrailer(text);
|
|
2988
|
-
const parts = [];
|
|
2989
|
-
if (trailer.changed) parts.push(`Changed: ${trailer.changed}`);
|
|
2990
|
-
if (trailer.verified) parts.push(`Verified: ${trailer.verified}`);
|
|
2991
|
-
if (trailer.skipped) parts.push(`Skipped: ${trailer.skipped}`);
|
|
2992
|
-
if (trailer.notes) parts.push(`Notes: ${trailer.notes}`);
|
|
2993
|
-
if (parts.length > 0) return clip(parts.join(" \xB7 "), maxLen);
|
|
2994
|
-
const beforeSummary = text.split(/^Changed:|^Skipped:|^Verified:|^Notes:|^Status:/im)[0];
|
|
2995
|
-
const stripped = beforeSummary.replace(/```[\s\S]*?```/g, "[code]").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/^\s*[-*]\s+/gm, "").replace(/^#+\s+/gm, "").replace(/\s+/g, " ").trim();
|
|
2996
|
-
if (!stripped) return "";
|
|
2997
|
-
const firstSentence = stripped.match(/^[^.!?\n]+[.!?]/);
|
|
2998
|
-
return clip(firstSentence ? firstSentence[0] : stripped, maxLen);
|
|
2999
|
-
}
|
|
3000
|
-
function statusGradeColor(grade, theme) {
|
|
3001
|
-
switch (grade) {
|
|
3002
|
-
case "DONE":
|
|
3003
|
-
return theme.success;
|
|
3004
|
-
case "UNVERIFIED":
|
|
3005
|
-
case "PARTIAL":
|
|
3006
|
-
return theme.warning;
|
|
3007
|
-
case "BLOCKED":
|
|
3008
|
-
return theme.error;
|
|
3009
|
-
case "INFO":
|
|
3010
|
-
return theme.textDim;
|
|
3011
|
-
default:
|
|
3012
|
-
return theme.textDim;
|
|
3013
|
-
}
|
|
3014
|
-
}
|
|
3015
|
-
function WorkerEventRow({ item }) {
|
|
3016
|
-
const theme = useTheme();
|
|
3017
|
-
const { columns } = useTerminalSize();
|
|
3018
|
-
const failedCount = item.toolsUsed.filter((t) => !t.ok).length;
|
|
3019
|
-
const total = item.toolsUsed.length;
|
|
3020
|
-
const grade = parseStatusGrade(item.finalText);
|
|
3021
|
-
const loaderStatus = grade === "BLOCKED" || failedCount > 0 ? "error" : grade === "UNVERIFIED" || grade === "PARTIAL" ? "queued" : "done";
|
|
3022
|
-
const headerColor = loaderStatus === "error" ? theme.toolError : projectColor(item.project);
|
|
3023
|
-
const toolSummary = total === 0 ? "no tools" : failedCount > 0 ? `${total} tools (${failedCount} failed)` : `${total} tool${total === 1 ? "" : "s"}`;
|
|
3024
|
-
const fieldMaxLen = Math.max(20, columns - 14);
|
|
3025
|
-
const trailer = parseWorkerTrailer(item.finalText);
|
|
3026
|
-
const hasTrailer = !!(trailer.changed || trailer.skipped || trailer.verified || trailer.notes);
|
|
3027
|
-
const fallbackSummary = hasTrailer ? "" : summarizeFinalText(item.finalText, fieldMaxLen);
|
|
3028
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
3029
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
3030
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolUseLoader, { status: loaderStatus }),
|
|
3031
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { wrap: "wrap", children: [
|
|
3032
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: headerColor, bold: true, children: item.project }),
|
|
3033
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.text, children: ` turn ${item.turnIndex}` }),
|
|
3034
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ` \xB7 ${toolSummary}` }),
|
|
3035
|
-
grade && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3036
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
|
|
3037
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: statusGradeColor(grade, theme), bold: true, children: grade })
|
|
3038
|
-
] })
|
|
3039
|
-
] }) })
|
|
3040
|
-
] }),
|
|
3041
|
-
hasTrailer ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3042
|
-
trailer.changed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TrailerLine, { label: "Changed", value: trailer.changed, maxLen: fieldMaxLen }),
|
|
3043
|
-
trailer.verified && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3044
|
-
TrailerLine,
|
|
3045
|
-
{
|
|
3046
|
-
label: "Verified",
|
|
3047
|
-
value: trailer.verified,
|
|
3048
|
-
maxLen: fieldMaxLen,
|
|
3049
|
-
labelColor: theme.success
|
|
3050
|
-
}
|
|
3051
|
-
),
|
|
3052
|
-
trailer.skipped && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3053
|
-
TrailerLine,
|
|
3054
|
-
{
|
|
3055
|
-
label: "Skipped",
|
|
3056
|
-
value: trailer.skipped,
|
|
3057
|
-
maxLen: fieldMaxLen,
|
|
3058
|
-
labelColor: theme.warning
|
|
3059
|
-
}
|
|
3060
|
-
),
|
|
3061
|
-
trailer.notes && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TrailerLine, { label: "Notes", value: trailer.notes, maxLen: fieldMaxLen })
|
|
3062
|
-
] }) : fallbackSummary && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, wrap: "truncate", children: fallbackSummary }) })
|
|
3063
|
-
] });
|
|
3064
|
-
}
|
|
3065
|
-
function TrailerLine({
|
|
3066
|
-
label,
|
|
3067
|
-
value,
|
|
3068
|
-
maxLen,
|
|
3069
|
-
labelColor
|
|
3070
|
-
}) {
|
|
3071
|
-
const theme = useTheme();
|
|
3072
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { wrap: "truncate", children: [
|
|
3073
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: labelColor ?? theme.textDim, bold: true, children: [
|
|
3074
|
-
label,
|
|
3075
|
-
":"
|
|
3076
|
-
] }),
|
|
3077
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.text, children: ` ${clip(value, maxLen - label.length - 2)}` })
|
|
3078
|
-
] }) });
|
|
3079
|
-
}
|
|
3080
|
-
function WorkerErrorRow({ item }) {
|
|
3081
|
-
const theme = useTheme();
|
|
3082
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
3083
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
3084
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolUseLoader, { status: "error" }),
|
|
3085
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { wrap: "wrap", children: [
|
|
3086
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.toolError, bold: true, children: item.project }),
|
|
3087
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " worker error" })
|
|
3088
|
-
] }) })
|
|
3089
|
-
] }),
|
|
3090
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.error, wrap: "wrap", children: item.message }) })
|
|
3091
|
-
] });
|
|
3092
|
-
}
|
|
3093
|
-
function InfoRow({
|
|
3094
|
-
text,
|
|
3095
|
-
level
|
|
3096
|
-
}) {
|
|
3097
|
-
if (level === "info") return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AssistantMessage, { text });
|
|
3098
|
-
const theme = useTheme();
|
|
3099
|
-
const color = level === "error" ? theme.error : theme.warning;
|
|
3100
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { marginTop: 1, flexDirection: "row", children: [
|
|
3101
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ToolUseLoader, { status: level === "error" ? "error" : "queued" }),
|
|
3102
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color, wrap: "wrap", children: text }) })
|
|
3103
|
-
] });
|
|
3104
|
-
}
|
|
3105
|
-
function StreamingTurnView({
|
|
3106
|
-
turn,
|
|
3107
|
-
isRunning
|
|
3108
|
-
}) {
|
|
3109
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
3110
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3111
|
-
StreamingArea,
|
|
3112
|
-
{
|
|
3113
|
-
isRunning,
|
|
3114
|
-
streamingText: turn.text,
|
|
3115
|
-
streamingThinking: turn.thinking,
|
|
3116
|
-
thinkingMs: turn.thinkingMs
|
|
3117
|
-
}
|
|
3118
|
-
),
|
|
3119
|
-
turn.tools.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StreamingToolRow, { tool: t }, t.toolCallId))
|
|
3120
|
-
] });
|
|
3121
|
-
}
|
|
3122
|
-
function StreamingToolRow({ tool }) {
|
|
3123
|
-
if (tool.status === "running") {
|
|
3124
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3125
|
-
ToolExecution,
|
|
3126
|
-
{
|
|
3127
|
-
status: "running",
|
|
3128
|
-
name: tool.name,
|
|
3129
|
-
args: tool.args,
|
|
3130
|
-
formatters: bossToolFormatters
|
|
3131
|
-
}
|
|
3132
|
-
);
|
|
3133
|
-
}
|
|
3134
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3135
|
-
ToolExecution,
|
|
3136
|
-
{
|
|
3137
|
-
status: "done",
|
|
3138
|
-
name: tool.name,
|
|
3139
|
-
args: tool.args,
|
|
3140
|
-
result: tool.result ?? "",
|
|
3141
|
-
isError: tool.status === "error",
|
|
3142
|
-
details: tool.details,
|
|
3143
|
-
formatters: bossToolFormatters
|
|
3144
|
-
}
|
|
3145
|
-
);
|
|
3146
|
-
}
|
|
3147
|
-
function renderBossApp(opts) {
|
|
3813
|
+
process.on("exit", onProcessExit);
|
|
3148
3814
|
const ref = { instance: null };
|
|
3149
|
-
const resetUI = () => {
|
|
3815
|
+
const resetUI = (reason = "viewport") => {
|
|
3150
3816
|
const old = ref.instance;
|
|
3151
3817
|
if (!old) return;
|
|
3152
|
-
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
3153
3818
|
old.unmount();
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3819
|
+
if (reason === "resize-redraw") {
|
|
3820
|
+
terminalHistoryPrinter.resetPrinted();
|
|
3821
|
+
process.stdout.write(SCREEN_CLEAR);
|
|
3822
|
+
const snapshot = getBossState();
|
|
3823
|
+
if (snapshot.history.length > 0) {
|
|
3824
|
+
terminalHistoryPrinter.print(snapshot.history, {
|
|
3825
|
+
theme: loadTheme("dark"),
|
|
3826
|
+
columns: Math.max(40, process.stdout.columns ?? 80),
|
|
3827
|
+
version: VERSION,
|
|
3828
|
+
model: snapshot.bossModel,
|
|
3829
|
+
provider: snapshot.bossProvider,
|
|
3830
|
+
cwd: process.cwd()
|
|
3831
|
+
});
|
|
3832
|
+
}
|
|
3833
|
+
} else if (reason === "session-clear") {
|
|
3834
|
+
terminalHistoryPrinter.clear();
|
|
3835
|
+
process.stdout.write(SCREEN_CLEAR);
|
|
3836
|
+
} else {
|
|
3837
|
+
process.stdout.write(VIEWPORT_CLEAR);
|
|
3838
|
+
}
|
|
3839
|
+
ref.instance = render_default(
|
|
3840
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3841
|
+
BossApp,
|
|
3842
|
+
{
|
|
3843
|
+
boss: opts.boss,
|
|
3844
|
+
resetUI,
|
|
3845
|
+
terminalHistoryPrinter
|
|
3846
|
+
}
|
|
3847
|
+
),
|
|
3848
|
+
INK_OPTIONS
|
|
3849
|
+
);
|
|
3157
3850
|
};
|
|
3158
|
-
const instance = render_default(
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
// the very first Ctrl+C and InputArea's onAbort never runs.
|
|
3163
|
-
exitOnCtrlC: false
|
|
3164
|
-
});
|
|
3851
|
+
const instance = render_default(
|
|
3852
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BossApp, { boss: opts.boss, resetUI, terminalHistoryPrinter }),
|
|
3853
|
+
INK_OPTIONS
|
|
3854
|
+
);
|
|
3165
3855
|
ref.instance = instance;
|
|
3166
3856
|
let resizeTimer = null;
|
|
3857
|
+
let resizeListenerEnabled = false;
|
|
3858
|
+
const enableResizeListener = setTimeout(() => {
|
|
3859
|
+
resizeListenerEnabled = true;
|
|
3860
|
+
}, 1e3);
|
|
3167
3861
|
const onTerminalResize = () => {
|
|
3862
|
+
if (!resizeListenerEnabled) return;
|
|
3168
3863
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
3169
3864
|
resizeTimer = setTimeout(() => {
|
|
3170
3865
|
resizeTimer = null;
|
|
3171
|
-
|
|
3866
|
+
if (getBossState().phase === "working") return;
|
|
3867
|
+
resetUI("resize-redraw");
|
|
3172
3868
|
}, 250);
|
|
3173
3869
|
};
|
|
3174
3870
|
process.stdout.on("resize", onTerminalResize);
|
|
@@ -3183,21 +3879,30 @@ function renderBossApp(opts) {
|
|
|
3183
3879
|
const current = ref.instance;
|
|
3184
3880
|
if (!current) {
|
|
3185
3881
|
process.stdout.off("resize", onTerminalResize);
|
|
3882
|
+
process.off("exit", onProcessExit);
|
|
3883
|
+
clearTimeout(enableResizeListener);
|
|
3186
3884
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
3885
|
+
onProcessExit();
|
|
3187
3886
|
return;
|
|
3188
3887
|
}
|
|
3189
3888
|
await current.waitUntilExit();
|
|
3190
3889
|
if (ref.instance === current) {
|
|
3191
3890
|
ref.instance = null;
|
|
3192
3891
|
process.stdout.off("resize", onTerminalResize);
|
|
3892
|
+
process.off("exit", onProcessExit);
|
|
3893
|
+
clearTimeout(enableResizeListener);
|
|
3193
3894
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
3895
|
+
onProcessExit();
|
|
3194
3896
|
return;
|
|
3195
3897
|
}
|
|
3196
3898
|
}
|
|
3197
3899
|
},
|
|
3198
3900
|
unmount: () => {
|
|
3199
3901
|
process.stdout.off("resize", onTerminalResize);
|
|
3902
|
+
process.off("exit", onProcessExit);
|
|
3903
|
+
clearTimeout(enableResizeListener);
|
|
3200
3904
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
3905
|
+
onProcessExit();
|
|
3201
3906
|
ref.instance?.unmount();
|
|
3202
3907
|
}
|
|
3203
3908
|
};
|
|
@@ -3205,8 +3910,8 @@ function renderBossApp(opts) {
|
|
|
3205
3910
|
|
|
3206
3911
|
// src/splash.tsx
|
|
3207
3912
|
init_esm_shims();
|
|
3208
|
-
var
|
|
3209
|
-
var
|
|
3913
|
+
var import_react16 = __toESM(require_react(), 1);
|
|
3914
|
+
var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
|
|
3210
3915
|
var SPLASH_LINES = [
|
|
3211
3916
|
" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ",
|
|
3212
3917
|
" \u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588 \u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588 \u2591\u2591\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588 ",
|
|
@@ -3224,33 +3929,33 @@ function colorForLine(lineIdx, totalLines, offset) {
|
|
|
3224
3929
|
return GRADIENT[idx];
|
|
3225
3930
|
}
|
|
3226
3931
|
function SplashLogo({ offset }) {
|
|
3227
|
-
return /* @__PURE__ */ (0,
|
|
3932
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { flexDirection: "column", children: SPLASH_LINES.map((line, i) => {
|
|
3228
3933
|
const hue = colorForLine(i, SPLASH_LINES.length, offset);
|
|
3229
3934
|
const segments = [];
|
|
3230
3935
|
let buf = "";
|
|
3231
3936
|
let bufDim = false;
|
|
3232
3937
|
for (const ch of line) {
|
|
3233
|
-
const
|
|
3938
|
+
const dim2 = ch === "\u2591";
|
|
3234
3939
|
if (segments.length === 0 && buf.length === 0) {
|
|
3235
3940
|
buf = ch;
|
|
3236
|
-
bufDim =
|
|
3941
|
+
bufDim = dim2;
|
|
3237
3942
|
continue;
|
|
3238
3943
|
}
|
|
3239
|
-
if (
|
|
3944
|
+
if (dim2 === bufDim) {
|
|
3240
3945
|
buf += ch;
|
|
3241
3946
|
} else {
|
|
3242
3947
|
segments.push({ text: buf, dim: bufDim });
|
|
3243
3948
|
buf = ch;
|
|
3244
|
-
bufDim =
|
|
3949
|
+
bufDim = dim2;
|
|
3245
3950
|
}
|
|
3246
3951
|
}
|
|
3247
3952
|
if (buf) segments.push({ text: buf, dim: bufDim });
|
|
3248
|
-
return /* @__PURE__ */ (0,
|
|
3953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { children: segments.map((seg, j) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { color: hue, dimColor: seg.dim, children: seg.text }, j)) }, i);
|
|
3249
3954
|
}) });
|
|
3250
3955
|
}
|
|
3251
3956
|
function SplashScreen({ caption }) {
|
|
3252
|
-
const [offset, setOffset] = (0,
|
|
3253
|
-
(0,
|
|
3957
|
+
const [offset, setOffset] = (0, import_react16.useState)(0);
|
|
3958
|
+
(0, import_react16.useEffect)(() => {
|
|
3254
3959
|
const timer = setInterval(() => {
|
|
3255
3960
|
setOffset((o) => o + 1);
|
|
3256
3961
|
}, 120);
|
|
@@ -3258,11 +3963,11 @@ function SplashScreen({ caption }) {
|
|
|
3258
3963
|
clearInterval(timer);
|
|
3259
3964
|
};
|
|
3260
3965
|
}, []);
|
|
3261
|
-
const [size, setSize] = (0,
|
|
3966
|
+
const [size, setSize] = (0, import_react16.useState)(() => ({
|
|
3262
3967
|
columns: process.stdout.columns ?? 80,
|
|
3263
3968
|
rows: process.stdout.rows ?? 24
|
|
3264
3969
|
}));
|
|
3265
|
-
(0,
|
|
3970
|
+
(0, import_react16.useEffect)(() => {
|
|
3266
3971
|
const handler = () => setSize({
|
|
3267
3972
|
columns: process.stdout.columns ?? 80,
|
|
3268
3973
|
rows: process.stdout.rows ?? 24
|
|
@@ -3274,27 +3979,27 @@ function SplashScreen({ caption }) {
|
|
|
3274
3979
|
}, []);
|
|
3275
3980
|
const SPLASH_BLOCK_HEIGHT = SPLASH_LINES.length + 3;
|
|
3276
3981
|
const verticalPad = Math.max(0, Math.floor((size.rows - SPLASH_BLOCK_HEIGHT) / 2));
|
|
3277
|
-
return /* @__PURE__ */ (0,
|
|
3278
|
-
/* @__PURE__ */ (0,
|
|
3279
|
-
/* @__PURE__ */ (0,
|
|
3280
|
-
/* @__PURE__ */ (0,
|
|
3281
|
-
/* @__PURE__ */ (0,
|
|
3282
|
-
/* @__PURE__ */ (0,
|
|
3283
|
-
/* @__PURE__ */ (0,
|
|
3982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Box_default, { flexDirection: "column", width: size.columns, height: size.rows, alignItems: "center", children: [
|
|
3983
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { height: verticalPad, flexShrink: 0 }),
|
|
3984
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Box_default, { flexDirection: "column", alignItems: "flex-start", flexShrink: 0, children: [
|
|
3985
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SplashLogo, { offset }),
|
|
3986
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { width: SPLASH_WIDTH, marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Text, { children: [
|
|
3987
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { color: COLORS.text, bold: true, children: BRAND }),
|
|
3988
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Text, { color: COLORS.textDim, children: [
|
|
3284
3989
|
" v",
|
|
3285
3990
|
VERSION
|
|
3286
3991
|
] }),
|
|
3287
|
-
/* @__PURE__ */ (0,
|
|
3288
|
-
/* @__PURE__ */ (0,
|
|
3992
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { color: COLORS.textDim, children: " \xB7 By " }),
|
|
3993
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { color: COLORS.text, bold: true, children: AUTHOR })
|
|
3289
3994
|
] }) }),
|
|
3290
|
-
/* @__PURE__ */ (0,
|
|
3995
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { width: SPLASH_WIDTH, justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Text, { color: COLORS.textDim, children: caption ?? "Spinning up the orchestrator\u2026" }) })
|
|
3291
3996
|
] })
|
|
3292
3997
|
] });
|
|
3293
3998
|
}
|
|
3294
3999
|
function showSplash(opts) {
|
|
3295
4000
|
const start = Date.now();
|
|
3296
4001
|
void playSplashAudio();
|
|
3297
|
-
const instance = render_default(/* @__PURE__ */ (0,
|
|
4002
|
+
const instance = render_default(/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SplashScreen, { caption: opts.caption }));
|
|
3298
4003
|
const audioDurationMs = getSplashAudioDurationMs();
|
|
3299
4004
|
const defaultMinMs = audioDurationMs + 200;
|
|
3300
4005
|
return {
|
|
@@ -3353,12 +4058,12 @@ function parseArgs(argv) {
|
|
|
3353
4058
|
return args;
|
|
3354
4059
|
}
|
|
3355
4060
|
function printHelpAndExit() {
|
|
3356
|
-
const c = (
|
|
4061
|
+
const c = (color2, text) => source_default.hex(color2)(text);
|
|
3357
4062
|
process.stdout.write(
|
|
3358
4063
|
"\n" + c(COLORS.primary, "EZ Boss") + c(COLORS.textDim, " \u2014 orchestrator that drives multiple ezcoder workers from one chat.\n\n") + c(COLORS.text, "Usage\n") + " " + c(COLORS.accent, "ezboss") + c(
|
|
3359
4064
|
COLORS.textDim,
|
|
3360
4065
|
" start orchestrator using linked projects\n"
|
|
3361
|
-
) + " " + c(COLORS.accent, "ezboss link") + c(COLORS.textDim, " pick which projects to link (interactive)\n") + " " + c(COLORS.accent, "ezboss telegram") + c(COLORS.textDim, " configure Telegram bot integration\n") + " " + c(COLORS.accent, "ezboss serve") + c(COLORS.textDim, " run the boss over Telegram (no TUI)\n") + " " + c(COLORS.accent, "ezboss continue") + c(COLORS.textDim, " resume the most recent boss session\n") + " " + c(COLORS.accent, "ezboss --resume <id>") + c(COLORS.textDim, " resume a specific boss session\n") + " " + c(COLORS.accent, "ezboss --project <spec> [...]") + c(COLORS.textDim, " override links with explicit project(s)\n\n") + c(COLORS.text, "Options\n") + " " + c(COLORS.primary, "--project, -p <spec>") + c(COLORS.textDim, ' project to manage. spec is "cwd" or "name=cwd". repeatable.\n') + " " + c(COLORS.primary, "--boss-model <id>") + c(COLORS.textDim, " model for the orchestrator (default: claude-opus-4-
|
|
4066
|
+
) + " " + c(COLORS.accent, "ezboss link") + c(COLORS.textDim, " pick which projects to link (interactive)\n") + " " + c(COLORS.accent, "ezboss telegram") + c(COLORS.textDim, " configure Telegram bot integration\n") + " " + c(COLORS.accent, "ezboss serve") + c(COLORS.textDim, " run the boss over Telegram (no TUI)\n") + " " + c(COLORS.accent, "ezboss continue") + c(COLORS.textDim, " resume the most recent boss session\n") + " " + c(COLORS.accent, "ezboss --resume <id>") + c(COLORS.textDim, " resume a specific boss session\n") + " " + c(COLORS.accent, "ezboss --project <spec> [...]") + c(COLORS.textDim, " override links with explicit project(s)\n\n") + c(COLORS.text, "Options\n") + " " + c(COLORS.primary, "--project, -p <spec>") + c(COLORS.textDim, ' project to manage. spec is "cwd" or "name=cwd". repeatable.\n') + " " + c(COLORS.primary, "--boss-model <id>") + c(COLORS.textDim, " model for the orchestrator (default: claude-opus-4-8)\n") + " " + c(COLORS.primary, "--worker-model <id>") + c(COLORS.textDim, " model for workers (default: claude-sonnet-4-6)\n") + " " + c(COLORS.primary, "--help, -h") + c(COLORS.textDim, " show this help\n\n") + c(COLORS.textDim, "Talk to the boss at the prompt. Press ") + c(COLORS.accent, "Ctrl+C") + c(COLORS.textDim, " twice to exit.\n\n")
|
|
3362
4067
|
);
|
|
3363
4068
|
process.exit(0);
|
|
3364
4069
|
}
|
|
@@ -3394,7 +4099,7 @@ async function runServeSubcommand(argv) {
|
|
|
3394
4099
|
}
|
|
3395
4100
|
const settings = await loadSettings();
|
|
3396
4101
|
const bossProvider = settings.bossProvider ?? "anthropic";
|
|
3397
|
-
const bossModel = cliBossModel ?? settings.bossModel ?? "claude-opus-4-
|
|
4102
|
+
const bossModel = cliBossModel ?? settings.bossModel ?? "claude-opus-4-8";
|
|
3398
4103
|
const workerProvider = settings.workerProvider ?? "anthropic";
|
|
3399
4104
|
const workerModel = cliWorkerModel ?? settings.workerModel ?? "claude-sonnet-4-6";
|
|
3400
4105
|
await runBossServeMode({
|
|
@@ -3423,7 +4128,7 @@ async function runOrchestrator(args) {
|
|
|
3423
4128
|
});
|
|
3424
4129
|
const settings = await loadSettings();
|
|
3425
4130
|
const finalBossProvider = args.bossProvider ?? settings.bossProvider ?? "anthropic";
|
|
3426
|
-
const finalBossModel = args.bossModel ?? settings.bossModel ?? "claude-opus-4-
|
|
4131
|
+
const finalBossModel = args.bossModel ?? settings.bossModel ?? "claude-opus-4-8";
|
|
3427
4132
|
const finalWorkerProvider = args.workerProvider ?? settings.workerProvider ?? "anthropic";
|
|
3428
4133
|
const finalWorkerModel = args.workerModel ?? settings.workerModel ?? "claude-sonnet-4-6";
|
|
3429
4134
|
initLogger({
|