@kenkaiiii/gg-boss 4.3.164 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3,6 +3,7 @@ import { createRequire as __createRequire } from "node:module"; const require =
3
3
  import {
4
4
  AnimationProvider,
5
5
  AssistantMessage,
6
+ AuthStorage,
6
7
  Box_default,
7
8
  ChatControls,
8
9
  ChatInputStack,
@@ -15,6 +16,7 @@ import {
15
16
  MODELS,
16
17
  MessageResponse,
17
18
  RESPONSE_LEFT_PADDING,
19
+ TelegramBot,
18
20
  TerminalSizeProvider,
19
21
  Text,
20
22
  ThemeContext,
@@ -28,17 +30,21 @@ import {
28
30
  buildToolGroupSummary,
29
31
  closeLogger,
30
32
  color,
33
+ createAutoUpdater,
31
34
  dim,
32
35
  formatHistoryWrite,
33
36
  getAppPaths,
34
37
  getBossState,
35
38
  getContextWindow,
39
+ getDefaultModel,
40
+ getModel,
36
41
  getNextThinkingLevel,
37
42
  getSplashAudioDurationMs,
38
43
  getTranscriptItemMarginTop,
39
44
  gradientLine,
40
45
  indent,
41
46
  initLogger,
47
+ isModelLoaded,
42
48
  loadSettings,
43
49
  loadTheme,
44
50
  log,
@@ -48,6 +54,7 @@ import {
48
54
  require_react,
49
55
  saveSettings,
50
56
  serializeCompletedItemToTerminalHistory,
57
+ setProgressCallback,
51
58
  setStreamDiagnostic,
52
59
  shouldSeparateTranscriptItemKinds,
53
60
  shouldTopSpaceStreamingAssistant,
@@ -56,6 +63,7 @@ import {
56
63
  subscribeToBossStore,
57
64
  tasksStore,
58
65
  toolTonePalette,
66
+ transcribeVoice,
59
67
  truncatePlain,
60
68
  useAnimationActive,
61
69
  useAnimationTick,
@@ -68,7 +76,7 @@ import {
68
76
  use_input_default,
69
77
  use_stdout_default,
70
78
  wrapPlain
71
- } from "./chunk-SSDL6C2P.js";
79
+ } from "./chunk-5ENJR6XI.js";
72
80
  import "./chunk-JEGMYLRS.js";
73
81
  import {
74
82
  source_default
@@ -361,7 +369,7 @@ init_esm_shims();
361
369
  // package.json
362
370
  var package_default = {
363
371
  name: "@kenkaiiii/gg-boss",
364
- version: "4.3.164",
372
+ version: "4.4.0",
365
373
  type: "module",
366
374
  description: "Orchestrator agent that drives multiple ggcoder sessions across projects from a single chat",
367
375
  license: "MIT",
@@ -387,6 +395,7 @@ var package_default = {
387
395
  devDependencies: {
388
396
  "@kenkaiiii/gg-agent": "workspace:*",
389
397
  "@kenkaiiii/gg-ai": "workspace:*",
398
+ "@kenkaiiii/gg-core": "workspace:*",
390
399
  "@kenkaiiii/ggcoder": "workspace:*",
391
400
  "@types/node": "^25.6.0",
392
401
  "@types/react": "^19.2.14",
@@ -669,317 +678,6 @@ async function runLinkCommand() {
669
678
  init_esm_shims();
670
679
  import path3 from "path";
671
680
  import fs3 from "fs/promises";
672
-
673
- // src/voice-transcriber.ts
674
- init_esm_shims();
675
- var TARGET_SAMPLE_RATE = 16e3;
676
- var MODEL_ID = "Xenova/whisper-tiny.en";
677
- var transcriber = null;
678
- var loadPromise = null;
679
- var onProgress = null;
680
- function setProgressCallback(cb) {
681
- onProgress = cb;
682
- }
683
- function resample(audio, fromRate, toRate) {
684
- if (fromRate === toRate) return audio;
685
- const ratio = fromRate / toRate;
686
- const newLength = Math.round(audio.length / ratio);
687
- const result = new Float32Array(newLength);
688
- for (let i = 0; i < newLength; i++) {
689
- const srcIndex = i * ratio;
690
- const low = Math.floor(srcIndex);
691
- const high = Math.min(low + 1, audio.length - 1);
692
- const frac = srcIndex - low;
693
- result[i] = audio[low] * (1 - frac) + audio[high] * frac;
694
- }
695
- return result;
696
- }
697
- function downmixToMono(channelData) {
698
- if (channelData.length === 0) return new Float32Array();
699
- if (channelData.length === 1) return channelData[0];
700
- const samples = channelData[0].length;
701
- const out = new Float32Array(samples);
702
- const scale = 1 / channelData.length;
703
- for (let i = 0; i < samples; i++) {
704
- let mixed = 0;
705
- for (const channel of channelData) mixed += channel[i] ?? 0;
706
- out[i] = mixed * scale;
707
- }
708
- return out;
709
- }
710
- async function decodeOggOpus(buffer) {
711
- const { OggOpusDecoder } = await import("ogg-opus-decoder");
712
- const decoder = new OggOpusDecoder();
713
- await decoder.ready;
714
- try {
715
- const decoded = await decoder.decodeFile(buffer);
716
- if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {
717
- throw new Error("Decoded audio is empty");
718
- }
719
- const mono = downmixToMono(decoded.channelData);
720
- return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);
721
- } finally {
722
- decoder.free();
723
- }
724
- }
725
- async function getTranscriber() {
726
- if (transcriber) return transcriber;
727
- if (!loadPromise) {
728
- loadPromise = (async () => {
729
- const { pipeline } = await import("@huggingface/transformers");
730
- const instance = await pipeline("automatic-speech-recognition", MODEL_ID, {
731
- dtype: "fp32",
732
- progress_callback: onProgress ?? void 0
733
- });
734
- transcriber = instance;
735
- return instance;
736
- })();
737
- }
738
- return loadPromise;
739
- }
740
- function isModelLoaded() {
741
- return transcriber !== null;
742
- }
743
- async function transcribeVoice(fileUrl) {
744
- const response = await fetch(fileUrl);
745
- if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);
746
- const buffer = new Uint8Array(await response.arrayBuffer());
747
- const pcm = await decodeOggOpus(buffer);
748
- const asr = await getTranscriber();
749
- const result = await asr(pcm);
750
- const text = Array.isArray(result) ? result[0]?.text : result.text;
751
- return (text ?? "").trim();
752
- }
753
-
754
- // src/telegram.ts
755
- init_esm_shims();
756
- var TELEGRAM_API = "https://api.telegram.org";
757
- var MAX_MESSAGE_LENGTH = 4096;
758
- var TelegramBot = class {
759
- token;
760
- allowedUserId;
761
- offset = 0;
762
- running = false;
763
- onMessage = null;
764
- onVoiceMessage = null;
765
- onCallback = null;
766
- onBotAdded = null;
767
- onBotRemoved = null;
768
- constructor(config) {
769
- this.token = config.botToken;
770
- this.allowedUserId = config.allowedUserId;
771
- }
772
- /** Register handler for incoming text messages. */
773
- onText(handler) {
774
- this.onMessage = handler;
775
- }
776
- /** Register handler for incoming voice notes. */
777
- onVoice(handler) {
778
- this.onVoiceMessage = handler;
779
- }
780
- /** Register handler for inline keyboard button presses. */
781
- onCallbackQuery(handler) {
782
- this.onCallback = handler;
783
- }
784
- /** Register handler for when the bot is added to a group. */
785
- onAddedToGroup(handler) {
786
- this.onBotAdded = handler;
787
- }
788
- /** Register handler for when the bot is removed from a group. */
789
- onRemovedFromGroup(handler) {
790
- this.onBotRemoved = handler;
791
- }
792
- /** Start long polling. Blocks until stop() is called. */
793
- async start() {
794
- this.running = true;
795
- const me = await this.apiCall("getMe");
796
- if (!me.ok) {
797
- throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);
798
- }
799
- while (this.running) {
800
- try {
801
- const updates = await this.getUpdates();
802
- for (const update of updates) {
803
- await this.handleUpdate(update);
804
- }
805
- } catch (err) {
806
- if (!this.running) break;
807
- console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);
808
- await sleep(3e3);
809
- }
810
- }
811
- }
812
- /** Stop long polling. */
813
- stop() {
814
- this.running = false;
815
- }
816
- /** Send a text message to a specific chat. Converts markdown and splits long messages. */
817
- async send(chatId, text, buttons) {
818
- const converted = toTelegramMarkdown(text);
819
- const chunks = splitMessage(converted);
820
- for (let i = 0; i < chunks.length; i++) {
821
- const isLast = i === chunks.length - 1;
822
- const replyMarkup = isLast && buttons ? {
823
- inline_keyboard: buttons.map(
824
- (row) => row.map((b) => ({ text: b.text, callback_data: b.callback_data }))
825
- )
826
- } : void 0;
827
- await this.apiCall("sendMessage", {
828
- chat_id: chatId,
829
- text: chunks[i],
830
- parse_mode: "Markdown",
831
- ...replyMarkup ? { reply_markup: replyMarkup } : {}
832
- });
833
- }
834
- }
835
- /** Send a plain text message (no markdown parsing) to a specific chat. */
836
- async sendPlain(chatId, text) {
837
- const chunks = splitMessage(text);
838
- for (const chunk of chunks) {
839
- await this.apiCall("sendMessage", {
840
- chat_id: chatId,
841
- text: chunk
842
- });
843
- }
844
- }
845
- /** Send a typing indicator to a specific chat. */
846
- async sendTyping(chatId) {
847
- await this.apiCall("sendChatAction", {
848
- chat_id: chatId,
849
- action: "typing"
850
- });
851
- }
852
- /** Get a direct download URL for a Telegram file. */
853
- async getFileUrl(fileId) {
854
- const result = await this.apiCall("getFile", { file_id: fileId });
855
- if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);
856
- const filePath = result.result.file_path;
857
- return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;
858
- }
859
- // ── Private ───────────────────────────────────────────
860
- async getUpdates() {
861
- const result = await this.apiCall("getUpdates", {
862
- offset: this.offset,
863
- timeout: 30,
864
- allowed_updates: ["message", "callback_query", "my_chat_member"]
865
- });
866
- if (!result.ok || !Array.isArray(result.result)) return [];
867
- const updates = result.result;
868
- if (updates.length > 0) {
869
- this.offset = updates[updates.length - 1].update_id + 1;
870
- }
871
- return updates;
872
- }
873
- async handleUpdate(update) {
874
- if (update.message) {
875
- const msg = update.message;
876
- if (msg.from.id !== this.allowedUserId) {
877
- return;
878
- }
879
- if (msg.text && this.onMessage) {
880
- this.onMessage({
881
- text: msg.text,
882
- chatId: msg.chat.id,
883
- chatType: msg.chat.type,
884
- chatTitle: msg.chat.title
885
- });
886
- } else if (msg.voice && this.onVoiceMessage) {
887
- this.onVoiceMessage({
888
- fileId: msg.voice.file_id,
889
- duration: msg.voice.duration,
890
- chatId: msg.chat.id,
891
- chatType: msg.chat.type,
892
- chatTitle: msg.chat.title
893
- });
894
- }
895
- }
896
- if (update.my_chat_member) {
897
- const member = update.my_chat_member;
898
- const status = member.new_chat_member.status;
899
- if ((status === "member" || status === "administrator") && this.onBotAdded) {
900
- this.onBotAdded(member.chat.id, member.chat.title);
901
- } else if ((status === "left" || status === "kicked") && this.onBotRemoved) {
902
- this.onBotRemoved(member.chat.id);
903
- }
904
- }
905
- if (update.callback_query) {
906
- const cb = update.callback_query;
907
- if (cb.from.id !== this.allowedUserId) return;
908
- await this.apiCall("answerCallbackQuery", { callback_query_id: cb.id });
909
- if (cb.data && this.onCallback) {
910
- this.onCallback(cb.data, cb.message.chat.id);
911
- }
912
- }
913
- }
914
- async apiCall(method, body) {
915
- const url = `${TELEGRAM_API}/bot${this.token}/${method}`;
916
- const response = await fetch(url, {
917
- method: "POST",
918
- headers: { "Content-Type": "application/json" },
919
- body: body ? JSON.stringify(body) : void 0
920
- });
921
- if (!response.ok) {
922
- return { ok: false };
923
- }
924
- return response.json();
925
- }
926
- };
927
- function toTelegramMarkdown(text) {
928
- const lines = text.split("\n");
929
- const result = [];
930
- let inCodeBlock = false;
931
- for (const line of lines) {
932
- if (line.trimStart().startsWith("```")) {
933
- inCodeBlock = !inCodeBlock;
934
- result.push(line);
935
- continue;
936
- }
937
- if (inCodeBlock) {
938
- result.push(line);
939
- continue;
940
- }
941
- let transformed = line;
942
- const headingMatch = transformed.match(/^(#{1,6})\s+(.+)$/);
943
- if (headingMatch) {
944
- transformed = `*${headingMatch[2]}*`;
945
- result.push(transformed);
946
- continue;
947
- }
948
- if (/^(-{3,}|_{3,}|\*{3,})$/.test(transformed.trim())) {
949
- result.push("");
950
- continue;
951
- }
952
- transformed = transformed.replace(/\*\*(.+?)\*\*/g, "*$1*");
953
- result.push(transformed);
954
- }
955
- return result.join("\n");
956
- }
957
- function splitMessage(text) {
958
- if (text.length <= MAX_MESSAGE_LENGTH) return [text];
959
- const chunks = [];
960
- let remaining = text;
961
- while (remaining.length > 0) {
962
- if (remaining.length <= MAX_MESSAGE_LENGTH) {
963
- chunks.push(remaining);
964
- break;
965
- }
966
- let splitAt = remaining.lastIndexOf("\n", MAX_MESSAGE_LENGTH);
967
- if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {
968
- splitAt = remaining.lastIndexOf(" ", MAX_MESSAGE_LENGTH);
969
- }
970
- if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {
971
- splitAt = MAX_MESSAGE_LENGTH;
972
- }
973
- chunks.push(remaining.slice(0, splitAt));
974
- remaining = remaining.slice(splitAt).trimStart();
975
- }
976
- return chunks;
977
- }
978
- function sleep(ms) {
979
- return new Promise((r) => setTimeout(r, ms));
980
- }
981
-
982
- // src/serve-mode.ts
983
681
  function getTelegramConfigPath() {
984
682
  return path3.join(getAppPaths().agentDir, "boss", "telegram.json");
985
683
  }
@@ -1538,7 +1236,7 @@ function printSetupBanner() {
1538
1236
 
1539
1237
  // src/orchestrator-app.tsx
1540
1238
  init_esm_shims();
1541
- var import_react15 = __toESM(require_react(), 1);
1239
+ var import_react14 = __toESM(require_react(), 1);
1542
1240
 
1543
1241
  // ../ggcoder/dist/ui/components/index.js
1544
1242
  init_esm_shims();
@@ -1548,20 +1246,15 @@ init_esm_shims();
1548
1246
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
1549
1247
  var import_react3 = __toESM(require_react(), 1);
1550
1248
 
1551
- // ../ggcoder/dist/ui/components/Overlay.js
1249
+ // ../ggcoder/dist/ui/components/SelectList.js
1552
1250
  init_esm_shims();
1553
1251
  var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
1554
1252
  var import_react4 = __toESM(require_react(), 1);
1555
-
1556
- // ../ggcoder/dist/ui/components/SelectList.js
1557
- init_esm_shims();
1558
- var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
1559
- var import_react5 = __toESM(require_react(), 1);
1560
1253
  function SelectList({ items, onSelect, onCancel, initialIndex = 0, windowSize }) {
1561
1254
  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)(() => {
1255
+ const [selectedIndex, setSelectedIndex] = (0, import_react4.useState)(initialIndex);
1256
+ const [filter, setFilter] = (0, import_react4.useState)("");
1257
+ const filtered = (0, import_react4.useMemo)(() => {
1565
1258
  if (!filter)
1566
1259
  return items;
1567
1260
  const lower = filter.toLowerCase();
@@ -1608,30 +1301,30 @@ function SelectList({ items, onSelect, onCancel, initialIndex = 0, windowSize })
1608
1301
  const visible = useWindow ? filtered.slice(start, end) : filtered;
1609
1302
  const hasAbove = useWindow && start > 0;
1610
1303
  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) => {
1304
+ return (0, import_jsx_runtime4.jsxs)(Box_default, { flexDirection: "column", children: [filter && (0, import_jsx_runtime4.jsx)(Box_default, { marginBottom: 1, children: (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: ["Filter: ", filter] }) }), hasAbove && (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: [" \u2191 ", start, " more"] }), visible.map((item, i) => {
1612
1305
  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" }) })] });
1306
+ return (0, import_jsx_runtime4.jsxs)(Box_default, { children: [(0, import_jsx_runtime4.jsxs)(Text, { color: index === clampedIndex ? theme.primary : theme.text, children: [index === clampedIndex ? "\u276F " : " ", item.label] }), item.description && (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: [" \u2014 ", item.description] })] }, item.value);
1307
+ }), hasBelow && (0, import_jsx_runtime4.jsxs)(Text, { color: theme.textDim, children: [" \u2193 ", total - end, " more"] }), filtered.length === 0 && (0, import_jsx_runtime4.jsx)(Text, { color: theme.textDim, children: "No matches" }), (0, import_jsx_runtime4.jsx)(Box_default, { marginTop: 1, children: (0, import_jsx_runtime4.jsx)(Text, { color: theme.textDim, children: "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc cancel" }) })] });
1615
1308
  }
1616
1309
 
1617
1310
  // ../ggcoder/dist/ui/components/SessionSelector.js
1618
1311
  init_esm_shims();
1619
- var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
1620
- var import_react6 = __toESM(require_react(), 1);
1312
+ var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
1313
+ var import_react5 = __toESM(require_react(), 1);
1621
1314
 
1622
1315
  // ../ggcoder/dist/ui/components/SettingsSelector.js
1623
1316
  init_esm_shims();
1624
- var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
1625
- var import_react7 = __toESM(require_react(), 1);
1317
+ var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
1318
+ var import_react6 = __toESM(require_react(), 1);
1626
1319
 
1627
1320
  // src/boss-chat-screen.tsx
1628
1321
  init_esm_shims();
1629
- var import_react13 = __toESM(require_react(), 1);
1322
+ var import_react12 = __toESM(require_react(), 1);
1630
1323
 
1631
1324
  // src/boss-footer.tsx
1632
1325
  init_esm_shims();
1633
- var import_react8 = __toESM(require_react(), 1);
1634
- var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
1326
+ var import_react7 = __toESM(require_react(), 1);
1327
+ var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
1635
1328
  var PARTIAL_BLOCKS = [" ", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589", "\u2588"];
1636
1329
  var LIGHT_SHADE = "\u2591";
1637
1330
  var BAR_WIDTH = 8;
@@ -1685,7 +1378,7 @@ function renderContextBar({
1685
1378
  const cellFill = Math.max(0, Math.min(1, fillFloat - i));
1686
1379
  const eighths = Math.round(cellFill * 8);
1687
1380
  barChars.push(
1688
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: eighths > 0 ? contextColor : dimColor, children: eighths > 0 ? PARTIAL_BLOCKS[eighths] : LIGHT_SHADE }, i)
1381
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: eighths > 0 ? contextColor : dimColor, children: eighths > 0 ? PARTIAL_BLOCKS[eighths] : LIGHT_SHADE }, i)
1689
1382
  );
1690
1383
  }
1691
1384
  return barChars;
@@ -1706,11 +1399,11 @@ function BossFooter({
1706
1399
  const theme = useTheme();
1707
1400
  const { columns } = useTerminalSize();
1708
1401
  if (exitPending) {
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" }) });
1402
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { paddingLeft: 1, paddingRight: 1, width: columns, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.warning, children: "Press Ctrl+C again to exit" }) });
1710
1403
  }
1711
1404
  const contextPct = getBossFooterContextPercent(bossModel, tokensIn);
1712
1405
  const contextColor = getContextColor(contextPct, theme);
1713
- const sep = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.border, children: " \u2502 " });
1406
+ const sep = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.border, children: " \u2502 " });
1714
1407
  const bossName = shortModel(bossModel);
1715
1408
  const workerName = shortModel(workerModel);
1716
1409
  const thinkingText = getBossFooterThinkingLabel(bossThinkingLevel);
@@ -1727,48 +1420,48 @@ function BossFooter({
1727
1420
  const fitsOnOneLine = leftText.length + rightLen <= availableWidth;
1728
1421
  const hideRadio = !!radioName && leftText.length + rightLen > availableWidth + 8;
1729
1422
  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: [
1423
+ const rightContent = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1424
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: barChars }),
1425
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: contextColor, children: [
1733
1426
  " ",
1734
1427
  contextPct,
1735
1428
  "%"
1736
1429
  ] }),
1737
1430
  sep,
1738
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.primary, bold: true, children: bossName }),
1431
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.primary, bold: true, children: bossName }),
1739
1432
  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 }),
1433
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.textDim, children: "workers " }),
1434
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: COLORS.accent, bold: true, children: workerName }),
1742
1435
  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: [
1436
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: getThinkingColor(bossThinkingLevel, theme), bold: bossThinkingLevel === "high", children: thinkingText }),
1437
+ radioName && !hideRadio && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1745
1438
  sep,
1746
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: theme.secondary, children: [
1439
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { color: theme.secondary, children: [
1747
1440
  "\u266A ",
1748
1441
  radioName
1749
1442
  ] })
1750
1443
  ] }),
1751
- updateText && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1444
+ updateText && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1752
1445
  sep,
1753
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.success, bold: true, wrap: "truncate", children: compactUpdate ? "Update ready" : updateText })
1446
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.success, bold: true, wrap: "truncate", children: compactUpdate ? "Update ready" : updateText })
1754
1447
  ] })
1755
1448
  ] });
1756
1449
  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 })
1450
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { paddingLeft: 1, paddingRight: 1, width: columns, children: [
1451
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.textDim, wrap: "truncate", children: leftText }) }),
1452
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { flexShrink: 0, children: rightContent })
1760
1453
  ] });
1761
1454
  }
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 })
1455
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, width: columns, children: [
1456
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: theme.textDim, wrap: "truncate", children: leftText }) }),
1457
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { children: rightContent })
1765
1458
  ] });
1766
1459
  }
1767
1460
 
1768
1461
  // src/boss-model-selector.tsx
1769
1462
  init_esm_shims();
1770
- var import_react9 = __toESM(require_react(), 1);
1771
- var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
1463
+ var import_react8 = __toESM(require_react(), 1);
1464
+ var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
1772
1465
  var MAX_MODELS_TO_SHOW = 8;
1773
1466
  var PROVIDER_LABEL = {
1774
1467
  anthropic: "Anthropic",
@@ -1806,9 +1499,9 @@ function BossModelSelectList({
1806
1499
  }) {
1807
1500
  const theme = useTheme();
1808
1501
  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)(() => {
1502
+ const [selectedIndex, setSelectedIndex] = (0, import_react8.useState)(initialIndex);
1503
+ const [filter, setFilter] = (0, import_react8.useState)("");
1504
+ const filtered = (0, import_react8.useMemo)(() => {
1812
1505
  if (!filter) return items;
1813
1506
  const lower = filter.toLowerCase();
1814
1507
  return items.filter(
@@ -1854,38 +1547,38 @@ function BossModelSelectList({
1854
1547
  const width = Math.max(20, columns);
1855
1548
  const maxLabelLength = Math.max(0, ...filtered.map((item) => item.label.length));
1856
1549
  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: [
1550
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, width, children: [
1551
+ filter && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: theme.textDim, children: [
1859
1552
  "Filter: ",
1860
1553
  filter
1861
1554
  ] }),
1862
- start > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.text, children: "\u25B2" }),
1555
+ start > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.text, children: "\u25B2" }),
1863
1556
  visible.map((item, i) => {
1864
1557
  const actualIndex = start + i;
1865
1558
  const isSelected = actualIndex === idx;
1866
1559
  const textColor = isSelected ? theme.commandColor : theme.textDim;
1867
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1560
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1868
1561
  Box_default,
1869
1562
  {
1870
1563
  flexDirection: "row",
1871
1564
  backgroundColor: isSelected ? theme.border : void 0,
1872
1565
  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) }) })
1566
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: labelColumnWidth, flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: textColor, children: item.label }) }),
1567
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1, paddingLeft: 3, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: textColor, wrap: "truncate", children: item.description.slice(0, 100) }) })
1875
1568
  ]
1876
1569
  },
1877
1570
  item.value
1878
1571
  );
1879
1572
  }),
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: [
1573
+ end < total && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.textDim, children: "\u25BC" }),
1574
+ total > MAX_MODELS_TO_SHOW && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: theme.textDim, children: [
1882
1575
  "(",
1883
1576
  idx + 1,
1884
1577
  "/",
1885
1578
  total,
1886
1579
  ")"
1887
1580
  ] }),
1888
- total === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: "No matches" })
1581
+ total === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: theme.textDim, children: "No matches" })
1889
1582
  ] });
1890
1583
  }
1891
1584
  function BossModelSelector({
@@ -1895,7 +1588,7 @@ function BossModelSelector({
1895
1588
  currentProvider
1896
1589
  }) {
1897
1590
  const currentValue = `${currentProvider}:${currentModel}`;
1898
- const items = (0, import_react9.useMemo)(
1591
+ const items = (0, import_react8.useMemo)(
1899
1592
  () => MODELS.map((model) => {
1900
1593
  const value = `${model.provider}:${model.id}`;
1901
1594
  const isCurrent = value === currentValue;
@@ -1911,7 +1604,7 @@ function BossModelSelector({
1911
1604
  0,
1912
1605
  items.findIndex((item) => item.value === currentValue)
1913
1606
  );
1914
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1607
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1915
1608
  BossModelSelectList,
1916
1609
  {
1917
1610
  items,
@@ -1924,7 +1617,7 @@ function BossModelSelector({
1924
1617
 
1925
1618
  // src/boss-tasks-overlay.tsx
1926
1619
  init_esm_shims();
1927
- var import_react10 = __toESM(require_react(), 1);
1620
+ var import_react9 = __toESM(require_react(), 1);
1928
1621
 
1929
1622
  // src/colors.ts
1930
1623
  init_esm_shims();
@@ -1958,7 +1651,7 @@ function projectColor(name) {
1958
1651
  }
1959
1652
 
1960
1653
  // src/boss-tasks-overlay.tsx
1961
- var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
1654
+ var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
1962
1655
  function statusGlyph(status) {
1963
1656
  switch (status) {
1964
1657
  case "done":
@@ -1981,10 +1674,10 @@ function BossTasksOverlay({
1981
1674
  const theme = useTheme();
1982
1675
  const tasksState = useTasksState();
1983
1676
  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) => {
1677
+ const [selectedIndex, setSelectedIndex] = (0, import_react9.useState)(0);
1678
+ const [status, setStatusMsg] = (0, import_react9.useState)("");
1679
+ const statusTimer = (0, import_react9.useRef)(null);
1680
+ const showStatus = (0, import_react9.useCallback)((msg) => {
1988
1681
  setStatusMsg(msg);
1989
1682
  if (statusTimer.current) clearTimeout(statusTimer.current);
1990
1683
  statusTimer.current = setTimeout(() => setStatusMsg(""), 2500);
@@ -1994,7 +1687,7 @@ function BossTasksOverlay({
1994
1687
  tasks: tasks.filter((t) => t.project === w.name).sort((a, b) => a.createdAt.localeCompare(b.createdAt))
1995
1688
  }));
1996
1689
  const flatTasks = groupedTasks.flatMap((g) => g.tasks);
1997
- (0, import_react10.useEffect)(() => {
1690
+ (0, import_react9.useEffect)(() => {
1998
1691
  if (flatTasks.length === 0) {
1999
1692
  setSelectedIndex(0);
2000
1693
  } else if (selectedIndex >= flatTasks.length) {
@@ -2054,11 +1747,11 @@ function BossTasksOverlay({
2054
1747
  const inProgressCount = tasks.filter((t) => t.status === "in_progress").length;
2055
1748
  const pendingCount = tasks.filter((t) => t.status === "pending").length;
2056
1749
  const blockedCount = tasks.filter((t) => t.status === "blocked").length;
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)(
1750
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, paddingX: 1, children: [
1751
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
1752
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: COLORS.primary, bold: true, children: "Tasks" }),
1753
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: ` \xB7 ${tasks.length} total \xB7 ` }),
1754
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2062
1755
  CountsRow,
2063
1756
  {
2064
1757
  theme,
@@ -2069,20 +1762,20 @@ function BossTasksOverlay({
2069
1762
  }
2070
1763
  )
2071
1764
  ] }),
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: [
1765
+ flatTasks.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.textDim, children: [
2073
1766
  " No tasks yet. Ask the boss to plan some \u2014 e.g. ",
2074
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.text, children: '"plan some work"' }),
1767
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.text, children: '"plan some work"' }),
2075
1768
  "."
2076
1769
  ] }) }),
2077
- showingTop && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: ` \u2191 ${startIdx} more above` }),
1770
+ showingTop && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: ` \u2191 ${startIdx} more above` }),
2078
1771
  groupedTasks.map((group, gIdx) => {
2079
1772
  const startInFlat = groupedTasks.slice(0, gIdx).reduce((acc, g) => acc + g.tasks.length, 0);
2080
1773
  const visibleInSection = group.tasks.filter((t) => visibleIdSet.has(t.id));
2081
1774
  if (visibleInSection.length === 0) return null;
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}` })
1775
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
1776
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: projectColor(group.project), bold: true, children: group.project }),
1778
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: ` \xB7 ${group.tasks.length}` })
2086
1779
  ] }),
2087
1780
  visibleInSection.map((task) => {
2088
1781
  const realIdx = startInFlat + group.tasks.indexOf(task);
@@ -2090,7 +1783,7 @@ function BossTasksOverlay({
2090
1783
  const prefix = isSelected ? "\u276F " : " ";
2091
1784
  const glyph = statusGlyph(task.status);
2092
1785
  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: [
1786
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: color2, bold: isSelected, children: [
2094
1787
  prefix,
2095
1788
  "[",
2096
1789
  glyph,
@@ -2100,16 +1793,16 @@ function BossTasksOverlay({
2100
1793
  })
2101
1794
  ] }, group.project);
2102
1795
  }),
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" }),
1796
+ showingBottom && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: ` \u2193 ${flatTasks.length - endIdx} more below` }),
1797
+ status && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.success, children: " " + status }) }),
1798
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.textDim, children: [
1799
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.primary, children: "\u2191\u2193" }),
2107
1800
  " move \xB7 (",
2108
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "d" }),
1801
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.primary, children: "d" }),
2109
1802
  ")elete \xB7 (",
2110
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "r" }),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.primary, children: "r" }),
2111
1804
  ")un pending \xB7 ",
2112
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.primary, children: "ESC" }),
1805
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.primary, children: "ESC" }),
2113
1806
  " close"
2114
1807
  ] }) })
2115
1808
  ] });
@@ -2121,24 +1814,24 @@ function CountsRow({
2121
1814
  pending,
2122
1815
  blocked
2123
1816
  }) {
2124
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
2125
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.success, children: [
1817
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
1818
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.success, children: [
2126
1819
  done,
2127
1820
  " done"
2128
1821
  ] }),
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: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
1823
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.warning, children: [
2131
1824
  active,
2132
1825
  " active"
2133
1826
  ] }),
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: [
1827
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
1828
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.text, children: [
2136
1829
  pending,
2137
1830
  " pending"
2138
1831
  ] }),
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: [
1832
+ blocked > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1833
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
1834
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: theme.error, children: [
2142
1835
  blocked,
2143
1836
  " blocked"
2144
1837
  ] })
@@ -2148,8 +1841,8 @@ function CountsRow({
2148
1841
 
2149
1842
  // src/boss-worker-status-row.tsx
2150
1843
  init_esm_shims();
2151
- var import_react11 = __toESM(require_react(), 1);
2152
- var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
1844
+ var import_react10 = __toESM(require_react(), 1);
1845
+ var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
2153
1846
  var SHIMMER_WIDTH = 3;
2154
1847
  function formatWorkerElapsed(ms) {
2155
1848
  const total = Math.floor(ms / 1e3);
@@ -2168,9 +1861,9 @@ function ShimmerName({
2168
1861
  }) {
2169
1862
  const cycle = name.length + SHIMMER_WIDTH * 2;
2170
1863
  const shimmerPos = tick % cycle - SHIMMER_WIDTH;
2171
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: name.split("").map((ch, i) => {
1864
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: name.split("").map((ch, i) => {
2172
1865
  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);
1866
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: color2, bold: isBright, dimColor: !isBright, children: ch }, i);
2174
1867
  }) });
2175
1868
  }
2176
1869
  function BossWorkerStatusRow({
@@ -2191,9 +1884,9 @@ function BossWorkerStatusRow({
2191
1884
  const projectHue = projectColor(w.name);
2192
1885
  const elapsed = w.workStartedAt ? formatWorkerElapsed(now - w.workStartedAt) : null;
2193
1886
  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: [
1887
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react10.default.Fragment, { children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ShimmerName, { name: w.name, color: projectHue, tick }),
1889
+ elapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.textDim, children: [
2197
1890
  " ",
2198
1891
  elapsed
2199
1892
  ] })
@@ -2202,7 +1895,7 @@ function BossWorkerStatusRow({
2202
1895
  }
2203
1896
  for (const w of errored) {
2204
1897
  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: [
1898
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.default.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.error, children: [
2206
1899
  "\u2717 ",
2207
1900
  w.name
2208
1901
  ] }) }, `e-${w.name}`)
@@ -2210,23 +1903,23 @@ function BossWorkerStatusRow({
2210
1903
  }
2211
1904
  if (idleCount > 0) {
2212
1905
  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: [
1906
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react10.default.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.textDim, children: [
2214
1907
  "\u25CB ",
2215
1908
  idleCount,
2216
1909
  " idle"
2217
1910
  ] }) }, "idle")
2218
1911
  );
2219
1912
  }
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 " }),
1913
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { paddingX: 1, width: columns, flexShrink: 1, children: [
1914
+ anyWorking && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AnimationActiveSentinel, {}),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { wrap: "truncate", children: [
1916
+ slots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react10.default.Fragment, { children: [
1917
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.border, children: " \u2502 " }),
2225
1918
  slot
2226
1919
  ] }, 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: [
1920
+ pendingMessages > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1921
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: theme.textDim, children: " " }),
1922
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: theme.warning, children: [
2230
1923
  pendingMessages,
2231
1924
  " message",
2232
1925
  pendingMessages === 1 ? "" : "s",
@@ -2239,7 +1932,7 @@ function BossWorkerStatusRow({
2239
1932
 
2240
1933
  // src/radio-picker.tsx
2241
1934
  init_esm_shims();
2242
- var import_react12 = __toESM(require_react(), 1);
1935
+ var import_react11 = __toESM(require_react(), 1);
2243
1936
 
2244
1937
  // src/radio.ts
2245
1938
  init_esm_shims();
@@ -2407,7 +2100,7 @@ function buildInstallHint() {
2407
2100
  }
2408
2101
 
2409
2102
  // src/radio-picker.tsx
2410
- var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
2103
+ var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
2411
2104
  function RadioPicker({
2412
2105
  currentStationId: currentStationId2,
2413
2106
  onSelect,
@@ -2429,7 +2122,7 @@ function RadioPicker({
2429
2122
  0,
2430
2123
  items.findIndex((i) => i.value === (currentStationId2 ?? "off"))
2431
2124
  );
2432
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2125
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2433
2126
  SelectList,
2434
2127
  {
2435
2128
  items,
@@ -2442,7 +2135,7 @@ function RadioPicker({
2442
2135
  }
2443
2136
 
2444
2137
  // src/boss-chat-screen.tsx
2445
- var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
2138
+ var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
2446
2139
  function BossChatScreen({
2447
2140
  boss,
2448
2141
  columns,
@@ -2483,12 +2176,12 @@ function BossChatScreen({
2483
2176
  formatDuration
2484
2177
  }) {
2485
2178
  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 }) });
2179
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChatLayout, { columns, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BossTasksOverlay, { boss, workers, onClose: onCloseOverlay }) });
2487
2180
  }
2488
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ChatLayout, { columns, children: [
2181
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(ChatLayout, { columns, children: [
2489
2182
  livePane,
2490
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ChatControls, { controlsRef, children: [
2491
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2183
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(ChatControls, { controlsRef, children: [
2184
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2492
2185
  ChatInputStack,
2493
2186
  {
2494
2187
  columns,
@@ -2496,6 +2189,7 @@ function BossChatScreen({
2496
2189
  statusSlotVisible,
2497
2190
  activityVisible,
2498
2191
  stallStatusVisible,
2192
+ liveToolFeed: [],
2499
2193
  doneStatus,
2500
2194
  activityPhase: state.activityPhase,
2501
2195
  elapsedMs,
@@ -2515,7 +2209,7 @@ function BossChatScreen({
2515
2209
  formatDuration
2516
2210
  }
2517
2211
  ),
2518
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2212
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2519
2213
  InputArea,
2520
2214
  {
2521
2215
  onSubmit,
@@ -2530,7 +2224,7 @@ function BossChatScreen({
2530
2224
  onShiftTab
2531
2225
  }
2532
2226
  ),
2533
- overlay === "model-boss" || overlay === "model-workers" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2227
+ overlay === "model-boss" || overlay === "model-workers" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2534
2228
  BossModelSelector,
2535
2229
  {
2536
2230
  onSelect: onModelSelect,
@@ -2538,15 +2232,15 @@ function BossChatScreen({
2538
2232
  currentModel: overlay === "model-boss" ? state.bossModel : state.workerModel,
2539
2233
  currentProvider: overlay === "model-boss" ? state.bossProvider : state.workerProvider
2540
2234
  }
2541
- ) : overlay === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2235
+ ) : overlay === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2542
2236
  RadioPicker,
2543
2237
  {
2544
2238
  currentStationId: currentRadio,
2545
2239
  onCancel: onCloseOverlay,
2546
2240
  onSelect: onRadioSelect
2547
2241
  }
2548
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2549
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2242
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2243
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2550
2244
  BossFooter,
2551
2245
  {
2552
2246
  bossModel,
@@ -2559,7 +2253,7 @@ function BossChatScreen({
2559
2253
  scope: state.scope
2560
2254
  }
2561
2255
  ),
2562
- !state.exitPending && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BossWorkerStatusRow, { workers, pendingMessages })
2256
+ !state.exitPending && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BossWorkerStatusRow, { workers, pendingMessages })
2563
2257
  ] })
2564
2258
  ] })
2565
2259
  ] });
@@ -2636,7 +2330,7 @@ function buildHelpText() {
2636
2330
 
2637
2331
  // src/boss-transcript-rows.tsx
2638
2332
  init_esm_shims();
2639
- var import_react14 = __toESM(require_react(), 1);
2333
+ var import_react13 = __toESM(require_react(), 1);
2640
2334
 
2641
2335
  // src/boss-spacing.ts
2642
2336
  init_esm_shims();
@@ -2752,7 +2446,7 @@ var bossToolFormatters = {
2752
2446
  };
2753
2447
 
2754
2448
  // src/boss-transcript-rows.tsx
2755
- var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
2449
+ var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
2756
2450
  function getBossTranscriptMarginTop({
2757
2451
  row,
2758
2452
  previousRow
@@ -2771,26 +2465,26 @@ function BossTranscriptRow({
2771
2465
  previousRow
2772
2466
  }) {
2773
2467
  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 }) });
2468
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BossBanner, { subtitle: "Orchestrator", showShortcuts: true }) });
2775
2469
  }
2776
2470
  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 }));
2471
+ const renderWithSpacing = (node) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TranscriptItemFrame, { marginTop, children: node });
2472
+ if (row.kind === "user") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(UserMessage, { text: row.text }));
2473
+ if (row.kind === "assistant") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AssistantRow, { item: row }));
2474
+ if (row.kind === "tool_start") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolStartHistoryRow, { item: row }));
2475
+ if (row.kind === "tool_done") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolHistoryRow, { item: row }));
2476
+ if (row.kind === "tool_group") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolGroupRow, { item: row }));
2477
+ if (row.kind === "worker_event") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WorkerEventRow, { item: row }));
2478
+ if (row.kind === "worker_error") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WorkerErrorRow, { item: row }));
2785
2479
  if (row.kind === "info") {
2786
- return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(InfoRow, { text: row.text, level: row.level ?? "info" }));
2480
+ return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InfoRow, { text: row.text, level: row.level ?? "info" }));
2787
2481
  }
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 }));
2482
+ if (row.kind === "task_dispatch") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TaskDispatchRow, { tasks: row.tasks }));
2483
+ if (row.kind === "update_notice") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(UpdateNoticeRow, { text: row.text }));
2484
+ if (row.kind === "compacting") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactionSpinner, { staticDisplay: true }));
2791
2485
  if (row.kind === "compacted") {
2792
2486
  return renderWithSpacing(
2793
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2487
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2794
2488
  CompactionDone,
2795
2489
  {
2796
2490
  originalCount: row.originalCount,
@@ -2801,13 +2495,13 @@ function BossTranscriptRow({
2801
2495
  )
2802
2496
  );
2803
2497
  }
2804
- if (row.kind === "stopped") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(InfoRow, { text: row.text, level: "warning" }));
2498
+ if (row.kind === "stopped") return renderWithSpacing(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InfoRow, { text: row.text, level: "warning" }));
2805
2499
  return null;
2806
2500
  }
2807
2501
  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 })
2502
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexShrink: 1, borderStyle: "round", borderColor: COLORS.accent, paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { wrap: "wrap", children: [
2503
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: COLORS.accent, bold: true, children: "\u2728 " }),
2504
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: COLORS.primary, bold: true, children: text })
2811
2505
  ] }) });
2812
2506
  }
2813
2507
  function TaskDispatchRow({
@@ -2815,10 +2509,10 @@ function TaskDispatchRow({
2815
2509
  }) {
2816
2510
  const theme = useTheme();
2817
2511
  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: [
2512
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, children: [
2513
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { children: [
2514
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: COLORS.primary, bold: true, children: "\u23FA " }),
2515
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { color: theme.text, bold: true, children: [
2822
2516
  "Running ",
2823
2517
  count,
2824
2518
  " task",
@@ -2826,11 +2520,11 @@ function TaskDispatchRow({
2826
2520
  ":"
2827
2521
  ] })
2828
2522
  ] }),
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 })
2523
+ tasks.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { children: [
2524
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.textDim, children: " \u2022 " }),
2525
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: projectColor(t.project), bold: true, children: t.project }),
2526
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.textDim, children: ": " }),
2527
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.text, children: t.title })
2834
2528
  ] }, `${t.project}-${i}`))
2835
2529
  ] });
2836
2530
  }
@@ -2857,12 +2551,12 @@ function highlightShortcuts(text) {
2857
2551
  );
2858
2552
  }
2859
2553
  function AssistantRow({ item }) {
2860
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AssistantMessage, { text: highlightShortcuts(item.text), renderMarkdown: true });
2554
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AssistantMessage, { text: highlightShortcuts(item.text), renderMarkdown: true });
2861
2555
  }
2862
2556
  function ToolStartHistoryRow({
2863
2557
  item
2864
2558
  }) {
2865
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2559
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2866
2560
  ToolExecution,
2867
2561
  {
2868
2562
  status: "running",
@@ -2873,10 +2567,10 @@ function ToolStartHistoryRow({
2873
2567
  );
2874
2568
  }
2875
2569
  function ToolGroupRow({ item }) {
2876
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ToolGroupExecution, { tools: item.tools, summaryRenderers: bossToolGroupRenderers });
2570
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolGroupExecution, { tools: item.tools, summaryRenderers: bossToolGroupRenderers });
2877
2571
  }
2878
2572
  function ToolHistoryRow({ item }) {
2879
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2573
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2880
2574
  ToolExecution,
2881
2575
  {
2882
2576
  status: "done",
@@ -2918,41 +2612,41 @@ function WorkerEventRow({ item }) {
2918
2612
  const grade = parseStatusGrade(item.finalText);
2919
2613
  const loaderStatus = grade === "BLOCKED" || failedCount > 0 ? "error" : grade === "UNVERIFIED" || grade === "PARTIAL" ? "queued" : "done";
2920
2614
  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 })
2615
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "row", children: [
2616
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolUseLoader, { status: loaderStatus }),
2617
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { wrap: "wrap", children: [
2618
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: headerColor, bold: true, children: item.project }),
2619
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.text, children: ` turn ${item.turnIndex}` }),
2620
+ grade && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2621
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.textDim, children: " \xB7 " }),
2622
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: statusGradeColor(grade, theme), bold: true, children: grade })
2929
2623
  ] })
2930
2624
  ] }) })
2931
2625
  ] });
2932
2626
  }
2933
2627
  function WorkerErrorRow({ item }) {
2934
2628
  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" })
2629
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
2630
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "row", children: [
2631
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolUseLoader, { status: "error" }),
2632
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { wrap: "wrap", children: [
2633
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.toolError, bold: true, children: item.project }),
2634
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.textDim, children: " worker error" })
2941
2635
  ] }) })
2942
2636
  ] }),
2943
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.error, wrap: "wrap", children: item.message }) })
2637
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: theme.error, wrap: "wrap", children: item.message }) })
2944
2638
  ] });
2945
2639
  }
2946
2640
  function InfoRow({
2947
2641
  text,
2948
2642
  level
2949
2643
  }) {
2950
- if (level === "info") return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AssistantMessage, { text });
2644
+ if (level === "info") return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AssistantMessage, { text });
2951
2645
  const theme = useTheme();
2952
2646
  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 }) })
2647
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "row", children: [
2648
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ToolUseLoader, { status: level === "error" ? "error" : "queued" }),
2649
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexGrow: 1, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: color2, wrap: "wrap", children: text }) })
2956
2650
  ] });
2957
2651
  }
2958
2652
  function BossStreamingTurnView({
@@ -2979,11 +2673,11 @@ function BossStreamingTurnView({
2979
2673
  spacingKinds: BOSS_SPACING_KINDS,
2980
2674
  compactBoundaries: BOSS_COMPACT_BOUNDARIES
2981
2675
  }) ? 1 : 0;
2982
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2676
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2983
2677
  ChatLivePane,
2984
2678
  {
2985
2679
  liveItems: visibleLiveItems,
2986
- renderItem: (_item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2680
+ renderItem: (_item, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2987
2681
  BossTranscriptRow,
2988
2682
  {
2989
2683
  row: visibleLiveItems[index],
@@ -3305,176 +2999,23 @@ function renderRoundNoticeBox(lines, context, borderColor) {
3305
2999
 
3306
3000
  // src/auto-update.ts
3307
3001
  init_esm_shims();
3308
- import { spawn as spawn2 } from "child_process";
3309
- import fs4 from "fs";
3310
3002
  import path4 from "path";
3311
3003
  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
- }
3342
- return 0;
3343
- }
3344
- function detectInstallInfo() {
3345
- const scriptPath = (process.argv[1] ?? "").replace(/\\/g, "/");
3346
- if (scriptPath.includes("/_npx/")) {
3347
- return { packageManager: "unknown" /* UNKNOWN */, updateCommand: null };
3348
- }
3349
- if (scriptPath.includes("/.pnpm") || scriptPath.includes("/pnpm/global")) {
3350
- return {
3351
- packageManager: "pnpm" /* PNPM */,
3352
- updateCommand: `pnpm add -g ${PACKAGE_NAME}@latest`
3353
- };
3354
- }
3355
- if (scriptPath.includes("/.yarn/") || scriptPath.includes("/yarn/global")) {
3356
- return {
3357
- packageManager: "yarn" /* YARN */,
3358
- updateCommand: `yarn global add ${PACKAGE_NAME}@latest`
3359
- };
3360
- }
3361
- return {
3362
- packageManager: "npm" /* NPM */,
3363
- updateCommand: `npm install -g ${PACKAGE_NAME}@latest`
3364
- };
3365
- }
3366
- async function fetchLatestVersion() {
3367
- try {
3368
- const controller = new AbortController();
3369
- const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
3370
- const response = await fetch(REGISTRY_URL, { signal: controller.signal });
3371
- clearTimeout(timeout);
3372
- const data = await response.json();
3373
- const version = data.version?.trim();
3374
- return version && /^\d+\.\d+\.\d+/.test(version) ? version : null;
3375
- } catch {
3376
- return null;
3377
- }
3378
- }
3379
- function performUpdateInBackground(command) {
3380
- try {
3381
- const parts = command.split(" ");
3382
- const child = spawn2(parts[0], parts.slice(1), {
3383
- detached: true,
3384
- stdio: "ignore",
3385
- env: { ...process.env, npm_config_loglevel: "silent" }
3386
- });
3387
- child.unref();
3388
- } catch {
3389
- }
3390
- }
3391
- function checkAndAutoUpdate(currentVersion) {
3392
- try {
3393
- const state = readState();
3394
- let message = null;
3395
- if (state?.updatePending && state.latestVersion) {
3396
- if (compareVersions(state.latestVersion, currentVersion) > 0) {
3397
- const info = detectInstallInfo();
3398
- if (info.updateCommand) {
3399
- performUpdateInBackground(info.updateCommand);
3400
- message = `Ken just shipped ${state.latestVersion}! Installing in the background \u2014 takes effect next launch.`;
3401
- writeState({
3402
- ...state,
3403
- lastCheckedAt: Date.now(),
3404
- updatePending: false,
3405
- lastUpdateAttempt: Date.now()
3406
- });
3407
- }
3408
- } else {
3409
- writeState({ ...state, updatePending: false });
3410
- }
3411
- }
3412
- const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;
3413
- if (shouldCheck) scheduleBackgroundCheck(currentVersion);
3414
- return message;
3415
- } catch {
3416
- return null;
3417
- }
3418
- }
3419
- function getPendingUpdate(currentVersion) {
3420
- try {
3421
- const state = readState();
3422
- if (!state?.latestVersion) return null;
3423
- if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;
3424
- return { latestVersion: state.latestVersion };
3425
- } catch {
3426
- return null;
3427
- }
3428
- }
3429
- function scheduleBackgroundCheck(currentVersion) {
3430
- fetchLatestVersion().then((latestVersion) => {
3431
- const newState = {
3432
- lastCheckedAt: Date.now(),
3433
- latestVersion: latestVersion ?? void 0,
3434
- updatePending: false
3435
- };
3436
- if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
3437
- newState.updatePending = true;
3438
- }
3439
- writeState(newState);
3440
- }).catch(() => {
3441
- });
3442
- }
3443
- var periodicTimer = null;
3444
- function startPeriodicUpdateCheck(currentVersion, onUpdate) {
3445
- if (periodicTimer) return;
3446
- periodicTimer = setInterval(() => {
3447
- fetchLatestVersion().then((latestVersion) => {
3448
- if (!latestVersion) return;
3449
- if (compareVersions(latestVersion, currentVersion) <= 0) return;
3450
- const info = detectInstallInfo();
3451
- if (!info.updateCommand) return;
3452
- writeState({
3453
- lastCheckedAt: Date.now(),
3454
- latestVersion,
3455
- updatePending: true
3456
- });
3457
- onUpdate(
3458
- `Ken just pushed a fresh update \u2014 ${currentVersion} \u2192 ${latestVersion}! Restart ggboss to grab it (or run ${info.updateCommand} if you can't wait).`
3459
- );
3460
- stopPeriodicUpdateCheck();
3461
- }).catch(() => {
3462
- });
3463
- }, CHECK_INTERVAL_MS);
3464
- periodicTimer.unref();
3465
- }
3466
- function stopPeriodicUpdateCheck() {
3467
- if (periodicTimer) {
3468
- clearInterval(periodicTimer);
3469
- periodicTimer = null;
3470
- }
3471
- }
3004
+ var updater = createAutoUpdater({
3005
+ packageName: "@kenkaiiii/gg-boss",
3006
+ stateFilePath: () => path4.join(os2.homedir(), ".gg", "boss", "update-state.json"),
3007
+ periodicMessage: ({ currentVersion, latestVersion, updateCommand }) => `Ken just pushed a fresh update \u2014 ${currentVersion} \u2192 ${latestVersion}! Restart ggboss to grab it (or run ${updateCommand} if you can't wait).`
3008
+ });
3009
+ var checkAndAutoUpdate = updater.checkAndAutoUpdate;
3010
+ var getPendingUpdate = updater.getPendingUpdate;
3011
+ var startPeriodicUpdateCheck = updater.startPeriodicUpdateCheck;
3012
+ var stopPeriodicUpdateCheck = updater.stopPeriodicUpdateCheck;
3472
3013
 
3473
3014
  // src/orchestrator-app.tsx
3474
- var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
3015
+ var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
3475
3016
  function BossApp(props) {
3476
3017
  const theme = loadTheme("dark");
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 }) }) }) });
3018
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TerminalSizeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AnimationProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(BossAppInner, { ...props }) }) }) });
3478
3019
  }
3479
3020
  function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3480
3021
  const state = useBossState();
@@ -3482,19 +3023,19 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3482
3023
  const { exit } = use_app_default();
3483
3024
  const { stdout, write: writeStdout } = use_stdout_default();
3484
3025
  const { columns, rows } = useTerminalSize();
3485
- const runStartRef = (0, import_react15.useRef)(null);
3026
+ const runStartRef = (0, import_react14.useRef)(null);
3486
3027
  runStartRef.current = state.runStartMs;
3487
- const charCountRef = (0, import_react15.useRef)(0);
3028
+ const charCountRef = (0, import_react14.useRef)(0);
3488
3029
  charCountRef.current = state.streaming?.text.length ?? 0;
3489
- const realTokensAccumRef = (0, import_react15.useRef)(0);
3030
+ const realTokensAccumRef = (0, import_react14.useRef)(0);
3490
3031
  realTokensAccumRef.current = state.bossInputTokens;
3491
- const [lastUserMessage, setLastUserMessage] = (0, import_react15.useState)("");
3032
+ const [lastUserMessage, setLastUserMessage] = (0, import_react14.useState)("");
3492
3033
  const overlay = state.overlay;
3493
- const [currentRadio, setCurrentRadio] = (0, import_react15.useState)(() => getCurrentStation());
3494
- const [updatePending, setUpdatePending] = (0, import_react15.useState)(
3034
+ const [currentRadio, setCurrentRadio] = (0, import_react14.useState)(() => getCurrentStation());
3035
+ const [updatePending, setUpdatePending] = (0, import_react14.useState)(
3495
3036
  () => getPendingUpdate(VERSION) !== null
3496
3037
  );
3497
- (0, import_react15.useEffect)(() => {
3038
+ (0, import_react14.useEffect)(() => {
3498
3039
  startPeriodicUpdateCheck(VERSION, (msg) => {
3499
3040
  bossStore.appendUpdateNotice(msg);
3500
3041
  setUpdatePending(true);
@@ -3502,8 +3043,8 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3502
3043
  return () => stopPeriodicUpdateCheck();
3503
3044
  }, []);
3504
3045
  const workersRunning = state.workers.filter((w) => w.status === "working").length;
3505
- const titlePrevRef = (0, import_react15.useRef)("");
3506
- (0, import_react15.useEffect)(() => {
3046
+ const titlePrevRef = (0, import_react14.useRef)("");
3047
+ (0, import_react14.useEffect)(() => {
3507
3048
  if (!stdout) return;
3508
3049
  let title;
3509
3050
  if (workersRunning > 0) {
@@ -3519,13 +3060,13 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3519
3060
  stdout.write(`\x1B]0;${title}\x1B\\`);
3520
3061
  }
3521
3062
  }, [stdout, workersRunning, state.phase]);
3522
- (0, import_react15.useEffect)(() => {
3063
+ (0, import_react14.useEffect)(() => {
3523
3064
  return () => {
3524
3065
  stdout?.write(`\x1B]0;GG Boss\x1B\\`);
3525
3066
  };
3526
3067
  }, [stdout]);
3527
3068
  const liveItems = state.liveItems;
3528
- const terminalHistoryPrinterRef = (0, import_react15.useRef)(
3069
+ const terminalHistoryPrinterRef = (0, import_react14.useRef)(
3529
3070
  terminalHistoryPrinter ?? createBossTerminalHistoryPrinter({ stream: stdout })
3530
3071
  );
3531
3072
  const terminalHistoryContext = {
@@ -3536,21 +3077,21 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3536
3077
  provider: state.bossProvider,
3537
3078
  cwd: process.cwd()
3538
3079
  };
3539
- const printedHistoryIdsRef = (0, import_react15.useRef)(/* @__PURE__ */ new Set());
3540
- (0, import_react15.useEffect)(() => {
3080
+ const printedHistoryIdsRef = (0, import_react14.useRef)(/* @__PURE__ */ new Set());
3081
+ (0, import_react14.useEffect)(() => {
3541
3082
  const printer = terminalHistoryPrinterRef.current;
3542
3083
  const pending = state.history.filter((item) => !printedHistoryIdsRef.current.has(item.id));
3543
3084
  if (pending.length === 0) return;
3544
3085
  printer.print(pending, terminalHistoryContext, { write: writeStdout });
3545
3086
  for (const item of pending) printedHistoryIdsRef.current.add(item.id);
3546
3087
  }, [columns, state.bossModel, state.bossProvider, state.history, theme, writeStdout]);
3547
- const overlayResetTimerRef = (0, import_react15.useRef)(null);
3548
- (0, import_react15.useEffect)(() => {
3088
+ const overlayResetTimerRef = (0, import_react14.useRef)(null);
3089
+ (0, import_react14.useEffect)(() => {
3549
3090
  return () => {
3550
3091
  if (overlayResetTimerRef.current) clearTimeout(overlayResetTimerRef.current);
3551
3092
  };
3552
3093
  }, []);
3553
- const scheduleOverlayReset = (0, import_react15.useCallback)(() => {
3094
+ const scheduleOverlayReset = (0, import_react14.useCallback)(() => {
3554
3095
  if (!resetUI) return;
3555
3096
  if (overlayResetTimerRef.current) clearTimeout(overlayResetTimerRef.current);
3556
3097
  overlayResetTimerRef.current = setTimeout(() => {
@@ -3558,14 +3099,14 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3558
3099
  resetUI();
3559
3100
  }, 0);
3560
3101
  }, [resetUI]);
3561
- const openOverlay = (0, import_react15.useCallback)(
3102
+ const openOverlay = (0, import_react14.useCallback)(
3562
3103
  (next) => {
3563
3104
  bossStore.setOverlay(next);
3564
3105
  scheduleOverlayReset();
3565
3106
  },
3566
3107
  [scheduleOverlayReset]
3567
3108
  );
3568
- const closeOverlay = (0, import_react15.useCallback)(() => {
3109
+ const closeOverlay = (0, import_react14.useCallback)(() => {
3569
3110
  bossStore.setOverlay(null);
3570
3111
  scheduleOverlayReset();
3571
3112
  }, [scheduleOverlayReset]);
@@ -3574,12 +3115,12 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3574
3115
  (pending) => bossStore.setExitPending(pending),
3575
3116
  () => exit()
3576
3117
  );
3577
- (0, import_react15.useEffect)(() => {
3118
+ (0, import_react14.useEffect)(() => {
3578
3119
  if (state.pendingFlush.length > 0) {
3579
3120
  bossStore.commitPendingFlush();
3580
3121
  }
3581
3122
  }, [state.flushGeneration, state.pendingFlush.length]);
3582
- const handleAbort = (0, import_react15.useCallback)(() => {
3123
+ const handleAbort = (0, import_react14.useCallback)(() => {
3583
3124
  if (state.phase === "working") {
3584
3125
  boss.abort();
3585
3126
  return;
@@ -3674,14 +3215,14 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3674
3215
  const controlsRows = 7 + (statusSlotVisible ? 1 : 0) + (state.exitPending ? 0 : 1);
3675
3216
  const availableLiveRows = Math.max(1, rows - controlsRows);
3676
3217
  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}).` })
3218
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Box_default, { flexDirection: "column", width: columns, paddingX: 1, marginTop: 1, children: [
3219
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { bold: true, color: COLORS.accent, children: "Terminal too small" }),
3220
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: COLORS.primary, children: `Resize to at least 14 rows to use GG Boss (currently ${rows}).` })
3680
3221
  ] });
3681
3222
  }
3682
3223
  const lastPendingHistoryItem = state.pendingFlush[state.pendingFlush.length - 1];
3683
3224
  const lastHistoryItem = state.history[state.history.length - 1];
3684
- const livePane = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3225
+ const livePane = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3685
3226
  BossStreamingTurnView,
3686
3227
  {
3687
3228
  turn: state.streaming,
@@ -3692,7 +3233,7 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3692
3233
  availableTerminalHeight: availableLiveRows
3693
3234
  }
3694
3235
  );
3695
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3236
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3696
3237
  BossChatScreen,
3697
3238
  {
3698
3239
  boss,
@@ -3725,7 +3266,7 @@ function BossAppInner({ boss, resetUI, terminalHistoryPrinter }) {
3725
3266
  void boss.setBossThinking(next);
3726
3267
  },
3727
3268
  commands: BOSS_SLASH_COMMANDS,
3728
- scopeBadge: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ScopePill, { scope: state.scope }),
3269
+ scopeBadge: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ScopePill, { scope: state.scope }),
3729
3270
  onCloseOverlay: closeOverlay,
3730
3271
  onModelSelect: handleModelSelect,
3731
3272
  currentRadio,
@@ -3762,12 +3303,12 @@ function ScopePill({ scope }) {
3762
3303
  const isAll = scope === "all";
3763
3304
  const bg = isAll ? COLORS.accent : projectColor(scope);
3764
3305
  const label = isAll ? "All" : scope;
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: [
3306
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { children: [
3307
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.textDim, children: "Project " }),
3308
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: "black", backgroundColor: bg, bold: true, children: ` ${label} ` }),
3309
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { color: theme.textDim, children: [
3769
3310
  " ",
3770
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: theme.primary, children: "Tab" }),
3311
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Text, { color: theme.primary, children: "Tab" }),
3771
3312
  " to switch"
3772
3313
  ] })
3773
3314
  ] });
@@ -3831,7 +3372,7 @@ function renderBossApp(opts) {
3831
3372
  process.stdout.write(VIEWPORT_CLEAR);
3832
3373
  }
3833
3374
  ref.instance = render_default(
3834
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
3375
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3835
3376
  BossApp,
3836
3377
  {
3837
3378
  boss: opts.boss,
@@ -3843,7 +3384,7 @@ function renderBossApp(opts) {
3843
3384
  );
3844
3385
  };
3845
3386
  const instance = render_default(
3846
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(BossApp, { boss: opts.boss, resetUI, terminalHistoryPrinter }),
3387
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(BossApp, { boss: opts.boss, resetUI, terminalHistoryPrinter }),
3847
3388
  INK_OPTIONS
3848
3389
  );
3849
3390
  ref.instance = instance;
@@ -3904,8 +3445,8 @@ function renderBossApp(opts) {
3904
3445
 
3905
3446
  // src/splash.tsx
3906
3447
  init_esm_shims();
3907
- var import_react16 = __toESM(require_react(), 1);
3908
- var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
3448
+ var import_react15 = __toESM(require_react(), 1);
3449
+ var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
3909
3450
  var SPLASH_LINES = [
3910
3451
  " \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 ",
3911
3452
  " \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 ",
@@ -3923,7 +3464,7 @@ function colorForLine(lineIdx, totalLines, offset) {
3923
3464
  return GRADIENT[idx];
3924
3465
  }
3925
3466
  function SplashLogo({ offset }) {
3926
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Box_default, { flexDirection: "column", children: SPLASH_LINES.map((line, i) => {
3467
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { flexDirection: "column", children: SPLASH_LINES.map((line, i) => {
3927
3468
  const hue = colorForLine(i, SPLASH_LINES.length, offset);
3928
3469
  const segments = [];
3929
3470
  let buf = "";
@@ -3944,12 +3485,12 @@ function SplashLogo({ offset }) {
3944
3485
  }
3945
3486
  }
3946
3487
  if (buf) segments.push({ text: buf, dim: bufDim });
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);
3488
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: segments.map((seg, j) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: hue, dimColor: seg.dim, children: seg.text }, j)) }, i);
3948
3489
  }) });
3949
3490
  }
3950
3491
  function SplashScreen({ caption }) {
3951
- const [offset, setOffset] = (0, import_react16.useState)(0);
3952
- (0, import_react16.useEffect)(() => {
3492
+ const [offset, setOffset] = (0, import_react15.useState)(0);
3493
+ (0, import_react15.useEffect)(() => {
3953
3494
  const timer = setInterval(() => {
3954
3495
  setOffset((o) => o + 1);
3955
3496
  }, 120);
@@ -3957,11 +3498,11 @@ function SplashScreen({ caption }) {
3957
3498
  clearInterval(timer);
3958
3499
  };
3959
3500
  }, []);
3960
- const [size, setSize] = (0, import_react16.useState)(() => ({
3501
+ const [size, setSize] = (0, import_react15.useState)(() => ({
3961
3502
  columns: process.stdout.columns ?? 80,
3962
3503
  rows: process.stdout.rows ?? 24
3963
3504
  }));
3964
- (0, import_react16.useEffect)(() => {
3505
+ (0, import_react15.useEffect)(() => {
3965
3506
  const handler = () => setSize({
3966
3507
  columns: process.stdout.columns ?? 80,
3967
3508
  rows: process.stdout.rows ?? 24
@@ -3973,27 +3514,27 @@ function SplashScreen({ caption }) {
3973
3514
  }, []);
3974
3515
  const SPLASH_BLOCK_HEIGHT = SPLASH_LINES.length + 3;
3975
3516
  const verticalPad = Math.max(0, Math.floor((size.rows - SPLASH_BLOCK_HEIGHT) / 2));
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: [
3517
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", width: size.columns, height: size.rows, alignItems: "center", children: [
3518
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { height: verticalPad, flexShrink: 0 }),
3519
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", alignItems: "flex-start", flexShrink: 0, children: [
3520
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SplashLogo, { offset }),
3521
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { width: SPLASH_WIDTH, marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Text, { children: [
3522
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: COLORS.text, bold: true, children: BRAND }),
3523
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Text, { color: COLORS.textDim, children: [
3983
3524
  " v",
3984
3525
  VERSION
3985
3526
  ] }),
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 })
3527
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: COLORS.textDim, children: " \xB7 By " }),
3528
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: COLORS.text, bold: true, children: AUTHOR })
3988
3529
  ] }) }),
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" }) })
3530
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { width: SPLASH_WIDTH, justifyContent: "center", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: COLORS.textDim, children: caption ?? "Spinning up the orchestrator\u2026" }) })
3990
3531
  ] })
3991
3532
  ] });
3992
3533
  }
3993
3534
  function showSplash(opts) {
3994
3535
  const start = Date.now();
3995
3536
  void playSplashAudio();
3996
- const instance = render_default(/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SplashScreen, { caption: opts.caption }));
3537
+ const instance = render_default(/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SplashScreen, { caption: opts.caption }));
3997
3538
  const audioDurationMs = getSplashAudioDurationMs();
3998
3539
  const defaultMinMs = audioDurationMs + 200;
3999
3540
  return {
@@ -4092,10 +3633,12 @@ async function runServeSubcommand(argv) {
4092
3633
  process.exit(1);
4093
3634
  }
4094
3635
  const settings = await loadSettings();
4095
- const bossProvider = settings.bossProvider ?? "anthropic";
4096
- const bossModel = cliBossModel ?? settings.bossModel ?? "claude-opus-4-8";
4097
- const workerProvider = settings.workerProvider ?? "anthropic";
4098
- const workerModel = cliWorkerModel ?? settings.workerModel ?? "claude-sonnet-4-6";
3636
+ const { bossProvider, bossModel, workerProvider, workerModel } = await resolveBossAuth({
3637
+ bossProvider: settings.bossProvider ?? "anthropic",
3638
+ bossModel: cliBossModel ?? settings.bossModel ?? "claude-opus-4-8",
3639
+ workerProvider: settings.workerProvider ?? "anthropic",
3640
+ workerModel: cliWorkerModel ?? settings.workerModel ?? "claude-sonnet-4-6"
3641
+ });
4099
3642
  await runBossServeMode({
4100
3643
  bossProvider,
4101
3644
  bossModel,
@@ -4105,6 +3648,45 @@ async function runServeSubcommand(argv) {
4105
3648
  telegram: { botToken, userId }
4106
3649
  });
4107
3650
  }
3651
+ var ALL_PROVIDERS = [
3652
+ "anthropic",
3653
+ "openai",
3654
+ "xiaomi",
3655
+ "gemini",
3656
+ "glm",
3657
+ "moonshot",
3658
+ "minimax",
3659
+ "deepseek",
3660
+ "openrouter"
3661
+ ];
3662
+ function bossDefaultModel(provider) {
3663
+ return provider === "anthropic" ? "claude-opus-4-8" : getDefaultModel(provider).id;
3664
+ }
3665
+ async function resolveBossAuth(input) {
3666
+ const auth = new AuthStorage();
3667
+ await auth.load();
3668
+ const stored = await auth.listProviders();
3669
+ const loggedIn = ALL_PROVIDERS.filter((p) => stored.includes(p));
3670
+ if (loggedIn.length === 0) {
3671
+ throw new Error('Not logged in to any provider. Run "ggcoder login" to authenticate.');
3672
+ }
3673
+ const fallback = loggedIn[0];
3674
+ const resolve = (preferredProvider, preferredModel, defaultFor) => {
3675
+ const provider = loggedIn.includes(preferredProvider) ? preferredProvider : fallback;
3676
+ const modelFits = getModel(preferredModel)?.provider === provider;
3677
+ return { provider, model: modelFits ? preferredModel : defaultFor(provider) };
3678
+ };
3679
+ const boss = resolve(input.bossProvider, input.bossModel, bossDefaultModel);
3680
+ const worker = resolve(input.workerProvider, input.workerModel, (p) => getDefaultModel(p).id);
3681
+ const fellBack = boss.provider !== input.bossProvider || worker.provider !== input.workerProvider;
3682
+ return {
3683
+ bossProvider: boss.provider,
3684
+ bossModel: boss.model,
3685
+ workerProvider: worker.provider,
3686
+ workerModel: worker.model,
3687
+ fellBack
3688
+ };
3689
+ }
4108
3690
  async function runOrchestrator(args) {
4109
3691
  if (args.projects.length === 0) {
4110
3692
  const links = await loadLinks();
@@ -4121,10 +3703,30 @@ async function runOrchestrator(args) {
4121
3703
  caption: `Spinning up ${args.projects.length} worker${args.projects.length === 1 ? "" : "s"}\u2026`
4122
3704
  });
4123
3705
  const settings = await loadSettings();
4124
- const finalBossProvider = args.bossProvider ?? settings.bossProvider ?? "anthropic";
4125
- const finalBossModel = args.bossModel ?? settings.bossModel ?? "claude-opus-4-8";
4126
- const finalWorkerProvider = args.workerProvider ?? settings.workerProvider ?? "anthropic";
4127
- const finalWorkerModel = args.workerModel ?? settings.workerModel ?? "claude-sonnet-4-6";
3706
+ const preferredBossProvider = args.bossProvider ?? settings.bossProvider ?? "anthropic";
3707
+ const preferredBossModel = args.bossModel ?? settings.bossModel ?? "claude-opus-4-8";
3708
+ const preferredWorkerProvider = args.workerProvider ?? settings.workerProvider ?? "anthropic";
3709
+ const preferredWorkerModel = args.workerModel ?? settings.workerModel ?? "claude-sonnet-4-6";
3710
+ const {
3711
+ bossProvider: finalBossProvider,
3712
+ bossModel: finalBossModel,
3713
+ workerProvider: finalWorkerProvider,
3714
+ workerModel: finalWorkerModel,
3715
+ fellBack
3716
+ } = await resolveBossAuth({
3717
+ bossProvider: preferredBossProvider,
3718
+ bossModel: preferredBossModel,
3719
+ workerProvider: preferredWorkerProvider,
3720
+ workerModel: preferredWorkerModel
3721
+ });
3722
+ if (fellBack) {
3723
+ log("INFO", "cli", "provider fallback", {
3724
+ preferredBoss: preferredBossProvider,
3725
+ boss: finalBossProvider,
3726
+ preferredWorker: preferredWorkerProvider,
3727
+ worker: finalWorkerProvider
3728
+ });
3729
+ }
4128
3730
  initLogger({
4129
3731
  version: VERSION,
4130
3732
  bossProvider: finalBossProvider,