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