aemeathcli 1.0.10 → 1.0.12

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.
Files changed (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -54
  3. package/dist/App-JQ622M66.js +4431 -0
  4. package/dist/App-JQ622M66.js.map +1 -0
  5. package/dist/agent-store/architect.md +32 -0
  6. package/dist/agent-store/debugger.md +32 -0
  7. package/dist/agent-store/developer.md +29 -0
  8. package/dist/agent-store/documenter.md +30 -0
  9. package/dist/agent-store/researcher.md +31 -0
  10. package/dist/agent-store/reviewer.md +28 -0
  11. package/dist/agent-store/supervisor.md +37 -0
  12. package/dist/agent-store/tester.md +30 -0
  13. package/dist/api-key-fallback-RJLPM3KH.js +11 -0
  14. package/dist/{api-key-fallback-YQQBOQIL.js.map → api-key-fallback-RJLPM3KH.js.map} +1 -1
  15. package/dist/auth-status-JQJOKUPF.js +13 -0
  16. package/dist/auth-status-JQJOKUPF.js.map +1 -0
  17. package/dist/{chunk-RWCNNAL7.js → chunk-2KMA5RBC.js} +25 -48
  18. package/dist/chunk-2KMA5RBC.js.map +1 -0
  19. package/dist/{chunk-CYQNBB25.js → chunk-2Y7TR6BS.js} +28 -5
  20. package/dist/chunk-2Y7TR6BS.js.map +1 -0
  21. package/dist/{chunk-DAHGLHNR.js → chunk-2ZYK5IJG.js} +6 -141
  22. package/dist/chunk-2ZYK5IJG.js.map +1 -0
  23. package/dist/chunk-36RXCZOV.js +88 -0
  24. package/dist/chunk-36RXCZOV.js.map +1 -0
  25. package/dist/{chunk-DMBPX3RG.js → chunk-7EBLXPL4.js} +9 -9
  26. package/dist/{chunk-DMBPX3RG.js.map → chunk-7EBLXPL4.js.map} +1 -1
  27. package/dist/chunk-BIMQL4AG.js +186 -0
  28. package/dist/chunk-BIMQL4AG.js.map +1 -0
  29. package/dist/{chunk-NBR3GHMT.js → chunk-D275MCIH.js} +39 -7
  30. package/dist/chunk-D275MCIH.js.map +1 -0
  31. package/dist/{chunk-Y5XVD2CD.js → chunk-FFS4T7BZ.js} +109 -82
  32. package/dist/chunk-FFS4T7BZ.js.map +1 -0
  33. package/dist/{chunk-CARHU3DO.js → chunk-GXAJGP2T.js} +64 -16
  34. package/dist/chunk-GXAJGP2T.js.map +1 -0
  35. package/dist/{chunk-I5PZ4JTS.js → chunk-HESQLCLU.js} +4 -4
  36. package/dist/{chunk-I5PZ4JTS.js.map → chunk-HESQLCLU.js.map} +1 -1
  37. package/dist/{chunk-JAXXTYID.js → chunk-IR5HLBMH.js} +2 -2
  38. package/dist/{chunk-JAXXTYID.js.map → chunk-IR5HLBMH.js.map} +1 -1
  39. package/dist/{chunk-MFBHNWGV.js → chunk-K2FCMRXH.js} +11 -19
  40. package/dist/chunk-K2FCMRXH.js.map +1 -0
  41. package/dist/{chunk-H66O5Z2V.js → chunk-KIC7UI5U.js} +41 -6
  42. package/dist/chunk-KIC7UI5U.js.map +1 -0
  43. package/dist/{chunk-MXZSI3AY.js → chunk-KMOAJRDE.js} +42 -10
  44. package/dist/chunk-KMOAJRDE.js.map +1 -0
  45. package/dist/chunk-LQBALETG.js +71 -0
  46. package/dist/chunk-LQBALETG.js.map +1 -0
  47. package/dist/chunk-M3FPQSRU.js +12 -0
  48. package/dist/chunk-M3FPQSRU.js.map +1 -0
  49. package/dist/chunk-NQEUK763.js +26 -0
  50. package/dist/chunk-NQEUK763.js.map +1 -0
  51. package/dist/chunk-OPWAFS6Y.js +38 -0
  52. package/dist/chunk-OPWAFS6Y.js.map +1 -0
  53. package/dist/{chunk-6PDJ45T4.js → chunk-PS4WEFW6.js} +50 -25
  54. package/dist/chunk-PS4WEFW6.js.map +1 -0
  55. package/dist/{chunk-HMJRPNPZ.js → chunk-QK7TKNHV.js} +93 -21
  56. package/dist/chunk-QK7TKNHV.js.map +1 -0
  57. package/dist/{chunk-LSOYPSAT.js → chunk-RADJSEG5.js} +4 -4
  58. package/dist/chunk-RADJSEG5.js.map +1 -0
  59. package/dist/{chunk-4IJD72YB.js → chunk-SNWPI6XJ.js} +7 -7
  60. package/dist/chunk-SNWPI6XJ.js.map +1 -0
  61. package/dist/{chunk-TEVZS4FA.js → chunk-UM7MSLOV.js} +16 -9
  62. package/dist/chunk-UM7MSLOV.js.map +1 -0
  63. package/dist/chunk-VNZ3YTQD.js +232 -0
  64. package/dist/chunk-VNZ3YTQD.js.map +1 -0
  65. package/dist/{chunk-IYW62KKR.js → chunk-WXIN65UG.js} +66 -23
  66. package/dist/chunk-WXIN65UG.js.map +1 -0
  67. package/dist/chunk-XEXWX7C7.js +241 -0
  68. package/dist/chunk-XEXWX7C7.js.map +1 -0
  69. package/dist/{chunk-CGEV3ARR.js → chunk-YCCYXDW7.js} +3 -3
  70. package/dist/chunk-YCCYXDW7.js.map +1 -0
  71. package/dist/chunk-YPQ2MLAV.js +140 -0
  72. package/dist/chunk-YPQ2MLAV.js.map +1 -0
  73. package/dist/chunk-ZCOVMVK4.js +26 -0
  74. package/dist/chunk-ZCOVMVK4.js.map +1 -0
  75. package/dist/{claude-login-5WELXPKT.js → claude-login-AIFIWTYF.js} +9 -9
  76. package/dist/{claude-login-5WELXPKT.js.map → claude-login-AIFIWTYF.js.map} +1 -1
  77. package/dist/cli.js +370 -171
  78. package/dist/cli.js.map +1 -1
  79. package/dist/{codex-login-GZIFXUWD.js → codex-login-LW5X7GAM.js} +10 -10
  80. package/dist/codex-login-LW5X7GAM.js.map +1 -0
  81. package/dist/config-store-NF56VHFU.js +7 -0
  82. package/dist/{config-store-W6FBCQAQ.js.map → config-store-NF56VHFU.js.map} +1 -1
  83. package/dist/conversation-store-7GRDQZD2.js +4 -0
  84. package/dist/conversation-store-7GRDQZD2.js.map +1 -0
  85. package/dist/detect-providers-QICJ5U3R.js +4 -0
  86. package/dist/detect-providers-QICJ5U3R.js.map +1 -0
  87. package/dist/executor-FTABX2AW.js +4 -0
  88. package/dist/{executor-6RIKIGXK.js.map → executor-FTABX2AW.js.map} +1 -1
  89. package/dist/first-run-ADROZVYF.js +230 -0
  90. package/dist/first-run-ADROZVYF.js.map +1 -0
  91. package/dist/{gemini-login-AZGL3CE7.js → gemini-login-TST454MX.js} +9 -9
  92. package/dist/{gemini-login-AZGL3CE7.js.map → gemini-login-TST454MX.js.map} +1 -1
  93. package/dist/index.d.ts +46 -70
  94. package/dist/index.js +79 -468
  95. package/dist/index.js.map +1 -1
  96. package/dist/input-history-BEICE7PT.js +57 -0
  97. package/dist/input-history-BEICE7PT.js.map +1 -0
  98. package/dist/kimi-adapter-7FYOAKOI.js +6 -0
  99. package/dist/{kimi-adapter-JN4HFFHU.js.map → kimi-adapter-7FYOAKOI.js.map} +1 -1
  100. package/dist/{kimi-login-6LUWB7P6.js → kimi-login-3IGVOBJI.js} +9 -9
  101. package/dist/{kimi-login-6LUWB7P6.js.map → kimi-login-3IGVOBJI.js.map} +1 -1
  102. package/dist/logger-KGHUQ4VE.js +3 -0
  103. package/dist/logger-KGHUQ4VE.js.map +1 -0
  104. package/dist/model-discovery-AAJDHRFO.js +6 -0
  105. package/dist/model-discovery-AAJDHRFO.js.map +1 -0
  106. package/dist/native-cli-adapters-CLONTZOA.js +8 -0
  107. package/dist/{native-cli-adapters-OLW3XX57.js.map → native-cli-adapters-CLONTZOA.js.map} +1 -1
  108. package/dist/ollama-adapter-2N5OQIEV.js +5 -0
  109. package/dist/{ollama-adapter-OJQ3FKWK.js.map → ollama-adapter-2N5OQIEV.js.map} +1 -1
  110. package/dist/pathResolver-UVAB2FCW.js +3 -0
  111. package/dist/pathResolver-UVAB2FCW.js.map +1 -0
  112. package/dist/profile-loader-EMLV4J7S.js +162 -0
  113. package/dist/profile-loader-EMLV4J7S.js.map +1 -0
  114. package/dist/registry-LRURZVUL.js +5 -0
  115. package/dist/{registry-AZ2LOHHJ.js.map → registry-LRURZVUL.js.map} +1 -1
  116. package/dist/registry-MVNSXCEF.js +6 -0
  117. package/dist/{registry-H7B3AHPQ.js.map → registry-MVNSXCEF.js.map} +1 -1
  118. package/dist/server-manager-THGZBBZB.js +5 -0
  119. package/dist/{server-manager-PTGBHCLS.js.map → server-manager-THGZBBZB.js.map} +1 -1
  120. package/dist/session-manager-X3DXT53M.js +12 -0
  121. package/dist/{session-manager-XOMDMC77.js.map → session-manager-X3DXT53M.js.map} +1 -1
  122. package/dist/skills/built-in/code-review/SKILL.md +85 -0
  123. package/dist/skills/built-in/commit/SKILL.md +83 -0
  124. package/dist/skills/built-in/debug/SKILL.md +119 -0
  125. package/dist/skills/built-in/plan/SKILL.md +123 -0
  126. package/dist/skills/built-in/refactor/SKILL.md +132 -0
  127. package/dist/skills/built-in/test/SKILL.md +128 -0
  128. package/dist/sqlite-store-7OECRTXM.js +5 -0
  129. package/dist/sqlite-store-7OECRTXM.js.map +1 -0
  130. package/dist/team-manager-2VSMALAA.js +11 -0
  131. package/dist/{team-manager-HC4XGCFY.js.map → team-manager-2VSMALAA.js.map} +1 -1
  132. package/dist/team-state-HZNVMQHT.js +3 -0
  133. package/dist/team-state-HZNVMQHT.js.map +1 -0
  134. package/dist/tmux-manager-57QCUVHU.js +6 -0
  135. package/dist/{tmux-manager-GPYZ3WQH.js.map → tmux-manager-57QCUVHU.js.map} +1 -1
  136. package/dist/tools-KWFSYT56.js +6 -0
  137. package/dist/{tools-TSMXMHIF.js.map → tools-KWFSYT56.js.map} +1 -1
  138. package/package.json +11 -11
  139. package/dist/App-FKRSMFMB.js +0 -2789
  140. package/dist/App-FKRSMFMB.js.map +0 -1
  141. package/dist/api-key-fallback-YQQBOQIL.js +0 -11
  142. package/dist/chunk-4IJD72YB.js.map +0 -1
  143. package/dist/chunk-6PDJ45T4.js.map +0 -1
  144. package/dist/chunk-CARHU3DO.js.map +0 -1
  145. package/dist/chunk-CGEV3ARR.js.map +0 -1
  146. package/dist/chunk-CS5X3BWX.js +0 -27
  147. package/dist/chunk-CS5X3BWX.js.map +0 -1
  148. package/dist/chunk-CYQNBB25.js.map +0 -1
  149. package/dist/chunk-DAHGLHNR.js.map +0 -1
  150. package/dist/chunk-H66O5Z2V.js.map +0 -1
  151. package/dist/chunk-HMJRPNPZ.js.map +0 -1
  152. package/dist/chunk-IYW62KKR.js.map +0 -1
  153. package/dist/chunk-LSOYPSAT.js.map +0 -1
  154. package/dist/chunk-MFBHNWGV.js.map +0 -1
  155. package/dist/chunk-MXZSI3AY.js.map +0 -1
  156. package/dist/chunk-NBR3GHMT.js.map +0 -1
  157. package/dist/chunk-RWCNNAL7.js.map +0 -1
  158. package/dist/chunk-TEVZS4FA.js.map +0 -1
  159. package/dist/chunk-UY2SYSEZ.js +0 -211
  160. package/dist/chunk-UY2SYSEZ.js.map +0 -1
  161. package/dist/chunk-WAHVZH7V.js +0 -260
  162. package/dist/chunk-WAHVZH7V.js.map +0 -1
  163. package/dist/chunk-WPP3PEDE.js +0 -234
  164. package/dist/chunk-WPP3PEDE.js.map +0 -1
  165. package/dist/chunk-Y5XVD2CD.js.map +0 -1
  166. package/dist/claude-adapter-QMLFMSP3.js +0 -6
  167. package/dist/claude-adapter-QMLFMSP3.js.map +0 -1
  168. package/dist/codex-login-GZIFXUWD.js.map +0 -1
  169. package/dist/config-store-W6FBCQAQ.js +0 -6
  170. package/dist/executor-6RIKIGXK.js +0 -4
  171. package/dist/gemini-adapter-6JIHZ7WI.js +0 -6
  172. package/dist/gemini-adapter-6JIHZ7WI.js.map +0 -1
  173. package/dist/kimi-adapter-JN4HFFHU.js +0 -6
  174. package/dist/native-cli-adapters-OLW3XX57.js +0 -6
  175. package/dist/ollama-adapter-OJQ3FKWK.js +0 -6
  176. package/dist/openai-adapter-XU46EN7B.js +0 -6
  177. package/dist/openai-adapter-XU46EN7B.js.map +0 -1
  178. package/dist/registry-AZ2LOHHJ.js +0 -6
  179. package/dist/registry-H7B3AHPQ.js +0 -5
  180. package/dist/server-manager-PTGBHCLS.js +0 -5
  181. package/dist/session-manager-XOMDMC77.js +0 -12
  182. package/dist/team-manager-HC4XGCFY.js +0 -11
  183. package/dist/tmux-manager-GPYZ3WQH.js +0 -6
  184. package/dist/tools-TSMXMHIF.js +0 -6
@@ -0,0 +1,4431 @@
1
+ import { getCliProviderEntry, getCliProviderForModelProvider } from './chunk-LQBALETG.js';
2
+ import { getActiveTeamName, getActiveTeamManager, getActiveTmuxCleanup, setActiveTmuxCleanup, setActiveTeamManager, setActiveTeamName } from './chunk-ZCOVMVK4.js';
3
+ import { CostTracker } from './chunk-2ZYK5IJG.js';
4
+ import { getEventBus } from './chunk-YL5XFHR3.js';
5
+ import { createModelRouter } from './chunk-YPQ2MLAV.js';
6
+ import { formatCost, formatTokenCount } from './chunk-YCCYXDW7.js';
7
+ import './chunk-OPWAFS6Y.js';
8
+ import './chunk-ZGOHARPV.js';
9
+ import { getThinkingConfigForModel, SUPPORTED_MODELS, PROVIDER_MODEL_ORDER } from './chunk-HCIHOHLX.js';
10
+ import { DEFAULT_CONFIG, PACKAGE_VERSION } from './chunk-2Y7TR6BS.js';
11
+ import './chunk-IR5HLBMH.js';
12
+ import './chunk-D275MCIH.js';
13
+ import React11, { useRef, useState, useCallback, useEffect, useMemo, startTransition } from 'react';
14
+ import { Box, Text, render, useInput } from 'ink';
15
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
16
+ import { randomUUID } from 'crypto';
17
+
18
+ // src/ui/theme.ts
19
+ var BRAND_COLOR = "#F0C5DA";
20
+ var colors = {
21
+ text: {
22
+ primary: "#F9F5F5",
23
+ secondary: "#d3acb3",
24
+ muted: "#9e8085",
25
+ accent: "#F0C5DA",
26
+ response: "#F9F5F5"
27
+ },
28
+ border: {
29
+ dim: "#6b5459",
30
+ active: "#d3acb3"},
31
+ syntax: {
32
+ keyword: "#F0C5DA",
33
+ string: "#EDD6DC"},
34
+ status: {
35
+ success: "#F0C5DA",
36
+ error: "#f87171",
37
+ warning: "#EDD6DC",
38
+ info: "#F0C5DA",
39
+ active: "#F0C5DA"
40
+ },
41
+ role: {
42
+ user: "#F0C5DA",
43
+ assistant: "#F9F5F5",
44
+ system: "#EDD6DC",
45
+ tool: "#d3acb3"
46
+ }
47
+ };
48
+ function parseBlocks(raw) {
49
+ const blocks = [];
50
+ const lines = raw.split("\n");
51
+ let i = 0;
52
+ while (i < lines.length) {
53
+ const line = lines[i];
54
+ if (line === void 0) {
55
+ break;
56
+ }
57
+ if (line.startsWith("```")) {
58
+ const lang = line.slice(3).trim();
59
+ const codeLines = [];
60
+ i++;
61
+ while (i < lines.length) {
62
+ const currentLine = lines[i];
63
+ if (currentLine === void 0 || currentLine.startsWith("```")) {
64
+ break;
65
+ }
66
+ codeLines.push(currentLine);
67
+ i++;
68
+ }
69
+ blocks.push({ type: "code", content: codeLines.join("\n"), lang });
70
+ i++;
71
+ continue;
72
+ }
73
+ const headerMatch = line.match(/^(#{1,4})\s+(.+)$/);
74
+ if (headerMatch) {
75
+ const hashes = headerMatch[1];
76
+ const headerContent = headerMatch[2];
77
+ if (hashes === void 0 || headerContent === void 0) {
78
+ i++;
79
+ continue;
80
+ }
81
+ blocks.push({
82
+ type: "header",
83
+ content: headerContent,
84
+ level: hashes.length
85
+ });
86
+ i++;
87
+ continue;
88
+ }
89
+ if (/^[-*_]{3,}\s*$/.test(line)) {
90
+ blocks.push({ type: "hr", content: "" });
91
+ i++;
92
+ continue;
93
+ }
94
+ if (line.startsWith("> ")) {
95
+ const quoteLines = [];
96
+ while (i < lines.length) {
97
+ const quoteLine = lines[i];
98
+ if (quoteLine === void 0 || !quoteLine.startsWith("> ")) {
99
+ break;
100
+ }
101
+ quoteLines.push(quoteLine.slice(2));
102
+ i++;
103
+ }
104
+ blocks.push({ type: "blockquote", content: quoteLines.join("\n") });
105
+ continue;
106
+ }
107
+ if (/^\s*[-*+]\s/.test(line) || /^\s*\d+\.\s/.test(line)) {
108
+ const listLines = [];
109
+ while (i < lines.length) {
110
+ const l = lines[i];
111
+ if (l === void 0) {
112
+ break;
113
+ }
114
+ if (/^\s*[-*+]\s/.test(l) || /^\s*\d+\.\s/.test(l) || l.startsWith(" ") && listLines.length > 0) {
115
+ listLines.push(l);
116
+ i++;
117
+ } else {
118
+ break;
119
+ }
120
+ }
121
+ blocks.push({ type: "list", content: listLines.join("\n") });
122
+ continue;
123
+ }
124
+ const textLines = [];
125
+ while (i < lines.length) {
126
+ const l = lines[i];
127
+ if (l === void 0) {
128
+ break;
129
+ }
130
+ if (l.startsWith("```") || l.startsWith("#") || l.startsWith("> ") || /^[-*_]{3,}\s*$/.test(l) || /^\s*[-*+]\s/.test(l) || /^\s*\d+\.\s/.test(l)) {
131
+ break;
132
+ }
133
+ textLines.push(l);
134
+ i++;
135
+ }
136
+ if (textLines.length > 0) {
137
+ blocks.push({ type: "text", content: textLines.join("\n") });
138
+ }
139
+ }
140
+ return blocks.length > 0 ? blocks : [{ type: "text", content: raw }];
141
+ }
142
+ function InlineMarkdown({
143
+ text
144
+ }) {
145
+ const segments = [];
146
+ let remaining = text;
147
+ let key = 0;
148
+ while (remaining.length > 0) {
149
+ const boldMatch = remaining.match(/^\*\*(.+?)\*\*/);
150
+ if (boldMatch) {
151
+ segments.push(
152
+ /* @__PURE__ */ jsx(Text, { bold: true, children: boldMatch[1] }, key++)
153
+ );
154
+ remaining = remaining.slice(boldMatch[0].length);
155
+ continue;
156
+ }
157
+ const italicMatch = remaining.match(/^\*(.+?)\*/);
158
+ if (italicMatch) {
159
+ segments.push(
160
+ /* @__PURE__ */ jsx(Text, { italic: true, children: italicMatch[1] }, key++)
161
+ );
162
+ remaining = remaining.slice(italicMatch[0].length);
163
+ continue;
164
+ }
165
+ const codeMatch = remaining.match(/^`([^`]+)`/);
166
+ if (codeMatch) {
167
+ segments.push(
168
+ /* @__PURE__ */ jsx(Text, { color: colors.syntax.string, bold: true, children: codeMatch[1] }, key++)
169
+ );
170
+ remaining = remaining.slice(codeMatch[0].length);
171
+ continue;
172
+ }
173
+ const strikeMatch = remaining.match(/^~~(.+?)~~/);
174
+ if (strikeMatch) {
175
+ segments.push(
176
+ /* @__PURE__ */ jsx(Text, { strikethrough: true, dimColor: true, children: strikeMatch[1] }, key++)
177
+ );
178
+ remaining = remaining.slice(strikeMatch[0].length);
179
+ continue;
180
+ }
181
+ const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)]+)\)/);
182
+ if (linkMatch) {
183
+ segments.push(
184
+ /* @__PURE__ */ jsx(Text, { color: colors.status.info, underline: true, children: linkMatch[1] }, key++)
185
+ );
186
+ remaining = remaining.slice(linkMatch[0].length);
187
+ continue;
188
+ }
189
+ const nextSpecial = remaining.search(/[[*`~]/);
190
+ if (nextSpecial === -1) {
191
+ segments.push(/* @__PURE__ */ jsx(Text, { children: remaining }, key++));
192
+ break;
193
+ } else if (nextSpecial === 0) {
194
+ segments.push(/* @__PURE__ */ jsx(Text, { children: remaining[0] }, key++));
195
+ remaining = remaining.slice(1);
196
+ } else {
197
+ segments.push(
198
+ /* @__PURE__ */ jsx(Text, { children: remaining.slice(0, nextSpecial) }, key++)
199
+ );
200
+ remaining = remaining.slice(nextSpecial);
201
+ }
202
+ }
203
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: segments });
204
+ }
205
+ function HeaderBlock({
206
+ content,
207
+ level
208
+ }) {
209
+ const headerColors = [
210
+ colors.text.accent,
211
+ colors.status.active,
212
+ colors.syntax.keyword,
213
+ colors.text.secondary
214
+ ];
215
+ const color = headerColors[level - 1] ?? colors.text.primary;
216
+ const prefix = level === 1 ? "\u25C6 " : level === 2 ? "\u25B8 " : " ";
217
+ return /* @__PURE__ */ jsx(Box, { marginY: level <= 2 ? 1 : 0, children: /* @__PURE__ */ jsxs(Text, { color, bold: level <= 2, children: [
218
+ prefix,
219
+ content
220
+ ] }) });
221
+ }
222
+ function ListBlock({
223
+ content
224
+ }) {
225
+ const items = content.split("\n");
226
+ const bullets = ["\u25B8", "\u25E6", "\xB7", "\u2023"];
227
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: items.map((item, i) => {
228
+ const indent = item.match(/^(\s*)/)?.[1]?.length ?? 0;
229
+ const bulletLevel = Math.floor(indent / 2);
230
+ const clean = item.replace(/^\s*[-*+]\s/, "").replace(/^\s*\d+\.\s/, "");
231
+ const bullet = bullets[bulletLevel % bullets.length];
232
+ return /* @__PURE__ */ jsxs(Box, { marginLeft: bulletLevel * 2, children: [
233
+ /* @__PURE__ */ jsxs(Text, { color: colors.status.active, children: [
234
+ bullet,
235
+ " "
236
+ ] }),
237
+ /* @__PURE__ */ jsx(InlineMarkdown, { text: clean })
238
+ ] }, i);
239
+ }) });
240
+ }
241
+ function CodeBlockRender({
242
+ content,
243
+ lang
244
+ }) {
245
+ const lines = content.split("\n");
246
+ if (lines.length > 0 && lines[lines.length - 1]?.trim() === "") {
247
+ lines.pop();
248
+ }
249
+ return /* @__PURE__ */ jsxs(
250
+ Box,
251
+ {
252
+ flexDirection: "column",
253
+ borderStyle: "round",
254
+ borderColor: colors.border.dim,
255
+ marginY: 1,
256
+ children: [
257
+ lang ? /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, dimColor: true, children: lang }) }) : null,
258
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, children: lines.map((line, i) => /* @__PURE__ */ jsxs(Box, { children: [
259
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
260
+ String(i + 1).padStart(3, " "),
261
+ " ",
262
+ "\u2502",
263
+ " "
264
+ ] }),
265
+ /* @__PURE__ */ jsx(Text, { color: colors.text.response, children: line })
266
+ ] }, i)) })
267
+ ]
268
+ }
269
+ );
270
+ }
271
+ function MarkdownContent({
272
+ content
273
+ }) {
274
+ const blocks = parseBlocks(content);
275
+ if (blocks.length === 1 && blocks[0]?.type === "text") {
276
+ const text = blocks[0].content;
277
+ if (!/[[*`~]/.test(text)) {
278
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: text });
279
+ }
280
+ return /* @__PURE__ */ jsx(InlineMarkdown, { text });
281
+ }
282
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: blocks.map((block, i) => {
283
+ switch (block.type) {
284
+ case "code":
285
+ return /* @__PURE__ */ jsx(
286
+ CodeBlockRender,
287
+ {
288
+ content: block.content,
289
+ lang: block.lang
290
+ },
291
+ i
292
+ );
293
+ case "header":
294
+ return /* @__PURE__ */ jsx(
295
+ HeaderBlock,
296
+ {
297
+ content: block.content,
298
+ level: block.level ?? 1
299
+ },
300
+ i
301
+ );
302
+ case "list":
303
+ return /* @__PURE__ */ jsx(ListBlock, { content: block.content }, i);
304
+ case "hr":
305
+ return /* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.border.dim, children: "\u2500".repeat(40) }) }, i);
306
+ case "blockquote":
307
+ return /* @__PURE__ */ jsx(
308
+ Box,
309
+ {
310
+ marginLeft: 1,
311
+ borderStyle: "single",
312
+ borderLeft: true,
313
+ borderRight: false,
314
+ borderTop: false,
315
+ borderBottom: false,
316
+ borderColor: colors.border.active,
317
+ paddingLeft: 1,
318
+ children: /* @__PURE__ */ jsx(Text, { color: colors.text.secondary, italic: true, wrap: "wrap", children: block.content })
319
+ },
320
+ i
321
+ );
322
+ case "text":
323
+ default:
324
+ return /* @__PURE__ */ jsx(InlineMarkdown, { text: block.content }, i);
325
+ }
326
+ }) });
327
+ }
328
+ var animationBuckets = /* @__PURE__ */ new Map();
329
+ function getOrCreateBucket(intervalMs) {
330
+ const existing = animationBuckets.get(intervalMs);
331
+ if (existing !== void 0) {
332
+ return existing;
333
+ }
334
+ const bucket = {
335
+ tick: 0,
336
+ listeners: /* @__PURE__ */ new Set(),
337
+ timer: setInterval(() => {
338
+ bucket.tick += 1;
339
+ for (const listener of bucket.listeners) {
340
+ listener(bucket.tick);
341
+ }
342
+ }, intervalMs)
343
+ };
344
+ animationBuckets.set(intervalMs, bucket);
345
+ return bucket;
346
+ }
347
+ function useAnimationTick(intervalMs, enabled = true) {
348
+ const [tick, setTick] = useState(0);
349
+ useEffect(() => {
350
+ if (!enabled) {
351
+ setTick(0);
352
+ return void 0;
353
+ }
354
+ const bucket = getOrCreateBucket(intervalMs);
355
+ setTick(bucket.tick);
356
+ const listener = (nextTick) => {
357
+ setTick(nextTick);
358
+ };
359
+ bucket.listeners.add(listener);
360
+ return () => {
361
+ bucket.listeners.delete(listener);
362
+ if (bucket.listeners.size === 0) {
363
+ clearInterval(bucket.timer);
364
+ animationBuckets.delete(intervalMs);
365
+ }
366
+ };
367
+ }, [enabled, intervalMs]);
368
+ return tick;
369
+ }
370
+ var SPINNER_VARIANTS = {
371
+ dots: {
372
+ frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
373
+ interval: 120
374
+ },
375
+ braille: {
376
+ frames: ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"],
377
+ interval: 120
378
+ },
379
+ arc: {
380
+ frames: ["\u25DC", "\u25E0", "\u25DD", "\u25DE", "\u25E1", "\u25DF"],
381
+ interval: 100
382
+ },
383
+ pulse: {
384
+ frames: ["\u25C9", "\u25CE", "\u25CB", "\u25CE", "\u25C9", "\u25CF"],
385
+ interval: 120
386
+ },
387
+ bounce: {
388
+ frames: ["\u2801", "\u2802", "\u2804", "\u2840", "\u2880", "\u2820", "\u2810", "\u2808"],
389
+ interval: 120
390
+ }
391
+ };
392
+ function GradientSpinner({
393
+ label,
394
+ labelColor = "#888888",
395
+ variant = "dots",
396
+ speed
397
+ }) {
398
+ const spinnerDef = SPINNER_VARIANTS[variant] ?? SPINNER_VARIANTS["dots"];
399
+ if (!spinnerDef) {
400
+ throw new Error("Missing default spinner configuration");
401
+ }
402
+ const interval = speed ?? spinnerDef.interval;
403
+ const tick = useAnimationTick(interval);
404
+ const frame = tick % spinnerDef.frames.length;
405
+ return /* @__PURE__ */ jsxs(Text, { children: [
406
+ /* @__PURE__ */ jsx(Text, { color: BRAND_COLOR, children: spinnerDef.frames[frame] }),
407
+ label ? /* @__PURE__ */ jsxs(Text, { color: labelColor, children: [
408
+ " ",
409
+ label
410
+ ] }) : null
411
+ ] });
412
+ }
413
+ function StatusIcon({
414
+ status
415
+ }) {
416
+ switch (status) {
417
+ case "pending":
418
+ return /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "\u25CB" });
419
+ case "executing":
420
+ return /* @__PURE__ */ jsx(GradientSpinner, { variant: "dots" });
421
+ case "success":
422
+ return /* @__PURE__ */ jsx(Text, { color: colors.status.success, children: "\u2713" });
423
+ case "error":
424
+ return /* @__PURE__ */ jsx(Text, { color: colors.status.error, children: "\u2717" });
425
+ case "cancelled":
426
+ return /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "\u2298" });
427
+ }
428
+ }
429
+ function formatDuration(ms) {
430
+ if (ms < 1e3) return `${ms}ms`;
431
+ return `${(ms / 1e3).toFixed(1)}s`;
432
+ }
433
+ function getToolIcon(name) {
434
+ switch (name) {
435
+ case "read":
436
+ return "\u{1F4C4}";
437
+ case "write":
438
+ return "\u270F\uFE0F";
439
+ case "edit":
440
+ return "\u{1F4DD}";
441
+ case "glob":
442
+ return "\u{1F50D}";
443
+ case "grep":
444
+ return "\u{1F50E}";
445
+ case "bash":
446
+ return "\u26A1";
447
+ case "web_search":
448
+ case "webSearch":
449
+ return "\u{1F310}";
450
+ case "web_fetch":
451
+ case "webFetch":
452
+ return "\u{1F4E1}";
453
+ default:
454
+ return "\u2699";
455
+ }
456
+ }
457
+ function ToolCallDisplay({
458
+ toolName,
459
+ status,
460
+ description,
461
+ output,
462
+ isError,
463
+ duration,
464
+ isCollapsed = true
465
+ }) {
466
+ const borderColor = status === "error" ? colors.status.error : status === "executing" ? colors.status.active : colors.border.dim;
467
+ const icon = getToolIcon(toolName);
468
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 0, children: [
469
+ /* @__PURE__ */ jsxs(Box, { children: [
470
+ /* @__PURE__ */ jsx(StatusIcon, { status }),
471
+ /* @__PURE__ */ jsx(Text, { children: " " }),
472
+ /* @__PURE__ */ jsxs(Text, { color: colors.role.tool, bold: true, children: [
473
+ icon,
474
+ " ",
475
+ toolName
476
+ ] }),
477
+ description ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
478
+ " ",
479
+ description
480
+ ] }) : null,
481
+ duration !== void 0 && status !== "executing" ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
482
+ " ",
483
+ "(",
484
+ formatDuration(duration),
485
+ ")"
486
+ ] }) : null
487
+ ] }),
488
+ !isCollapsed && output ? /* @__PURE__ */ jsx(
489
+ Box,
490
+ {
491
+ flexDirection: "column",
492
+ marginLeft: 2,
493
+ borderStyle: "single",
494
+ borderLeft: true,
495
+ borderRight: false,
496
+ borderTop: false,
497
+ borderBottom: false,
498
+ borderColor,
499
+ paddingLeft: 1,
500
+ children: /* @__PURE__ */ jsx(
501
+ Text,
502
+ {
503
+ wrap: "wrap",
504
+ color: isError ? colors.status.error : colors.text.secondary,
505
+ children: output.length > 2e3 ? output.slice(0, 2e3) + "\n\u2026 (truncated)" : output
506
+ }
507
+ )
508
+ }
509
+ ) : null
510
+ ] });
511
+ }
512
+ function getRoleColor(role) {
513
+ switch (role) {
514
+ case "user":
515
+ return colors.role.user;
516
+ case "assistant":
517
+ return colors.role.assistant;
518
+ case "system":
519
+ return colors.role.system;
520
+ case "tool":
521
+ return colors.role.tool;
522
+ }
523
+ }
524
+ function getRoleIcon(role) {
525
+ switch (role) {
526
+ case "user":
527
+ return "\u276F";
528
+ case "assistant":
529
+ return "\u2726";
530
+ case "system":
531
+ return "\u2022";
532
+ case "tool":
533
+ return "\u2699";
534
+ }
535
+ }
536
+ function getRoleLabel(role, model) {
537
+ switch (role) {
538
+ case "user":
539
+ return "You";
540
+ case "assistant":
541
+ return model ?? "Assistant";
542
+ case "system":
543
+ return "System";
544
+ case "tool":
545
+ return "Tool";
546
+ }
547
+ }
548
+ function shortModelName(model) {
549
+ if (model.includes("opus")) return "Opus 4.6";
550
+ if (model.includes("sonnet")) return "Sonnet 4.6";
551
+ if (model.includes("haiku")) return "Haiku 4.5";
552
+ if (model.includes("gpt-5.2-mini")) return "GPT-5.2 mini";
553
+ if (model.includes("gpt-5.2")) return "GPT-5.2";
554
+ if (model.includes("o3")) return "o3";
555
+ if (model.includes("gemini") && model.includes("pro")) return "Gemini Pro";
556
+ if (model.includes("gemini") && model.includes("flash")) return "Gemini Flash";
557
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi K2.5";
558
+ return model;
559
+ }
560
+ function formatToolArgs(name, args) {
561
+ switch (name) {
562
+ case "read":
563
+ case "write":
564
+ case "edit":
565
+ return typeof args["file_path"] === "string" ? args["file_path"] : "";
566
+ case "glob":
567
+ return typeof args["pattern"] === "string" ? args["pattern"] : "";
568
+ case "grep": {
569
+ const pat = typeof args["pattern"] === "string" ? args["pattern"] : "";
570
+ const dir = typeof args["path"] === "string" ? ` in ${args["path"]}` : "";
571
+ return `"${pat}"${dir}`;
572
+ }
573
+ case "bash": {
574
+ const cmd = typeof args["command"] === "string" ? args["command"] : "";
575
+ return cmd.length > 60 ? cmd.slice(0, 60) + "\u2026" : cmd;
576
+ }
577
+ default:
578
+ return JSON.stringify(args).slice(0, 80);
579
+ }
580
+ }
581
+ function MessageItem({ message }) {
582
+ const color = getRoleColor(message.role);
583
+ const icon = getRoleIcon(message.role);
584
+ const label = getRoleLabel(
585
+ message.role,
586
+ message.model ? shortModelName(message.model) : void 0
587
+ );
588
+ if (message.role === "system") {
589
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs(Box, { children: [
590
+ /* @__PURE__ */ jsxs(Text, { color: colors.role.system, dimColor: true, children: [
591
+ icon,
592
+ " "
593
+ ] }),
594
+ /* @__PURE__ */ jsx(Text, { color: colors.role.system, dimColor: true, wrap: "wrap", children: message.content })
595
+ ] }) });
596
+ }
597
+ if (message.role === "tool" && message.toolCalls && message.toolCalls.length > 0) {
598
+ const firstCall = message.toolCalls[0];
599
+ if (firstCall) {
600
+ return /* @__PURE__ */ jsx(Box, { marginY: 0, marginLeft: 2, children: /* @__PURE__ */ jsx(
601
+ ToolCallDisplay,
602
+ {
603
+ toolName: firstCall.name,
604
+ status: message.content.startsWith("Error:") ? "error" : "success",
605
+ description: formatToolArgs(firstCall.name, firstCall.arguments),
606
+ output: message.content,
607
+ isError: message.content.startsWith("Error:"),
608
+ isCollapsed: message.content.length > 500
609
+ }
610
+ ) });
611
+ }
612
+ }
613
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
614
+ /* @__PURE__ */ jsxs(Box, { children: [
615
+ /* @__PURE__ */ jsxs(Text, { color, bold: true, children: [
616
+ icon,
617
+ " ",
618
+ label
619
+ ] }),
620
+ message.tokenUsage ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
621
+ " ",
622
+ "(",
623
+ message.tokenUsage.totalTokens,
624
+ " tokens)"
625
+ ] }) : null
626
+ ] }),
627
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: /* @__PURE__ */ jsx(MarkdownContent, { content: message.content }) }),
628
+ message.toolCalls && message.toolCalls.length > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", marginTop: 0, children: message.toolCalls.map((call) => {
629
+ const argSummary = formatToolArgs(call.name, call.arguments);
630
+ return /* @__PURE__ */ jsx(
631
+ ToolCallDisplay,
632
+ {
633
+ toolName: call.name,
634
+ status: "success",
635
+ description: argSummary
636
+ },
637
+ call.id
638
+ );
639
+ }) }) : null
640
+ ] });
641
+ }
642
+ var MAX_VISIBLE_MESSAGES = 50;
643
+ function MessageView({
644
+ messages
645
+ }) {
646
+ const visibleMessages = messages.length > MAX_VISIBLE_MESSAGES ? messages.slice(-MAX_VISIBLE_MESSAGES) : messages;
647
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
648
+ messages.length > MAX_VISIBLE_MESSAGES ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
649
+ " ",
650
+ "(",
651
+ messages.length - MAX_VISIBLE_MESSAGES,
652
+ " earlier messages hidden)"
653
+ ] }) : null,
654
+ visibleMessages.map((msg) => /* @__PURE__ */ jsx(MessageItem, { message: msg }, msg.id))
655
+ ] });
656
+ }
657
+ var MAX_VISIBLE_ITEMS = 8;
658
+ var SCROLL_UP_LABEL = "\u25B2";
659
+ var SCROLL_DOWN_LABEL = "\u25BC";
660
+ var SELECTED_LABEL = "\u25B8 ";
661
+ function AutocompletePopup({
662
+ items,
663
+ selectedIndex
664
+ }) {
665
+ if (items.length === 0) return null;
666
+ const totalItems = items.length;
667
+ const windowSize = Math.min(MAX_VISIBLE_ITEMS, totalItems);
668
+ let scrollOffset = 0;
669
+ if (selectedIndex >= windowSize) {
670
+ scrollOffset = selectedIndex - windowSize + 1;
671
+ }
672
+ scrollOffset = Math.max(
673
+ 0,
674
+ Math.min(scrollOffset, totalItems - windowSize)
675
+ );
676
+ const visibleItems = items.slice(scrollOffset, scrollOffset + windowSize);
677
+ const hasMore = scrollOffset + windowSize < totalItems;
678
+ const hasLess = scrollOffset > 0;
679
+ return /* @__PURE__ */ jsxs(
680
+ Box,
681
+ {
682
+ flexDirection: "column",
683
+ borderStyle: "round",
684
+ borderColor: colors.status.active,
685
+ paddingX: 1,
686
+ marginBottom: 0,
687
+ children: [
688
+ hasLess ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
689
+ " ",
690
+ SCROLL_UP_LABEL,
691
+ " ",
692
+ scrollOffset,
693
+ " above"
694
+ ] }) : null,
695
+ visibleItems.map((item, visibleIndex) => {
696
+ const actualIndex = scrollOffset + visibleIndex;
697
+ const isSelected = actualIndex === selectedIndex;
698
+ return /* @__PURE__ */ jsxs(Box, { children: [
699
+ /* @__PURE__ */ jsxs(
700
+ Text,
701
+ {
702
+ color: isSelected ? colors.status.active : colors.text.primary,
703
+ bold: isSelected,
704
+ children: [
705
+ isSelected ? SELECTED_LABEL : " ",
706
+ item.label
707
+ ]
708
+ }
709
+ ),
710
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
711
+ " ",
712
+ item.description
713
+ ] })
714
+ ] }, `${item.label}-${actualIndex}`);
715
+ }),
716
+ hasMore ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
717
+ " ",
718
+ SCROLL_DOWN_LABEL,
719
+ " ",
720
+ totalItems - scrollOffset - windowSize,
721
+ " more"
722
+ ] }) : null
723
+ ]
724
+ }
725
+ );
726
+ }
727
+
728
+ // src/ui/autocomplete-data.ts
729
+ var SLASH_COMMANDS = [
730
+ { command: "/login", description: "Log in to a provider (interactive)" },
731
+ { command: "/help", description: "Show available commands" },
732
+ { command: "/model", description: "Select a model with provider-specific thinking options" },
733
+ { command: "/role", description: "Switch role (planning, coding, review, testing, bugfix)" },
734
+ { command: "/cost", description: "Show session cost breakdown" },
735
+ { command: "/clear", description: "Clear conversation" },
736
+ { command: "/compact", description: "Compress context" },
737
+ { command: "/team list", description: "List active teams" },
738
+ { command: "/team stop", description: "Deactivate team and return to single-pane" },
739
+ { command: "/mcp list", description: "List connected MCP servers" },
740
+ { command: "/mcp add", description: "Add an MCP server" },
741
+ { command: "/skill list", description: "List available skills" },
742
+ { command: "/panel", description: "Show swarm layout information" },
743
+ { command: "/login status", description: "Show login status for all providers" },
744
+ { command: "/login logout", description: "Log out of a provider" },
745
+ { command: "/config get", description: "Get a configuration value" },
746
+ { command: "/config set", description: "Set a configuration value" },
747
+ { command: "/history", description: "List past conversations" },
748
+ { command: "/resume", description: "Resume a past conversation by number or ID" },
749
+ { command: "/quit", description: "Exit" },
750
+ { command: "/exit", description: "Exit" }
751
+ ];
752
+ var BUILTIN_CONTEXT_REFS = [
753
+ { label: "@codebase", description: "Reference the entire codebase" },
754
+ { label: "@git", description: "Reference git state" },
755
+ { label: "@docs", description: "Reference project docs" },
756
+ { label: "@web", description: "Reference web context" }
757
+ ];
758
+ var dynamicFileRefs = [];
759
+ var CODE_REFS = [
760
+ { label: "`src/", description: "Source directory" },
761
+ { label: "`src/ui/", description: "UI components" },
762
+ { label: "`src/auth/", description: "Authentication modules" },
763
+ { label: "`src/providers/", description: "LLM provider adapters" },
764
+ { label: "`src/teams/", description: "Team management" },
765
+ { label: "`src/core/", description: "Core engine" },
766
+ { label: "`src/tools/", description: "Tool implementations" },
767
+ { label: "`src/types/", description: "Type definitions" },
768
+ { label: "`src/storage/", description: "Storage layer" },
769
+ { label: "`src/utils/", description: "Utility functions" }
770
+ ];
771
+ var BUILTIN_SKILL_REFS = [
772
+ { label: "$review", description: "Comprehensive code review" },
773
+ { label: "$commit", description: "Smart git commit with message generation" },
774
+ { label: "$plan", description: "Create implementation plan from requirements" },
775
+ { label: "$debug", description: "Systematic debugging workflow" },
776
+ { label: "$test", description: "Generate tests for code" },
777
+ { label: "$refactor", description: "Refactoring with safety checks" }
778
+ ];
779
+ var dynamicSkillRefs = BUILTIN_SKILL_REFS;
780
+ function registerDynamicSkills(skills) {
781
+ dynamicSkillRefs = skills.length > 0 ? skills : BUILTIN_SKILL_REFS;
782
+ }
783
+ function registerDynamicFileRefs(files) {
784
+ dynamicFileRefs = files;
785
+ }
786
+ function getAutocompleteItems(trigger, query) {
787
+ const normalizedQuery = query.toLowerCase();
788
+ switch (trigger) {
789
+ case "/": {
790
+ const filtered = SLASH_COMMANDS.filter((cmd) => cmd.command.toLowerCase().includes(normalizedQuery));
791
+ return filtered.map((cmd) => ({ label: cmd.command, description: cmd.description }));
792
+ }
793
+ case "@": {
794
+ const fileMatches = dynamicFileRefs.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
795
+ const builtinMatches = BUILTIN_CONTEXT_REFS.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
796
+ return [...fileMatches, ...builtinMatches];
797
+ }
798
+ case "`": {
799
+ return CODE_REFS.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
800
+ }
801
+ case "$": {
802
+ return dynamicSkillRefs.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
803
+ }
804
+ }
805
+ }
806
+
807
+ // src/ui/input-utils.ts
808
+ function toCodePoints(value) {
809
+ return Array.from(value);
810
+ }
811
+ function codePointLength(value) {
812
+ return toCodePoints(value).length;
813
+ }
814
+ function sliceCodePoints(value, start, end) {
815
+ return toCodePoints(value).slice(start, end).join("");
816
+ }
817
+ function clampCursorOffset(value, offset) {
818
+ return Math.max(0, Math.min(offset, codePointLength(value)));
819
+ }
820
+ function insertTextAtCursor(value, cursorOffset, insertedText) {
821
+ const points = toCodePoints(value);
822
+ const insertion = toCodePoints(insertedText);
823
+ const safeOffset = clampCursorOffset(value, cursorOffset);
824
+ points.splice(safeOffset, 0, ...insertion);
825
+ return {
826
+ text: points.join(""),
827
+ cursorOffset: safeOffset + insertion.length
828
+ };
829
+ }
830
+ function backspaceAtCursor(value, cursorOffset) {
831
+ const safeOffset = clampCursorOffset(value, cursorOffset);
832
+ if (safeOffset === 0) {
833
+ return { text: value, cursorOffset: safeOffset };
834
+ }
835
+ const points = toCodePoints(value);
836
+ points.splice(safeOffset - 1, 1);
837
+ return {
838
+ text: points.join(""),
839
+ cursorOffset: safeOffset - 1
840
+ };
841
+ }
842
+ function deleteAtCursor(value, cursorOffset) {
843
+ const safeOffset = clampCursorOffset(value, cursorOffset);
844
+ const points = toCodePoints(value);
845
+ if (safeOffset >= points.length) {
846
+ return { text: value, cursorOffset: safeOffset };
847
+ }
848
+ points.splice(safeOffset, 1);
849
+ return {
850
+ text: points.join(""),
851
+ cursorOffset: safeOffset
852
+ };
853
+ }
854
+
855
+ // src/ui/history-navigation.ts
856
+ function navigateHistoryState(state, nextIndex, defaultCursor) {
857
+ const cache = { ...state.cache };
858
+ const previousIndex = state.historyIndex;
859
+ cache[previousIndex] = {
860
+ text: state.currentInput,
861
+ cursorOffset: clampCursorOffset(state.currentInput, state.currentCursorOffset)
862
+ };
863
+ const saved = cache[nextIndex];
864
+ const isReturningToPrevious = nextIndex === -1 || nextIndex === state.previousHistoryIndex;
865
+ if (isReturningToPrevious && saved && saved.cursorOffset > 0 && saved.cursorOffset < codePointLength(saved.text)) {
866
+ return {
867
+ historyIndex: nextIndex,
868
+ previousHistoryIndex: previousIndex,
869
+ cache,
870
+ input: saved.text,
871
+ cursorOffset: saved.cursorOffset
872
+ };
873
+ }
874
+ if (nextIndex === -1) {
875
+ const text = saved?.text ?? "";
876
+ return {
877
+ historyIndex: nextIndex,
878
+ previousHistoryIndex: previousIndex,
879
+ cache,
880
+ input: text,
881
+ cursorOffset: defaultCursor === "start" ? 0 : codePointLength(text)
882
+ };
883
+ }
884
+ if (saved) {
885
+ return {
886
+ historyIndex: nextIndex,
887
+ previousHistoryIndex: previousIndex,
888
+ cache,
889
+ input: saved.text,
890
+ cursorOffset: defaultCursor === "start" ? 0 : codePointLength(saved.text)
891
+ };
892
+ }
893
+ const input = state.history[state.history.length - 1 - nextIndex] ?? "";
894
+ return {
895
+ historyIndex: nextIndex,
896
+ previousHistoryIndex: previousIndex,
897
+ cache,
898
+ input,
899
+ cursorOffset: defaultCursor === "start" ? 0 : codePointLength(input)
900
+ };
901
+ }
902
+ var MODE_ORDER = ["agent-swarm", "accept-edits", "chat"];
903
+ var MODE_DISPLAY = {
904
+ "agent-swarm": {
905
+ label: "swarm orchestrator",
906
+ icon: "\u25B6\u25B6",
907
+ color: BRAND_COLOR
908
+ },
909
+ "accept-edits": {
910
+ label: "guided edits",
911
+ icon: "\u2551\u2551",
912
+ color: "#EDD6DC"
913
+ },
914
+ chat: {
915
+ label: "direct chat",
916
+ icon: "\u25CB",
917
+ color: "#8D7176"
918
+ }
919
+ };
920
+ var TRIGGER_CHARS = /* @__PURE__ */ new Set(["/", "@", "`", "$"]);
921
+ function detectTrigger(input, cursorOffset) {
922
+ const safeOffset = clampCursorOffset(input, cursorOffset);
923
+ const beforeCursor = sliceCodePoints(input, 0, safeOffset);
924
+ if (beforeCursor.length === 0) return null;
925
+ if (beforeCursor[0] === "/") return { trigger: "/", query: beforeCursor, rangeStart: 0 };
926
+ if (beforeCursor[0] === "$") return { trigger: "$", query: beforeCursor, rangeStart: 0 };
927
+ const points = Array.from(beforeCursor);
928
+ for (let i = points.length - 1; i >= 0; i--) {
929
+ const ch = points[i];
930
+ if (ch === void 0) continue;
931
+ if (TRIGGER_CHARS.has(ch) && ch !== "/" && ch !== "$") {
932
+ if (i === 0 || points[i - 1] === " ") {
933
+ return {
934
+ trigger: ch,
935
+ query: points.slice(i).join(""),
936
+ rangeStart: i
937
+ };
938
+ }
939
+ }
940
+ if (ch === " ") break;
941
+ }
942
+ return null;
943
+ }
944
+ function InputBar({
945
+ onSubmit,
946
+ isProcessing,
947
+ placeholder,
948
+ onCancel,
949
+ initialHistory,
950
+ mode = "agent-swarm",
951
+ onModeChange
952
+ }) {
953
+ const [input, setInput] = useState("");
954
+ const [cursorOffset, setCursorOffset] = useState(0);
955
+ const [selectedIndex, setSelectedIndex] = useState(0);
956
+ const [history, setHistory] = useState(
957
+ initialHistory ? [...initialHistory] : []
958
+ );
959
+ const [historyIndex, setHistoryIndex] = useState(-1);
960
+ const inputRef = useRef(input);
961
+ const cursorOffsetRef = useRef(cursorOffset);
962
+ const historyRef = useRef(history);
963
+ const historyIndexRef = useRef(historyIndex);
964
+ const triggerStateRef = useRef(null);
965
+ const autocompleteItemsRef = useRef([]);
966
+ const isAutocompleteActiveRef = useRef(false);
967
+ const previousHistoryIndexRef = useRef(void 0);
968
+ const historyCacheRef = useRef({});
969
+ const setInputWithCursor = useCallback(
970
+ (nextInput, cursorPosition = "end") => {
971
+ const nextCursor = cursorPosition === "start" ? 0 : cursorPosition === "end" ? codePointLength(nextInput) : clampCursorOffset(nextInput, cursorPosition);
972
+ inputRef.current = nextInput;
973
+ cursorOffsetRef.current = nextCursor;
974
+ setInput(nextInput);
975
+ setCursorOffset(nextCursor);
976
+ setSelectedIndex(0);
977
+ },
978
+ []
979
+ );
980
+ const setCursorPosition = useCallback(
981
+ (nextCursor) => {
982
+ const clamped = clampCursorOffset(inputRef.current, nextCursor);
983
+ cursorOffsetRef.current = clamped;
984
+ setCursorOffset(clamped);
985
+ },
986
+ []
987
+ );
988
+ const resetHistoryNavigation = useCallback(() => {
989
+ historyIndexRef.current = -1;
990
+ setHistoryIndex(-1);
991
+ previousHistoryIndexRef.current = void 0;
992
+ historyCacheRef.current = {};
993
+ }, []);
994
+ const navigateHistory = useCallback(
995
+ (nextIndex, defaultCursor) => {
996
+ const result = navigateHistoryState(
997
+ {
998
+ history: historyRef.current,
999
+ historyIndex: historyIndexRef.current,
1000
+ previousHistoryIndex: previousHistoryIndexRef.current,
1001
+ cache: historyCacheRef.current,
1002
+ currentInput: inputRef.current,
1003
+ currentCursorOffset: cursorOffsetRef.current
1004
+ },
1005
+ nextIndex,
1006
+ defaultCursor
1007
+ );
1008
+ historyCacheRef.current = result.cache;
1009
+ historyIndexRef.current = result.historyIndex;
1010
+ previousHistoryIndexRef.current = result.previousHistoryIndex;
1011
+ setHistoryIndex(result.historyIndex);
1012
+ setInputWithCursor(result.input, result.cursorOffset);
1013
+ },
1014
+ [setInputWithCursor]
1015
+ );
1016
+ const applyAutocompleteSelection = useCallback(
1017
+ (selected, triggerMatch) => {
1018
+ const currentInput = inputRef.current;
1019
+ const currentCursorOffset = cursorOffsetRef.current;
1020
+ const before = sliceCodePoints(currentInput, 0, triggerMatch.rangeStart);
1021
+ const after = sliceCodePoints(currentInput, currentCursorOffset);
1022
+ const nextInput = `${before}${selected.label} ${after}`;
1023
+ setInputWithCursor(nextInput, codePointLength(before) + codePointLength(selected.label) + 1);
1024
+ },
1025
+ [setInputWithCursor]
1026
+ );
1027
+ useEffect(() => {
1028
+ if (initialHistory && initialHistory.length > 0) {
1029
+ setHistory((prev) => {
1030
+ if (prev.length === 0) return [...initialHistory];
1031
+ return prev;
1032
+ });
1033
+ }
1034
+ }, [initialHistory]);
1035
+ useEffect(() => {
1036
+ inputRef.current = input;
1037
+ cursorOffsetRef.current = cursorOffset;
1038
+ historyRef.current = history;
1039
+ historyIndexRef.current = historyIndex;
1040
+ }, [cursorOffset, history, historyIndex, input]);
1041
+ const triggerState = useMemo(() => detectTrigger(input, cursorOffset), [cursorOffset, input]);
1042
+ const autocompleteItems = useMemo(() => {
1043
+ if (triggerState === null) return [];
1044
+ return getAutocompleteItems(triggerState.trigger, triggerState.query);
1045
+ }, [triggerState]);
1046
+ const isAutocompleteActive = autocompleteItems.length > 0;
1047
+ useEffect(() => {
1048
+ triggerStateRef.current = triggerState;
1049
+ autocompleteItemsRef.current = autocompleteItems;
1050
+ isAutocompleteActiveRef.current = isAutocompleteActive;
1051
+ }, [autocompleteItems, isAutocompleteActive, triggerState]);
1052
+ const appendToHistory = useCallback((entry) => {
1053
+ setHistory((prev) => {
1054
+ const next = [...prev.slice(-99), entry];
1055
+ historyRef.current = next;
1056
+ return next;
1057
+ });
1058
+ }, []);
1059
+ useInput((inputChar, key) => {
1060
+ const currentInput = inputRef.current;
1061
+ const currentCursorOffset = cursorOffsetRef.current;
1062
+ const currentHistoryIndex = historyIndexRef.current;
1063
+ const currentHistory = historyRef.current;
1064
+ const currentTriggerState = triggerStateRef.current;
1065
+ const currentAutocompleteItems = autocompleteItemsRef.current;
1066
+ const currentAutocompleteActive = isAutocompleteActiveRef.current;
1067
+ if (isProcessing) {
1068
+ if (key.escape && onCancel) {
1069
+ onCancel();
1070
+ }
1071
+ return;
1072
+ }
1073
+ if (key.leftArrow) {
1074
+ setCursorPosition(currentCursorOffset - 1);
1075
+ return;
1076
+ }
1077
+ if (key.rightArrow) {
1078
+ setCursorPosition(currentCursorOffset + 1);
1079
+ return;
1080
+ }
1081
+ if (key.tab && key.shift) {
1082
+ if (onModeChange) {
1083
+ const idx = MODE_ORDER.indexOf(mode);
1084
+ const next = MODE_ORDER[(idx + 1) % MODE_ORDER.length];
1085
+ if (next) {
1086
+ onModeChange(next);
1087
+ }
1088
+ }
1089
+ return;
1090
+ }
1091
+ if (key.upArrow) {
1092
+ if (currentHistoryIndex !== -1) {
1093
+ if (currentHistoryIndex < currentHistory.length - 1) {
1094
+ navigateHistory(currentHistoryIndex + 1, "end");
1095
+ }
1096
+ return;
1097
+ }
1098
+ if (currentAutocompleteActive) {
1099
+ setSelectedIndex(
1100
+ (prev) => prev > 0 ? prev - 1 : currentAutocompleteItems.length - 1
1101
+ );
1102
+ return;
1103
+ }
1104
+ if (currentHistory.length > 0) {
1105
+ navigateHistory(0, "end");
1106
+ }
1107
+ return;
1108
+ }
1109
+ if (key.downArrow) {
1110
+ if (currentHistoryIndex !== -1) {
1111
+ navigateHistory(currentHistoryIndex - 1, "end");
1112
+ return;
1113
+ }
1114
+ if (currentAutocompleteActive) {
1115
+ setSelectedIndex(
1116
+ (prev) => prev < currentAutocompleteItems.length - 1 ? prev + 1 : 0
1117
+ );
1118
+ }
1119
+ return;
1120
+ }
1121
+ if (currentAutocompleteActive) {
1122
+ if (key.tab) {
1123
+ const selected = currentAutocompleteItems[selectedIndex];
1124
+ if (selected && currentTriggerState) {
1125
+ applyAutocompleteSelection(selected, currentTriggerState);
1126
+ }
1127
+ return;
1128
+ }
1129
+ if (key.escape) {
1130
+ const result = insertTextAtCursor(currentInput, currentCursorOffset, " ");
1131
+ setInputWithCursor(result.text, result.cursorOffset);
1132
+ return;
1133
+ }
1134
+ }
1135
+ if (key.return) {
1136
+ if (currentHistoryIndex !== -1 && currentInput.trim().length > 0) {
1137
+ appendToHistory(currentInput.trim());
1138
+ onSubmit(currentInput.trim());
1139
+ setInputWithCursor("");
1140
+ resetHistoryNavigation();
1141
+ return;
1142
+ }
1143
+ if (currentAutocompleteActive) {
1144
+ const selected = currentAutocompleteItems[selectedIndex];
1145
+ if (selected && currentTriggerState) {
1146
+ if (currentTriggerState.trigger === "/" && currentHistoryIndex === -1) {
1147
+ appendToHistory(selected.label.trim());
1148
+ onSubmit(selected.label.trim());
1149
+ setInputWithCursor("");
1150
+ } else {
1151
+ applyAutocompleteSelection(selected, currentTriggerState);
1152
+ }
1153
+ resetHistoryNavigation();
1154
+ return;
1155
+ }
1156
+ }
1157
+ if (currentInput.trim().length > 0) {
1158
+ appendToHistory(currentInput.trim());
1159
+ onSubmit(currentInput.trim());
1160
+ setInputWithCursor("");
1161
+ resetHistoryNavigation();
1162
+ }
1163
+ return;
1164
+ }
1165
+ if (key.backspace || key.delete || key.ctrl && inputChar === "h") {
1166
+ const result = backspaceAtCursor(currentInput, currentCursorOffset);
1167
+ setInputWithCursor(result.text, result.cursorOffset);
1168
+ return;
1169
+ }
1170
+ if (key.ctrl && inputChar === "d" && currentInput.length > 0) {
1171
+ const result = deleteAtCursor(currentInput, currentCursorOffset);
1172
+ setInputWithCursor(result.text, result.cursorOffset);
1173
+ return;
1174
+ }
1175
+ if (key.ctrl && inputChar === "c") {
1176
+ process.exit(0);
1177
+ return;
1178
+ }
1179
+ if (key.ctrl && inputChar === "l") return;
1180
+ if (!key.ctrl && !key.meta && inputChar) {
1181
+ const result = insertTextAtCursor(currentInput, currentCursorOffset, inputChar);
1182
+ setInputWithCursor(result.text, result.cursorOffset);
1183
+ }
1184
+ });
1185
+ const modeInfo = MODE_DISPLAY[mode];
1186
+ const borderColor = isProcessing ? colors.border.dim : modeInfo.color;
1187
+ const cursorChar = sliceCodePoints(input, cursorOffset, cursorOffset + 1);
1188
+ const beforeCursor = sliceCodePoints(input, 0, cursorOffset);
1189
+ const afterCursor = cursorChar.length > 0 ? sliceCodePoints(input, cursorOffset + 1) : "";
1190
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1191
+ isAutocompleteActive ? /* @__PURE__ */ jsx(AutocompletePopup, { items: autocompleteItems, selectedIndex }) : null,
1192
+ /* @__PURE__ */ jsxs(Box, { children: [
1193
+ /* @__PURE__ */ jsxs(Text, { color: colors.border.dim, children: [
1194
+ "\u2500".repeat(4),
1195
+ " "
1196
+ ] }),
1197
+ /* @__PURE__ */ jsxs(Text, { color: modeInfo.color, bold: true, children: [
1198
+ modeInfo.icon,
1199
+ " "
1200
+ ] }),
1201
+ /* @__PURE__ */ jsx(Text, { color: modeInfo.color, bold: true, children: modeInfo.label }),
1202
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: " (shift+tab to cycle)" })
1203
+ ] }),
1204
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor, paddingX: 1, children: [
1205
+ /* @__PURE__ */ jsxs(Text, { color: modeInfo.color, bold: true, children: [
1206
+ "\u276F",
1207
+ " "
1208
+ ] }),
1209
+ isProcessing ? /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: onCancel ? "esc to cancel" : "Processing\u2026" }) : input.length > 0 ? /* @__PURE__ */ jsxs(Text, { children: [
1210
+ /* @__PURE__ */ jsx(Text, { color: colors.text.primary, children: beforeCursor }),
1211
+ cursorChar.length > 0 ? /* @__PURE__ */ jsx(Text, { color: colors.text.primary, inverse: true, children: cursorChar }) : /* @__PURE__ */ jsx(Text, { color: modeInfo.color, children: "\u2588" }),
1212
+ afterCursor.length > 0 ? /* @__PURE__ */ jsx(Text, { color: colors.text.primary, children: afterCursor }) : null
1213
+ ] }) : /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
1214
+ placeholder ?? "Type a message\u2026",
1215
+ /* @__PURE__ */ jsx(Text, { color: modeInfo.color, children: "\u2588" })
1216
+ ] })
1217
+ ] })
1218
+ ] });
1219
+ }
1220
+ function shortModelLabel(model) {
1221
+ if (model.includes("opus")) return "Opus 4.6";
1222
+ if (model.includes("sonnet")) return "Sonnet 4.6";
1223
+ if (model.includes("haiku")) return "Haiku 4.5";
1224
+ if (model.includes("gpt-5.2-mini")) return "GPT-5.2m";
1225
+ if (model.includes("gpt-5.2")) return "GPT-5.2";
1226
+ if (model.includes("o3")) return "o3";
1227
+ if (model.includes("gemini") && model.includes("pro")) return "Gem Pro";
1228
+ if (model.includes("gemini") && model.includes("flash")) return "Gem Flash";
1229
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi";
1230
+ return model;
1231
+ }
1232
+ var SEP = " \u2502 ";
1233
+ function StatusBar({
1234
+ model,
1235
+ role,
1236
+ tokenCount,
1237
+ cost,
1238
+ gitBranch,
1239
+ gitChanges
1240
+ }) {
1241
+ return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: colors.border.dim, paddingX: 1, children: [
1242
+ /* @__PURE__ */ jsxs(Text, { color: BRAND_COLOR, bold: true, children: [
1243
+ "\u25C6",
1244
+ " "
1245
+ ] }),
1246
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: "Aemeath Agent Swarm" }),
1247
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: SEP }),
1248
+ /* @__PURE__ */ jsx(Text, { color: colors.status.warning, bold: true, children: shortModelLabel(model) }),
1249
+ role ? /* @__PURE__ */ jsxs(Fragment, { children: [
1250
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: SEP }),
1251
+ /* @__PURE__ */ jsx(Text, { color: colors.role.tool, children: role })
1252
+ ] }) : null,
1253
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: SEP }),
1254
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.secondary, children: [
1255
+ tokenCount,
1256
+ " tok"
1257
+ ] }),
1258
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: SEP }),
1259
+ /* @__PURE__ */ jsx(Text, { color: colors.status.success, children: cost }),
1260
+ gitBranch ? /* @__PURE__ */ jsxs(Fragment, { children: [
1261
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: SEP }),
1262
+ /* @__PURE__ */ jsxs(Text, { color: colors.status.info, children: [
1263
+ "\u2387",
1264
+ " ",
1265
+ gitBranch,
1266
+ gitChanges !== void 0 && gitChanges > 0 ? ` \xB1${gitChanges}` : ""
1267
+ ] })
1268
+ ] }) : null
1269
+ ] });
1270
+ }
1271
+ var THINKING_PHRASES = [
1272
+ "Thinking",
1273
+ "Analyzing",
1274
+ "Reasoning",
1275
+ "Processing",
1276
+ "Understanding",
1277
+ "Considering",
1278
+ "Evaluating"
1279
+ ];
1280
+ var PHRASE_CYCLE_MS = 2500;
1281
+ function ThinkingIndicator({
1282
+ activity,
1283
+ isStreaming,
1284
+ modelName,
1285
+ startTime
1286
+ }) {
1287
+ const tick = useAnimationTick(1e3);
1288
+ const elapsed = startTime === void 0 ? 0 : Math.max(0, Date.now() - startTime);
1289
+ const phraseIndex = Math.floor(elapsed / PHRASE_CYCLE_MS) % THINKING_PHRASES.length;
1290
+ const elapsedStr = useMemo(() => {
1291
+ const secs = Math.floor(elapsed / 1e3);
1292
+ if (secs < 1) return "";
1293
+ if (secs < 60) return `${secs}s`;
1294
+ const mins = Math.floor(secs / 60);
1295
+ return `${mins}m${secs % 60}s`;
1296
+ }, [elapsed]);
1297
+ const dotCount = tick % 4;
1298
+ const dots = ".".repeat(dotCount);
1299
+ const phrase = THINKING_PHRASES[phraseIndex] ?? "Thinking";
1300
+ const displayText = activity ? activity : isStreaming ? "Streaming response" : `${phrase}${dots}`;
1301
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1302
+ modelName ? /* @__PURE__ */ jsxs(Box, { children: [
1303
+ /* @__PURE__ */ jsxs(Text, { color: colors.role.assistant, bold: true, children: [
1304
+ "\u2726",
1305
+ " "
1306
+ ] }),
1307
+ /* @__PURE__ */ jsx(Text, { color: colors.role.assistant, bold: true, children: modelName })
1308
+ ] }) : null,
1309
+ /* @__PURE__ */ jsxs(Box, { marginLeft: 2, children: [
1310
+ /* @__PURE__ */ jsx(
1311
+ GradientSpinner,
1312
+ {
1313
+ variant: activity ? "braille" : "dots",
1314
+ label: displayText,
1315
+ labelColor: activity ? colors.text.secondary : colors.text.muted
1316
+ }
1317
+ ),
1318
+ elapsedStr ? /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
1319
+ " (",
1320
+ elapsedStr,
1321
+ ")"
1322
+ ] }) : null
1323
+ ] }),
1324
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, dimColor: true, children: [
1325
+ " ",
1326
+ "esc to cancel"
1327
+ ] }) })
1328
+ ] });
1329
+ }
1330
+ var MASCOT_LINES = [
1331
+ " :- ",
1332
+ " :::::::: ",
1333
+ " .:.:::.:::: ",
1334
+ " ::--:::-:: :: ",
1335
+ " -:##**%%:- ",
1336
+ " :=+==++: : ",
1337
+ " ::==++=-:. ",
1338
+ "-:-=*:----:=-::*==:-",
1339
+ " = -::::- - "
1340
+ ];
1341
+ var LOGO_LINES = [
1342
+ " \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
1343
+ "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2554\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551",
1344
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551",
1345
+ "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u2554\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551",
1346
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2554\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551",
1347
+ "\u2554\u2550\u255D \u2554\u2550\u255D\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u2554\u2550\u255D \u2554\u2550\u255D\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u2554\u2550\u255D \u2554\u2550\u255D \u2554\u2550\u255D \u2554\u2550\u255D \u2554\u2550\u255D"
1348
+ ];
1349
+ var TIPS = [
1350
+ { key: "/help", desc: "Show all commands" },
1351
+ { key: "/model", desc: "Switch AI model" },
1352
+ { key: "Shift+Tab", desc: "Cycle swarm/edit/chat modes" },
1353
+ { key: "Tab", desc: "Autocomplete or focus next agent" },
1354
+ { key: "@", desc: "Reference project files" },
1355
+ { key: "$skill", desc: "Invoke skills" }
1356
+ ];
1357
+ var TIP_ROWS = [TIPS.slice(0, 2), TIPS.slice(2, 4), TIPS.slice(4)];
1358
+ function WelcomeScreen({
1359
+ version
1360
+ }) {
1361
+ return /* @__PURE__ */ jsxs(
1362
+ Box,
1363
+ {
1364
+ flexDirection: "column",
1365
+ flexGrow: 1,
1366
+ paddingX: 2,
1367
+ justifyContent: "center",
1368
+ alignItems: "center",
1369
+ marginBottom: 1,
1370
+ children: [
1371
+ /* @__PURE__ */ jsxs(Box, { alignItems: "center", children: [
1372
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginRight: 2, children: MASCOT_LINES.map((line, i) => /* @__PURE__ */ jsx(Text, { color: BRAND_COLOR, children: line }, `m${i}`)) }),
1373
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: LOGO_LINES.map((line, i) => /* @__PURE__ */ jsx(Text, { color: BRAND_COLOR, children: line }, i)) })
1374
+ ] }),
1375
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 0, children: [
1376
+ /* @__PURE__ */ jsxs(Text, { color: colors.border.active, children: [
1377
+ "\u2500".repeat(16),
1378
+ " "
1379
+ ] }),
1380
+ /* @__PURE__ */ jsx(Text, { color: colors.text.accent, bold: true, children: "Aemeath Agent Swarm" }),
1381
+ /* @__PURE__ */ jsxs(Text, { color: colors.border.active, children: [
1382
+ " ",
1383
+ "\u2500".repeat(16)
1384
+ ] })
1385
+ ] }),
1386
+ version ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
1387
+ "v",
1388
+ version
1389
+ ] }) }) : null,
1390
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
1391
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.text.secondary, bold: true, children: "Quick Start" }) }),
1392
+ TIP_ROWS.map((row, rowIndex) => /* @__PURE__ */ jsx(Box, { children: row.map((tip, tipIndex) => /* @__PURE__ */ jsxs(
1393
+ Box,
1394
+ {
1395
+ flexDirection: "column",
1396
+ width: 40,
1397
+ marginRight: tipIndex < row.length - 1 ? 3 : 0,
1398
+ children: [
1399
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: tip.key }),
1400
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: tip.desc })
1401
+ ]
1402
+ },
1403
+ tip.key
1404
+ )) }, `tip-row-${rowIndex}`))
1405
+ ] })
1406
+ ]
1407
+ }
1408
+ );
1409
+ }
1410
+ function shortModelName2(model) {
1411
+ if (model.includes("opus")) return "Opus 4.6";
1412
+ if (model.includes("sonnet")) return "Sonnet 4.6";
1413
+ if (model.includes("haiku")) return "Haiku 4.5";
1414
+ if (model.includes("gpt-5.2-mini")) return "GPT-5.2m";
1415
+ if (model.includes("gpt-5.2")) return "GPT-5.2";
1416
+ if (model.includes("o3")) return "o3";
1417
+ if (model.includes("gemini") && model.includes("pro")) return "Gem Pro";
1418
+ if (model.includes("gemini") && model.includes("flash")) return "Gem Flash";
1419
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi";
1420
+ return model;
1421
+ }
1422
+ function tailLines(text, maxLines) {
1423
+ const lines = text.split("\n");
1424
+ if (lines.length <= maxLines) return text;
1425
+ return lines.slice(-maxLines).join("\n");
1426
+ }
1427
+ function SinglePane({
1428
+ messages,
1429
+ isProcessing,
1430
+ onSubmit,
1431
+ onCancel,
1432
+ model,
1433
+ role,
1434
+ tokenCount,
1435
+ cost,
1436
+ gitBranch,
1437
+ gitChanges,
1438
+ streamingContent,
1439
+ activity,
1440
+ initialHistory,
1441
+ mode,
1442
+ onModeChange
1443
+ }) {
1444
+ const processingStartRef = useRef(void 0);
1445
+ if (isProcessing && processingStartRef.current === void 0) {
1446
+ processingStartRef.current = Date.now();
1447
+ } else if (!isProcessing) {
1448
+ processingStartRef.current = void 0;
1449
+ }
1450
+ const hasContent = streamingContent !== void 0 && streamingContent.length > 0;
1451
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: "100%", children: [
1452
+ /* @__PURE__ */ jsx(
1453
+ StatusBar,
1454
+ {
1455
+ model,
1456
+ role,
1457
+ tokenCount,
1458
+ cost,
1459
+ gitBranch,
1460
+ gitChanges
1461
+ }
1462
+ ),
1463
+ messages.length === 0 && !isProcessing ? (
1464
+ /* ── Welcome screen ────────────────────────────────── */
1465
+ /* @__PURE__ */ jsx(
1466
+ WelcomeScreen,
1467
+ {
1468
+ version: PACKAGE_VERSION
1469
+ }
1470
+ )
1471
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1472
+ /* @__PURE__ */ jsx(MessageView, { messages }),
1473
+ isProcessing ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 1, marginBottom: 1, children: [
1474
+ hasContent ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [
1475
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: colors.role.assistant, bold: true, children: [
1476
+ "\u2726",
1477
+ " ",
1478
+ shortModelName2(model)
1479
+ ] }) }),
1480
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(MarkdownContent, { content: tailLines(streamingContent, 12) }) })
1481
+ ] }) : null,
1482
+ /* @__PURE__ */ jsx(
1483
+ ThinkingIndicator,
1484
+ {
1485
+ activity,
1486
+ isStreaming: hasContent,
1487
+ modelName: hasContent ? void 0 : shortModelName2(model),
1488
+ startTime: processingStartRef.current
1489
+ }
1490
+ )
1491
+ ] }) : null
1492
+ ] }),
1493
+ /* @__PURE__ */ jsx(
1494
+ InputBar,
1495
+ {
1496
+ onSubmit,
1497
+ isProcessing,
1498
+ onCancel,
1499
+ initialHistory,
1500
+ mode,
1501
+ onModeChange
1502
+ }
1503
+ )
1504
+ ] });
1505
+ }
1506
+ function getStatusColor(status) {
1507
+ switch (status) {
1508
+ case "active":
1509
+ return colors.status.success;
1510
+ case "idle":
1511
+ return colors.status.warning;
1512
+ case "error":
1513
+ return colors.status.error;
1514
+ case "shutdown":
1515
+ return colors.text.muted;
1516
+ default:
1517
+ return colors.text.primary;
1518
+ }
1519
+ }
1520
+ function shortModelLabel2(model) {
1521
+ if (model.includes("opus")) return "Opus";
1522
+ if (model.includes("sonnet")) return "Sonnet";
1523
+ if (model.includes("haiku")) return "Haiku";
1524
+ if (model.includes("gpt-5")) return "GPT-5";
1525
+ if (model.includes("gemini") && model.includes("pro")) return "Gem-Pro";
1526
+ if (model.includes("gemini") && model.includes("flash")) return "Gem-Flash";
1527
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi";
1528
+ const parts = model.split("-");
1529
+ return parts[parts.length - 1] ?? model.slice(0, 8);
1530
+ }
1531
+ function statusIndicator(status) {
1532
+ switch (status) {
1533
+ case "active":
1534
+ return "\u25CF";
1535
+ case "idle":
1536
+ return "\u25CB";
1537
+ case "error":
1538
+ return "\u2716";
1539
+ default:
1540
+ return "\u2500";
1541
+ }
1542
+ }
1543
+ function classifyLine(line) {
1544
+ if (line.length === 0) return "empty";
1545
+ if (line.startsWith("\u2699") || line.startsWith("\u2699\uFE0F")) return "tool";
1546
+ if (line.startsWith(" \u2192")) return "result";
1547
+ if (line.startsWith("Error:") || line.startsWith("Stream error:")) return "error";
1548
+ return "text";
1549
+ }
1550
+ function renderLine(line, key) {
1551
+ const type = classifyLine(line);
1552
+ switch (type) {
1553
+ case "tool":
1554
+ return /* @__PURE__ */ jsx(Text, { color: colors.role.tool, children: line }, key);
1555
+ case "result":
1556
+ return /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: line }, key);
1557
+ case "error":
1558
+ return /* @__PURE__ */ jsx(Text, { color: colors.status.error, bold: true, children: line }, key);
1559
+ case "empty":
1560
+ return /* @__PURE__ */ jsx(Text, { children: " " }, key);
1561
+ default:
1562
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: line }, key);
1563
+ }
1564
+ }
1565
+ function getVisibleLines(output, maxLines) {
1566
+ const lines = output.split("\n");
1567
+ const startIndex = Math.max(0, lines.length - maxLines);
1568
+ return lines.slice(startIndex).map((content, index) => ({
1569
+ absoluteIndex: startIndex + index,
1570
+ content
1571
+ }));
1572
+ }
1573
+ function getLastActivity(output) {
1574
+ const lines = output.split("\n");
1575
+ for (let index = lines.length - 1; index >= 0; index--) {
1576
+ const line = lines[index];
1577
+ if (!line) continue;
1578
+ const trimmed = line.trim();
1579
+ if (trimmed.length === 0) continue;
1580
+ const type = classifyLine(trimmed);
1581
+ if (type === "tool" || type === "result" || type === "error") {
1582
+ return trimmed;
1583
+ }
1584
+ }
1585
+ return void 0;
1586
+ }
1587
+ function AgentFrameComponent({
1588
+ agent,
1589
+ output,
1590
+ titlePrefix,
1591
+ isFocused,
1592
+ maxLines
1593
+ }) {
1594
+ const previewLines = React11.useMemo(
1595
+ () => getVisibleLines(output, maxLines),
1596
+ [maxLines, output]
1597
+ );
1598
+ const lastActivity = React11.useMemo(
1599
+ () => getLastActivity(output),
1600
+ [output]
1601
+ );
1602
+ return /* @__PURE__ */ jsxs(
1603
+ Box,
1604
+ {
1605
+ flexDirection: "column",
1606
+ borderStyle: isFocused ? "round" : "single",
1607
+ borderColor: isFocused ? colors.status.active : colors.border.dim,
1608
+ paddingX: 1,
1609
+ paddingY: 0,
1610
+ marginBottom: 1,
1611
+ children: [
1612
+ /* @__PURE__ */ jsxs(Box, { children: [
1613
+ /* @__PURE__ */ jsxs(Text, { color: getStatusColor(agent.status), children: [
1614
+ statusIndicator(agent.status),
1615
+ " "
1616
+ ] }),
1617
+ /* @__PURE__ */ jsxs(Text, { color: colors.status.active, bold: true, children: [
1618
+ titlePrefix,
1619
+ " ",
1620
+ agent.config.name
1621
+ ] }),
1622
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
1623
+ " ",
1624
+ "\u2014",
1625
+ " ",
1626
+ agent.config.role,
1627
+ " ",
1628
+ "\xB7",
1629
+ " ",
1630
+ shortModelLabel2(agent.config.model)
1631
+ ] })
1632
+ ] }),
1633
+ lastActivity ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, dimColor: true, children: lastActivity.length > 72 ? `${lastActivity.slice(0, 72)}\u2026` : lastActivity }) }) : null,
1634
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: previewLines.length > 0 ? previewLines.map((line) => renderLine(
1635
+ line.content,
1636
+ `${agent.config.agentId}-${line.absoluteIndex}`
1637
+ )) : /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: agent.status === "active" ? "Initializing\u2026" : "Waiting for work\u2026" }) }),
1638
+ agent.status === "active" ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: titlePrefix === "Master" ? "Coordinating\u2026" : "Working\u2026" }) }) : null
1639
+ ]
1640
+ }
1641
+ );
1642
+ }
1643
+ var AgentFrame = React11.memo(
1644
+ AgentFrameComponent,
1645
+ (previousProps, nextProps) => previousProps.agent === nextProps.agent && previousProps.output === nextProps.output && previousProps.titlePrefix === nextProps.titlePrefix && previousProps.isFocused === nextProps.isFocused && previousProps.maxLines === nextProps.maxLines
1646
+ );
1647
+ function SplitPanel({
1648
+ agents,
1649
+ activeAgentIndex,
1650
+ onSelectAgent,
1651
+ agentOutputs
1652
+ }) {
1653
+ useInput((input, key) => {
1654
+ if (key.tab) {
1655
+ onSelectAgent((activeAgentIndex + 1) % agents.length);
1656
+ return;
1657
+ }
1658
+ const numericKey = Number.parseInt(input, 10);
1659
+ if (!Number.isNaN(numericKey) && numericKey >= 1 && numericKey <= agents.length && key.ctrl) {
1660
+ onSelectAgent(numericKey - 1);
1661
+ }
1662
+ });
1663
+ const [masterAgent, ...workerAgents] = agents;
1664
+ const focusedAgent = agents[activeAgentIndex];
1665
+ if (!masterAgent) {
1666
+ return /* @__PURE__ */ jsx(Box, { flexGrow: 1, borderStyle: "round", borderColor: colors.border.dim, paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "No agents active" }) });
1667
+ }
1668
+ const masterOutput = agentOutputs.get(masterAgent.config.agentId) ?? "";
1669
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
1670
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1671
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "Focus: " }),
1672
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: focusedAgent?.config.name ?? masterAgent.config.name }),
1673
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: " " }),
1674
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: "Tab" }),
1675
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: " cycle " }),
1676
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: "Ctrl+1" }),
1677
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "-" }),
1678
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: agents.length }),
1679
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: " jump " }),
1680
+ /* @__PURE__ */ jsx(Text, { color: colors.status.warning, bold: true, children: "/team stop" }),
1681
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: " exit swarm" })
1682
+ ] }),
1683
+ /* @__PURE__ */ jsxs(Box, { flexGrow: 1, children: [
1684
+ /* @__PURE__ */ jsx(Box, { flexBasis: "50%", flexDirection: "column", paddingRight: 1, children: /* @__PURE__ */ jsx(
1685
+ AgentFrame,
1686
+ {
1687
+ agent: masterAgent,
1688
+ output: masterOutput,
1689
+ titlePrefix: "Master",
1690
+ isFocused: activeAgentIndex === 0,
1691
+ maxLines: 28
1692
+ }
1693
+ ) }),
1694
+ /* @__PURE__ */ jsx(Box, { flexBasis: "50%", flexDirection: "column", paddingLeft: 1, children: workerAgents.length > 0 ? workerAgents.map((agent, index) => /* @__PURE__ */ jsx(
1695
+ AgentFrame,
1696
+ {
1697
+ agent,
1698
+ output: agentOutputs.get(agent.config.agentId) ?? "",
1699
+ titlePrefix: "Worker",
1700
+ isFocused: activeAgentIndex === index + 1,
1701
+ maxLines: 8
1702
+ },
1703
+ agent.config.agentId
1704
+ )) : /* @__PURE__ */ jsx(Box, { borderStyle: "single", borderColor: colors.border.dim, paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "No worker agents in this swarm." }) }) })
1705
+ ] }),
1706
+ /* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "Input is sent to the focused agent. The master agent remains pinned to the left pane." }) })
1707
+ ] });
1708
+ }
1709
+ function SplitPane({
1710
+ agents,
1711
+ activeAgentIndex,
1712
+ onSelectAgent,
1713
+ agentOutputs,
1714
+ isProcessing,
1715
+ onSubmit,
1716
+ onCancel,
1717
+ model,
1718
+ role,
1719
+ tokenCount,
1720
+ cost,
1721
+ gitBranch
1722
+ }) {
1723
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: "100%", children: [
1724
+ /* @__PURE__ */ jsx(StatusBar, { model, role, tokenCount, cost, gitBranch }),
1725
+ /* @__PURE__ */ jsx(
1726
+ SplitPanel,
1727
+ {
1728
+ agents,
1729
+ activeAgentIndex,
1730
+ onSelectAgent,
1731
+ agentOutputs
1732
+ }
1733
+ ),
1734
+ /* @__PURE__ */ jsx(InputBar, { onSubmit, isProcessing, onCancel })
1735
+ ] });
1736
+ }
1737
+ function useModel(config, initialModel, initialRole) {
1738
+ const router = useMemo(() => createModelRouter(config), [config]);
1739
+ const [userOverride, setUserOverride] = useState(initialModel);
1740
+ const [currentRole, setCurrentRole] = useState(initialRole);
1741
+ const resolution = useMemo(
1742
+ () => {
1743
+ router.setUserOverride(userOverride);
1744
+ return router.resolve(currentRole);
1745
+ },
1746
+ [router, currentRole, userOverride]
1747
+ );
1748
+ const switchModel = useCallback((modelId) => {
1749
+ setUserOverride(modelId);
1750
+ }, []);
1751
+ const switchRole = useCallback(
1752
+ (role) => {
1753
+ router.setUserOverride(void 0);
1754
+ setCurrentRole(role);
1755
+ setUserOverride(void 0);
1756
+ },
1757
+ [router]
1758
+ );
1759
+ return {
1760
+ resolution,
1761
+ modelId: resolution.modelId,
1762
+ switchModel,
1763
+ switchRole,
1764
+ router
1765
+ };
1766
+ }
1767
+ function formatToolActivity(toolCall) {
1768
+ const args = toolCall.arguments;
1769
+ switch (toolCall.name) {
1770
+ case "read": {
1771
+ const fp = typeof args["file_path"] === "string" ? args["file_path"] : "";
1772
+ const short = fp.split("/").slice(-2).join("/");
1773
+ return `Reading ${short || "file"}`;
1774
+ }
1775
+ case "write": {
1776
+ const fp = typeof args["file_path"] === "string" ? args["file_path"] : "";
1777
+ const short = fp.split("/").slice(-2).join("/");
1778
+ return `Writing ${short || "file"}`;
1779
+ }
1780
+ case "edit": {
1781
+ const fp = typeof args["file_path"] === "string" ? args["file_path"] : "";
1782
+ const short = fp.split("/").slice(-2).join("/");
1783
+ return `Editing ${short || "file"}`;
1784
+ }
1785
+ case "glob": {
1786
+ const pat = typeof args["pattern"] === "string" ? args["pattern"] : "";
1787
+ return `Searching files ${pat}`;
1788
+ }
1789
+ case "grep": {
1790
+ const pat = typeof args["pattern"] === "string" ? args["pattern"] : "";
1791
+ return `Searching for "${pat.length > 30 ? pat.slice(0, 30) + "\u2026" : pat}"`;
1792
+ }
1793
+ case "bash": {
1794
+ const cmd = typeof args["command"] === "string" ? args["command"] : "";
1795
+ const short = cmd.length > 40 ? cmd.slice(0, 40) + "\u2026" : cmd;
1796
+ return `Running ${short}`;
1797
+ }
1798
+ case "web_search":
1799
+ case "webSearch":
1800
+ return "Searching the web";
1801
+ case "web_fetch":
1802
+ case "webFetch":
1803
+ return "Fetching URL";
1804
+ default:
1805
+ return `Calling ${toolCall.name}`;
1806
+ }
1807
+ }
1808
+ function useStream() {
1809
+ const [state, setState] = useState({
1810
+ isStreaming: false,
1811
+ content: "",
1812
+ usage: void 0,
1813
+ error: void 0,
1814
+ activity: void 0,
1815
+ toolCalls: [],
1816
+ startTime: void 0
1817
+ });
1818
+ const cancelRef = useRef(false);
1819
+ const isCancelled = () => cancelRef.current;
1820
+ const startStream = useCallback(
1821
+ async (stream) => {
1822
+ cancelRef.current = false;
1823
+ setState({
1824
+ isStreaming: true,
1825
+ content: "",
1826
+ usage: void 0,
1827
+ error: void 0,
1828
+ activity: void 0,
1829
+ toolCalls: [],
1830
+ startTime: Date.now()
1831
+ });
1832
+ try {
1833
+ for await (const chunk of stream) {
1834
+ if (isCancelled()) break;
1835
+ switch (chunk.type) {
1836
+ case "text":
1837
+ if (chunk.content !== void 0) {
1838
+ const text = chunk.content;
1839
+ setState((prev) => ({
1840
+ ...prev,
1841
+ content: prev.content + text,
1842
+ activity: void 0
1843
+ }));
1844
+ }
1845
+ break;
1846
+ case "tool_call":
1847
+ if (chunk.toolCall !== void 0) {
1848
+ const toolCall = chunk.toolCall;
1849
+ const desc = formatToolActivity(toolCall);
1850
+ const callState = {
1851
+ id: toolCall.name + "-" + Date.now().toString(36),
1852
+ name: toolCall.name,
1853
+ description: desc,
1854
+ status: "executing",
1855
+ startTime: Date.now()
1856
+ };
1857
+ setState((prev) => ({
1858
+ ...prev,
1859
+ activity: desc,
1860
+ toolCalls: [
1861
+ // Mark previous executing calls as success
1862
+ ...prev.toolCalls.map(
1863
+ (tc) => tc.status === "executing" ? {
1864
+ ...tc,
1865
+ status: "success",
1866
+ endTime: Date.now()
1867
+ } : tc
1868
+ ),
1869
+ callState
1870
+ ]
1871
+ }));
1872
+ }
1873
+ break;
1874
+ case "usage":
1875
+ if (chunk.usage) {
1876
+ setState((prev) => ({
1877
+ ...prev,
1878
+ usage: chunk.usage
1879
+ }));
1880
+ }
1881
+ break;
1882
+ case "error":
1883
+ setState((prev) => ({
1884
+ ...prev,
1885
+ error: chunk.error,
1886
+ isStreaming: false,
1887
+ activity: void 0,
1888
+ toolCalls: prev.toolCalls.map(
1889
+ (tc) => tc.status === "executing" ? {
1890
+ ...tc,
1891
+ status: "error",
1892
+ endTime: Date.now()
1893
+ } : tc
1894
+ )
1895
+ }));
1896
+ return;
1897
+ case "done":
1898
+ setState((prev) => ({
1899
+ ...prev,
1900
+ isStreaming: false,
1901
+ usage: chunk.usage ?? prev.usage,
1902
+ activity: void 0,
1903
+ toolCalls: prev.toolCalls.map(
1904
+ (tc) => tc.status === "executing" ? {
1905
+ ...tc,
1906
+ status: "success",
1907
+ endTime: Date.now()
1908
+ } : tc
1909
+ )
1910
+ }));
1911
+ return;
1912
+ }
1913
+ }
1914
+ setState((prev) => ({
1915
+ ...prev,
1916
+ isStreaming: false,
1917
+ activity: void 0,
1918
+ toolCalls: prev.toolCalls.map(
1919
+ (tc) => tc.status === "executing" ? {
1920
+ ...tc,
1921
+ status: "success",
1922
+ endTime: Date.now()
1923
+ } : tc
1924
+ )
1925
+ }));
1926
+ } catch (error) {
1927
+ setState((prev) => ({
1928
+ ...prev,
1929
+ isStreaming: false,
1930
+ error: error instanceof Error ? error.message : String(error),
1931
+ activity: void 0
1932
+ }));
1933
+ }
1934
+ },
1935
+ []
1936
+ );
1937
+ const cancelStream = useCallback(() => {
1938
+ cancelRef.current = true;
1939
+ setState((prev) => ({
1940
+ ...prev,
1941
+ isStreaming: false,
1942
+ toolCalls: prev.toolCalls.map(
1943
+ (tc) => tc.status === "executing" ? {
1944
+ ...tc,
1945
+ status: "cancelled",
1946
+ endTime: Date.now()
1947
+ } : tc
1948
+ )
1949
+ }));
1950
+ }, []);
1951
+ const reset = useCallback(() => {
1952
+ cancelRef.current = true;
1953
+ setState({
1954
+ isStreaming: false,
1955
+ content: "",
1956
+ usage: void 0,
1957
+ error: void 0,
1958
+ activity: void 0,
1959
+ toolCalls: [],
1960
+ startTime: void 0
1961
+ });
1962
+ }, []);
1963
+ return { state, startStream, cancelStream, reset };
1964
+ }
1965
+ function useCost(config) {
1966
+ const trackerRef = useRef(new CostTracker(config));
1967
+ const [totalCost, setTotalCost] = useState("$0.00");
1968
+ const [totalTokens, setTotalTokens] = useState("0");
1969
+ const [isBudgetExceeded, setIsBudgetExceeded] = useState(false);
1970
+ useEffect(() => {
1971
+ const eventBus = getEventBus();
1972
+ const unsubCost = eventBus.on("cost:updated", ({ total }) => {
1973
+ setTotalCost(formatCost(total));
1974
+ const tokens = trackerRef.current.getSessionTokens();
1975
+ setTotalTokens(formatTokenCount(tokens.total));
1976
+ });
1977
+ const unsubExceeded = eventBus.on("cost:exceeded", () => {
1978
+ setIsBudgetExceeded(true);
1979
+ });
1980
+ return () => {
1981
+ unsubCost();
1982
+ unsubExceeded();
1983
+ };
1984
+ }, []);
1985
+ const record = useCallback(
1986
+ (provider, model, inputTokens, outputTokens, role) => {
1987
+ trackerRef.current.record(provider, model, inputTokens, outputTokens, role);
1988
+ },
1989
+ []
1990
+ );
1991
+ return {
1992
+ totalCost,
1993
+ totalTokens,
1994
+ isBudgetExceeded,
1995
+ record,
1996
+ tracker: trackerRef.current
1997
+ };
1998
+ }
1999
+ function usePanel() {
2000
+ const flushIntervalMs = 100;
2001
+ const [agents, setAgentsState] = useState([]);
2002
+ const [activeAgentIndex, setActiveAgentIndex] = useState(0);
2003
+ const [agentOutputs, setAgentOutputs] = useState(/* @__PURE__ */ new Map());
2004
+ const [isSplitPanelActive, setIsSplitPanelActive] = useState(false);
2005
+ const pendingOutputRef = useRef(/* @__PURE__ */ new Map());
2006
+ const flushTimerRef = useRef(void 0);
2007
+ const flushPendingOutput = useCallback(() => {
2008
+ flushTimerRef.current = void 0;
2009
+ if (pendingOutputRef.current.size === 0) {
2010
+ return;
2011
+ }
2012
+ const pending = pendingOutputRef.current;
2013
+ pendingOutputRef.current = /* @__PURE__ */ new Map();
2014
+ startTransition(() => {
2015
+ setAgentOutputs((prev) => {
2016
+ const next = new Map(prev);
2017
+ for (const [agentId, content] of pending.entries()) {
2018
+ const existing = next.get(agentId) ?? "";
2019
+ next.set(agentId, existing + content);
2020
+ }
2021
+ return next;
2022
+ });
2023
+ });
2024
+ }, []);
2025
+ useEffect(() => {
2026
+ return () => {
2027
+ if (flushTimerRef.current !== void 0) {
2028
+ clearTimeout(flushTimerRef.current);
2029
+ }
2030
+ };
2031
+ }, []);
2032
+ const selectAgent = useCallback((index) => {
2033
+ setActiveAgentIndex(index);
2034
+ }, []);
2035
+ const appendOutput = useCallback((agentId, content, options) => {
2036
+ const pending = pendingOutputRef.current;
2037
+ pending.set(agentId, (pending.get(agentId) ?? "") + content);
2038
+ if (options?.immediate === true) {
2039
+ if (flushTimerRef.current !== void 0) {
2040
+ clearTimeout(flushTimerRef.current);
2041
+ }
2042
+ flushPendingOutput();
2043
+ return;
2044
+ }
2045
+ if (flushTimerRef.current === void 0) {
2046
+ flushTimerRef.current = setTimeout(flushPendingOutput, flushIntervalMs);
2047
+ }
2048
+ }, [flushIntervalMs, flushPendingOutput]);
2049
+ const updateAgentStatus = useCallback((agentId, status) => {
2050
+ setAgentsState(
2051
+ (prev) => prev.map(
2052
+ (agent) => agent.config.agentId === agentId ? { ...agent, status } : agent
2053
+ )
2054
+ );
2055
+ }, []);
2056
+ const setAgents = useCallback((newAgents) => {
2057
+ setAgentsState(newAgents);
2058
+ setActiveAgentIndex(0);
2059
+ }, []);
2060
+ const activate = useCallback(() => {
2061
+ setIsSplitPanelActive(true);
2062
+ }, []);
2063
+ const deactivate = useCallback(() => {
2064
+ if (flushTimerRef.current !== void 0) {
2065
+ clearTimeout(flushTimerRef.current);
2066
+ flushTimerRef.current = void 0;
2067
+ }
2068
+ pendingOutputRef.current = /* @__PURE__ */ new Map();
2069
+ setIsSplitPanelActive(false);
2070
+ setAgentsState([]);
2071
+ setAgentOutputs(/* @__PURE__ */ new Map());
2072
+ setActiveAgentIndex(0);
2073
+ }, []);
2074
+ return useMemo(() => ({
2075
+ agents,
2076
+ activeAgentIndex,
2077
+ agentOutputs,
2078
+ isSplitPanelActive,
2079
+ selectAgent,
2080
+ appendOutput,
2081
+ updateAgentStatus,
2082
+ setAgents,
2083
+ activate,
2084
+ deactivate
2085
+ }), [agents, activeAgentIndex, agentOutputs, isSplitPanelActive, selectAgent, appendOutput, updateAgentStatus, setAgents, activate, deactivate]);
2086
+ }
2087
+ function v4Id() {
2088
+ return randomUUID();
2089
+ }
2090
+ var PROVIDER_LABELS = {
2091
+ anthropic: "\u2726 Claude (Anthropic)",
2092
+ openai: "\u2B22 Codex (OpenAI)",
2093
+ google: "\u25C6 Gemini (Google)",
2094
+ kimi: "\u25CE Kimi (Moonshot)"
2095
+ };
2096
+ function ModelSelector({
2097
+ currentModelId,
2098
+ onSelect,
2099
+ onCancel,
2100
+ modelOrder
2101
+ }) {
2102
+ const rows = useMemo(() => {
2103
+ const order = modelOrder ?? {};
2104
+ const result = [];
2105
+ for (const [providerKey, entries] of Object.entries(order)) {
2106
+ result.push({
2107
+ type: "header",
2108
+ label: PROVIDER_LABELS[providerKey] ?? providerKey
2109
+ });
2110
+ for (const entry of entries) {
2111
+ result.push({
2112
+ type: "model",
2113
+ label: entry.label,
2114
+ description: entry.description,
2115
+ modelId: entry.id,
2116
+ isCurrent: entry.id === currentModelId
2117
+ });
2118
+ }
2119
+ }
2120
+ return result;
2121
+ }, [currentModelId]);
2122
+ const selectableIndices = useMemo(() => {
2123
+ const indices = [];
2124
+ for (let i = 0; i < rows.length; i++) {
2125
+ if (rows[i]?.type === "model") indices.push(i);
2126
+ }
2127
+ return indices;
2128
+ }, [rows]);
2129
+ const initialIndex = useMemo(() => {
2130
+ const rowIdx = rows.findIndex(
2131
+ (r) => r.type === "model" && r.modelId === currentModelId
2132
+ );
2133
+ const selectIdx = selectableIndices.indexOf(rowIdx);
2134
+ return selectIdx >= 0 ? selectIdx : 0;
2135
+ }, [rows, selectableIndices, currentModelId]);
2136
+ const [cursor, setCursor] = useState(initialIndex);
2137
+ useInput((_input, key) => {
2138
+ if (key.upArrow) {
2139
+ setCursor(
2140
+ (prev) => prev > 0 ? prev - 1 : selectableIndices.length - 1
2141
+ );
2142
+ } else if (key.downArrow) {
2143
+ setCursor(
2144
+ (prev) => prev < selectableIndices.length - 1 ? prev + 1 : 0
2145
+ );
2146
+ } else if (key.return) {
2147
+ const rowIdx = selectableIndices[cursor];
2148
+ const row = rowIdx !== void 0 ? rows[rowIdx] : void 0;
2149
+ if (row?.modelId) onSelect(row.modelId);
2150
+ } else if (key.escape) {
2151
+ onCancel();
2152
+ }
2153
+ });
2154
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
2155
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
2156
+ /* @__PURE__ */ jsx(Text, { bold: true, color: colors.status.active, children: "Select Model" }),
2157
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
2158
+ " ",
2159
+ "\\u2191\\u2193 navigate \\u00B7 Enter select \\u00B7 Esc cancel"
2160
+ ] })
2161
+ ] }),
2162
+ rows.map((row, idx) => {
2163
+ if (row.type === "header") {
2164
+ return /* @__PURE__ */ jsx(Box, { marginTop: idx > 0 ? 1 : 0, children: /* @__PURE__ */ jsxs(Text, { bold: true, color: colors.status.warning, children: [
2165
+ " ",
2166
+ row.label
2167
+ ] }) }, `header-${idx}`);
2168
+ }
2169
+ const isHighlighted = selectableIndices[cursor] === idx;
2170
+ const currentTag = row.isCurrent ? " (current)" : "";
2171
+ return /* @__PURE__ */ jsxs(Box, { children: [
2172
+ /* @__PURE__ */ jsxs(
2173
+ Text,
2174
+ {
2175
+ color: isHighlighted ? colors.status.success : row.isCurrent ? colors.text.accent : colors.text.primary,
2176
+ bold: isHighlighted,
2177
+ children: [
2178
+ isHighlighted ? "\u25B8 " : " ",
2179
+ row.label.padEnd(30)
2180
+ ]
2181
+ }
2182
+ ),
2183
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
2184
+ " ",
2185
+ row.description,
2186
+ currentTag
2187
+ ] })
2188
+ ] }, row.modelId ?? `row-${idx}`);
2189
+ }),
2190
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
2191
+ " ",
2192
+ "Current: ",
2193
+ currentModelId
2194
+ ] }) })
2195
+ ] });
2196
+ }
2197
+ function formatMethod(method) {
2198
+ switch (method) {
2199
+ case "extended_thinking":
2200
+ return "Extended Thinking";
2201
+ case "reasoning_effort":
2202
+ return "Reasoning Effort";
2203
+ case "thinking_budget":
2204
+ return "Thinking Budget";
2205
+ case "thinking_level":
2206
+ return "Thinking Level";
2207
+ case "thinking_mode":
2208
+ return "Thinking Mode";
2209
+ default:
2210
+ return "Thinking";
2211
+ }
2212
+ }
2213
+ function ThinkingSelector({
2214
+ modelId,
2215
+ modelName,
2216
+ currentValue,
2217
+ onSelect,
2218
+ onBack
2219
+ }) {
2220
+ const config = useMemo(() => getThinkingConfigForModel(modelId), [modelId]);
2221
+ const initialIdx = useMemo(() => {
2222
+ if (!config) return 0;
2223
+ const idx = config.options.findIndex((o) => o.value === currentValue);
2224
+ if (idx >= 0) return idx;
2225
+ const defaultIdx = config.options.findIndex((o) => o.value === config.defaultValue);
2226
+ return Math.max(0, defaultIdx);
2227
+ }, [config, currentValue]);
2228
+ const [cursor, setCursor] = useState(initialIdx);
2229
+ useInput((_input, key) => {
2230
+ if (!config) {
2231
+ if (key.return || key.escape) onBack();
2232
+ return;
2233
+ }
2234
+ if (key.upArrow) {
2235
+ setCursor((prev) => prev > 0 ? prev - 1 : config.options.length - 1);
2236
+ } else if (key.downArrow) {
2237
+ setCursor((prev) => prev < config.options.length - 1 ? prev + 1 : 0);
2238
+ } else if (key.return) {
2239
+ const option = config.options[cursor];
2240
+ if (option) onSelect(option.value);
2241
+ } else if (key.escape) {
2242
+ onBack();
2243
+ }
2244
+ });
2245
+ if (!config) {
2246
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
2247
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
2248
+ "No thinking options available for ",
2249
+ modelName,
2250
+ "."
2251
+ ] }),
2252
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Enter or Esc to continue." })
2253
+ ] });
2254
+ }
2255
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
2256
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
2257
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: formatMethod(config.method) }),
2258
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
2259
+ " Model: ",
2260
+ modelName,
2261
+ " (up/down navigate, Enter select, Esc back)"
2262
+ ] })
2263
+ ] }),
2264
+ config.options.map((option, idx) => {
2265
+ const isHighlighted = cursor === idx;
2266
+ const isCurrent = option.value === currentValue;
2267
+ const currentTag = isCurrent ? " (current)" : "";
2268
+ return /* @__PURE__ */ jsxs(Box, { children: [
2269
+ /* @__PURE__ */ jsxs(Text, { ...isHighlighted ? { color: "green" } : {}, bold: isHighlighted, children: [
2270
+ isHighlighted ? "> " : " ",
2271
+ option.label.padEnd(22)
2272
+ ] }),
2273
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
2274
+ " ",
2275
+ option.description,
2276
+ currentTag
2277
+ ] })
2278
+ ] }, option.value);
2279
+ })
2280
+ ] });
2281
+ }
2282
+ var PROVIDERS = [
2283
+ { label: "Claude", value: "claude", description: "Anthropic \u2014 Claude models" },
2284
+ { label: "Codex", value: "codex", description: "OpenAI \u2014 GPT / Codex models" },
2285
+ { label: "Gemini", value: "gemini", description: "Google \u2014 Gemini models" },
2286
+ { label: "Kimi", value: "kimi", description: "Moonshot \u2014 Kimi models" }
2287
+ ];
2288
+ function LoginSelector({ onSelect, onCancel }) {
2289
+ const [cursor, setCursor] = useState(0);
2290
+ useInput((_input, key) => {
2291
+ if (key.upArrow) {
2292
+ setCursor((prev) => prev > 0 ? prev - 1 : PROVIDERS.length - 1);
2293
+ } else if (key.downArrow) {
2294
+ setCursor((prev) => prev < PROVIDERS.length - 1 ? prev + 1 : 0);
2295
+ } else if (key.return) {
2296
+ const selected = PROVIDERS[cursor];
2297
+ if (selected) onSelect(selected.value);
2298
+ } else if (key.escape) {
2299
+ onCancel();
2300
+ }
2301
+ });
2302
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
2303
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
2304
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Select a provider to log in to" }),
2305
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: " (up/down navigate, Enter select, Esc cancel)" })
2306
+ ] }),
2307
+ PROVIDERS.map((provider, idx) => {
2308
+ const isHighlighted = cursor === idx;
2309
+ return /* @__PURE__ */ jsxs(Box, { children: [
2310
+ /* @__PURE__ */ jsxs(Text, { ...isHighlighted ? { color: "green" } : {}, bold: isHighlighted, children: [
2311
+ isHighlighted ? "> " : " ",
2312
+ provider.label.padEnd(12)
2313
+ ] }),
2314
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
2315
+ " ",
2316
+ provider.description
2317
+ ] })
2318
+ ] }, provider.value);
2319
+ }),
2320
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: " Login will open your browser for authentication." }) })
2321
+ ] });
2322
+ }
2323
+ function SwarmOnboarding({
2324
+ detectedProviders,
2325
+ currentPrimaryProvider,
2326
+ onSelect,
2327
+ onSkip
2328
+ }) {
2329
+ const entries = useMemo(
2330
+ () => detectedProviders.map((provider) => getCliProviderEntry(provider)),
2331
+ [detectedProviders]
2332
+ );
2333
+ const initialCursor = useMemo(() => {
2334
+ if (!currentPrimaryProvider) {
2335
+ return 0;
2336
+ }
2337
+ const currentIndex = detectedProviders.indexOf(currentPrimaryProvider);
2338
+ return currentIndex >= 0 ? currentIndex : 0;
2339
+ }, [currentPrimaryProvider, detectedProviders]);
2340
+ const [cursor, setCursor] = useState(initialCursor);
2341
+ useInput((_input, key) => {
2342
+ if (entries.length === 0) {
2343
+ if (key.return || key.escape) {
2344
+ onSkip();
2345
+ }
2346
+ return;
2347
+ }
2348
+ if (key.upArrow) {
2349
+ setCursor((prev) => prev > 0 ? prev - 1 : entries.length - 1);
2350
+ return;
2351
+ }
2352
+ if (key.downArrow) {
2353
+ setCursor((prev) => prev < entries.length - 1 ? prev + 1 : 0);
2354
+ return;
2355
+ }
2356
+ if (key.return) {
2357
+ const selected = detectedProviders[cursor];
2358
+ if (selected) {
2359
+ onSelect(selected);
2360
+ }
2361
+ return;
2362
+ }
2363
+ if (key.escape && entries.length === 0) {
2364
+ onSkip();
2365
+ }
2366
+ });
2367
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
2368
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
2369
+ /* @__PURE__ */ jsx(Text, { color: colors.status.active, bold: true, children: "Swarm Setup" }),
2370
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "Select the master agent provider for swarm orchestration." })
2371
+ ] }),
2372
+ entries.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2373
+ entries.map((entry, index) => {
2374
+ const isSelected = index === cursor;
2375
+ const isCurrent = currentPrimaryProvider === entry.type;
2376
+ return /* @__PURE__ */ jsxs(Box, { children: [
2377
+ /* @__PURE__ */ jsxs(
2378
+ Text,
2379
+ {
2380
+ color: isSelected ? colors.status.success : colors.text.primary,
2381
+ bold: isSelected,
2382
+ children: [
2383
+ isSelected ? "\u25B8 " : " ",
2384
+ entry.label.padEnd(16)
2385
+ ]
2386
+ }
2387
+ ),
2388
+ /* @__PURE__ */ jsxs(Text, { color: colors.text.muted, children: [
2389
+ entry.description,
2390
+ isCurrent ? " (current)" : ""
2391
+ ] })
2392
+ ] }, entry.type);
2393
+ }),
2394
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
2395
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "Enter sets the master agent. Remaining detected providers become fallbacks." }),
2396
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "\\u2191\\u2193 navigate \xB7 Enter confirm" })
2397
+ ] })
2398
+ ] }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
2399
+ /* @__PURE__ */ jsx(Text, { color: colors.status.warning, children: "No supported native agent CLI was detected." }),
2400
+ /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "Install Claude Code, Codex, Gemini CLI, Kimi CLI, or Ollama, then restart." }),
2401
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.text.muted, children: "Enter or Esc continues without swarm setup." }) })
2402
+ ] })
2403
+ ] });
2404
+ }
2405
+
2406
+ // src/ui/commands/types.ts
2407
+ function addSystemMessage(ctx, content) {
2408
+ ctx.setMessages((prev) => [
2409
+ ...prev,
2410
+ {
2411
+ id: v4Id(),
2412
+ role: "system",
2413
+ content,
2414
+ createdAt: /* @__PURE__ */ new Date()
2415
+ }
2416
+ ]);
2417
+ }
2418
+
2419
+ // src/ui/commands/model-helpers.ts
2420
+ function resolveModelSelection(input) {
2421
+ if (SUPPORTED_MODELS[input]) {
2422
+ return input;
2423
+ }
2424
+ if (/^\d+$/.test(input)) {
2425
+ const index = Number(input);
2426
+ let globalIndex = 1;
2427
+ for (const entries of Object.values(PROVIDER_MODEL_ORDER)) {
2428
+ for (const entry of entries) {
2429
+ if (globalIndex === index) {
2430
+ return entry.id;
2431
+ }
2432
+ globalIndex++;
2433
+ }
2434
+ }
2435
+ }
2436
+ return void 0;
2437
+ }
2438
+ function formatThinkingMethod(method) {
2439
+ switch (method) {
2440
+ case "extended_thinking":
2441
+ return "Extended Thinking";
2442
+ case "reasoning_effort":
2443
+ return "Reasoning Effort";
2444
+ case "thinking_budget":
2445
+ return "Thinking Budget";
2446
+ case "thinking_level":
2447
+ return "Thinking Level";
2448
+ case "thinking_mode":
2449
+ return "Thinking Mode";
2450
+ default:
2451
+ return "Thinking";
2452
+ }
2453
+ }
2454
+
2455
+ // src/ui/commands/team-commands.ts
2456
+ async function handleTeamCommand(args, ctx) {
2457
+ const subcommand = args[0];
2458
+ if (subcommand === "stop") {
2459
+ const cleanup = getActiveTmuxCleanup();
2460
+ if (cleanup) {
2461
+ try {
2462
+ await cleanup();
2463
+ } catch (error) {
2464
+ const errMsg = error instanceof Error ? error.message : String(error);
2465
+ addSystemMessage(ctx, `Warning: tmux cleanup failed (${errMsg}). Session may need manual cleanup.`);
2466
+ }
2467
+ setActiveTmuxCleanup(void 0);
2468
+ }
2469
+ const manager = getActiveTeamManager();
2470
+ const teamName = getActiveTeamName();
2471
+ if (manager && teamName) {
2472
+ try {
2473
+ await manager.deleteTeam(teamName);
2474
+ } catch (error) {
2475
+ const errMsg = error instanceof Error ? error.message : String(error);
2476
+ addSystemMessage(ctx, `Warning: team cleanup failed (${errMsg}). Processes may need manual cleanup.`);
2477
+ }
2478
+ setActiveTeamManager(void 0);
2479
+ }
2480
+ setActiveTeamName(void 0);
2481
+ ctx.panel.deactivate();
2482
+ addSystemMessage(ctx, "Team shut down. All agents stopped. Returned to single-pane mode.");
2483
+ return;
2484
+ }
2485
+ if (subcommand === "list") {
2486
+ try {
2487
+ const { TeamManager } = await import('./team-manager-2VSMALAA.js');
2488
+ const manager = new TeamManager();
2489
+ const teams = manager.listTeams();
2490
+ if (teams.length === 0) {
2491
+ addSystemMessage(ctx, "No active teams.");
2492
+ } else {
2493
+ const lines = teams.map((t) => ` ${t.teamName} \u2014 ${t.members.length} agents (${t.status})`);
2494
+ addSystemMessage(ctx, lines.join("\n"));
2495
+ }
2496
+ } catch (error) {
2497
+ const msg = error instanceof Error ? error.message : String(error);
2498
+ addSystemMessage(ctx, `Failed to list teams: ${msg}`);
2499
+ }
2500
+ return;
2501
+ }
2502
+ addSystemMessage(
2503
+ ctx,
2504
+ 'Usage: /team list | /team stop\nTeams are created automatically from natural language.\nExamples: "Create a team to refactor the auth module"\n "I need agents to review this PR from different angles"'
2505
+ );
2506
+ }
2507
+
2508
+ // src/ui/commands/mcp-commands.ts
2509
+ async function handleMcpCommand(args, ctx) {
2510
+ const subcommand = args[0];
2511
+ if (subcommand === "list") {
2512
+ try {
2513
+ const { MCPServerManager } = await import('./server-manager-THGZBBZB.js');
2514
+ const manager = new MCPServerManager();
2515
+ const connected = manager.getConnectedServers();
2516
+ if (connected.length === 0) {
2517
+ addSystemMessage(ctx, "No MCP servers connected.\nConfigure servers in ~/.aemeathcli/mcp.json");
2518
+ } else {
2519
+ const lines = connected.map((name) => {
2520
+ const status = manager.getServerStatus(name) ?? "unknown";
2521
+ return ` ${name} \u2014 ${status}`;
2522
+ });
2523
+ addSystemMessage(ctx, `MCP Servers:
2524
+ ${lines.join("\n")}`);
2525
+ }
2526
+ } catch (error) {
2527
+ const msg = error instanceof Error ? error.message : String(error);
2528
+ addSystemMessage(ctx, `Failed to list MCP servers: ${msg}`);
2529
+ }
2530
+ return;
2531
+ }
2532
+ if (subcommand === "add") {
2533
+ const name = args[1];
2534
+ if (!name) {
2535
+ addSystemMessage(ctx, "Usage: /mcp add <server-name>\n\nExample:\n /mcp add my-server");
2536
+ return;
2537
+ }
2538
+ addSystemMessage(
2539
+ ctx,
2540
+ `To add MCP server "${name}", add this to ~/.aemeathcli/mcp.json:
2541
+
2542
+ {
2543
+ "mcpServers": {
2544
+ "${name}": {
2545
+ "command": "npx",
2546
+ "args": ["-y", "@your-org/${name}-server"],
2547
+ "env": {}
2548
+ }
2549
+ }
2550
+ }
2551
+
2552
+ Then restart AemeathCLI. Use /mcp list to verify the connection.`
2553
+ );
2554
+ return;
2555
+ }
2556
+ addSystemMessage(ctx, "Usage: /mcp list | /mcp add <name>");
2557
+ }
2558
+
2559
+ // src/ui/commands/skill-commands.ts
2560
+ async function handleSkillCommand(args, ctx) {
2561
+ const subcommand = args[0];
2562
+ if (subcommand === "list") {
2563
+ try {
2564
+ const { SkillRegistry } = await import('./registry-LRURZVUL.js');
2565
+ const { findProjectRoot } = await import('./pathResolver-UVAB2FCW.js');
2566
+ const registry = new SkillRegistry();
2567
+ await registry.initialize(findProjectRoot());
2568
+ const skills = registry.listAll();
2569
+ if (skills.length === 0) {
2570
+ addSystemMessage(ctx, "No skills found.\nAdd skills in ~/.agents/skills/, ~/.aemeathcli/skills/, .agents/skills/, or .aemeathcli/skills/");
2571
+ } else {
2572
+ const lines = skills.map((s) => ` $${s.name.padEnd(16)} ${s.description} [${s.source}]`);
2573
+ addSystemMessage(ctx, `Available Skills:
2574
+ ${lines.join("\n")}`);
2575
+ }
2576
+ } catch (error) {
2577
+ const msg = error instanceof Error ? error.message : String(error);
2578
+ addSystemMessage(ctx, `Failed to list skills: ${msg}`);
2579
+ }
2580
+ return;
2581
+ }
2582
+ addSystemMessage(ctx, "Usage: /skill list\nInvoke a skill with $skill-name (e.g., $review, $commit, $plan)");
2583
+ }
2584
+ async function handleSkillInvocation(input, setMessages) {
2585
+ const parts = input.trim().split(/\s+/);
2586
+ const trigger = parts[0] ?? "";
2587
+ const skillName = trigger.replace(/^\$/, "");
2588
+ if (!skillName) {
2589
+ setMessages((prev) => [
2590
+ ...prev,
2591
+ { id: v4Id(), role: "system", content: "Usage: $skill-name [args]\nType /skill list to see available skills.", createdAt: /* @__PURE__ */ new Date() }
2592
+ ]);
2593
+ return;
2594
+ }
2595
+ setMessages((prev) => [
2596
+ ...prev,
2597
+ { id: v4Id(), role: "user", content: input, createdAt: /* @__PURE__ */ new Date() }
2598
+ ]);
2599
+ try {
2600
+ const { SkillRegistry } = await import('./registry-LRURZVUL.js');
2601
+ const { SkillExecutor } = await import('./executor-FTABX2AW.js');
2602
+ const { findProjectRoot } = await import('./pathResolver-UVAB2FCW.js');
2603
+ const registry = new SkillRegistry();
2604
+ await registry.initialize(findProjectRoot());
2605
+ const executor = new SkillExecutor(registry);
2606
+ const result = await executor.activateByTrigger(trigger);
2607
+ if (!result.success) {
2608
+ setMessages((prev) => [
2609
+ ...prev,
2610
+ { id: v4Id(), role: "system", content: result.errorMessage ?? `Skill not found: "${skillName}"
2611
+ Type /skill list to see available skills.`, createdAt: /* @__PURE__ */ new Date() }
2612
+ ]);
2613
+ return;
2614
+ }
2615
+ const content = executor.getActiveSkillContent();
2616
+ const warningText = result.warnings && result.warnings.length > 0 ? `
2617
+ Warnings: ${result.warnings.join(", ")}` : "";
2618
+ setMessages((prev) => [
2619
+ ...prev,
2620
+ { id: v4Id(), role: "system", content: `Skill "$${skillName}" activated.${warningText}
2621
+ ${content ? content.slice(0, 500) : ""}`, createdAt: /* @__PURE__ */ new Date() }
2622
+ ]);
2623
+ } catch (error) {
2624
+ const msg = error instanceof Error ? error.message : String(error);
2625
+ setMessages((prev) => [
2626
+ ...prev,
2627
+ { id: v4Id(), role: "system", content: `Skill error: ${msg}`, createdAt: /* @__PURE__ */ new Date() }
2628
+ ]);
2629
+ }
2630
+ }
2631
+
2632
+ // src/ui/commands/login-commands.ts
2633
+ async function handleLoginSlashCommand(args, ctx) {
2634
+ const subcommand = args[0];
2635
+ if (subcommand === "status") {
2636
+ try {
2637
+ const { getAuthStatusRecords, formatCompactAuthStatusLine } = await import('./auth-status-JQJOKUPF.js');
2638
+ const records = await getAuthStatusRecords();
2639
+ const lines = records.map((record) => formatCompactAuthStatusLine(record));
2640
+ addSystemMessage(ctx, lines.join("\n"));
2641
+ } catch (error) {
2642
+ const msg = error instanceof Error ? error.message : String(error);
2643
+ addSystemMessage(ctx, `Failed to get auth status: ${msg}`);
2644
+ }
2645
+ return;
2646
+ }
2647
+ if (subcommand === "logout") {
2648
+ const provider = args[1];
2649
+ if (!provider) {
2650
+ addSystemMessage(ctx, "Usage: /login logout <provider>\nProviders: claude, codex, gemini, kimi");
2651
+ return;
2652
+ }
2653
+ try {
2654
+ const loginMod = await loadLoginModuleForSlash(provider);
2655
+ await loginMod.logout();
2656
+ addSystemMessage(ctx, `Logged out of ${provider}`);
2657
+ } catch (error) {
2658
+ const msg = error instanceof Error ? error.message : String(error);
2659
+ addSystemMessage(ctx, `Logout failed: ${msg}`);
2660
+ }
2661
+ return;
2662
+ }
2663
+ ctx.setSelectionMode({ type: "login" });
2664
+ }
2665
+ async function loadLoginModuleForSlash(provider) {
2666
+ switch (provider) {
2667
+ case "claude": {
2668
+ const mod = await import('./claude-login-AIFIWTYF.js');
2669
+ return new mod.ClaudeLogin();
2670
+ }
2671
+ case "codex": {
2672
+ const mod = await import('./codex-login-LW5X7GAM.js');
2673
+ return new mod.CodexLogin();
2674
+ }
2675
+ case "gemini": {
2676
+ const mod = await import('./gemini-login-TST454MX.js');
2677
+ return new mod.GeminiLogin();
2678
+ }
2679
+ case "kimi": {
2680
+ const mod = await import('./kimi-login-3IGVOBJI.js');
2681
+ return new mod.KimiLogin();
2682
+ }
2683
+ default:
2684
+ throw new Error(`Unknown provider: ${provider}`);
2685
+ }
2686
+ }
2687
+
2688
+ // src/ui/commands/config-commands.ts
2689
+ async function handleConfigSlashCommand(args, ctx) {
2690
+ const subcommand = args[0];
2691
+ if (subcommand === "get") {
2692
+ const key = args[1];
2693
+ try {
2694
+ const { ConfigStore } = await import('./config-store-NF56VHFU.js');
2695
+ const store = new ConfigStore();
2696
+ const cfg = store.loadGlobal();
2697
+ if (!key) {
2698
+ addSystemMessage(ctx, JSON.stringify(cfg, null, 2));
2699
+ } else {
2700
+ const value = getNestedConfigValue(cfg, key);
2701
+ if (value === void 0) {
2702
+ addSystemMessage(ctx, `Key not found: ${key}`);
2703
+ } else {
2704
+ addSystemMessage(ctx, `${key} = ${JSON.stringify(value, null, 2)}`);
2705
+ }
2706
+ }
2707
+ } catch (error) {
2708
+ const msg = error instanceof Error ? error.message : String(error);
2709
+ addSystemMessage(ctx, `Failed to read config: ${msg}`);
2710
+ }
2711
+ return;
2712
+ }
2713
+ if (subcommand === "set") {
2714
+ const key = args[1];
2715
+ const value = args.slice(2).join(" ");
2716
+ if (!key || !value) {
2717
+ addSystemMessage(ctx, "Usage: /config set <key> <value>");
2718
+ return;
2719
+ }
2720
+ try {
2721
+ const { ConfigStore } = await import('./config-store-NF56VHFU.js');
2722
+ const store = new ConfigStore();
2723
+ const cfg = store.loadGlobal();
2724
+ let parsedValue;
2725
+ try {
2726
+ parsedValue = JSON.parse(value);
2727
+ } catch {
2728
+ parsedValue = value;
2729
+ }
2730
+ setNestedConfigValue(cfg, key, parsedValue);
2731
+ store.saveGlobal(cfg);
2732
+ addSystemMessage(ctx, `Set ${key} = ${JSON.stringify(parsedValue)}`);
2733
+ } catch (error) {
2734
+ const msg = error instanceof Error ? error.message : String(error);
2735
+ addSystemMessage(ctx, `Failed to set config: ${msg}`);
2736
+ }
2737
+ return;
2738
+ }
2739
+ addSystemMessage(ctx, "Usage: /config get [key] | /config set <key> <value>");
2740
+ }
2741
+ function getNestedConfigValue(obj, path) {
2742
+ const keys = path.split(".");
2743
+ let current = obj;
2744
+ for (const key of keys) {
2745
+ if (current === null || current === void 0 || typeof current !== "object") return void 0;
2746
+ current = current[key];
2747
+ }
2748
+ return current;
2749
+ }
2750
+ function setNestedConfigValue(obj, path, value) {
2751
+ const keys = path.split(".");
2752
+ let current = obj;
2753
+ for (let i = 0; i < keys.length - 1; i++) {
2754
+ const key = keys[i];
2755
+ if (!key) continue;
2756
+ if (typeof current[key] !== "object" || current[key] === null) current[key] = {};
2757
+ current = current[key];
2758
+ }
2759
+ const lastKey = keys[keys.length - 1];
2760
+ if (lastKey) current[lastKey] = value;
2761
+ }
2762
+
2763
+ // src/ui/commands/history-commands.ts
2764
+ async function handleHistoryCommand(ctx) {
2765
+ try {
2766
+ const { SqliteStore } = await import('./sqlite-store-7OECRTXM.js');
2767
+ const { ConversationStore } = await import('./conversation-store-7GRDQZD2.js');
2768
+ const db = new SqliteStore();
2769
+ db.open();
2770
+ const store = new ConversationStore(db);
2771
+ const conversations = store.listConversations(ctx.projectRoot);
2772
+ db.close();
2773
+ if (conversations.length === 0) {
2774
+ addSystemMessage(ctx, "No conversation history for this project.");
2775
+ return;
2776
+ }
2777
+ const lines = conversations.slice(0, 20).map((c, i) => {
2778
+ const date = new Date(c.createdAt).toLocaleDateString();
2779
+ const model = c.defaultModel ?? "unknown";
2780
+ return ` ${String(i + 1).padStart(2)}. ${date} ${model.padEnd(20)} ${c.id.slice(0, 8)}\u2026`;
2781
+ });
2782
+ addSystemMessage(
2783
+ ctx,
2784
+ `Conversations in this project (${conversations.length} total):
2785
+ ${lines.join("\n")}
2786
+
2787
+ Use /resume <number> or /resume <id> to load.`
2788
+ );
2789
+ } catch (error) {
2790
+ const msg = error instanceof Error ? error.message : String(error);
2791
+ addSystemMessage(ctx, `Failed to load history: ${msg}`);
2792
+ }
2793
+ }
2794
+ async function handleResumeCommand(arg, ctx) {
2795
+ if (!arg) {
2796
+ addSystemMessage(ctx, "Usage: /resume <number> or /resume <conversation-id>\nUse /history to see past conversations.");
2797
+ return;
2798
+ }
2799
+ try {
2800
+ const { SqliteStore } = await import('./sqlite-store-7OECRTXM.js');
2801
+ const { ConversationStore } = await import('./conversation-store-7GRDQZD2.js');
2802
+ const db = new SqliteStore();
2803
+ db.open();
2804
+ const store = new ConversationStore(db);
2805
+ let conversationId;
2806
+ const num = parseInt(arg, 10);
2807
+ if (!isNaN(num) && num > 0) {
2808
+ const conversations = store.listConversations(ctx.projectRoot);
2809
+ const target = conversations[num - 1];
2810
+ if (!target) {
2811
+ db.close();
2812
+ addSystemMessage(ctx, `Conversation #${num} not found. Use /history to see available.`);
2813
+ return;
2814
+ }
2815
+ conversationId = target.id;
2816
+ } else {
2817
+ const conversations = store.listConversations(ctx.projectRoot);
2818
+ const match = conversations.find((c) => c.id.startsWith(arg));
2819
+ if (!match) {
2820
+ db.close();
2821
+ addSystemMessage(ctx, `No conversation matching "${arg}". Use /history to see available.`);
2822
+ return;
2823
+ }
2824
+ conversationId = match.id;
2825
+ }
2826
+ const storedMessages = store.getMessages(conversationId);
2827
+ db.close();
2828
+ if (storedMessages.length === 0) {
2829
+ addSystemMessage(ctx, "Conversation found but contains no messages.");
2830
+ return;
2831
+ }
2832
+ const restored = storedMessages.map((m) => ({
2833
+ id: v4Id(),
2834
+ role: m.role,
2835
+ content: m.content,
2836
+ model: m.model ?? void 0,
2837
+ provider: m.provider ?? void 0,
2838
+ createdAt: new Date(m.createdAt)
2839
+ }));
2840
+ ctx.setMessages(restored);
2841
+ addSystemMessage(ctx, `Resumed conversation (${restored.length} messages loaded).`);
2842
+ } catch (error) {
2843
+ const msg = error instanceof Error ? error.message : String(error);
2844
+ addSystemMessage(ctx, `Failed to resume: ${msg}`);
2845
+ }
2846
+ }
2847
+
2848
+ // src/ui/commands/slash-router.ts
2849
+ async function handleInternalCommand(input, switchModel, switchRole, ctx) {
2850
+ const parts = input.trim().split(/\s+/);
2851
+ const command = parts[0];
2852
+ const args = parts.slice(1);
2853
+ const arg = args[0];
2854
+ switch (command) {
2855
+ case "/help": {
2856
+ const helpLines = SLASH_COMMANDS.map((cmd) => ` ${cmd.command.padEnd(17)}${cmd.description}`).join("\n");
2857
+ addSystemMessage(ctx, helpLines);
2858
+ break;
2859
+ }
2860
+ case "/model": {
2861
+ if (arg) {
2862
+ const resolvedId = resolveModelSelection(arg);
2863
+ if (!resolvedId) {
2864
+ addSystemMessage(ctx, `Unknown model: ${arg}`);
2865
+ break;
2866
+ }
2867
+ const info = SUPPORTED_MODELS[resolvedId];
2868
+ if (!info) {
2869
+ addSystemMessage(ctx, `Unknown model: ${arg}`);
2870
+ break;
2871
+ }
2872
+ switchModel(resolvedId);
2873
+ const thinkingCfg = getThinkingConfigForModel(resolvedId);
2874
+ if (thinkingCfg) {
2875
+ const isValid = thinkingCfg.options.some((o) => o.value === ctx.thinkingValue);
2876
+ if (!isValid) ctx.setThinkingValue(thinkingCfg.defaultValue);
2877
+ }
2878
+ addSystemMessage(ctx, `Switched to model: ${info.name}`);
2879
+ } else {
2880
+ ctx.setSelectionMode({ type: "model" });
2881
+ }
2882
+ break;
2883
+ }
2884
+ case "/role": {
2885
+ if (arg) {
2886
+ const validRoles = ["planning", "coding", "review", "testing", "bugfix", "documentation"];
2887
+ if (validRoles.includes(arg)) {
2888
+ switchRole(arg);
2889
+ addSystemMessage(ctx, `Switched to role: ${arg}`);
2890
+ } else {
2891
+ addSystemMessage(ctx, `Unknown role: ${arg}
2892
+ Valid roles: ${validRoles.join(", ")}`);
2893
+ }
2894
+ } else {
2895
+ addSystemMessage(ctx, `Current role: ${ctx.resolution.role ?? "default"}`);
2896
+ }
2897
+ break;
2898
+ }
2899
+ case "/cost":
2900
+ addSystemMessage(ctx, `Session cost: ${ctx.totalCost} | Tokens: ${ctx.totalTokens}`);
2901
+ break;
2902
+ case "/clear":
2903
+ ctx.setMessages([]);
2904
+ break;
2905
+ case "/compact":
2906
+ ctx.setMessages((prev) => {
2907
+ if (prev.length <= 4) return prev;
2908
+ const systemMsgs = prev.filter((m) => m.role === "system");
2909
+ const recent = prev.filter((m) => m.role !== "system").slice(-4);
2910
+ return [...systemMsgs, ...recent];
2911
+ });
2912
+ addSystemMessage(ctx, `Context compacted \u2014 kept last 4 messages. Use /clear to remove all.`);
2913
+ break;
2914
+ case "/team":
2915
+ await handleTeamCommand(args, ctx);
2916
+ break;
2917
+ case "/mcp":
2918
+ await handleMcpCommand(args, ctx);
2919
+ break;
2920
+ case "/skill":
2921
+ await handleSkillCommand(args, ctx);
2922
+ break;
2923
+ case "/panel": {
2924
+ const layout = arg;
2925
+ if (!layout) {
2926
+ addSystemMessage(
2927
+ ctx,
2928
+ "Swarm layout is fixed to hub-and-spoke:\n- master agent on the left half\n- worker agents stacked on the right\nUse Shift+Tab to enter swarm mode, then Tab/Ctrl+N to focus agents."
2929
+ );
2930
+ } else {
2931
+ addSystemMessage(ctx, `Panel layout overrides are disabled. Active swarm layout remains hub-spoke (master left, workers right). Ignored: ${layout}`);
2932
+ }
2933
+ break;
2934
+ }
2935
+ case "/login":
2936
+ await handleLoginSlashCommand(args, ctx);
2937
+ break;
2938
+ case "/config":
2939
+ await handleConfigSlashCommand(args, ctx);
2940
+ break;
2941
+ case "/launch":
2942
+ addSystemMessage(
2943
+ ctx,
2944
+ "Swarm orchestration now lives inside the default TUI.\n\nUse Shift+Tab to switch into swarm mode, then describe the work you want the team to handle.\nThe configured master agent will sponsor the team and own the left pane."
2945
+ );
2946
+ break;
2947
+ case "/history":
2948
+ await handleHistoryCommand(ctx);
2949
+ break;
2950
+ case "/resume":
2951
+ await handleResumeCommand(arg, ctx);
2952
+ break;
2953
+ case "/quit":
2954
+ case "/exit": {
2955
+ const { getActiveTeamManager: getActiveTeamManager2, getActiveTeamName: getActiveTeamName2, getActiveTmuxCleanup: getActiveTmuxCleanup2 } = await import('./team-state-HZNVMQHT.js');
2956
+ const teamCleanup = getActiveTmuxCleanup2();
2957
+ if (teamCleanup) {
2958
+ try {
2959
+ await teamCleanup();
2960
+ } catch {
2961
+ }
2962
+ }
2963
+ const mgr = getActiveTeamManager2();
2964
+ const name = getActiveTeamName2();
2965
+ if (mgr && name) {
2966
+ try {
2967
+ await mgr.deleteTeam(name);
2968
+ } catch {
2969
+ }
2970
+ }
2971
+ process.exit(0);
2972
+ break;
2973
+ }
2974
+ default:
2975
+ addSystemMessage(ctx, `Unknown command: ${command}. Type /help for available commands.`);
2976
+ }
2977
+ }
2978
+
2979
+ // src/ui/conversation-persistence.ts
2980
+ var convDbRef;
2981
+ async function persistMessages(projectRoot, userMsg, assistantMsg, model, provider) {
2982
+ try {
2983
+ const { SqliteStore } = await import('./sqlite-store-7OECRTXM.js');
2984
+ const { ConversationStore } = await import('./conversation-store-7GRDQZD2.js');
2985
+ if (!convDbRef) {
2986
+ const db = new SqliteStore();
2987
+ db.open();
2988
+ const store2 = new ConversationStore(db);
2989
+ const conv = store2.createConversation(projectRoot, model);
2990
+ convDbRef = { store: store2, convId: conv.id };
2991
+ }
2992
+ const { store, convId } = convDbRef;
2993
+ store.addMessage({
2994
+ conversationId: convId,
2995
+ role: "user",
2996
+ content: userMsg.content
2997
+ });
2998
+ store.addMessage({
2999
+ conversationId: convId,
3000
+ role: "assistant",
3001
+ model,
3002
+ provider,
3003
+ content: assistantMsg.content
3004
+ });
3005
+ } catch (error) {
3006
+ const { logger } = await import('./logger-KGHUQ4VE.js');
3007
+ const msg = error instanceof Error ? error.message : String(error);
3008
+ logger.warn({ error: msg }, "Conversation persistence failed");
3009
+ }
3010
+ }
3011
+
3012
+ // src/ui/team-design.ts
3013
+ var TEAM_DESIGN_SYSTEM_PROMPT = `You are an expert team architect for an AI-powered CLI coding tool. Your job is to analyze a user's request and design an optimal agent team to accomplish it.
3014
+
3015
+ You MUST respond with ONLY a JSON array (no markdown, no explanation, no code fences). Each element represents one agent with these exact fields:
3016
+ - "name": string \u2014 PascalCase name describing the agent's function (e.g. "ProjectManager", "TypeScriptDeveloper", "SecurityAuditor")
3017
+ - "agentType": string \u2014 short role type (e.g. "lead", "developer", "reviewer", "researcher", "designer", "architect", "auditor", "tester")
3018
+ - "model": string \u2014 one of the available models (provided in the user message)
3019
+ - "role": string \u2014 one of: "planning", "coding", "review", "testing", "bugfix", "documentation"
3020
+ - "taskPrompt": string \u2014 detailed, specific instructions for this agent. Include: what to focus on, what files/areas to examine, what deliverables are expected, and what tools to use. This must be tailored to the user's actual request, NOT generic.
3021
+
3022
+ Guidelines for team design:
3023
+ - Use the MINIMUM number of agents needed to accomplish the task (typically 2-5, max 8)
3024
+ - Assign the most capable models (opus, gpt-5.2, gemini pro) to critical roles like planning and review
3025
+ - Assign efficient models (sonnet, haiku, flash) to implementation, testing, and documentation
3026
+ - Every team MUST have at least one agent with role "coding" to do actual implementation
3027
+ - For complex tasks, include a planner/lead agent and a reviewer agent
3028
+ - If only one provider's models are available, use those models for all agents
3029
+ - Each agent's taskPrompt must be highly specific to the user's request \u2014 never use generic instructions
3030
+ - Agent names should reflect their specific responsibility in this task
3031
+ `;
3032
+ var VALID_ROLES = /* @__PURE__ */ new Set([
3033
+ "planning",
3034
+ "coding",
3035
+ "review",
3036
+ "testing",
3037
+ "bugfix",
3038
+ "documentation"
3039
+ ]);
3040
+ function parseLLMTeamDesign(response, availableModels, fallbackModel) {
3041
+ let jsonStr = response.trim();
3042
+ const fenceMatch = /```(?:json)?\s*\n?([\s\S]*?)\n?```/.exec(jsonStr);
3043
+ if (fenceMatch?.[1] !== void 0) {
3044
+ jsonStr = fenceMatch[1].trim();
3045
+ }
3046
+ const arrayStart = jsonStr.indexOf("[");
3047
+ const arrayEnd = jsonStr.lastIndexOf("]");
3048
+ if (arrayStart === -1 || arrayEnd === -1 || arrayEnd <= arrayStart) {
3049
+ throw new Error("LLM response does not contain a valid JSON array for team design");
3050
+ }
3051
+ jsonStr = jsonStr.slice(arrayStart, arrayEnd + 1);
3052
+ let parsed;
3053
+ try {
3054
+ parsed = JSON.parse(jsonStr);
3055
+ } catch {
3056
+ throw new Error("Failed to parse LLM team design as JSON");
3057
+ }
3058
+ if (!Array.isArray(parsed) || parsed.length === 0) {
3059
+ throw new Error("LLM team design must be a non-empty array");
3060
+ }
3061
+ const availableSet = new Set(availableModels);
3062
+ const specs = [];
3063
+ for (const item of parsed) {
3064
+ if (typeof item !== "object" || item === null) continue;
3065
+ const record = item;
3066
+ const name = typeof record["name"] === "string" && record["name"].length > 0 ? record["name"] : `Agent${specs.length + 1}`;
3067
+ const agentType = typeof record["agentType"] === "string" && record["agentType"].length > 0 ? record["agentType"] : "developer";
3068
+ const rawModel = typeof record["model"] === "string" ? record["model"] : "";
3069
+ const rawRole = typeof record["role"] === "string" ? record["role"] : "coding";
3070
+ const taskPrompt = typeof record["taskPrompt"] === "string" ? record["taskPrompt"] : "";
3071
+ const model = availableSet.has(rawModel) ? rawModel : fallbackModel;
3072
+ const role = VALID_ROLES.has(rawRole) ? rawRole : "coding";
3073
+ specs.push({ name, agentType, model, role, taskPrompt });
3074
+ }
3075
+ if (specs.length === 0) {
3076
+ throw new Error("LLM team design produced no valid agent specifications");
3077
+ }
3078
+ return specs.slice(0, 8);
3079
+ }
3080
+ function buildTeamDesignUserPrompt(userRequest, availableModels) {
3081
+ const modelList = availableModels.map((id) => {
3082
+ const info = SUPPORTED_MODELS[id];
3083
+ if (!info) return `- ${id}`;
3084
+ return `- ${id} (${info.provider}, ${info.name})`;
3085
+ }).join("\n");
3086
+ return `Available models:
3087
+ ${modelList}
3088
+
3089
+ User request:
3090
+ ${userRequest}
3091
+
3092
+ Design the agent team. Respond with ONLY a JSON array.`;
3093
+ }
3094
+ function resolveMasterProviderPriority(swarmConfig, installedProviders) {
3095
+ const configuredProviders = [
3096
+ ...swarmConfig.primaryMasterProvider ? [swarmConfig.primaryMasterProvider] : [],
3097
+ ...swarmConfig.fallbackMasterProviders
3098
+ ];
3099
+ const prioritized = configuredProviders.filter((provider) => installedProviders.includes(provider));
3100
+ const remaining = installedProviders.filter((provider) => !prioritized.includes(provider));
3101
+ return [...prioritized, ...remaining];
3102
+ }
3103
+ function getAvailableModelsForProviders(providers) {
3104
+ const allowedProviders = new Set(
3105
+ providers.map((provider) => getCliProviderEntry(provider).provider)
3106
+ );
3107
+ return Object.keys(SUPPORTED_MODELS).filter((modelId) => {
3108
+ const info = SUPPORTED_MODELS[modelId];
3109
+ return info !== void 0 && allowedProviders.has(info.provider);
3110
+ });
3111
+ }
3112
+ function pickLeadModel(config, prioritizedProviders, availableModels) {
3113
+ for (const provider of prioritizedProviders) {
3114
+ const providerName = getCliProviderEntry(provider).provider;
3115
+ const planningCandidates = [
3116
+ config.roles.planning?.primary,
3117
+ ...config.roles.planning?.fallback ?? []
3118
+ ].filter((modelId) => modelId !== void 0);
3119
+ const preferredPlanningModel = planningCandidates.find((modelId) => {
3120
+ const info = SUPPORTED_MODELS[modelId];
3121
+ return info?.provider === providerName && availableModels.includes(modelId);
3122
+ });
3123
+ if (preferredPlanningModel) {
3124
+ return preferredPlanningModel;
3125
+ }
3126
+ const firstAvailableModel = availableModels.find((modelId) => {
3127
+ const info = SUPPORTED_MODELS[modelId];
3128
+ return info?.provider === providerName;
3129
+ });
3130
+ if (firstAvailableModel) {
3131
+ return firstAvailableModel;
3132
+ }
3133
+ }
3134
+ return availableModels[0];
3135
+ }
3136
+ function normalizeLeadAgentSpec(specs, masterModel) {
3137
+ const leadSpec = specs.find((spec) => spec.agentType === "lead") ?? specs.find((spec) => spec.role === "planning") ?? specs[0];
3138
+ if (!leadSpec) {
3139
+ return specs;
3140
+ }
3141
+ const normalizedLead = {
3142
+ ...leadSpec,
3143
+ name: leadSpec.name,
3144
+ agentType: "lead",
3145
+ model: masterModel,
3146
+ role: "planning",
3147
+ taskPrompt: `${leadSpec.taskPrompt}
3148
+
3149
+ You are the sponsoring master agent. Own planning, delegation, and final synthesis.`
3150
+ };
3151
+ const workerSpecs = specs.filter((spec) => spec.name !== leadSpec.name);
3152
+ return [normalizedLead, ...workerSpecs];
3153
+ }
3154
+ function writeAgentLauncherScript(provider, model, promptFile, launcherFile, projectRoot, shellEscapeFn, writeFileSyncFn) {
3155
+ if (process.platform === "win32") {
3156
+ return writeWindowsLauncherScript(
3157
+ provider,
3158
+ model,
3159
+ promptFile,
3160
+ launcherFile,
3161
+ projectRoot,
3162
+ writeFileSyncFn
3163
+ );
3164
+ }
3165
+ const cliProvider = getCliProviderForModelProvider(provider);
3166
+ if (cliProvider) {
3167
+ const startCommand = getCliProviderEntry(cliProvider).startCommand(model);
3168
+ const script2 = [
3169
+ "#!/bin/bash",
3170
+ `cd '${shellEscapeFn(projectRoot)}' || exit 1`,
3171
+ `${startCommand} "$(cat '${shellEscapeFn(promptFile)}')"`
3172
+ ].join("\n");
3173
+ writeFileSyncFn(launcherFile, script2, { mode: 493 });
3174
+ return `bash '${shellEscapeFn(launcherFile)}'`;
3175
+ }
3176
+ const script = [
3177
+ "#!/bin/bash",
3178
+ `cd '${shellEscapeFn(projectRoot)}' || exit 1`,
3179
+ `export AEMEATHCLI_PROMPT_FILE='${shellEscapeFn(promptFile)}'`,
3180
+ `'${shellEscapeFn(process.execPath)}' '${shellEscapeFn(process.argv[1] ?? "aemeathcli")}' --model ${model}`
3181
+ ].join("\n");
3182
+ writeFileSyncFn(launcherFile, script, { mode: 493 });
3183
+ return `bash '${shellEscapeFn(launcherFile)}'`;
3184
+ }
3185
+ function writeWindowsLauncherScript(provider, model, promptFile, launcherFile, projectRoot, writeFileSyncFn) {
3186
+ const ps1File = launcherFile.replace(/\.[^.]+$/, ".ps1");
3187
+ const cliProvider = getCliProviderForModelProvider(provider);
3188
+ if (cliProvider) {
3189
+ const startCommand = getCliProviderEntry(cliProvider).startCommand(model);
3190
+ const script2 = [
3191
+ `Set-Location -Path '${projectRoot.replace(/'/g, "''")}'`,
3192
+ `$prompt = Get-Content -Path '${promptFile.replace(/'/g, "''")}' -Raw`,
3193
+ `& ${startCommand} $prompt`
3194
+ ].join("\r\n");
3195
+ writeFileSyncFn(ps1File, script2);
3196
+ return `powershell -ExecutionPolicy Bypass -File "${ps1File}"`;
3197
+ }
3198
+ const script = [
3199
+ `Set-Location -Path '${projectRoot.replace(/'/g, "''")}'`,
3200
+ `$env:AEMEATHCLI_PROMPT_FILE = '${promptFile.replace(/'/g, "''")}'`,
3201
+ `& '${process.execPath.replace(/'/g, "''")}' '${(process.argv[1] ?? "aemeathcli").replace(/'/g, "''")}' --model ${model}`
3202
+ ].join("\r\n");
3203
+ writeFileSyncFn(ps1File, script);
3204
+ return `powershell -ExecutionPolicy Bypass -File "${ps1File}"`;
3205
+ }
3206
+
3207
+ // src/ui/team-launcher.ts
3208
+ function sysMsg(setMessages, content) {
3209
+ setMessages((prev) => [
3210
+ ...prev,
3211
+ { id: v4Id(), role: "system", content, createdAt: /* @__PURE__ */ new Date() }
3212
+ ]);
3213
+ }
3214
+ async function handlePromptBasedTeamCreation(input, setMessages, panel, getRegistry, currentModelId, config, swarmConfig) {
3215
+ const teamName = `team-${Date.now()}`;
3216
+ setMessages((prev) => [
3217
+ ...prev,
3218
+ { id: v4Id(), role: "user", content: input, createdAt: /* @__PURE__ */ new Date() },
3219
+ { id: v4Id(), role: "system", content: "Analyzing your request to design the agent team...", createdAt: /* @__PURE__ */ new Date() }
3220
+ ]);
3221
+ try {
3222
+ const registry = await getRegistry();
3223
+ const { detectInstalledProviders } = await import('./detect-providers-QICJ5U3R.js');
3224
+ const installedClis = detectInstalledProviders();
3225
+ const prioritizedMasterProviders = resolveMasterProviderPriority(swarmConfig, installedClis);
3226
+ const availableModels = getAvailableModelsForProviders(installedClis);
3227
+ if (availableModels.length === 0) {
3228
+ sysMsg(setMessages, "No AI CLI tools detected. Install at least one: claude, codex, gemini, kimi, or ollama.");
3229
+ return;
3230
+ }
3231
+ const masterLeadModel = pickLeadModel(config, prioritizedMasterProviders, availableModels);
3232
+ if (masterLeadModel === void 0) {
3233
+ return;
3234
+ }
3235
+ const designModel = registry.hasModel(currentModelId) ? currentModelId : registry.hasModel(masterLeadModel) ? masterLeadModel : void 0;
3236
+ if (!designModel) {
3237
+ sysMsg(setMessages, "Swarm team design needs at least one authenticated chat provider. Run `aemeathcli auth login` or configure an API key, then try again.");
3238
+ return;
3239
+ }
3240
+ const designProvider = registry.getForModel(designModel);
3241
+ const primaryMasterLabel = prioritizedMasterProviders[0] ? getCliProviderEntry(prioritizedMasterProviders[0]).label : "current configuration";
3242
+ const userPrompt = `${buildTeamDesignUserPrompt(input, availableModels)}
3243
+
3244
+ Master-agent provider priority:
3245
+ ${prioritizedMasterProviders.map((provider) => `- ${getCliProviderEntry(provider).label}`).join("\n")}
3246
+
3247
+ The sponsoring lead agent must use ${primaryMasterLabel} when possible.`;
3248
+ const DESIGN_TIMEOUT_MS = 6e4;
3249
+ sysMsg(setMessages, `Designing team with ${designModel}...`);
3250
+ const designStream = designProvider.stream({
3251
+ model: designModel,
3252
+ messages: [{ id: v4Id(), role: "user", content: userPrompt, createdAt: /* @__PURE__ */ new Date() }],
3253
+ system: TEAM_DESIGN_SYSTEM_PROMPT,
3254
+ maxTokens: 4e3
3255
+ });
3256
+ let designResponse = "";
3257
+ const designResult = await Promise.race([
3258
+ (async () => {
3259
+ for await (const chunk of designStream) {
3260
+ if (chunk.type === "text" && chunk.content) designResponse += chunk.content;
3261
+ if (chunk.type === "error" && chunk.error) throw new Error(`Design stream error: ${chunk.error}`);
3262
+ }
3263
+ return designResponse;
3264
+ })(),
3265
+ new Promise((_resolve, reject) => {
3266
+ setTimeout(() => {
3267
+ reject(new Error(`Team design timed out after ${DESIGN_TIMEOUT_MS / 1e3}s. Check your API credentials and try again.`));
3268
+ }, DESIGN_TIMEOUT_MS);
3269
+ })
3270
+ ]);
3271
+ designResponse = designResult;
3272
+ const teamMasterModel = availableModels.includes(currentModelId) ? currentModelId : masterLeadModel;
3273
+ const agentSpecs = normalizeLeadAgentSpec(
3274
+ parseLLMTeamDesign(designResponse, availableModels, designModel),
3275
+ teamMasterModel
3276
+ );
3277
+ const projectRoot = process.cwd();
3278
+ const isWindows = process.platform === "win32";
3279
+ const isWindowsTerminal = isWindows && typeof process.env["WT_SESSION"] === "string" && process.env["WT_SESSION"].length > 0;
3280
+ if (isWindows && !isWindowsTerminal) {
3281
+ await launchInProcess(
3282
+ agentSpecs,
3283
+ input,
3284
+ teamName,
3285
+ config,
3286
+ panel,
3287
+ setMessages,
3288
+ projectRoot
3289
+ );
3290
+ return void 0;
3291
+ }
3292
+ const fs = await import('fs');
3293
+ const path = await import('path');
3294
+ const os = await import('os');
3295
+ const { execa: execaPane } = await import('execa');
3296
+ const boardDir = path.join(process.cwd(), ".aemeathcli", "team-board");
3297
+ fs.mkdirSync(boardDir, { recursive: true });
3298
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "aemeathcli-team-"));
3299
+ const shellEscape = (s) => s.replace(/'/gu, "'\\''");
3300
+ const [leadSpec, ...workerSpecs] = agentSpecs;
3301
+ if (!leadSpec) return;
3302
+ const teamManifest = {
3303
+ teamName,
3304
+ task: input,
3305
+ boardDir,
3306
+ leadAgent: leadSpec.name,
3307
+ agents: agentSpecs.map((s) => ({
3308
+ name: s.name,
3309
+ agentType: s.agentType,
3310
+ model: s.model,
3311
+ role: s.role,
3312
+ outputFile: path.join(boardDir, `${s.name}.md`)
3313
+ })),
3314
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
3315
+ };
3316
+ fs.writeFileSync(path.join(boardDir, "team-manifest.json"), JSON.stringify(teamManifest, null, 2), "utf-8");
3317
+ const teamRoster = agentSpecs.map((s) => ` - ${s.name} (${s.agentType}, ${s.model}) \u2014 role: ${s.role}`).join("\n");
3318
+ const workerCommands = [];
3319
+ for (const spec of workerSpecs) {
3320
+ const outputFile = path.join(boardDir, `${spec.name}.md`);
3321
+ const promptFile = path.join(tempDir, `${spec.name}.txt`);
3322
+ const prompt = [
3323
+ `# Team Role: ${spec.name}`,
3324
+ `Type: ${spec.agentType} | Model: ${spec.model} | Role: ${spec.role}`,
3325
+ "",
3326
+ "## Your Task",
3327
+ spec.taskPrompt,
3328
+ "",
3329
+ "## Team Context",
3330
+ `You are part of a ${agentSpecs.length}-agent team working collaboratively.`,
3331
+ `Each agent has a specific domain. Do NOT overlap with other agents' responsibilities.`,
3332
+ "",
3333
+ "### Team Members:",
3334
+ teamRoster,
3335
+ "",
3336
+ "## Shared Workspace",
3337
+ `Team board directory: ${boardDir}`,
3338
+ `Your output file: ${outputFile}`,
3339
+ `Team manifest: ${path.join(boardDir, "team-manifest.json")}`,
3340
+ "",
3341
+ "## Coordination Protocol",
3342
+ `1. Write ALL your findings, analysis, and deliverables to your output file: ${outputFile}`,
3343
+ `2. You can read other agents' output files in ${boardDir}/ to check their progress and avoid duplication.`,
3344
+ `3. Focus on YOUR specific domain. Reference other agents' work when relevant to your analysis.`,
3345
+ `4. Read and analyze source files in the project directory to complete your task.`,
3346
+ `5. Be thorough and specific. Include file paths, line numbers, and code snippets in your findings.`,
3347
+ "",
3348
+ "## Coordination with Lead",
3349
+ `The team lead is ${leadSpec.name}. Check their coordination plan at: ${path.join(boardDir, "coordinator.md")}`,
3350
+ `After completing your work, the lead agent will read your output and synthesize findings.`,
3351
+ "",
3352
+ "## User's Original Request",
3353
+ input
3354
+ ].join("\n");
3355
+ fs.writeFileSync(promptFile, prompt, "utf-8");
3356
+ const modelInfo = SUPPORTED_MODELS[spec.model];
3357
+ const provider = modelInfo?.provider ?? "anthropic";
3358
+ const launcherFile = path.join(tempDir, `${spec.name}-launch.sh`);
3359
+ const cmd = writeAgentLauncherScript(
3360
+ provider,
3361
+ spec.model,
3362
+ promptFile,
3363
+ launcherFile,
3364
+ projectRoot,
3365
+ shellEscape,
3366
+ fs.writeFileSync
3367
+ );
3368
+ workerCommands.push({ name: spec.name, command: cmd });
3369
+ }
3370
+ const leadOutputFile = path.join(boardDir, `${leadSpec.name}.md`);
3371
+ const leadCoordinationTask = [
3372
+ `I am the team coordinator (${leadSpec.name}, ${leadSpec.model}).`,
3373
+ "",
3374
+ leadSpec.taskPrompt,
3375
+ "",
3376
+ `## My Responsibilities`,
3377
+ `1. Break down the user's request into clear subtasks for each team member.`,
3378
+ `2. Write my coordination plan and task assignments to: ${path.join(boardDir, "coordinator.md")}`,
3379
+ `3. After completing my own analysis, read other agents' output files in ${boardDir}/ to check progress.`,
3380
+ `4. Synthesize findings from all agents into a final team summary at: ${path.join(boardDir, "SUMMARY.md")}`,
3381
+ `5. Flag any conflicts, gaps, or overlaps between agents' work.`,
3382
+ "",
3383
+ `## Team Members Working in Parallel Panes`,
3384
+ ...workerSpecs.map((s) => `- ${s.name} (${s.model}): writing to ${path.join(boardDir, s.name + ".md")}`),
3385
+ "",
3386
+ `## My Output File: ${leadOutputFile}`,
3387
+ "",
3388
+ `## User's Original Request`,
3389
+ input,
3390
+ "",
3391
+ `Start by reading the codebase and writing my coordination plan to ${path.join(boardDir, "coordinator.md")}.`
3392
+ ].join("\n");
3393
+ const leadPromptFile = path.join(tempDir, `${leadSpec.name}.txt`);
3394
+ const leadLauncherFile = path.join(tempDir, `${leadSpec.name}-launch.sh`);
3395
+ fs.writeFileSync(leadPromptFile, leadCoordinationTask, "utf-8");
3396
+ const leadCommand = writeAgentLauncherScript(
3397
+ SUPPORTED_MODELS[leadSpec.model]?.provider ?? "anthropic",
3398
+ leadSpec.model,
3399
+ leadPromptFile,
3400
+ leadLauncherFile,
3401
+ projectRoot,
3402
+ shellEscape,
3403
+ fs.writeFileSync
3404
+ );
3405
+ const allPaneCommands = [{ name: leadSpec.name, command: leadCommand }, ...workerCommands];
3406
+ const formatAgentLines = (lead) => agentSpecs.map(
3407
+ (spec) => spec.name === lead ? ` ${spec.name} (${spec.model}) \u2014 ${spec.role} [LEAD \u2014 this pane]` : ` ${spec.name} (${spec.model}) \u2014 ${spec.role}`
3408
+ );
3409
+ const isITerm2 = process.platform === "darwin" && process.env["TERM_PROGRAM"] === "iTerm.app";
3410
+ if (isITerm2) {
3411
+ return await launchITerm2(
3412
+ agentSpecs,
3413
+ leadSpec,
3414
+ workerCommands,
3415
+ teamName,
3416
+ tempDir,
3417
+ boardDir,
3418
+ shellEscape,
3419
+ fs,
3420
+ path,
3421
+ execaPane,
3422
+ setMessages,
3423
+ formatAgentLines,
3424
+ leadCoordinationTask
3425
+ );
3426
+ }
3427
+ const isGhostty = process.platform === "darwin" && process.env["TERM_PROGRAM"] === "ghostty";
3428
+ if (isGhostty) {
3429
+ return await launchGhostty(
3430
+ agentSpecs,
3431
+ leadSpec,
3432
+ workerCommands,
3433
+ teamName,
3434
+ tempDir,
3435
+ boardDir,
3436
+ fs,
3437
+ path,
3438
+ execaPane,
3439
+ setMessages,
3440
+ formatAgentLines,
3441
+ leadCoordinationTask
3442
+ );
3443
+ }
3444
+ const isTerminalApp = process.platform === "darwin" && process.env["TERM_PROGRAM"] === "Apple_Terminal";
3445
+ if (isTerminalApp) {
3446
+ return await launchTerminalApp(
3447
+ agentSpecs,
3448
+ leadSpec,
3449
+ workerCommands,
3450
+ teamName,
3451
+ tempDir,
3452
+ boardDir,
3453
+ fs,
3454
+ path,
3455
+ execaPane,
3456
+ setMessages,
3457
+ formatAgentLines,
3458
+ leadCoordinationTask
3459
+ );
3460
+ }
3461
+ if (isWindowsTerminal) {
3462
+ return await launchWindowsTerminal(
3463
+ agentSpecs,
3464
+ leadSpec,
3465
+ workerCommands,
3466
+ teamName,
3467
+ tempDir,
3468
+ boardDir,
3469
+ fs,
3470
+ execaPane,
3471
+ setMessages,
3472
+ formatAgentLines,
3473
+ leadCoordinationTask,
3474
+ projectRoot
3475
+ );
3476
+ }
3477
+ const { TmuxManager } = await import('./tmux-manager-57QCUVHU.js');
3478
+ const tmux = new TmuxManager();
3479
+ const tmuxAvailable = await tmux.isAvailable();
3480
+ if (tmuxAvailable) {
3481
+ const insideTmux = typeof process.env["TMUX"] === "string" && process.env["TMUX"].length > 0;
3482
+ if (insideTmux) {
3483
+ return await launchTmuxInSession(
3484
+ agentSpecs,
3485
+ leadSpec,
3486
+ workerCommands,
3487
+ teamName,
3488
+ tempDir,
3489
+ boardDir,
3490
+ fs,
3491
+ execaPane,
3492
+ setMessages,
3493
+ formatAgentLines,
3494
+ leadCoordinationTask
3495
+ );
3496
+ }
3497
+ return await launchTmuxNewSession(
3498
+ agentSpecs,
3499
+ teamName,
3500
+ tempDir,
3501
+ boardDir,
3502
+ allPaneCommands,
3503
+ tmux,
3504
+ fs,
3505
+ setMessages,
3506
+ formatAgentLines,
3507
+ leadSpec,
3508
+ leadCoordinationTask
3509
+ );
3510
+ }
3511
+ await launchInProcess(
3512
+ agentSpecs,
3513
+ input,
3514
+ teamName,
3515
+ config,
3516
+ panel,
3517
+ setMessages,
3518
+ projectRoot
3519
+ );
3520
+ return void 0;
3521
+ } catch (error) {
3522
+ const msg = error instanceof Error ? error.message : String(error);
3523
+ sysMsg(setMessages, `Failed to create team: ${msg}`);
3524
+ return void 0;
3525
+ }
3526
+ }
3527
+ async function launchITerm2(agentSpecs, leadSpec, workerCommands, teamName, tempDir, boardDir, shellEscape, fs, path, execaPane, setMessages, formatAgentLines, leadCoordinationTask) {
3528
+ sysMsg(setMessages, `Designed ${agentSpecs.length}-agent team. Creating iTerm2 split panes...`);
3529
+ const asEscape = (s) => s.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"');
3530
+ const scriptLines = [];
3531
+ scriptLines.push('tell application "iTerm2"');
3532
+ scriptLines.push(" tell current window");
3533
+ scriptLines.push(" set leaderSession to current session of current tab");
3534
+ for (const [i, agent] of workerCommands.entries()) {
3535
+ const prevVar = i === 0 ? "leaderSession" : `agent${i - 1}`;
3536
+ const curVar = `agent${i}`;
3537
+ const splitDir = i === 0 ? "vertically" : "horizontally";
3538
+ scriptLines.push(` tell ${prevVar}`);
3539
+ scriptLines.push(` set ${curVar} to (split ${splitDir} with default profile)`);
3540
+ scriptLines.push(" end tell");
3541
+ scriptLines.push(` tell ${curVar}`);
3542
+ scriptLines.push(` set name to "${asEscape(agent.name)}"`);
3543
+ scriptLines.push(` write text "${asEscape(agent.command)}"`);
3544
+ scriptLines.push(" end tell");
3545
+ }
3546
+ scriptLines.push(" select leaderSession");
3547
+ scriptLines.push(" end tell");
3548
+ scriptLines.push("end tell");
3549
+ const scriptFile = path.join(tempDir, "create-panes.applescript");
3550
+ fs.writeFileSync(scriptFile, scriptLines.join("\n"), "utf-8");
3551
+ try {
3552
+ await execaPane("osascript", [scriptFile]);
3553
+ } catch (scriptErr) {
3554
+ const errMsg = scriptErr instanceof Error ? scriptErr.message : String(scriptErr);
3555
+ sysMsg(setMessages, `Failed to create iTerm2 panes: ${errMsg.slice(0, 200)}`);
3556
+ return;
3557
+ }
3558
+ setActiveTeamName(teamName);
3559
+ setActiveTeamManager(void 0);
3560
+ setActiveTmuxCleanup(async () => {
3561
+ try {
3562
+ const { execFileSync } = await import('child_process');
3563
+ execFileSync("pkill", ["-f", tempDir], { stdio: "ignore" });
3564
+ } catch {
3565
+ }
3566
+ try {
3567
+ fs.rmSync(tempDir, { recursive: true, force: true });
3568
+ fs.rmSync(boardDir, { recursive: true, force: true });
3569
+ } catch {
3570
+ }
3571
+ });
3572
+ const agentLines = formatAgentLines(leadSpec.name);
3573
+ sysMsg(
3574
+ setMessages,
3575
+ `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
3576
+ ${workerCommands.length} worker panes in iTerm2 + lead coordinating here.
3577
+ ${agentLines.join("\n")}
3578
+ /team stop to shut down all agents.`
3579
+ );
3580
+ return leadCoordinationTask;
3581
+ }
3582
+ async function launchGhostty(agentSpecs, leadSpec, workerCommands, teamName, tempDir, boardDir, fs, path, execaPane, setMessages, formatAgentLines, leadCoordinationTask) {
3583
+ sysMsg(setMessages, `Designed ${agentSpecs.length}-agent team. Creating Ghostty split panes...`);
3584
+ const asEscape = (s) => s.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"');
3585
+ const scriptLines = [];
3586
+ scriptLines.push('tell application "Ghostty" to activate');
3587
+ scriptLines.push("delay 0.5");
3588
+ scriptLines.push('tell application "System Events"');
3589
+ for (const [i, agent] of workerCommands.entries()) {
3590
+ if (i === 0) {
3591
+ scriptLines.push(' keystroke "d" using {command down}');
3592
+ } else {
3593
+ scriptLines.push(' keystroke "d" using {command down, shift down}');
3594
+ }
3595
+ scriptLines.push(" delay 1.0");
3596
+ const escapedCmd = asEscape(agent.command);
3597
+ scriptLines.push(` keystroke "${escapedCmd}"`);
3598
+ scriptLines.push(" delay 0.2");
3599
+ scriptLines.push(" keystroke return");
3600
+ scriptLines.push(" delay 0.5");
3601
+ }
3602
+ if (workerCommands.length > 0) {
3603
+ for (let i = 0; i < workerCommands.length; i++) {
3604
+ scriptLines.push(" key code 123 using {command down, option down}");
3605
+ scriptLines.push(" delay 0.2");
3606
+ }
3607
+ }
3608
+ scriptLines.push("end tell");
3609
+ const scriptFile = path.join(tempDir, "create-panes.applescript");
3610
+ fs.writeFileSync(scriptFile, scriptLines.join("\n"), "utf-8");
3611
+ try {
3612
+ await execaPane("osascript", [scriptFile]);
3613
+ } catch (scriptErr) {
3614
+ const errMsg = scriptErr instanceof Error ? scriptErr.message : String(scriptErr);
3615
+ sysMsg(
3616
+ setMessages,
3617
+ `Failed to create Ghostty panes: ${errMsg.slice(0, 200)}
3618
+ Ensure macOS accessibility permissions are granted and Ghostty uses default split keybindings (Cmd+D = new_split:right, Cmd+Shift+D = new_split:down).`
3619
+ );
3620
+ return;
3621
+ }
3622
+ setActiveTeamName(teamName);
3623
+ setActiveTeamManager(void 0);
3624
+ setActiveTmuxCleanup(async () => {
3625
+ try {
3626
+ const { execFileSync } = await import('child_process');
3627
+ execFileSync("pkill", ["-f", tempDir], { stdio: "ignore" });
3628
+ } catch {
3629
+ }
3630
+ try {
3631
+ fs.rmSync(tempDir, { recursive: true, force: true });
3632
+ fs.rmSync(boardDir, { recursive: true, force: true });
3633
+ } catch {
3634
+ }
3635
+ });
3636
+ const agentLines = formatAgentLines(leadSpec.name);
3637
+ sysMsg(
3638
+ setMessages,
3639
+ `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
3640
+ ${workerCommands.length} worker panes in Ghostty + lead coordinating here.
3641
+ ${agentLines.join("\n")}
3642
+ Keybindings:
3643
+ Cmd+Opt+Arrows Switch pane
3644
+ Cmd+Shift+Enter Zoom pane
3645
+ Cmd+Ctrl+= Equalize splits
3646
+ /team stop to shut down all agents.`
3647
+ );
3648
+ return leadCoordinationTask;
3649
+ }
3650
+ async function launchTerminalApp(agentSpecs, leadSpec, workerCommands, teamName, tempDir, boardDir, fs, path, execaPane, setMessages, formatAgentLines, leadCoordinationTask) {
3651
+ sysMsg(setMessages, `Designed ${agentSpecs.length}-agent team. Creating Terminal.app split panes...`);
3652
+ const asEscape = (s) => s.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"');
3653
+ const scriptLines = [];
3654
+ scriptLines.push('tell application "Terminal" to activate');
3655
+ scriptLines.push("delay 0.5");
3656
+ scriptLines.push('tell application "System Events"');
3657
+ for (const agent of workerCommands) {
3658
+ scriptLines.push(' keystroke "d" using {command down}');
3659
+ scriptLines.push(" delay 1.0");
3660
+ const escapedCmd = asEscape(agent.command);
3661
+ scriptLines.push(` keystroke "${escapedCmd}"`);
3662
+ scriptLines.push(" delay 0.2");
3663
+ scriptLines.push(" keystroke return");
3664
+ scriptLines.push(" delay 0.5");
3665
+ }
3666
+ scriptLines.push("end tell");
3667
+ const scriptFile = path.join(tempDir, "create-panes.applescript");
3668
+ fs.writeFileSync(scriptFile, scriptLines.join("\n"), "utf-8");
3669
+ try {
3670
+ await execaPane("osascript", [scriptFile]);
3671
+ } catch (scriptErr) {
3672
+ const errMsg = scriptErr instanceof Error ? scriptErr.message : String(scriptErr);
3673
+ sysMsg(
3674
+ setMessages,
3675
+ `Failed to create Terminal.app panes: ${errMsg.slice(0, 200)}
3676
+ Ensure macOS accessibility permissions are granted for Terminal.app.`
3677
+ );
3678
+ return;
3679
+ }
3680
+ setActiveTeamName(teamName);
3681
+ setActiveTeamManager(void 0);
3682
+ setActiveTmuxCleanup(async () => {
3683
+ try {
3684
+ const { execFileSync } = await import('child_process');
3685
+ execFileSync("pkill", ["-f", tempDir], { stdio: "ignore" });
3686
+ } catch {
3687
+ }
3688
+ try {
3689
+ fs.rmSync(tempDir, { recursive: true, force: true });
3690
+ fs.rmSync(boardDir, { recursive: true, force: true });
3691
+ } catch {
3692
+ }
3693
+ });
3694
+ const agentLines = formatAgentLines(leadSpec.name);
3695
+ sysMsg(
3696
+ setMessages,
3697
+ `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
3698
+ ${workerCommands.length} worker panes in Terminal.app + lead coordinating here.
3699
+ ${agentLines.join("\n")}
3700
+ Click the lead pane to switch back. Shift+Cmd+D to close a split pane.
3701
+ /team stop to shut down all agents.`
3702
+ );
3703
+ return leadCoordinationTask;
3704
+ }
3705
+ async function launchWindowsTerminal(agentSpecs, leadSpec, workerCommands, teamName, tempDir, boardDir, fs, execaPane, setMessages, formatAgentLines, leadCoordinationTask, projectRoot) {
3706
+ sysMsg(setMessages, `Designed ${agentSpecs.length}-agent team. Creating Windows Terminal split panes...`);
3707
+ for (const [i, agent] of workerCommands.entries()) {
3708
+ const splitDir = i === 0 ? "-V" : "-H";
3709
+ const args = ["-w", "0", "sp", splitDir];
3710
+ if (i === 0) args.push("-s", "0.5");
3711
+ args.push("-d", projectRoot, "--title", agent.name);
3712
+ args.push("cmd", "/c", agent.command);
3713
+ try {
3714
+ await execaPane("wt", args);
3715
+ } catch (err) {
3716
+ const errMsg = err instanceof Error ? err.message : String(err);
3717
+ sysMsg(setMessages, `Failed to create WT pane for ${agent.name}: ${errMsg.slice(0, 200)}`);
3718
+ }
3719
+ }
3720
+ try {
3721
+ await execaPane("wt", ["-w", "0", "mf", "first"]);
3722
+ } catch {
3723
+ }
3724
+ setActiveTeamName(teamName);
3725
+ setActiveTeamManager(void 0);
3726
+ setActiveTmuxCleanup(async () => {
3727
+ try {
3728
+ fs.rmSync(tempDir, { recursive: true, force: true });
3729
+ fs.rmSync(boardDir, { recursive: true, force: true });
3730
+ } catch {
3731
+ }
3732
+ });
3733
+ const agentLines = formatAgentLines(leadSpec.name);
3734
+ sysMsg(
3735
+ setMessages,
3736
+ `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
3737
+ ${workerCommands.length} worker panes in Windows Terminal + lead coordinating here.
3738
+ ${agentLines.join("\n")}
3739
+ Keybindings:
3740
+ Alt+Arrow Switch pane
3741
+ Alt+Shift+Arrow Resize pane
3742
+ /team stop to shut down all agents.`
3743
+ );
3744
+ return leadCoordinationTask;
3745
+ }
3746
+ async function launchTmuxInSession(agentSpecs, leadSpec, workerCommands, teamName, tempDir, boardDir, fs, execaPane, setMessages, formatAgentLines, leadCoordinationTask) {
3747
+ sysMsg(setMessages, `Designed ${agentSpecs.length}-agent team. Creating tmux split panes...`);
3748
+ const currentResult = await execaPane("tmux", ["display-message", "-p", "#{pane_id}"]);
3749
+ const leaderPaneId = currentResult.stdout.trim();
3750
+ const agentPaneIds = [];
3751
+ for (const [i, agent] of workerCommands.entries()) {
3752
+ const splitResult = await execaPane("tmux", [
3753
+ "split-window",
3754
+ i === 0 ? "-h" : "-v",
3755
+ "-P",
3756
+ "-F",
3757
+ "#{pane_id}"
3758
+ ]);
3759
+ const newPaneId = splitResult.stdout.trim();
3760
+ agentPaneIds.push(newPaneId);
3761
+ await execaPane("tmux", ["send-keys", "-t", newPaneId, agent.command, "Enter"]);
3762
+ }
3763
+ if (workerCommands.length > 0) {
3764
+ try {
3765
+ await execaPane("tmux", ["select-layout", "main-vertical"]);
3766
+ } catch {
3767
+ }
3768
+ }
3769
+ try {
3770
+ await execaPane("tmux", ["select-pane", "-t", leaderPaneId]);
3771
+ } catch {
3772
+ }
3773
+ setActiveTeamName(teamName);
3774
+ setActiveTeamManager(void 0);
3775
+ setActiveTmuxCleanup(async () => {
3776
+ const { execa: ex } = await import('execa');
3777
+ for (const pid of agentPaneIds) {
3778
+ try {
3779
+ await ex("tmux", ["kill-pane", "-t", pid]);
3780
+ } catch {
3781
+ }
3782
+ }
3783
+ try {
3784
+ fs.rmSync(tempDir, { recursive: true, force: true });
3785
+ fs.rmSync(boardDir, { recursive: true, force: true });
3786
+ } catch {
3787
+ }
3788
+ });
3789
+ const agentLines = formatAgentLines(leadSpec.name);
3790
+ sysMsg(
3791
+ setMessages,
3792
+ `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
3793
+ ${workerCommands.length} worker panes in tmux + lead coordinating here.
3794
+ ${agentLines.join("\n")}
3795
+ /team stop to shut down all agents.`
3796
+ );
3797
+ return leadCoordinationTask;
3798
+ }
3799
+ async function launchTmuxNewSession(agentSpecs, teamName, tempDir, boardDir, allPaneCommands, tmux, fs, setMessages, formatAgentLines, leadSpec, leadCoordinationTask) {
3800
+ sysMsg(setMessages, `Designed ${agentSpecs.length}-agent team. Opening tmux split-panel view...`);
3801
+ const sessionName = await tmux.createSession(teamName);
3802
+ const paneConfigs = agentSpecs.map((spec, i) => ({
3803
+ paneId: `pane-${i}`,
3804
+ agentName: spec.name,
3805
+ model: spec.model,
3806
+ role: spec.role,
3807
+ title: `${spec.name} (${spec.model})`
3808
+ }));
3809
+ const layoutConfig = {
3810
+ layout: "hub-spoke",
3811
+ panes: paneConfigs,
3812
+ maxPanes: paneConfigs.length
3813
+ };
3814
+ await tmux.createPanes(layoutConfig);
3815
+ for (const [i, agent] of allPaneCommands.entries()) {
3816
+ await tmux.sendCommand(`pane-${i}`, agent.command);
3817
+ }
3818
+ setActiveTeamName(teamName);
3819
+ setActiveTeamManager(void 0);
3820
+ setActiveTmuxCleanup(async () => {
3821
+ await tmux.destroy();
3822
+ try {
3823
+ fs.rmSync(tempDir, { recursive: true, force: true });
3824
+ fs.rmSync(boardDir, { recursive: true, force: true });
3825
+ } catch {
3826
+ }
3827
+ });
3828
+ sysMsg(
3829
+ setMessages,
3830
+ `Attaching to tmux session "${sessionName}" with ${agentSpecs.length} agents\u2026
3831
+
3832
+ Inside tmux:
3833
+ Ctrl+B \u2192/\u2190/\u2191/\u2193 Switch pane
3834
+ Ctrl+B d Detach (return to aemeath)
3835
+ Ctrl+B z Zoom pane fullscreen`
3836
+ );
3837
+ const { execFileSync } = await import('child_process');
3838
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
3839
+ process.stdin.setRawMode(false);
3840
+ }
3841
+ process.stdin.pause();
3842
+ try {
3843
+ execFileSync("tmux", ["attach-session", "-t", sessionName], { stdio: "inherit" });
3844
+ } catch {
3845
+ }
3846
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
3847
+ process.stdin.setRawMode(true);
3848
+ }
3849
+ process.stdin.resume();
3850
+ const agentLines = formatAgentLines(leadSpec.name);
3851
+ sysMsg(
3852
+ setMessages,
3853
+ `Detached from tmux. Agents may still be running.
3854
+
3855
+ Agents:
3856
+ ${agentLines.join("\n")}
3857
+
3858
+ Keybindings (inside tmux):
3859
+ Ctrl+B \u2192 \u2190 \u2191 \u2193 Switch between panes
3860
+ Ctrl+B d Detach (return here)
3861
+ Ctrl+B z Zoom active pane (fullscreen toggle)
3862
+ Ctrl+B x Close active pane
3863
+
3864
+ Re-attach: tmux attach -t ${sessionName}
3865
+ /team stop Shut down all agents and kill session`
3866
+ );
3867
+ return leadCoordinationTask;
3868
+ }
3869
+ async function launchInProcess(agentSpecs, input, teamName, config, panel, setMessages, projectRoot) {
3870
+ sysMsg(
3871
+ setMessages,
3872
+ `Designed ${agentSpecs.length}-agent team. Starting agents (in-process mode)\u2026
3873
+
3874
+ Keybindings:
3875
+ Tab Switch to next agent
3876
+ Ctrl+1-${agentSpecs.length} Jump to agent N
3877
+ /team stop Exit team mode`
3878
+ );
3879
+ const agentDefinitions = agentSpecs.map((spec) => {
3880
+ const modelInfo = SUPPORTED_MODELS[spec.model];
3881
+ const provider = modelInfo?.provider ?? "anthropic";
3882
+ return { name: spec.name, agentType: spec.agentType, model: spec.model, provider, role: spec.role };
3883
+ });
3884
+ const { TeamManager: TM } = await import('./team-manager-2VSMALAA.js');
3885
+ const manager = new TM();
3886
+ setActiveTeamManager(manager);
3887
+ setActiveTeamName(teamName);
3888
+ setActiveTmuxCleanup(void 0);
3889
+ const agentAllowedPaths = Array.from(/* @__PURE__ */ new Set([projectRoot, ...config.permissions.allowedPaths]));
3890
+ const teamConfig = manager.createTeam(teamName, {
3891
+ description: `Agent team for: ${input.slice(0, 120)}`,
3892
+ agents: agentDefinitions,
3893
+ agentEnv: {
3894
+ AEMEATHCLI_TOOL_PROJECT_ROOT: projectRoot,
3895
+ AEMEATHCLI_TOOL_WORKING_DIRECTORY: projectRoot,
3896
+ AEMEATHCLI_TOOL_PERMISSION_MODE: config.permissions.mode,
3897
+ AEMEATHCLI_TOOL_ALLOWED_PATHS: JSON.stringify(agentAllowedPaths),
3898
+ AEMEATHCLI_TOOL_BLOCKED_COMMANDS: JSON.stringify(config.permissions.blockedCommands)
3899
+ }
3900
+ });
3901
+ const agentStates = teamConfig.members.map((member) => ({
3902
+ config: member,
3903
+ status: "idle"
3904
+ }));
3905
+ panel.setAgents(agentStates);
3906
+ panel.activate();
3907
+ for (const member of teamConfig.members) {
3908
+ panel.appendOutput(member.agentId, `[${member.name}] Starting (${member.model})...
3909
+ `, { immediate: true });
3910
+ }
3911
+ manager.onAgentMessages(teamName, (_agentName, method, params) => {
3912
+ if (method === "agent.streamChunk") {
3913
+ const agentId = typeof params["agentId"] === "string" ? params["agentId"] : "";
3914
+ const content = typeof params["content"] === "string" ? params["content"] : "";
3915
+ if (agentId && content) panel.appendOutput(agentId, content);
3916
+ }
3917
+ if (method === "agent.taskUpdate") {
3918
+ const agentId = typeof params["agentId"] === "string" ? params["agentId"] : "";
3919
+ const rawStatus = typeof params["status"] === "string" ? params["status"] : "";
3920
+ if (agentId && rawStatus) {
3921
+ const statusMap = { in_progress: "active", completed: "idle" };
3922
+ const mapped = statusMap[rawStatus];
3923
+ if (mapped) panel.updateAgentStatus(agentId, mapped);
3924
+ }
3925
+ }
3926
+ });
3927
+ try {
3928
+ await manager.startAgents(teamName);
3929
+ } catch (startErr) {
3930
+ const errMsg = startErr instanceof Error ? startErr.message : String(startErr);
3931
+ sysMsg(setMessages, `Warning: Some agents failed to start: ${errMsg.slice(0, 200)}`);
3932
+ }
3933
+ const agentStatesAfterStart = manager.getAgentStates(teamName);
3934
+ const aliveCount = agentStatesAfterStart.filter((s) => s.status !== "error" && s.status !== "shutdown").length;
3935
+ if (aliveCount === 0) {
3936
+ sysMsg(setMessages, "All agents failed to start. Check your API credentials and try again.");
3937
+ return void 0;
3938
+ }
3939
+ for (const [i, member] of teamConfig.members.entries()) {
3940
+ const spec = agentSpecs[i];
3941
+ const taskId = v4Id();
3942
+ const prompt = spec ? `You are ${spec.name} (${spec.agentType}).
3943
+
3944
+ ${spec.taskPrompt}
3945
+
3946
+ User request:
3947
+ ${input}` : `Work on the following task:
3948
+
3949
+ ${input}`;
3950
+ manager.assignTask(teamName, member.name, taskId, `${member.role}: ${input.slice(0, 80)}`, prompt);
3951
+ }
3952
+ const agentLines = agentSpecs.map((spec) => ` ${spec.name} (${spec.model}) \u2014 ${spec.role}`);
3953
+ sysMsg(
3954
+ setMessages,
3955
+ `Team "${teamName}" created with ${teamConfig.members.length} agents \u2014 split-panel active.
3956
+ ${agentLines.join("\n")}
3957
+ Use Tab to switch agents. /team stop to return to single-pane.`
3958
+ );
3959
+ return void 0;
3960
+ }
3961
+
3962
+ // src/ui/app-helpers.ts
3963
+ var DEFAULT_SYSTEM_PROMPT = "You are AemeathCLI (aemeathcli), a multi-model AI agent orchestrator. You help users with coding tasks, code review, debugging, refactoring, and project management. You are NOT Claude Code, Codex, or Gemini CLI \u2014 you are Aemeath Agent Swarm, an independent tool that orchestrates multiple AI providers (Anthropic, OpenAI, Google, Kimi, Ollama).\n\nAnswer concisely and directly. Key features:\n- Multi-model: /model to switch between Claude, GPT, Gemini, Kimi, Ollama\n- Agent orchestration: use Shift+Tab to switch into swarm mode inside the TUI\n - swarm mode designs and coordinates multi-agent teams from natural language\n - the master agent owns the left pane, worker agents stream on the right\n - follow the configured master-agent provider preference when building teams\n- Skills: $review, $commit, $plan, $debug, $test, $refactor\n- Commands: /help, /model, /role, /history, /resume, /cost\n\nWhen users ask about agent swarm, multi-agent, team mode, or orchestration, keep them in the current TUI session and tell them to switch modes with Shift+Tab. Do not redirect them to a separate `launch` command.";
3964
+ function getCandidateModels(config, resolution, activeModelId) {
3965
+ const candidates = [activeModelId];
3966
+ if (resolution.source !== "user_override" && resolution.role) {
3967
+ const roleConfig = config.roles[resolution.role];
3968
+ if (roleConfig) {
3969
+ candidates.push(roleConfig.primary, ...roleConfig.fallback);
3970
+ }
3971
+ }
3972
+ const seen = /* @__PURE__ */ new Set();
3973
+ const unique = [];
3974
+ for (const modelId of candidates) {
3975
+ if (!seen.has(modelId)) {
3976
+ seen.add(modelId);
3977
+ unique.push(modelId);
3978
+ }
3979
+ }
3980
+ return unique;
3981
+ }
3982
+ function cliProviderListsEqual(left, right) {
3983
+ return left.length === right.length && left.every((value, index) => value === right[index]);
3984
+ }
3985
+ function normalizeSwarmConfig(swarm, detectedProviders) {
3986
+ const primaryMasterProvider = swarm.primaryMasterProvider !== void 0 && detectedProviders.includes(swarm.primaryMasterProvider) ? swarm.primaryMasterProvider : void 0;
3987
+ const fallbackMasterProviders = swarm.fallbackMasterProviders.filter(
3988
+ (provider) => provider !== primaryMasterProvider && detectedProviders.includes(provider)
3989
+ );
3990
+ return {
3991
+ onboardingComplete: swarm.onboardingComplete && primaryMasterProvider !== void 0,
3992
+ detectedProviders: [...detectedProviders],
3993
+ primaryMasterProvider,
3994
+ fallbackMasterProviders
3995
+ };
3996
+ }
3997
+ function swarmConfigsEqual(left, right) {
3998
+ return left.onboardingComplete === right.onboardingComplete && left.primaryMasterProvider === right.primaryMasterProvider && cliProviderListsEqual(left.detectedProviders, right.detectedProviders) && cliProviderListsEqual(left.fallbackMasterProviders, right.fallbackMasterProviders);
3999
+ }
4000
+ function App({ config, options }) {
4001
+ const { resolution, modelId, switchModel, switchRole } = useModel(
4002
+ config,
4003
+ options.model,
4004
+ options.role
4005
+ );
4006
+ const { state: streamState, startStream, cancelStream, reset: resetStream } = useStream();
4007
+ const { totalCost, totalTokens, record } = useCost(config.cost);
4008
+ const totalCostRef = useRef(totalCost);
4009
+ totalCostRef.current = totalCost;
4010
+ const totalTokensRef = useRef(totalTokens);
4011
+ totalTokensRef.current = totalTokens;
4012
+ const panel = usePanel();
4013
+ const [messages, setMessages] = useState([]);
4014
+ const [isProcessing, setIsProcessing] = useState(false);
4015
+ const messagesRef = useRef([]);
4016
+ messagesRef.current = messages;
4017
+ const [gitBranch, setGitBranch] = useState();
4018
+ const [thinkingValue, setThinkingValue] = useState("medium");
4019
+ const [selectionMode, setSelectionMode] = useState({ type: "none" });
4020
+ const [modelDisplayOrder, setModelDisplayOrder] = useState(void 0);
4021
+ const [persistentHistory, setPersistentHistory] = useState([]);
4022
+ const [inputMode, setInputMode] = useState("agent-swarm");
4023
+ const [swarmConfig, setSwarmConfig] = useState(config.swarm);
4024
+ const [swarmOnboardingDeferred, setSwarmOnboardingDeferred] = useState(false);
4025
+ const registryRef = useRef(void 0);
4026
+ const getRegistry = useCallback(async () => {
4027
+ if (registryRef.current !== void 0) return registryRef.current;
4028
+ const { createDefaultRegistry } = await import('./registry-MVNSXCEF.js');
4029
+ registryRef.current = await createDefaultRegistry();
4030
+ return registryRef.current;
4031
+ }, []);
4032
+ const projectRootRef = useRef(process.cwd());
4033
+ useEffect(() => {
4034
+ void import('./pathResolver-UVAB2FCW.js').then(({ findProjectRoot }) => {
4035
+ projectRootRef.current = findProjectRoot();
4036
+ }).catch(() => {
4037
+ });
4038
+ }, []);
4039
+ useEffect(() => {
4040
+ void (async () => {
4041
+ try {
4042
+ const { findProjectRoot } = await import('./pathResolver-UVAB2FCW.js');
4043
+ const root = findProjectRoot();
4044
+ projectRootRef.current = root;
4045
+ const { loadInputHistory } = await import('./input-history-BEICE7PT.js');
4046
+ const history = await loadInputHistory(root);
4047
+ if (history.length > 0) setPersistentHistory(history);
4048
+ } catch {
4049
+ }
4050
+ })();
4051
+ }, []);
4052
+ useEffect(() => {
4053
+ void import('child_process').then(({ execFile }) => {
4054
+ execFile("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: 2e3 }, (error, stdout) => {
4055
+ if (!error && stdout) setGitBranch(stdout.trim());
4056
+ });
4057
+ }).catch(() => {
4058
+ });
4059
+ }, []);
4060
+ useEffect(() => {
4061
+ if (options.isAgentPane) return;
4062
+ void import('./detect-providers-QICJ5U3R.js').then(({ detectInstalledProviders }) => {
4063
+ const detected = detectInstalledProviders();
4064
+ if (detected.length > 0) setSwarmOnboardingDeferred(false);
4065
+ setSwarmConfig((prev) => {
4066
+ const next = normalizeSwarmConfig(prev, detected);
4067
+ return swarmConfigsEqual(prev, next) ? prev : next;
4068
+ });
4069
+ }).catch(() => {
4070
+ });
4071
+ }, [options.isAgentPane]);
4072
+ useEffect(() => {
4073
+ void (async () => {
4074
+ try {
4075
+ const { findProjectRoot } = await import('./pathResolver-UVAB2FCW.js');
4076
+ const projectRoot = findProjectRoot();
4077
+ projectRootRef.current = projectRoot;
4078
+ const { default: fg } = await import('fast-glob');
4079
+ const pathModule = await import('path');
4080
+ const fileRefs = await fg(["**/*"], {
4081
+ cwd: projectRoot,
4082
+ onlyFiles: true,
4083
+ dot: false,
4084
+ followSymbolicLinks: false,
4085
+ unique: true,
4086
+ suppressErrors: true,
4087
+ ignore: [".git/**", "node_modules/**", "dist/**", "coverage/**", ".aemeathcli/**", ".agents/**", "reference-gemini-cli/**", "cli-agent-orchestrator/**"]
4088
+ });
4089
+ const autocompleteItems = fileRefs.sort((left, right) => left.length !== right.length ? left.length - right.length : left.localeCompare(right)).slice(0, 400).map((filePath) => ({
4090
+ label: `@${filePath}`,
4091
+ description: pathModule.dirname(filePath) === "." ? "project root file" : pathModule.dirname(filePath)
4092
+ }));
4093
+ registerDynamicFileRefs(autocompleteItems);
4094
+ } catch {
4095
+ registerDynamicFileRefs([]);
4096
+ }
4097
+ })();
4098
+ }, []);
4099
+ useEffect(() => {
4100
+ void (async () => {
4101
+ try {
4102
+ const { SkillRegistry } = await import('./registry-LRURZVUL.js');
4103
+ const { findProjectRoot } = await import('./pathResolver-UVAB2FCW.js');
4104
+ const registry = new SkillRegistry();
4105
+ await registry.initialize(findProjectRoot());
4106
+ const all = registry.listAll();
4107
+ if (all.length > 0) {
4108
+ registerDynamicSkills(all.map((s) => ({ label: `$${s.name}`, description: s.description })));
4109
+ }
4110
+ } catch {
4111
+ }
4112
+ })();
4113
+ }, []);
4114
+ useEffect(() => {
4115
+ void (async () => {
4116
+ try {
4117
+ const { discoverModels, getDisplayOrder } = await import('./model-discovery-AAJDHRFO.js');
4118
+ await discoverModels();
4119
+ setModelDisplayOrder(getDisplayOrder());
4120
+ } catch {
4121
+ }
4122
+ })();
4123
+ }, []);
4124
+ const handleSubmit = useCallback(
4125
+ async (input) => {
4126
+ if (input.startsWith("/")) {
4127
+ await handleInternalCommand(input, switchModel, switchRole, {
4128
+ totalCost: totalCostRef.current,
4129
+ totalTokens: totalTokensRef.current,
4130
+ setMessages,
4131
+ modelId,
4132
+ thinkingValue,
4133
+ setThinkingValue,
4134
+ setSelectionMode,
4135
+ resolution,
4136
+ panel: { setAgents: panel.setAgents, activate: panel.activate, deactivate: panel.deactivate, appendOutput: panel.appendOutput },
4137
+ getRegistry,
4138
+ projectRoot: projectRootRef.current
4139
+ });
4140
+ return;
4141
+ }
4142
+ if (input.startsWith("$")) {
4143
+ await handleSkillInvocation(input, setMessages);
4144
+ return;
4145
+ }
4146
+ const activeTeamName = getActiveTeamName();
4147
+ const activeTeamManager = getActiveTeamManager();
4148
+ if (inputMode === "agent-swarm" && !options.isAgentPane && !panel.isSplitPanelActive && !activeTeamName) {
4149
+ setIsProcessing(true);
4150
+ try {
4151
+ const leaderTask = await handlePromptBasedTeamCreation(
4152
+ input,
4153
+ setMessages,
4154
+ panel,
4155
+ getRegistry,
4156
+ modelId,
4157
+ config,
4158
+ swarmConfig
4159
+ );
4160
+ if (leaderTask) setTimeout(() => void handleSubmit(leaderTask), 1500);
4161
+ } finally {
4162
+ setIsProcessing(false);
4163
+ }
4164
+ return;
4165
+ }
4166
+ if (panel.isSplitPanelActive && activeTeamManager && activeTeamName) {
4167
+ const targetAgent = panel.agents[panel.activeAgentIndex] ?? panel.agents[0];
4168
+ if (!targetAgent) {
4169
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: "No active swarm agent is available to receive input.", createdAt: /* @__PURE__ */ new Date() }]);
4170
+ return;
4171
+ }
4172
+ const taskId = v4Id();
4173
+ activeTeamManager.assignTask(activeTeamName, targetAgent.config.name, taskId, `User steering: ${input.slice(0, 72)}`, input);
4174
+ panel.appendOutput(targetAgent.config.agentId, `
4175
+ [User] ${input}
4176
+ `);
4177
+ panel.updateAgentStatus(targetAgent.config.agentId, "active");
4178
+ return;
4179
+ }
4180
+ const userMessage = { id: v4Id(), role: "user", content: input, createdAt: /* @__PURE__ */ new Date() };
4181
+ import('./input-history-BEICE7PT.js').then(({ appendInputHistory }) => appendInputHistory(projectRootRef.current, input)).catch(() => {
4182
+ });
4183
+ setMessages((prev) => [...prev, userMessage]);
4184
+ setIsProcessing(true);
4185
+ resetStream();
4186
+ try {
4187
+ const registry = await getRegistry();
4188
+ const allMessages = [...messagesRef.current, userMessage].filter((m) => m.role !== "system");
4189
+ const candidateModels = getCandidateModels(config, resolution, modelId);
4190
+ let responseModel = modelId;
4191
+ let responseProvider = resolution.provider;
4192
+ let fullContent = "";
4193
+ let completed = false;
4194
+ let lastError;
4195
+ for (const candidateModel of candidateModels) {
4196
+ const providerOrUndefined = registry.hasModel(candidateModel) ? registry.getForModel(candidateModel) : void 0;
4197
+ if (!providerOrUndefined) {
4198
+ lastError = new Error(`No provider available for model "${candidateModel}"`);
4199
+ continue;
4200
+ }
4201
+ const candidateProvider = providerOrUndefined;
4202
+ let candidateContent = "";
4203
+ let caughtError;
4204
+ const stream = candidateProvider.stream({
4205
+ model: candidateModel,
4206
+ messages: allMessages,
4207
+ system: options.systemPrompt ?? DEFAULT_SYSTEM_PROMPT,
4208
+ maxTokens: 16e3
4209
+ });
4210
+ async function* instrumentedStream(source) {
4211
+ try {
4212
+ for await (const chunk of source) {
4213
+ if (chunk.type === "text" && chunk.content) candidateContent += chunk.content;
4214
+ if (chunk.type === "usage" && chunk.usage) {
4215
+ record(candidateProvider.name, candidateModel, chunk.usage.inputTokens, chunk.usage.outputTokens, resolution.role);
4216
+ }
4217
+ if (chunk.type === "error") caughtError = new Error(chunk.error ?? `Model "${candidateModel}" stream failed`);
4218
+ yield chunk;
4219
+ }
4220
+ } catch (err) {
4221
+ caughtError = err;
4222
+ throw err;
4223
+ }
4224
+ }
4225
+ resetStream();
4226
+ await startStream(instrumentedStream(stream));
4227
+ if (caughtError !== void 0) {
4228
+ lastError = caughtError;
4229
+ continue;
4230
+ }
4231
+ responseModel = candidateModel;
4232
+ responseProvider = candidateProvider.name;
4233
+ fullContent = candidateContent;
4234
+ completed = true;
4235
+ break;
4236
+ }
4237
+ if (!completed) {
4238
+ throw lastError instanceof Error ? lastError : new Error(typeof lastError === "string" ? lastError : "No model could produce a response");
4239
+ }
4240
+ if (fullContent.length > 0) {
4241
+ const assistantMessage = {
4242
+ id: v4Id(),
4243
+ role: "assistant",
4244
+ content: fullContent,
4245
+ model: responseModel,
4246
+ provider: responseProvider,
4247
+ createdAt: /* @__PURE__ */ new Date()
4248
+ };
4249
+ setMessages((prev) => {
4250
+ const output = [...prev];
4251
+ if (responseModel !== modelId) {
4252
+ output.push({ id: v4Id(), role: "system", content: `Primary model "${modelId}" failed. Switched to fallback "${responseModel}".`, createdAt: /* @__PURE__ */ new Date() });
4253
+ }
4254
+ output.push(assistantMessage);
4255
+ return output;
4256
+ });
4257
+ void persistMessages(projectRootRef.current, userMessage, assistantMessage, responseModel, responseProvider);
4258
+ }
4259
+ } catch (error) {
4260
+ const errorContent = error instanceof Error ? error.message : String(error);
4261
+ setMessages((prev) => [...prev, { id: v4Id(), role: "assistant", content: `Error: ${errorContent}`, model: modelId, createdAt: /* @__PURE__ */ new Date() }]);
4262
+ } finally {
4263
+ setIsProcessing(false);
4264
+ }
4265
+ },
4266
+ [config, modelId, resolution, options.systemPrompt, record, switchModel, switchRole, startStream, resetStream, getRegistry, panel, thinkingValue, inputMode, options.isAgentPane, swarmConfig]
4267
+ );
4268
+ useEffect(() => {
4269
+ if (options.initialMessage) void handleSubmit(options.initialMessage);
4270
+ }, [handleSubmit, options.initialMessage]);
4271
+ const handleSubmitSync = useCallback((input) => {
4272
+ void handleSubmit(input);
4273
+ }, [handleSubmit]);
4274
+ const handleCancel = useCallback(() => {
4275
+ cancelStream();
4276
+ setIsProcessing(false);
4277
+ }, [cancelStream]);
4278
+ const handleModelSelected = useCallback((selectedModelId) => {
4279
+ const thinkingCfg = getThinkingConfigForModel(selectedModelId);
4280
+ if (thinkingCfg) {
4281
+ setSelectionMode({ type: "thinking", modelId: selectedModelId });
4282
+ } else {
4283
+ switchModel(selectedModelId);
4284
+ setSelectionMode({ type: "none" });
4285
+ const info = SUPPORTED_MODELS[selectedModelId];
4286
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: `Switched to model: ${info?.name ?? selectedModelId}`, createdAt: /* @__PURE__ */ new Date() }]);
4287
+ }
4288
+ }, [switchModel]);
4289
+ const handleThinkingSelected = useCallback((value) => {
4290
+ if (selectionMode.type !== "thinking") return;
4291
+ const { modelId: selectedModelId } = selectionMode;
4292
+ switchModel(selectedModelId);
4293
+ setThinkingValue(value);
4294
+ setSelectionMode({ type: "none" });
4295
+ const info = SUPPORTED_MODELS[selectedModelId];
4296
+ const cfg = getThinkingConfigForModel(selectedModelId);
4297
+ const methodLabel = cfg ? formatThinkingMethod(cfg.method) : "Thinking";
4298
+ const optionLabel = cfg?.options.find((o) => o.value === value)?.label ?? value;
4299
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: `Switched to model: ${info?.name ?? selectedModelId}
4300
+ ${methodLabel}: ${optionLabel}`, createdAt: /* @__PURE__ */ new Date() }]);
4301
+ }, [selectionMode, switchModel]);
4302
+ const handleSelectionCancel = useCallback(() => {
4303
+ setSelectionMode({ type: "none" });
4304
+ }, []);
4305
+ const handleLoginSelected = useCallback(async (provider) => {
4306
+ setSelectionMode({ type: "none" });
4307
+ const loginMsg = provider === "gemini" ? "Logging in to gemini... A new terminal window will open for authentication." : `Logging in to ${provider}...`;
4308
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: loginMsg, createdAt: /* @__PURE__ */ new Date() }]);
4309
+ try {
4310
+ const loginModule = await loadLoginModuleForSlash(provider);
4311
+ await loginModule.login();
4312
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: `Successfully logged in to ${provider}`, createdAt: /* @__PURE__ */ new Date() }]);
4313
+ } catch (error) {
4314
+ const msg = error instanceof Error ? error.message : String(error);
4315
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: `Login failed: ${msg}`, createdAt: /* @__PURE__ */ new Date() }]);
4316
+ }
4317
+ }, []);
4318
+ const handleSwarmOnboardingSelected = useCallback(async (primaryProvider) => {
4319
+ const nextSwarmConfig = {
4320
+ onboardingComplete: true,
4321
+ detectedProviders: swarmConfig.detectedProviders,
4322
+ primaryMasterProvider: primaryProvider,
4323
+ fallbackMasterProviders: swarmConfig.detectedProviders.filter((p) => p !== primaryProvider)
4324
+ };
4325
+ try {
4326
+ const { ConfigStore } = await import('./config-store-NF56VHFU.js');
4327
+ const store = new ConfigStore();
4328
+ const currentConfig = store.loadGlobal();
4329
+ const nextProviders = { ...currentConfig.providers };
4330
+ for (const provider of nextSwarmConfig.detectedProviders) {
4331
+ const entry = getCliProviderEntry(provider);
4332
+ nextProviders[entry.provider] = { ...nextProviders[entry.provider], enabled: true };
4333
+ }
4334
+ store.saveGlobal({ ...currentConfig, providers: nextProviders, swarm: nextSwarmConfig });
4335
+ setSwarmOnboardingDeferred(false);
4336
+ setSwarmConfig(nextSwarmConfig);
4337
+ setSelectionMode({ type: "none" });
4338
+ } catch (error) {
4339
+ const message = error instanceof Error ? error.message : String(error);
4340
+ setMessages((prev) => [...prev, { id: v4Id(), role: "system", content: `Failed to save swarm setup: ${message}`, createdAt: /* @__PURE__ */ new Date() }]);
4341
+ }
4342
+ }, [swarmConfig.detectedProviders]);
4343
+ const handleSwarmOnboardingSkip = useCallback(() => {
4344
+ setSwarmOnboardingDeferred(true);
4345
+ setSelectionMode({ type: "none" });
4346
+ }, []);
4347
+ useEffect(() => {
4348
+ if (options.isAgentPane || panel.isSplitPanelActive || messages.length > 0 || isProcessing) return;
4349
+ if (selectionMode.type !== "none" || swarmOnboardingDeferred) return;
4350
+ if (swarmConfig.primaryMasterProvider === void 0) setSelectionMode({ type: "swarm-onboarding" });
4351
+ }, [isProcessing, messages.length, options.isAgentPane, panel.isSplitPanelActive, selectionMode.type, swarmConfig.primaryMasterProvider, swarmOnboardingDeferred]);
4352
+ if (selectionMode.type === "swarm-onboarding") {
4353
+ return /* @__PURE__ */ jsx(
4354
+ SwarmOnboarding,
4355
+ {
4356
+ detectedProviders: swarmConfig.detectedProviders,
4357
+ currentPrimaryProvider: swarmConfig.primaryMasterProvider,
4358
+ onSelect: (provider) => void handleSwarmOnboardingSelected(provider),
4359
+ onSkip: handleSwarmOnboardingSkip
4360
+ }
4361
+ );
4362
+ }
4363
+ if (selectionMode.type === "login") {
4364
+ return /* @__PURE__ */ jsx(LoginSelector, { onSelect: (provider) => void handleLoginSelected(provider), onCancel: handleSelectionCancel });
4365
+ }
4366
+ if (selectionMode.type === "model") {
4367
+ return /* @__PURE__ */ jsx(ModelSelector, { currentModelId: modelId, onSelect: handleModelSelected, onCancel: handleSelectionCancel, modelOrder: modelDisplayOrder ?? PROVIDER_MODEL_ORDER });
4368
+ }
4369
+ if (selectionMode.type === "thinking") {
4370
+ const selectedInfo = SUPPORTED_MODELS[selectionMode.modelId];
4371
+ return /* @__PURE__ */ jsx(ThinkingSelector, { modelId: selectionMode.modelId, modelName: selectedInfo?.name ?? selectionMode.modelId, currentValue: thinkingValue, onSelect: handleThinkingSelected, onBack: handleSelectionCancel });
4372
+ }
4373
+ if (panel.isSplitPanelActive) {
4374
+ return /* @__PURE__ */ jsx(
4375
+ SplitPane,
4376
+ {
4377
+ agents: panel.agents,
4378
+ activeAgentIndex: panel.activeAgentIndex,
4379
+ onSelectAgent: panel.selectAgent,
4380
+ agentOutputs: panel.agentOutputs,
4381
+ isProcessing,
4382
+ onSubmit: handleSubmitSync,
4383
+ onCancel: handleCancel,
4384
+ model: modelId,
4385
+ role: resolution.role,
4386
+ tokenCount: totalTokens,
4387
+ cost: totalCost,
4388
+ gitBranch
4389
+ }
4390
+ );
4391
+ }
4392
+ return /* @__PURE__ */ jsx(
4393
+ SinglePane,
4394
+ {
4395
+ messages,
4396
+ isProcessing,
4397
+ onSubmit: handleSubmitSync,
4398
+ onCancel: handleCancel,
4399
+ model: modelId,
4400
+ role: resolution.role,
4401
+ tokenCount: totalTokens,
4402
+ cost: totalCost,
4403
+ gitBranch,
4404
+ streamingContent: streamState.content,
4405
+ activity: streamState.activity,
4406
+ initialHistory: persistentHistory,
4407
+ mode: inputMode,
4408
+ onModeChange: setInputMode
4409
+ }
4410
+ );
4411
+ }
4412
+ async function startChatSession(options) {
4413
+ let config;
4414
+ try {
4415
+ const { ConfigStore } = await import('./config-store-NF56VHFU.js');
4416
+ const store = new ConfigStore();
4417
+ config = store.loadGlobal();
4418
+ } catch {
4419
+ config = DEFAULT_CONFIG;
4420
+ }
4421
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx(App, { config, options }));
4422
+ await waitUntilExit();
4423
+ }
4424
+ async function runFirstRunSetup() {
4425
+ const { runFirstRunSetup: runCliFirstRunSetup } = await import('./first-run-ADROZVYF.js');
4426
+ await runCliFirstRunSetup();
4427
+ }
4428
+
4429
+ export { runFirstRunSetup, startChatSession };
4430
+ //# sourceMappingURL=App-JQ622M66.js.map
4431
+ //# sourceMappingURL=App-JQ622M66.js.map