aemeathcli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +607 -0
  2. package/dist/App-P4MYD4QY.js +2719 -0
  3. package/dist/App-P4MYD4QY.js.map +1 -0
  4. package/dist/api-key-fallback-YQQBOQIL.js +11 -0
  5. package/dist/api-key-fallback-YQQBOQIL.js.map +1 -0
  6. package/dist/chunk-4IJD72YB.js +184 -0
  7. package/dist/chunk-4IJD72YB.js.map +1 -0
  8. package/dist/chunk-6PDJ45T4.js +325 -0
  9. package/dist/chunk-6PDJ45T4.js.map +1 -0
  10. package/dist/chunk-CARHU3DO.js +562 -0
  11. package/dist/chunk-CARHU3DO.js.map +1 -0
  12. package/dist/chunk-CGEV3ARR.js +80 -0
  13. package/dist/chunk-CGEV3ARR.js.map +1 -0
  14. package/dist/chunk-CS5X3BWX.js +27 -0
  15. package/dist/chunk-CS5X3BWX.js.map +1 -0
  16. package/dist/chunk-CYQNBB25.js +44 -0
  17. package/dist/chunk-CYQNBB25.js.map +1 -0
  18. package/dist/chunk-DAHGLHNR.js +657 -0
  19. package/dist/chunk-DAHGLHNR.js.map +1 -0
  20. package/dist/chunk-H66O5Z2V.js +305 -0
  21. package/dist/chunk-H66O5Z2V.js.map +1 -0
  22. package/dist/chunk-HCIHOHLX.js +322 -0
  23. package/dist/chunk-HCIHOHLX.js.map +1 -0
  24. package/dist/chunk-HMJRPNPZ.js +1031 -0
  25. package/dist/chunk-HMJRPNPZ.js.map +1 -0
  26. package/dist/chunk-I5PZ4JTS.js +119 -0
  27. package/dist/chunk-I5PZ4JTS.js.map +1 -0
  28. package/dist/chunk-IYW62KKR.js +255 -0
  29. package/dist/chunk-IYW62KKR.js.map +1 -0
  30. package/dist/chunk-JAXXTYID.js +51 -0
  31. package/dist/chunk-JAXXTYID.js.map +1 -0
  32. package/dist/chunk-LSOYPSAT.js +183 -0
  33. package/dist/chunk-LSOYPSAT.js.map +1 -0
  34. package/dist/chunk-MFBHNWGV.js +416 -0
  35. package/dist/chunk-MFBHNWGV.js.map +1 -0
  36. package/dist/chunk-MXZSI3AY.js +311 -0
  37. package/dist/chunk-MXZSI3AY.js.map +1 -0
  38. package/dist/chunk-NBR3GHMT.js +72 -0
  39. package/dist/chunk-NBR3GHMT.js.map +1 -0
  40. package/dist/chunk-O3ZF22SW.js +246 -0
  41. package/dist/chunk-O3ZF22SW.js.map +1 -0
  42. package/dist/chunk-SUSJPZU2.js +181 -0
  43. package/dist/chunk-SUSJPZU2.js.map +1 -0
  44. package/dist/chunk-TEVZS4FA.js +310 -0
  45. package/dist/chunk-TEVZS4FA.js.map +1 -0
  46. package/dist/chunk-UY2SYSEZ.js +211 -0
  47. package/dist/chunk-UY2SYSEZ.js.map +1 -0
  48. package/dist/chunk-WAHVZH7V.js +260 -0
  49. package/dist/chunk-WAHVZH7V.js.map +1 -0
  50. package/dist/chunk-WPP3PEDE.js +234 -0
  51. package/dist/chunk-WPP3PEDE.js.map +1 -0
  52. package/dist/chunk-Y5XVD2CD.js +1610 -0
  53. package/dist/chunk-Y5XVD2CD.js.map +1 -0
  54. package/dist/chunk-YL5XFHR3.js +56 -0
  55. package/dist/chunk-YL5XFHR3.js.map +1 -0
  56. package/dist/chunk-ZGOHARPV.js +122 -0
  57. package/dist/chunk-ZGOHARPV.js.map +1 -0
  58. package/dist/claude-adapter-QMLFMSP3.js +6 -0
  59. package/dist/claude-adapter-QMLFMSP3.js.map +1 -0
  60. package/dist/claude-login-5WELXPKT.js +324 -0
  61. package/dist/claude-login-5WELXPKT.js.map +1 -0
  62. package/dist/cli.d.ts +1 -0
  63. package/dist/cli.js +703 -0
  64. package/dist/cli.js.map +1 -0
  65. package/dist/codex-login-7HHLJHBF.js +164 -0
  66. package/dist/codex-login-7HHLJHBF.js.map +1 -0
  67. package/dist/config-store-W6FBCQAQ.js +6 -0
  68. package/dist/config-store-W6FBCQAQ.js.map +1 -0
  69. package/dist/executor-6RIKIGXK.js +4 -0
  70. package/dist/executor-6RIKIGXK.js.map +1 -0
  71. package/dist/gemini-adapter-6JIHZ7WI.js +6 -0
  72. package/dist/gemini-adapter-6JIHZ7WI.js.map +1 -0
  73. package/dist/gemini-login-ZZLYC3J6.js +346 -0
  74. package/dist/gemini-login-ZZLYC3J6.js.map +1 -0
  75. package/dist/index.d.ts +2210 -0
  76. package/dist/index.js +1419 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/kimi-adapter-JN4HFFHU.js +6 -0
  79. package/dist/kimi-adapter-JN4HFFHU.js.map +1 -0
  80. package/dist/kimi-login-CZPS63NK.js +149 -0
  81. package/dist/kimi-login-CZPS63NK.js.map +1 -0
  82. package/dist/native-cli-adapters-OLW3XX57.js +6 -0
  83. package/dist/native-cli-adapters-OLW3XX57.js.map +1 -0
  84. package/dist/ollama-adapter-OJQ3FKWK.js +6 -0
  85. package/dist/ollama-adapter-OJQ3FKWK.js.map +1 -0
  86. package/dist/openai-adapter-XU46EN7B.js +6 -0
  87. package/dist/openai-adapter-XU46EN7B.js.map +1 -0
  88. package/dist/registry-4KD24ZC3.js +6 -0
  89. package/dist/registry-4KD24ZC3.js.map +1 -0
  90. package/dist/registry-H7B3AHPQ.js +5 -0
  91. package/dist/registry-H7B3AHPQ.js.map +1 -0
  92. package/dist/server-manager-PTGBHCLS.js +5 -0
  93. package/dist/server-manager-PTGBHCLS.js.map +1 -0
  94. package/dist/session-manager-ECEEACGY.js +12 -0
  95. package/dist/session-manager-ECEEACGY.js.map +1 -0
  96. package/dist/team-manager-HC4XGCFY.js +11 -0
  97. package/dist/team-manager-HC4XGCFY.js.map +1 -0
  98. package/dist/tmux-manager-GPYZ3WQH.js +6 -0
  99. package/dist/tmux-manager-GPYZ3WQH.js.map +1 -0
  100. package/dist/tools-TSMXMHIF.js +6 -0
  101. package/dist/tools-TSMXMHIF.js.map +1 -0
  102. package/package.json +89 -0
@@ -0,0 +1,2719 @@
1
+ import { createModelRouter, CostTracker } from './chunk-DAHGLHNR.js';
2
+ import { getEventBus } from './chunk-YL5XFHR3.js';
3
+ import { formatCost, formatTokenCount } from './chunk-CGEV3ARR.js';
4
+ import { DEFAULT_CONFIG } from './chunk-CYQNBB25.js';
5
+ import './chunk-NBR3GHMT.js';
6
+ import './chunk-CS5X3BWX.js';
7
+ import { getThinkingConfigForModel, SUPPORTED_MODELS, PROVIDER_MODEL_ORDER } from './chunk-HCIHOHLX.js';
8
+ import './chunk-ZGOHARPV.js';
9
+ import './chunk-JAXXTYID.js';
10
+ import { useRef, useState, useCallback, useEffect, useMemo } from 'react';
11
+ import { render, useInput, Box, Text } from 'ink';
12
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
13
+ import { randomUUID } from 'crypto';
14
+
15
+ function ToolOutput({
16
+ toolName,
17
+ content,
18
+ isError
19
+ }) {
20
+ return /* @__PURE__ */ jsxs(
21
+ Box,
22
+ {
23
+ flexDirection: "column",
24
+ borderStyle: "single",
25
+ borderColor: isError ? "red" : "gray",
26
+ paddingX: 1,
27
+ marginY: 1,
28
+ children: [
29
+ /* @__PURE__ */ jsxs(Text, { color: isError ? "red" : "magenta", bold: true, children: [
30
+ isError ? "Error" : "Tool",
31
+ ": ",
32
+ toolName
33
+ ] }),
34
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { wrap: "wrap", ...isError ? { color: "red" } : {}, children: content.length > 2e3 ? content.slice(0, 2e3) + "\n... (truncated)" : content }) })
35
+ ]
36
+ }
37
+ );
38
+ }
39
+ function getRoleColor(role) {
40
+ switch (role) {
41
+ case "user":
42
+ return "green";
43
+ case "assistant":
44
+ return "cyan";
45
+ case "system":
46
+ return "yellow";
47
+ case "tool":
48
+ return "magenta";
49
+ }
50
+ }
51
+ function getRoleIcon(role) {
52
+ switch (role) {
53
+ case "user":
54
+ return "\u276F";
55
+ // ❯
56
+ case "assistant":
57
+ return "\u2726";
58
+ // ✦
59
+ case "system":
60
+ return "\u2022";
61
+ // •
62
+ case "tool":
63
+ return "\u2699";
64
+ }
65
+ }
66
+ function getRoleLabel(role, model) {
67
+ switch (role) {
68
+ case "user":
69
+ return "You";
70
+ case "assistant":
71
+ return model ?? "Assistant";
72
+ case "system":
73
+ return "System";
74
+ case "tool":
75
+ return "Tool";
76
+ }
77
+ }
78
+ function shortModelName(model) {
79
+ if (model.includes("opus")) return "Opus 4.6";
80
+ if (model.includes("sonnet")) return "Sonnet 4.6";
81
+ if (model.includes("haiku")) return "Haiku 4.5";
82
+ if (model.includes("gpt-5.2-mini")) return "GPT-5.2 mini";
83
+ if (model.includes("gpt-5.2")) return "GPT-5.2";
84
+ if (model.includes("o3")) return "o3";
85
+ if (model.includes("gemini") && model.includes("pro")) return "Gemini Pro";
86
+ if (model.includes("gemini") && model.includes("flash")) return "Gemini Flash";
87
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi K2.5";
88
+ return model;
89
+ }
90
+ function MessageItem({ message }) {
91
+ const color = getRoleColor(message.role);
92
+ const icon = getRoleIcon(message.role);
93
+ const label = getRoleLabel(message.role, message.model ? shortModelName(message.model) : void 0);
94
+ if (message.role === "system") {
95
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs(Box, { children: [
96
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", dimColor: true, children: [
97
+ icon,
98
+ " "
99
+ ] }),
100
+ /* @__PURE__ */ jsx(Text, { color: "yellow", dimColor: true, wrap: "wrap", children: message.content })
101
+ ] }) });
102
+ }
103
+ if (message.role === "tool" && message.toolCalls && message.toolCalls.length > 0) {
104
+ const firstCall = message.toolCalls[0];
105
+ if (firstCall) {
106
+ return /* @__PURE__ */ jsx(
107
+ ToolOutput,
108
+ {
109
+ toolName: firstCall.name,
110
+ content: message.content,
111
+ isError: message.content.startsWith("Error:")
112
+ }
113
+ );
114
+ }
115
+ }
116
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
117
+ /* @__PURE__ */ jsxs(Box, { children: [
118
+ /* @__PURE__ */ jsxs(Text, { color, bold: true, children: [
119
+ icon,
120
+ " ",
121
+ label
122
+ ] }),
123
+ message.tokenUsage ? /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
124
+ " (",
125
+ message.tokenUsage.totalTokens,
126
+ " tokens)"
127
+ ] }) : null
128
+ ] }),
129
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: /* @__PURE__ */ jsx(ContentRenderer, { content: message.content }) }),
130
+ message.toolCalls && message.toolCalls.length > 0 ? /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", marginTop: 0, children: message.toolCalls.map((call) => {
131
+ const argSummary = formatToolArgs(call.name, call.arguments);
132
+ return /* @__PURE__ */ jsxs(Box, { children: [
133
+ /* @__PURE__ */ jsxs(Text, { color: "magenta", children: [
134
+ "\u2699",
135
+ " "
136
+ ] }),
137
+ /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: call.name }),
138
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
139
+ " ",
140
+ argSummary
141
+ ] })
142
+ ] }, call.id);
143
+ }) }) : null
144
+ ] });
145
+ }
146
+ function formatToolArgs(name, args) {
147
+ switch (name) {
148
+ case "read":
149
+ case "write":
150
+ case "edit":
151
+ return typeof args["file_path"] === "string" ? args["file_path"] : "";
152
+ case "glob":
153
+ return typeof args["pattern"] === "string" ? args["pattern"] : "";
154
+ case "grep": {
155
+ const pat = typeof args["pattern"] === "string" ? args["pattern"] : "";
156
+ const dir = typeof args["path"] === "string" ? ` in ${args["path"]}` : "";
157
+ return `"${pat}"${dir}`;
158
+ }
159
+ case "bash": {
160
+ const cmd = typeof args["command"] === "string" ? args["command"] : "";
161
+ return cmd.length > 60 ? cmd.slice(0, 60) + "..." : cmd;
162
+ }
163
+ default:
164
+ return JSON.stringify(args).slice(0, 80);
165
+ }
166
+ }
167
+ function splitCodeBlocks(content) {
168
+ const parts = [];
169
+ const regex = /```(\w*)\n?([\s\S]*?)```/g;
170
+ let lastIndex = 0;
171
+ let match;
172
+ while ((match = regex.exec(content)) !== null) {
173
+ if (match.index > lastIndex) {
174
+ parts.push({ type: "text", content: content.slice(lastIndex, match.index), lang: "" });
175
+ }
176
+ parts.push({ type: "code", content: match[2] ?? "", lang: match[1] ?? "" });
177
+ lastIndex = match.index + match[0].length;
178
+ }
179
+ if (lastIndex < content.length) {
180
+ parts.push({ type: "text", content: content.slice(lastIndex), lang: "" });
181
+ }
182
+ return parts.length > 0 ? parts : [{ type: "text", content, lang: "" }];
183
+ }
184
+ function ContentRenderer({ content }) {
185
+ const parts = splitCodeBlocks(content);
186
+ if (parts.length === 1 && parts[0].type === "text") {
187
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: content });
188
+ }
189
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: parts.map((part, index) => {
190
+ if (part.type === "code") {
191
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
192
+ part.lang.length > 0 ? /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: part.lang }) : null,
193
+ /* @__PURE__ */ jsx(Text, { children: part.content })
194
+ ] }, index);
195
+ }
196
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: part.content }, index);
197
+ }) });
198
+ }
199
+ var MAX_VISIBLE_MESSAGES = 50;
200
+ function MessageView({ messages }) {
201
+ const visibleMessages = messages.length > MAX_VISIBLE_MESSAGES ? messages.slice(-MAX_VISIBLE_MESSAGES) : messages;
202
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [
203
+ messages.length > MAX_VISIBLE_MESSAGES ? /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
204
+ " (",
205
+ messages.length - MAX_VISIBLE_MESSAGES,
206
+ " earlier messages hidden)"
207
+ ] }) : null,
208
+ visibleMessages.map((msg) => /* @__PURE__ */ jsx(MessageItem, { message: msg }, msg.id))
209
+ ] });
210
+ }
211
+ var MAX_VISIBLE_ITEMS = 8;
212
+ function AutocompletePopup({ items, selectedIndex }) {
213
+ if (items.length === 0) {
214
+ return null;
215
+ }
216
+ const totalItems = items.length;
217
+ const windowSize = Math.min(MAX_VISIBLE_ITEMS, totalItems);
218
+ let scrollOffset = 0;
219
+ if (selectedIndex >= windowSize) {
220
+ scrollOffset = selectedIndex - windowSize + 1;
221
+ }
222
+ scrollOffset = Math.max(0, Math.min(scrollOffset, totalItems - windowSize));
223
+ const visibleItems = items.slice(scrollOffset, scrollOffset + windowSize);
224
+ const hasMore = scrollOffset + windowSize < totalItems;
225
+ const hasLess = scrollOffset > 0;
226
+ return /* @__PURE__ */ jsxs(
227
+ Box,
228
+ {
229
+ flexDirection: "column",
230
+ borderStyle: "round",
231
+ borderColor: "cyan",
232
+ paddingX: 1,
233
+ marginBottom: 0,
234
+ children: [
235
+ hasLess ? /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
236
+ " ",
237
+ "... ",
238
+ scrollOffset,
239
+ " above"
240
+ ] }) : null,
241
+ visibleItems.map((item, visibleIndex) => {
242
+ const actualIndex = scrollOffset + visibleIndex;
243
+ const isSelected = actualIndex === selectedIndex;
244
+ return /* @__PURE__ */ jsxs(Box, { children: [
245
+ /* @__PURE__ */ jsxs(Text, { color: isSelected ? "cyan" : "white", bold: isSelected, children: [
246
+ isSelected ? "> " : " ",
247
+ item.label
248
+ ] }),
249
+ /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
250
+ " ",
251
+ item.description
252
+ ] })
253
+ ] }, `${item.label}-${actualIndex}`);
254
+ }),
255
+ hasMore ? /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
256
+ " ",
257
+ "... ",
258
+ totalItems - scrollOffset - windowSize,
259
+ " more"
260
+ ] }) : null
261
+ ]
262
+ }
263
+ );
264
+ }
265
+
266
+ // src/ui/autocomplete-data.ts
267
+ var SLASH_COMMANDS = [
268
+ { command: "/help", description: "Show available commands" },
269
+ { command: "/model", description: "Select a model with provider-specific thinking options" },
270
+ { command: "/role", description: "Switch role (planning, coding, review, testing, bugfix)" },
271
+ { command: "/cost", description: "Show session cost breakdown" },
272
+ { command: "/clear", description: "Clear conversation" },
273
+ { command: "/compact", description: "Compress context" },
274
+ { command: "/team list", description: "List active teams" },
275
+ { command: "/team stop", description: "Deactivate team and return to single-pane" },
276
+ { command: "/mcp list", description: "List connected MCP servers" },
277
+ { command: "/mcp add", description: "Add an MCP server" },
278
+ { command: "/skill list", description: "List available skills" },
279
+ { command: "/panel", description: "Change split-panel layout" },
280
+ { command: "/auth login", description: "Log in to a provider (claude, codex, gemini, kimi)" },
281
+ { command: "/auth status", description: "Show login status for all providers" },
282
+ { command: "/auth logout", description: "Log out of a provider" },
283
+ { command: "/config get", description: "Get a configuration value" },
284
+ { command: "/config set", description: "Set a configuration value" },
285
+ { command: "/quit", description: "Exit" },
286
+ { command: "/exit", description: "Exit" }
287
+ ];
288
+ var CONTEXT_REFS = [
289
+ { label: "@file", description: "Reference a file in the project" },
290
+ { label: "@codebase", description: "Reference the entire codebase" },
291
+ { label: "@anthropic", description: "Anthropic/Claude provider context" },
292
+ { label: "@openai", description: "OpenAI/Codex provider context" },
293
+ { label: "@google", description: "Google/Gemini provider context" },
294
+ { label: "@kimi", description: "Kimi/Moonshot provider context" },
295
+ { label: "@web", description: "Web search context" },
296
+ { label: "@git", description: "Git repository context" },
297
+ { label: "@docs", description: "Project documentation context" },
298
+ { label: "@errors", description: "Recent error context" }
299
+ ];
300
+ var CODE_REFS = [
301
+ { label: "`src/", description: "Source directory" },
302
+ { label: "`src/ui/", description: "UI components" },
303
+ { label: "`src/auth/", description: "Authentication modules" },
304
+ { label: "`src/providers/", description: "LLM provider adapters" },
305
+ { label: "`src/teams/", description: "Team management" },
306
+ { label: "`src/core/", description: "Core engine" },
307
+ { label: "`src/tools/", description: "Tool implementations" },
308
+ { label: "`src/types/", description: "Type definitions" },
309
+ { label: "`src/storage/", description: "Storage layer" },
310
+ { label: "`src/utils/", description: "Utility functions" }
311
+ ];
312
+ var SKILL_REFS = [
313
+ { label: "$review", description: "Comprehensive code review" },
314
+ { label: "$commit", description: "Smart git commit with message generation" },
315
+ { label: "$plan", description: "Create implementation plan from requirements" },
316
+ { label: "$debug", description: "Systematic debugging workflow" },
317
+ { label: "$test", description: "Generate tests for code" },
318
+ { label: "$refactor", description: "Refactoring with safety checks" }
319
+ ];
320
+ function getAutocompleteItems(trigger, query) {
321
+ const normalizedQuery = query.toLowerCase();
322
+ switch (trigger) {
323
+ case "/": {
324
+ const filtered = SLASH_COMMANDS.filter((cmd) => cmd.command.toLowerCase().includes(normalizedQuery));
325
+ return filtered.map((cmd) => ({ label: cmd.command, description: cmd.description }));
326
+ }
327
+ case "@": {
328
+ return CONTEXT_REFS.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
329
+ }
330
+ case "`": {
331
+ return CODE_REFS.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
332
+ }
333
+ case "$": {
334
+ return SKILL_REFS.filter((ref) => ref.label.toLowerCase().includes(normalizedQuery));
335
+ }
336
+ }
337
+ }
338
+ var TRIGGER_CHARS = /* @__PURE__ */ new Set(["/", "@", "`", "$"]);
339
+ function detectTrigger(input) {
340
+ if (input.length === 0) {
341
+ return null;
342
+ }
343
+ if (input[0] === "/") {
344
+ return { trigger: "/", query: input };
345
+ }
346
+ if (input[0] === "$") {
347
+ return { trigger: "$", query: input };
348
+ }
349
+ for (let i = input.length - 1; i >= 0; i--) {
350
+ const ch = input[i];
351
+ if (ch === void 0) continue;
352
+ if (TRIGGER_CHARS.has(ch) && ch !== "/" && ch !== "$") {
353
+ if (i === 0 || input[i - 1] === " ") {
354
+ return {
355
+ trigger: ch,
356
+ query: input.slice(i)
357
+ };
358
+ }
359
+ }
360
+ if (ch === " ") {
361
+ break;
362
+ }
363
+ }
364
+ return null;
365
+ }
366
+ function InputBar({ onSubmit, isProcessing, placeholder, onCancel }) {
367
+ const [input, setInput] = useState("");
368
+ const [selectedIndex, setSelectedIndex] = useState(0);
369
+ const [history, setHistory] = useState([]);
370
+ const [historyIndex, setHistoryIndex] = useState(-1);
371
+ const [savedInput, setSavedInput] = useState("");
372
+ const triggerState = useMemo(() => detectTrigger(input), [input]);
373
+ const autocompleteItems = useMemo(() => {
374
+ if (triggerState === null) return [];
375
+ return getAutocompleteItems(triggerState.trigger, triggerState.query);
376
+ }, [triggerState]);
377
+ const isAutocompleteActive = autocompleteItems.length > 0;
378
+ useInput((inputChar, key) => {
379
+ if (isProcessing) {
380
+ if (key.escape && onCancel) {
381
+ onCancel();
382
+ }
383
+ return;
384
+ }
385
+ if (isAutocompleteActive) {
386
+ if (key.upArrow) {
387
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : autocompleteItems.length - 1);
388
+ return;
389
+ }
390
+ if (key.downArrow) {
391
+ setSelectedIndex((prev) => prev < autocompleteItems.length - 1 ? prev + 1 : 0);
392
+ return;
393
+ }
394
+ if (key.tab) {
395
+ const selected = autocompleteItems[selectedIndex];
396
+ if (selected && triggerState) {
397
+ const beforeTrigger = input.slice(0, input.length - triggerState.query.length);
398
+ const newInput = beforeTrigger + selected.label + " ";
399
+ setInput(newInput);
400
+ setSelectedIndex(0);
401
+ }
402
+ return;
403
+ }
404
+ if (key.escape) {
405
+ setInput((prev) => prev + " ");
406
+ setSelectedIndex(0);
407
+ return;
408
+ }
409
+ }
410
+ if (key.upArrow) {
411
+ if (history.length === 0) return;
412
+ if (historyIndex === -1) {
413
+ setSavedInput(input);
414
+ }
415
+ const newIndex = historyIndex === -1 ? history.length - 1 : Math.max(0, historyIndex - 1);
416
+ setHistoryIndex(newIndex);
417
+ setInput(history[newIndex] ?? "");
418
+ return;
419
+ }
420
+ if (key.downArrow) {
421
+ if (historyIndex === -1) return;
422
+ const newIndex = historyIndex + 1;
423
+ if (newIndex >= history.length) {
424
+ setHistoryIndex(-1);
425
+ setInput(savedInput);
426
+ } else {
427
+ setHistoryIndex(newIndex);
428
+ setInput(history[newIndex] ?? "");
429
+ }
430
+ return;
431
+ }
432
+ if (key.return) {
433
+ if (isAutocompleteActive && triggerState?.trigger === "/") {
434
+ const selected = autocompleteItems[selectedIndex];
435
+ if (selected) {
436
+ setHistory((prev) => [...prev.slice(-99), selected.label.trim()]);
437
+ onSubmit(selected.label.trim());
438
+ setInput("");
439
+ setSelectedIndex(0);
440
+ setHistoryIndex(-1);
441
+ return;
442
+ }
443
+ }
444
+ if (input.trim().length > 0) {
445
+ setHistory((prev) => [...prev.slice(-99), input.trim()]);
446
+ onSubmit(input.trim());
447
+ setInput("");
448
+ setSelectedIndex(0);
449
+ setHistoryIndex(-1);
450
+ }
451
+ return;
452
+ }
453
+ if (key.backspace || key.delete) {
454
+ setInput((prev) => prev.slice(0, -1));
455
+ setSelectedIndex(0);
456
+ setHistoryIndex(-1);
457
+ return;
458
+ }
459
+ if (key.ctrl && inputChar === "c") {
460
+ process.exit(0);
461
+ return;
462
+ }
463
+ if (key.ctrl && inputChar === "l") {
464
+ return;
465
+ }
466
+ if (!key.ctrl && !key.meta && inputChar) {
467
+ setInput((prev) => prev + inputChar);
468
+ setSelectedIndex(0);
469
+ setHistoryIndex(-1);
470
+ }
471
+ });
472
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
473
+ isAutocompleteActive ? /* @__PURE__ */ jsx(AutocompletePopup, { items: autocompleteItems, selectedIndex }) : null,
474
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: isProcessing ? "gray" : "green", paddingX: 1, children: [
475
+ /* @__PURE__ */ jsxs(Text, { color: "green", bold: true, children: [
476
+ ">",
477
+ " "
478
+ ] }),
479
+ isProcessing ? /* @__PURE__ */ jsx(Text, { color: "gray", children: onCancel ? "Esc to cancel" : "Processing..." }) : input.length > 0 ? /* @__PURE__ */ jsx(Text, { children: input }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: placeholder ?? "Type a message..." }),
480
+ !isProcessing ? /* @__PURE__ */ jsx(Text, { color: "green", children: "_" }) : null
481
+ ] })
482
+ ] });
483
+ }
484
+ function shortModelLabel(model) {
485
+ if (model.includes("opus")) return "Opus 4.6";
486
+ if (model.includes("sonnet")) return "Sonnet 4.6";
487
+ if (model.includes("haiku")) return "Haiku 4.5";
488
+ if (model.includes("gpt-5.2-mini")) return "GPT-5.2m";
489
+ if (model.includes("gpt-5.2")) return "GPT-5.2";
490
+ if (model.includes("o3")) return "o3";
491
+ if (model.includes("gemini") && model.includes("pro")) return "Gem Pro";
492
+ if (model.includes("gemini") && model.includes("flash")) return "Gem Flash";
493
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi";
494
+ return model;
495
+ }
496
+ function StatusBar({
497
+ model,
498
+ role,
499
+ tokenCount,
500
+ cost,
501
+ gitBranch,
502
+ gitChanges
503
+ }) {
504
+ return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
505
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
506
+ "\u2726",
507
+ " aemeathcli"
508
+ ] }),
509
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
510
+ " ",
511
+ "\u2502",
512
+ " "
513
+ ] }),
514
+ /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: shortModelLabel(model) }),
515
+ role ? /* @__PURE__ */ jsxs(Fragment, { children: [
516
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
517
+ " ",
518
+ "\u2502",
519
+ " "
520
+ ] }),
521
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: role })
522
+ ] }) : null,
523
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
524
+ " ",
525
+ "\u2502",
526
+ " "
527
+ ] }),
528
+ /* @__PURE__ */ jsxs(Text, { children: [
529
+ tokenCount,
530
+ " tok"
531
+ ] }),
532
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
533
+ " ",
534
+ "\u2502",
535
+ " "
536
+ ] }),
537
+ /* @__PURE__ */ jsx(Text, { color: "green", children: cost }),
538
+ gitBranch ? /* @__PURE__ */ jsxs(Fragment, { children: [
539
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
540
+ " ",
541
+ "\u2502",
542
+ " "
543
+ ] }),
544
+ /* @__PURE__ */ jsxs(Text, { color: "blue", children: [
545
+ "\u2387",
546
+ " ",
547
+ gitBranch,
548
+ gitChanges !== void 0 && gitChanges > 0 ? ` \xB1${gitChanges}` : ""
549
+ ] })
550
+ ] }) : null
551
+ ] });
552
+ }
553
+ var SPINNER_FRAMES = ["\u25CB", "\u25D4", "\u25D1", "\u25D5", "\u25CF", "\u25D5", "\u25D1", "\u25D4"];
554
+ var SPINNER_INTERVAL_MS = 300;
555
+ function Spinner({ label }) {
556
+ const [frame, setFrame] = useState(0);
557
+ useEffect(() => {
558
+ const timer = setInterval(() => {
559
+ setFrame((prev) => (prev + 1) % SPINNER_FRAMES.length);
560
+ }, SPINNER_INTERVAL_MS);
561
+ return () => clearInterval(timer);
562
+ }, []);
563
+ return /* @__PURE__ */ jsxs(Text, { children: [
564
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: SPINNER_FRAMES[frame] }),
565
+ label ? /* @__PURE__ */ jsxs(Text, { children: [
566
+ " ",
567
+ label
568
+ ] }) : null
569
+ ] });
570
+ }
571
+ function shortModelName2(model) {
572
+ if (model.includes("opus")) return "Opus 4.6";
573
+ if (model.includes("sonnet")) return "Sonnet 4.6";
574
+ if (model.includes("haiku")) return "Haiku 4.5";
575
+ if (model.includes("gpt-5.2-mini")) return "GPT-5.2m";
576
+ if (model.includes("gpt-5.2")) return "GPT-5.2";
577
+ if (model.includes("o3")) return "o3";
578
+ if (model.includes("gemini") && model.includes("pro")) return "Gem Pro";
579
+ if (model.includes("gemini") && model.includes("flash")) return "Gem Flash";
580
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi";
581
+ return model;
582
+ }
583
+ function tailLines(text, maxLines) {
584
+ const lines = text.split("\n");
585
+ if (lines.length <= maxLines) return text;
586
+ return lines.slice(-maxLines).join("\n");
587
+ }
588
+ function SinglePane({
589
+ messages,
590
+ isProcessing,
591
+ onSubmit,
592
+ onCancel,
593
+ model,
594
+ role,
595
+ tokenCount,
596
+ cost,
597
+ gitBranch,
598
+ gitChanges,
599
+ streamingContent,
600
+ activity
601
+ }) {
602
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: "100%", children: [
603
+ /* @__PURE__ */ jsx(
604
+ StatusBar,
605
+ {
606
+ model,
607
+ role,
608
+ tokenCount,
609
+ cost,
610
+ gitBranch,
611
+ gitChanges
612
+ }
613
+ ),
614
+ messages.length === 0 && !isProcessing ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 2, justifyContent: "center", children: [
615
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
616
+ "\u2726",
617
+ " AemeathCLI"
618
+ ] }),
619
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Multi-model AI coding assistant" }),
620
+ /* @__PURE__ */ jsx(Text, { children: " " }),
621
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Type a message to start, or use /help for commands." }),
622
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Tab for autocomplete on /commands, @context, and $skills." })
623
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
624
+ /* @__PURE__ */ jsx(MessageView, { messages }),
625
+ isProcessing ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 1, marginBottom: 1, children: [
626
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
627
+ "\u2726",
628
+ " ",
629
+ shortModelName2(model)
630
+ ] }) }),
631
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: streamingContent && streamingContent.length > 0 ? tailLines(streamingContent, 12) : "" }) }),
632
+ /* @__PURE__ */ jsx(Box, { marginLeft: 1, children: /* @__PURE__ */ jsx(
633
+ Spinner,
634
+ {
635
+ label: activity ? activity : streamingContent && streamingContent.length > 0 ? "Streaming response..." : "Thinking..."
636
+ }
637
+ ) })
638
+ ] }) : null
639
+ ] }),
640
+ /* @__PURE__ */ jsx(InputBar, { onSubmit, isProcessing, onCancel })
641
+ ] });
642
+ }
643
+ function getStatusColor(status) {
644
+ switch (status) {
645
+ case "active":
646
+ return "green";
647
+ case "idle":
648
+ return "yellow";
649
+ case "error":
650
+ return "red";
651
+ case "shutdown":
652
+ return "gray";
653
+ default:
654
+ return "white";
655
+ }
656
+ }
657
+ function shortModelLabel2(model) {
658
+ if (model.includes("opus")) return "Opus";
659
+ if (model.includes("sonnet")) return "Sonnet";
660
+ if (model.includes("haiku")) return "Haiku";
661
+ if (model.includes("gpt-5")) return "GPT-5";
662
+ if (model.includes("gemini") && model.includes("pro")) return "Gem-Pro";
663
+ if (model.includes("gemini") && model.includes("flash")) return "Gem-Flash";
664
+ if (model.includes("kimi") || model.includes("k2")) return "Kimi";
665
+ const parts = model.split("-");
666
+ return parts[parts.length - 1] ?? model.slice(0, 8);
667
+ }
668
+ function statusIndicator(status) {
669
+ switch (status) {
670
+ case "active":
671
+ return "\u25CF";
672
+ // ●
673
+ case "idle":
674
+ return "\u25CB";
675
+ // ○
676
+ case "error":
677
+ return "\u2716";
678
+ // ✖
679
+ default:
680
+ return "\u2500";
681
+ }
682
+ }
683
+ var MAX_OUTPUT_LINES = 40;
684
+ function classifyLine(line) {
685
+ if (line.length === 0) return "empty";
686
+ if (line.startsWith("\u2699") || line.startsWith("\u2699")) return "tool";
687
+ if (line.startsWith(" \u2192") || line.startsWith(" \u2192")) return "result";
688
+ if (line.startsWith("Error:") || line.startsWith("Stream error:")) return "error";
689
+ return "text";
690
+ }
691
+ function extractLastActivity(output) {
692
+ const lines = output.split("\n");
693
+ for (let i = lines.length - 1; i >= 0; i--) {
694
+ const line = lines[i].trim();
695
+ if (line.length === 0) continue;
696
+ const type = classifyLine(line);
697
+ if (type === "tool") return line;
698
+ if (type === "result") return line;
699
+ }
700
+ return void 0;
701
+ }
702
+ function AgentOutput({
703
+ output,
704
+ isActive
705
+ }) {
706
+ const lines = output.split("\n");
707
+ const truncated = lines.length > MAX_OUTPUT_LINES;
708
+ const visible = truncated ? lines.slice(-MAX_OUTPUT_LINES) : lines;
709
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
710
+ truncated ? /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
711
+ " (",
712
+ lines.length - MAX_OUTPUT_LINES,
713
+ " lines hidden)"
714
+ ] }) : null,
715
+ visible.map((line, i) => {
716
+ const type = classifyLine(line);
717
+ switch (type) {
718
+ case "tool":
719
+ return /* @__PURE__ */ jsx(Text, { color: "magenta", children: line }, i);
720
+ case "result":
721
+ return /* @__PURE__ */ jsx(Text, { color: "gray", children: line }, i);
722
+ case "error":
723
+ return /* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: line }, i);
724
+ case "empty":
725
+ return /* @__PURE__ */ jsx(Text, { children: " " }, i);
726
+ default:
727
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: line }, i);
728
+ }
729
+ }),
730
+ isActive ? /* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(Spinner, { label: "Working..." }) }) : null
731
+ ] });
732
+ }
733
+ function SplitPanel({
734
+ agents,
735
+ activeAgentIndex,
736
+ onSelectAgent,
737
+ agentOutputs
738
+ }) {
739
+ useInput((input, key) => {
740
+ if (key.tab) {
741
+ const nextIndex = (activeAgentIndex + 1) % agents.length;
742
+ onSelectAgent(nextIndex);
743
+ }
744
+ const numKey = parseInt(input, 10);
745
+ if (!isNaN(numKey) && numKey >= 1 && numKey <= agents.length && key.ctrl) {
746
+ onSelectAgent(numKey - 1);
747
+ }
748
+ });
749
+ const activeAgent = agents[activeAgentIndex];
750
+ const activeOutput = activeAgent ? agentOutputs.get(activeAgent.config.agentId) ?? "" : "";
751
+ const lastActivity = activeOutput.length > 0 ? extractLastActivity(activeOutput) : void 0;
752
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
753
+ /* @__PURE__ */ jsx(Box, { children: agents.map((agent, index) => {
754
+ const isActive = index === activeAgentIndex;
755
+ const sColor = getStatusColor(agent.status);
756
+ const indicator = statusIndicator(agent.status);
757
+ const modelShort = shortModelLabel2(agent.config.model);
758
+ const typeLabel = agent.config.agentType.charAt(0).toUpperCase() + agent.config.agentType.slice(1);
759
+ return /* @__PURE__ */ jsxs(
760
+ Box,
761
+ {
762
+ borderStyle: isActive ? "bold" : "single",
763
+ borderColor: isActive ? "cyan" : "gray",
764
+ paddingX: 1,
765
+ children: [
766
+ /* @__PURE__ */ jsxs(Text, { color: sColor, children: [
767
+ indicator,
768
+ " "
769
+ ] }),
770
+ /* @__PURE__ */ jsx(Text, { bold: isActive, children: typeLabel }),
771
+ /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
772
+ " ",
773
+ modelShort
774
+ ] })
775
+ ]
776
+ },
777
+ agent.config.agentId
778
+ );
779
+ }) }),
780
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
781
+ " Tab: switch agent | Ctrl+1-",
782
+ agents.length,
783
+ ": jump | /team stop: exit"
784
+ ] }) }),
785
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, marginTop: 1, borderStyle: "round", borderColor: "gray", children: activeAgent ? /* @__PURE__ */ jsxs(Fragment, { children: [
786
+ /* @__PURE__ */ jsxs(Box, { children: [
787
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
788
+ "\u2726",
789
+ " ",
790
+ activeAgent.config.name
791
+ ] }),
792
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
793
+ " ",
794
+ "\u2014",
795
+ " ",
796
+ activeAgent.config.role,
797
+ " "
798
+ ] }),
799
+ /* @__PURE__ */ jsxs(Text, { color: getStatusColor(activeAgent.status), children: [
800
+ "[",
801
+ activeAgent.status,
802
+ "]"
803
+ ] })
804
+ ] }),
805
+ lastActivity ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
806
+ " ",
807
+ lastActivity.length > 80 ? lastActivity.slice(0, 80) + "..." : lastActivity
808
+ ] }) }) : null,
809
+ /* @__PURE__ */ jsx(Box, { borderStyle: "single", borderColor: "gray", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, marginY: 0 }),
810
+ activeOutput.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 0, children: /* @__PURE__ */ jsx(AgentOutput, { output: activeOutput, isActive: activeAgent.status === "active" }) }) : activeAgent.status === "active" ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Spinner, { label: "Initializing agent..." }) }) : /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
811
+ "\u231B",
812
+ " Waiting for task..."
813
+ ] })
814
+ ] }) : /* @__PURE__ */ jsx(Text, { color: "gray", children: "No agents active" }) })
815
+ ] });
816
+ }
817
+ function SplitPane({
818
+ agents,
819
+ activeAgentIndex,
820
+ onSelectAgent,
821
+ agentOutputs,
822
+ isProcessing,
823
+ onSubmit,
824
+ onCancel,
825
+ model,
826
+ role,
827
+ tokenCount,
828
+ cost,
829
+ gitBranch
830
+ }) {
831
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: "100%", children: [
832
+ /* @__PURE__ */ jsx(StatusBar, { model, role, tokenCount, cost, gitBranch }),
833
+ /* @__PURE__ */ jsx(
834
+ SplitPanel,
835
+ {
836
+ agents,
837
+ activeAgentIndex,
838
+ onSelectAgent,
839
+ agentOutputs
840
+ }
841
+ ),
842
+ /* @__PURE__ */ jsx(InputBar, { onSubmit, isProcessing, onCancel })
843
+ ] });
844
+ }
845
+ function useModel(config, initialModel, initialRole) {
846
+ const router = useMemo(() => createModelRouter(config), [config]);
847
+ const [userOverride, setUserOverride] = useState(initialModel);
848
+ const [currentRole, setCurrentRole] = useState(initialRole);
849
+ const resolution = useMemo(
850
+ () => {
851
+ router.setUserOverride(userOverride);
852
+ return router.resolve(currentRole);
853
+ },
854
+ [router, currentRole, userOverride]
855
+ );
856
+ const switchModel = useCallback((modelId) => {
857
+ setUserOverride(modelId);
858
+ }, []);
859
+ const switchRole = useCallback(
860
+ (role) => {
861
+ router.setUserOverride(void 0);
862
+ setCurrentRole(role);
863
+ setUserOverride(void 0);
864
+ },
865
+ [router]
866
+ );
867
+ return {
868
+ resolution,
869
+ modelId: resolution.modelId,
870
+ switchModel,
871
+ switchRole,
872
+ router
873
+ };
874
+ }
875
+ function formatToolActivity(toolCall) {
876
+ const args = toolCall.arguments;
877
+ switch (toolCall.name) {
878
+ case "read": {
879
+ const fp = typeof args["file_path"] === "string" ? args["file_path"] : "";
880
+ const short = fp.split("/").slice(-2).join("/");
881
+ return `Reading ${short || "file"}`;
882
+ }
883
+ case "write": {
884
+ const fp = typeof args["file_path"] === "string" ? args["file_path"] : "";
885
+ const short = fp.split("/").slice(-2).join("/");
886
+ return `Writing ${short || "file"}`;
887
+ }
888
+ case "edit": {
889
+ const fp = typeof args["file_path"] === "string" ? args["file_path"] : "";
890
+ const short = fp.split("/").slice(-2).join("/");
891
+ return `Editing ${short || "file"}`;
892
+ }
893
+ case "glob": {
894
+ const pat = typeof args["pattern"] === "string" ? args["pattern"] : "";
895
+ return `Searching files ${pat}`;
896
+ }
897
+ case "grep": {
898
+ const pat = typeof args["pattern"] === "string" ? args["pattern"] : "";
899
+ return `Searching for "${pat.length > 30 ? pat.slice(0, 30) + "..." : pat}"`;
900
+ }
901
+ case "bash": {
902
+ const cmd = typeof args["command"] === "string" ? args["command"] : "";
903
+ const short = cmd.length > 40 ? cmd.slice(0, 40) + "..." : cmd;
904
+ return `Running ${short}`;
905
+ }
906
+ case "web_search":
907
+ case "webSearch":
908
+ return "Searching the web";
909
+ case "web_fetch":
910
+ case "webFetch":
911
+ return "Fetching URL";
912
+ default:
913
+ return `Calling ${toolCall.name}`;
914
+ }
915
+ }
916
+ function useStream() {
917
+ const [state, setState] = useState({
918
+ isStreaming: false,
919
+ content: "",
920
+ usage: void 0,
921
+ error: void 0,
922
+ activity: void 0
923
+ });
924
+ const cancelRef = useRef(false);
925
+ const startStream = useCallback(async (stream) => {
926
+ cancelRef.current = false;
927
+ setState({
928
+ isStreaming: true,
929
+ content: "",
930
+ usage: void 0,
931
+ error: void 0,
932
+ activity: void 0
933
+ });
934
+ try {
935
+ for await (const chunk of stream) {
936
+ if (cancelRef.current) {
937
+ break;
938
+ }
939
+ switch (chunk.type) {
940
+ case "text":
941
+ if (chunk.content) {
942
+ setState((prev) => ({
943
+ ...prev,
944
+ content: prev.content + chunk.content,
945
+ // Clear activity once we get text back (model is responding)
946
+ activity: void 0
947
+ }));
948
+ }
949
+ break;
950
+ case "tool_call":
951
+ if (chunk.toolCall) {
952
+ setState((prev) => ({
953
+ ...prev,
954
+ activity: formatToolActivity(chunk.toolCall)
955
+ }));
956
+ }
957
+ break;
958
+ case "usage":
959
+ if (chunk.usage) {
960
+ setState((prev) => ({
961
+ ...prev,
962
+ usage: chunk.usage
963
+ }));
964
+ }
965
+ break;
966
+ case "error":
967
+ setState((prev) => ({
968
+ ...prev,
969
+ error: chunk.error,
970
+ isStreaming: false,
971
+ activity: void 0
972
+ }));
973
+ return;
974
+ case "done":
975
+ setState((prev) => ({
976
+ ...prev,
977
+ isStreaming: false,
978
+ usage: chunk.usage ?? prev.usage,
979
+ activity: void 0
980
+ }));
981
+ return;
982
+ }
983
+ }
984
+ setState((prev) => ({ ...prev, isStreaming: false, activity: void 0 }));
985
+ } catch (error) {
986
+ setState((prev) => ({
987
+ ...prev,
988
+ isStreaming: false,
989
+ error: error instanceof Error ? error.message : String(error),
990
+ activity: void 0
991
+ }));
992
+ }
993
+ }, []);
994
+ const cancelStream = useCallback(() => {
995
+ cancelRef.current = true;
996
+ setState((prev) => ({ ...prev, isStreaming: false }));
997
+ }, []);
998
+ const reset = useCallback(() => {
999
+ cancelRef.current = true;
1000
+ setState({
1001
+ isStreaming: false,
1002
+ content: "",
1003
+ usage: void 0,
1004
+ error: void 0,
1005
+ activity: void 0
1006
+ });
1007
+ }, []);
1008
+ return { state, startStream, cancelStream, reset };
1009
+ }
1010
+ function useCost(config) {
1011
+ const trackerRef = useRef(new CostTracker(config));
1012
+ const [totalCost, setTotalCost] = useState("$0.00");
1013
+ const [totalTokens, setTotalTokens] = useState("0");
1014
+ const [isBudgetExceeded, setIsBudgetExceeded] = useState(false);
1015
+ useEffect(() => {
1016
+ const eventBus = getEventBus();
1017
+ const unsubCost = eventBus.on("cost:updated", ({ total }) => {
1018
+ setTotalCost(formatCost(total));
1019
+ const tokens = trackerRef.current.getSessionTokens();
1020
+ setTotalTokens(formatTokenCount(tokens.total));
1021
+ });
1022
+ const unsubExceeded = eventBus.on("cost:exceeded", () => {
1023
+ setIsBudgetExceeded(true);
1024
+ });
1025
+ return () => {
1026
+ unsubCost();
1027
+ unsubExceeded();
1028
+ };
1029
+ }, []);
1030
+ const record = useCallback(
1031
+ (provider, model, inputTokens, outputTokens, role) => {
1032
+ trackerRef.current.record(provider, model, inputTokens, outputTokens, role);
1033
+ },
1034
+ []
1035
+ );
1036
+ return {
1037
+ totalCost,
1038
+ totalTokens,
1039
+ isBudgetExceeded,
1040
+ record,
1041
+ tracker: trackerRef.current
1042
+ };
1043
+ }
1044
+ function usePanel() {
1045
+ const [agents, setAgentsState] = useState([]);
1046
+ const [activeAgentIndex, setActiveAgentIndex] = useState(0);
1047
+ const [agentOutputs, setAgentOutputs] = useState(/* @__PURE__ */ new Map());
1048
+ const [isSplitPanelActive, setIsSplitPanelActive] = useState(false);
1049
+ const selectAgent = useCallback((index) => {
1050
+ setActiveAgentIndex(index);
1051
+ }, []);
1052
+ const appendOutput = useCallback((agentId, content) => {
1053
+ setAgentOutputs((prev) => {
1054
+ const next = new Map(prev);
1055
+ const existing = next.get(agentId) ?? "";
1056
+ next.set(agentId, existing + content);
1057
+ return next;
1058
+ });
1059
+ }, []);
1060
+ const updateAgentStatus = useCallback((agentId, status) => {
1061
+ setAgentsState(
1062
+ (prev) => prev.map(
1063
+ (agent) => agent.config.agentId === agentId ? { ...agent, status } : agent
1064
+ )
1065
+ );
1066
+ }, []);
1067
+ const setAgents = useCallback((newAgents) => {
1068
+ setAgentsState(newAgents);
1069
+ }, []);
1070
+ const activate = useCallback(() => {
1071
+ setIsSplitPanelActive(true);
1072
+ }, []);
1073
+ const deactivate = useCallback(() => {
1074
+ setIsSplitPanelActive(false);
1075
+ setAgentsState([]);
1076
+ setAgentOutputs(/* @__PURE__ */ new Map());
1077
+ setActiveAgentIndex(0);
1078
+ }, []);
1079
+ return useMemo(() => ({
1080
+ agents,
1081
+ activeAgentIndex,
1082
+ agentOutputs,
1083
+ isSplitPanelActive,
1084
+ selectAgent,
1085
+ appendOutput,
1086
+ updateAgentStatus,
1087
+ setAgents,
1088
+ activate,
1089
+ deactivate
1090
+ }), [agents, activeAgentIndex, agentOutputs, isSplitPanelActive, selectAgent, appendOutput, updateAgentStatus, setAgents, activate, deactivate]);
1091
+ }
1092
+ function v4Id() {
1093
+ return randomUUID();
1094
+ }
1095
+ var PROVIDER_LABELS = {
1096
+ anthropic: "Claude (Anthropic)",
1097
+ openai: "Codex (OpenAI)",
1098
+ google: "Gemini (Google)",
1099
+ kimi: "Kimi (Moonshot)"
1100
+ };
1101
+ function ModelSelector({ currentModelId, onSelect, onCancel }) {
1102
+ const rows = useMemo(() => {
1103
+ const result = [];
1104
+ for (const [providerKey, entries] of Object.entries(PROVIDER_MODEL_ORDER)) {
1105
+ result.push({ type: "header", label: PROVIDER_LABELS[providerKey] ?? providerKey });
1106
+ for (const entry of entries) {
1107
+ result.push({
1108
+ type: "model",
1109
+ label: entry.label,
1110
+ description: entry.description,
1111
+ modelId: entry.id,
1112
+ isCurrent: entry.id === currentModelId
1113
+ });
1114
+ }
1115
+ }
1116
+ return result;
1117
+ }, [currentModelId]);
1118
+ const selectableIndices = useMemo(() => {
1119
+ const indices = [];
1120
+ for (let i = 0; i < rows.length; i++) {
1121
+ if (rows[i]?.type === "model") indices.push(i);
1122
+ }
1123
+ return indices;
1124
+ }, [rows]);
1125
+ const initialIndex = useMemo(() => {
1126
+ const rowIdx = rows.findIndex((r) => r.type === "model" && r.modelId === currentModelId);
1127
+ const selectIdx = selectableIndices.indexOf(rowIdx);
1128
+ return selectIdx >= 0 ? selectIdx : 0;
1129
+ }, [rows, selectableIndices, currentModelId]);
1130
+ const [cursor, setCursor] = useState(initialIndex);
1131
+ useInput((_input, key) => {
1132
+ if (key.upArrow) {
1133
+ setCursor((prev) => prev > 0 ? prev - 1 : selectableIndices.length - 1);
1134
+ } else if (key.downArrow) {
1135
+ setCursor((prev) => prev < selectableIndices.length - 1 ? prev + 1 : 0);
1136
+ } else if (key.return) {
1137
+ const rowIdx = selectableIndices[cursor];
1138
+ const row = rowIdx !== void 0 ? rows[rowIdx] : void 0;
1139
+ if (row?.modelId) onSelect(row.modelId);
1140
+ } else if (key.escape) {
1141
+ onCancel();
1142
+ }
1143
+ });
1144
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
1145
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
1146
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Select Model" }),
1147
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: " (up/down navigate, Enter select, Esc cancel)" })
1148
+ ] }),
1149
+ rows.map((row, idx) => {
1150
+ if (row.type === "header") {
1151
+ return /* @__PURE__ */ jsx(Box, { marginTop: idx > 0 ? 1 : 0, children: /* @__PURE__ */ jsxs(Text, { bold: true, color: "yellow", children: [
1152
+ " [",
1153
+ row.label,
1154
+ "]"
1155
+ ] }) }, `header-${idx}`);
1156
+ }
1157
+ const isHighlighted = selectableIndices[cursor] === idx;
1158
+ const currentTag = row.isCurrent ? " (current)" : "";
1159
+ return /* @__PURE__ */ jsxs(Box, { children: [
1160
+ /* @__PURE__ */ jsxs(Text, { ...isHighlighted ? { color: "green" } : {}, bold: isHighlighted, children: [
1161
+ isHighlighted ? "> " : " ",
1162
+ (row.label ?? "").padEnd(30)
1163
+ ] }),
1164
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
1165
+ " ",
1166
+ row.description,
1167
+ currentTag
1168
+ ] })
1169
+ ] }, row.modelId ?? `row-${idx}`);
1170
+ }),
1171
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
1172
+ " Current: ",
1173
+ currentModelId
1174
+ ] }) })
1175
+ ] });
1176
+ }
1177
+ function formatMethod(method) {
1178
+ switch (method) {
1179
+ case "extended_thinking":
1180
+ return "Extended Thinking";
1181
+ case "reasoning_effort":
1182
+ return "Reasoning Effort";
1183
+ case "thinking_budget":
1184
+ return "Thinking Budget";
1185
+ case "thinking_level":
1186
+ return "Thinking Level";
1187
+ case "thinking_mode":
1188
+ return "Thinking Mode";
1189
+ default:
1190
+ return "Thinking";
1191
+ }
1192
+ }
1193
+ function ThinkingSelector({
1194
+ modelId,
1195
+ modelName,
1196
+ currentValue,
1197
+ onSelect,
1198
+ onBack
1199
+ }) {
1200
+ const config = useMemo(() => getThinkingConfigForModel(modelId), [modelId]);
1201
+ const initialIdx = useMemo(() => {
1202
+ if (!config) return 0;
1203
+ const idx = config.options.findIndex((o) => o.value === currentValue);
1204
+ if (idx >= 0) return idx;
1205
+ const defaultIdx = config.options.findIndex((o) => o.value === config.defaultValue);
1206
+ return Math.max(0, defaultIdx);
1207
+ }, [config, currentValue]);
1208
+ const [cursor, setCursor] = useState(initialIdx);
1209
+ useInput((_input, key) => {
1210
+ if (!config) {
1211
+ if (key.return || key.escape) onBack();
1212
+ return;
1213
+ }
1214
+ if (key.upArrow) {
1215
+ setCursor((prev) => prev > 0 ? prev - 1 : config.options.length - 1);
1216
+ } else if (key.downArrow) {
1217
+ setCursor((prev) => prev < config.options.length - 1 ? prev + 1 : 0);
1218
+ } else if (key.return) {
1219
+ const option = config.options[cursor];
1220
+ if (option) onSelect(option.value);
1221
+ } else if (key.escape) {
1222
+ onBack();
1223
+ }
1224
+ });
1225
+ if (!config) {
1226
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
1227
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
1228
+ "No thinking options available for ",
1229
+ modelName,
1230
+ "."
1231
+ ] }),
1232
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Press Enter or Esc to continue." })
1233
+ ] });
1234
+ }
1235
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
1236
+ /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [
1237
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: formatMethod(config.method) }),
1238
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
1239
+ " Model: ",
1240
+ modelName,
1241
+ " (up/down navigate, Enter select, Esc back)"
1242
+ ] })
1243
+ ] }),
1244
+ config.options.map((option, idx) => {
1245
+ const isHighlighted = cursor === idx;
1246
+ const isCurrent = option.value === currentValue;
1247
+ const currentTag = isCurrent ? " (current)" : "";
1248
+ return /* @__PURE__ */ jsxs(Box, { children: [
1249
+ /* @__PURE__ */ jsxs(Text, { ...isHighlighted ? { color: "green" } : {}, bold: isHighlighted, children: [
1250
+ isHighlighted ? "> " : " ",
1251
+ option.label.padEnd(22)
1252
+ ] }),
1253
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
1254
+ " ",
1255
+ option.description,
1256
+ currentTag
1257
+ ] })
1258
+ ] }, option.value);
1259
+ })
1260
+ ] });
1261
+ }
1262
+ function getCandidateModels(config, resolution, activeModelId) {
1263
+ const candidates = [activeModelId];
1264
+ if (resolution.source !== "user_override" && resolution.role) {
1265
+ const roleConfig = config.roles[resolution.role];
1266
+ if (roleConfig) {
1267
+ candidates.push(roleConfig.primary, ...roleConfig.fallback);
1268
+ }
1269
+ }
1270
+ const seen = /* @__PURE__ */ new Set();
1271
+ const unique = [];
1272
+ for (const modelId of candidates) {
1273
+ if (!seen.has(modelId)) {
1274
+ seen.add(modelId);
1275
+ unique.push(modelId);
1276
+ }
1277
+ }
1278
+ return unique;
1279
+ }
1280
+ function App({ config, options }) {
1281
+ const { resolution, modelId, switchModel, switchRole } = useModel(
1282
+ config,
1283
+ options.model,
1284
+ options.role
1285
+ );
1286
+ const { state: streamState, startStream, cancelStream, reset: resetStream } = useStream();
1287
+ const { totalCost, totalTokens, record } = useCost(config.cost);
1288
+ const totalCostRef = useRef(totalCost);
1289
+ totalCostRef.current = totalCost;
1290
+ const totalTokensRef = useRef(totalTokens);
1291
+ totalTokensRef.current = totalTokens;
1292
+ const panel = usePanel();
1293
+ const [messages, setMessages] = useState([]);
1294
+ const [isProcessing, setIsProcessing] = useState(false);
1295
+ const messagesRef = useRef([]);
1296
+ messagesRef.current = messages;
1297
+ const [gitBranch, setGitBranch] = useState();
1298
+ const [thinkingValue, setThinkingValue] = useState("medium");
1299
+ const [selectionMode, setSelectionMode] = useState({ type: "none" });
1300
+ const registryRef = useRef(void 0);
1301
+ const getRegistry = useCallback(async () => {
1302
+ if (registryRef.current !== void 0) return registryRef.current;
1303
+ const { createDefaultRegistry } = await import('./registry-4KD24ZC3.js');
1304
+ registryRef.current = await createDefaultRegistry();
1305
+ return registryRef.current;
1306
+ }, []);
1307
+ useEffect(() => {
1308
+ import('child_process').then(({ execFile }) => {
1309
+ execFile("git", ["rev-parse", "--abbrev-ref", "HEAD"], { timeout: 2e3 }, (error, stdout) => {
1310
+ if (!error && stdout) {
1311
+ setGitBranch(stdout.trim());
1312
+ }
1313
+ });
1314
+ }).catch(() => {
1315
+ });
1316
+ }, []);
1317
+ useEffect(() => {
1318
+ if (options.initialMessage) {
1319
+ void handleSubmit(options.initialMessage);
1320
+ }
1321
+ }, []);
1322
+ const handleSubmit = useCallback(
1323
+ async (input) => {
1324
+ if (input.startsWith("/")) {
1325
+ await handleInternalCommand(input, switchModel, switchRole, {
1326
+ totalCost: totalCostRef.current,
1327
+ totalTokens: totalTokensRef.current,
1328
+ setMessages,
1329
+ modelId,
1330
+ thinkingValue,
1331
+ setThinkingValue,
1332
+ setSelectionMode,
1333
+ resolution,
1334
+ panel: {
1335
+ setAgents: panel.setAgents,
1336
+ activate: panel.activate,
1337
+ deactivate: panel.deactivate,
1338
+ appendOutput: panel.appendOutput
1339
+ },
1340
+ getRegistry
1341
+ });
1342
+ return;
1343
+ }
1344
+ if (input.startsWith("$")) {
1345
+ await handleSkillInvocation(input, setMessages);
1346
+ return;
1347
+ }
1348
+ if (!options.isAgentPane && !panel.isSplitPanelActive && !activeTeamName && detectTeamCreationIntent(input)) {
1349
+ const leaderTask = await handlePromptBasedTeamCreation(input, setMessages, panel, getRegistry, modelId);
1350
+ if (leaderTask) {
1351
+ setTimeout(() => void handleSubmit(leaderTask), 1500);
1352
+ }
1353
+ return;
1354
+ }
1355
+ const userMessage = {
1356
+ id: v4Id(),
1357
+ role: "user",
1358
+ content: input,
1359
+ createdAt: /* @__PURE__ */ new Date()
1360
+ };
1361
+ setMessages((prev) => [...prev, userMessage]);
1362
+ setIsProcessing(true);
1363
+ resetStream();
1364
+ try {
1365
+ const registry = await getRegistry();
1366
+ const allMessages = [...messagesRef.current, userMessage].filter((m) => m.role !== "system");
1367
+ const candidateModels = getCandidateModels(config, resolution, modelId);
1368
+ let responseModel = modelId;
1369
+ let responseProvider = resolution.provider;
1370
+ let fullContent = "";
1371
+ let completed = false;
1372
+ let lastError;
1373
+ for (const candidateModel of candidateModels) {
1374
+ const provider = registry.hasModel(candidateModel) ? registry.getForModel(candidateModel) : void 0;
1375
+ if (!provider) {
1376
+ lastError = new Error(`No provider available for model "${candidateModel}"`);
1377
+ continue;
1378
+ }
1379
+ const candidateProvider = provider;
1380
+ let candidateContent = "";
1381
+ let caughtError;
1382
+ const stream = candidateProvider.stream({
1383
+ model: candidateModel,
1384
+ messages: allMessages,
1385
+ system: options.systemPrompt,
1386
+ maxTokens: 16e3
1387
+ });
1388
+ async function* instrumentedStream(source) {
1389
+ try {
1390
+ for await (const chunk of source) {
1391
+ if (chunk.type === "text" && chunk.content) {
1392
+ candidateContent += chunk.content;
1393
+ }
1394
+ if (chunk.type === "usage" && chunk.usage) {
1395
+ record(
1396
+ candidateProvider.name,
1397
+ candidateModel,
1398
+ chunk.usage.inputTokens,
1399
+ chunk.usage.outputTokens,
1400
+ resolution.role
1401
+ );
1402
+ }
1403
+ if (chunk.type === "error") {
1404
+ caughtError = new Error(
1405
+ chunk.error ?? `Model "${candidateModel}" stream failed`
1406
+ );
1407
+ }
1408
+ yield chunk;
1409
+ }
1410
+ } catch (err) {
1411
+ caughtError = err;
1412
+ throw err;
1413
+ }
1414
+ }
1415
+ resetStream();
1416
+ await startStream(instrumentedStream(stream));
1417
+ if (caughtError !== void 0) {
1418
+ lastError = caughtError;
1419
+ continue;
1420
+ }
1421
+ responseModel = candidateModel;
1422
+ responseProvider = candidateProvider.name;
1423
+ fullContent = candidateContent;
1424
+ completed = true;
1425
+ break;
1426
+ }
1427
+ if (!completed) {
1428
+ if (lastError instanceof Error) {
1429
+ throw lastError;
1430
+ }
1431
+ throw new Error(
1432
+ typeof lastError === "string" ? lastError : "No model could produce a response"
1433
+ );
1434
+ }
1435
+ if (fullContent.length > 0) {
1436
+ const assistantMessage = {
1437
+ id: v4Id(),
1438
+ role: "assistant",
1439
+ content: fullContent,
1440
+ model: responseModel,
1441
+ provider: responseProvider,
1442
+ createdAt: /* @__PURE__ */ new Date()
1443
+ };
1444
+ setMessages((prev) => {
1445
+ const output = [...prev];
1446
+ if (responseModel !== modelId) {
1447
+ output.push({
1448
+ id: v4Id(),
1449
+ role: "system",
1450
+ content: `Primary model "${modelId}" failed. Switched to fallback "${responseModel}".`,
1451
+ createdAt: /* @__PURE__ */ new Date()
1452
+ });
1453
+ }
1454
+ output.push(assistantMessage);
1455
+ return output;
1456
+ });
1457
+ }
1458
+ } catch (error) {
1459
+ const errorContent = error instanceof Error ? error.message : String(error);
1460
+ const errorMessage = {
1461
+ id: v4Id(),
1462
+ role: "assistant",
1463
+ content: `Error: ${errorContent}`,
1464
+ model: modelId,
1465
+ createdAt: /* @__PURE__ */ new Date()
1466
+ };
1467
+ setMessages((prev) => [...prev, errorMessage]);
1468
+ } finally {
1469
+ setIsProcessing(false);
1470
+ }
1471
+ },
1472
+ [
1473
+ config,
1474
+ modelId,
1475
+ resolution,
1476
+ options.systemPrompt,
1477
+ record,
1478
+ switchModel,
1479
+ switchRole,
1480
+ startStream,
1481
+ resetStream,
1482
+ getRegistry,
1483
+ panel,
1484
+ thinkingValue
1485
+ ]
1486
+ );
1487
+ const handleSubmitSync = useCallback((input) => {
1488
+ void handleSubmit(input);
1489
+ }, [handleSubmit]);
1490
+ const handleCancel = useCallback(() => {
1491
+ cancelStream();
1492
+ setIsProcessing(false);
1493
+ }, [cancelStream]);
1494
+ const handleModelSelected = useCallback((selectedModelId) => {
1495
+ const thinkingCfg = getThinkingConfigForModel(selectedModelId);
1496
+ if (thinkingCfg) {
1497
+ setSelectionMode({ type: "thinking", modelId: selectedModelId });
1498
+ } else {
1499
+ switchModel(selectedModelId);
1500
+ setSelectionMode({ type: "none" });
1501
+ const info = SUPPORTED_MODELS[selectedModelId];
1502
+ setMessages((prev) => [
1503
+ ...prev,
1504
+ { id: v4Id(), role: "system", content: `Switched to model: ${info?.name ?? selectedModelId}`, createdAt: /* @__PURE__ */ new Date() }
1505
+ ]);
1506
+ }
1507
+ }, [switchModel]);
1508
+ const handleThinkingSelected = useCallback((value) => {
1509
+ if (selectionMode.type !== "thinking") return;
1510
+ const { modelId: selectedModelId } = selectionMode;
1511
+ switchModel(selectedModelId);
1512
+ setThinkingValue(value);
1513
+ setSelectionMode({ type: "none" });
1514
+ const info = SUPPORTED_MODELS[selectedModelId];
1515
+ const cfg = getThinkingConfigForModel(selectedModelId);
1516
+ const methodLabel = cfg ? formatThinkingMethod(cfg.method) : "Thinking";
1517
+ const optionLabel = cfg?.options.find((o) => o.value === value)?.label ?? value;
1518
+ setMessages((prev) => [
1519
+ ...prev,
1520
+ { id: v4Id(), role: "system", content: `Switched to model: ${info?.name ?? selectedModelId}
1521
+ ${methodLabel}: ${optionLabel}`, createdAt: /* @__PURE__ */ new Date() }
1522
+ ]);
1523
+ }, [selectionMode, switchModel]);
1524
+ const handleSelectionCancel = useCallback(() => {
1525
+ setSelectionMode({ type: "none" });
1526
+ }, []);
1527
+ if (selectionMode.type === "model") {
1528
+ return /* @__PURE__ */ jsx(
1529
+ ModelSelector,
1530
+ {
1531
+ currentModelId: modelId,
1532
+ onSelect: handleModelSelected,
1533
+ onCancel: handleSelectionCancel
1534
+ }
1535
+ );
1536
+ }
1537
+ if (selectionMode.type === "thinking") {
1538
+ const selectedInfo = SUPPORTED_MODELS[selectionMode.modelId];
1539
+ return /* @__PURE__ */ jsx(
1540
+ ThinkingSelector,
1541
+ {
1542
+ modelId: selectionMode.modelId,
1543
+ modelName: selectedInfo?.name ?? selectionMode.modelId,
1544
+ currentValue: thinkingValue,
1545
+ onSelect: handleThinkingSelected,
1546
+ onBack: handleSelectionCancel
1547
+ }
1548
+ );
1549
+ }
1550
+ if (panel.isSplitPanelActive) {
1551
+ return /* @__PURE__ */ jsx(
1552
+ SplitPane,
1553
+ {
1554
+ agents: panel.agents,
1555
+ activeAgentIndex: panel.activeAgentIndex,
1556
+ onSelectAgent: panel.selectAgent,
1557
+ agentOutputs: panel.agentOutputs,
1558
+ isProcessing,
1559
+ onSubmit: handleSubmitSync,
1560
+ onCancel: handleCancel,
1561
+ model: modelId,
1562
+ role: resolution.role,
1563
+ tokenCount: totalTokens,
1564
+ cost: totalCost,
1565
+ gitBranch
1566
+ }
1567
+ );
1568
+ }
1569
+ return /* @__PURE__ */ jsx(
1570
+ SinglePane,
1571
+ {
1572
+ messages,
1573
+ isProcessing,
1574
+ onSubmit: handleSubmitSync,
1575
+ onCancel: handleCancel,
1576
+ model: modelId,
1577
+ role: resolution.role,
1578
+ tokenCount: totalTokens,
1579
+ cost: totalCost,
1580
+ gitBranch,
1581
+ streamingContent: streamState.content,
1582
+ activity: streamState.activity
1583
+ }
1584
+ );
1585
+ }
1586
+ function addSystemMessage(ctx, content) {
1587
+ ctx.setMessages((prev) => [
1588
+ ...prev,
1589
+ {
1590
+ id: v4Id(),
1591
+ role: "system",
1592
+ content,
1593
+ createdAt: /* @__PURE__ */ new Date()
1594
+ }
1595
+ ]);
1596
+ }
1597
+ function resolveModelSelection(input) {
1598
+ if (SUPPORTED_MODELS[input]) {
1599
+ return input;
1600
+ }
1601
+ if (/^\d+$/.test(input)) {
1602
+ const index = Number(input);
1603
+ let globalIndex = 1;
1604
+ for (const entries of Object.values(PROVIDER_MODEL_ORDER)) {
1605
+ for (const entry of entries) {
1606
+ if (globalIndex === index) {
1607
+ return entry.id;
1608
+ }
1609
+ globalIndex++;
1610
+ }
1611
+ }
1612
+ }
1613
+ return void 0;
1614
+ }
1615
+ function formatThinkingMethod(method) {
1616
+ switch (method) {
1617
+ case "extended_thinking":
1618
+ return "Extended Thinking";
1619
+ case "reasoning_effort":
1620
+ return "Reasoning Effort";
1621
+ case "thinking_budget":
1622
+ return "Thinking Budget";
1623
+ case "thinking_level":
1624
+ return "Thinking Level";
1625
+ case "thinking_mode":
1626
+ return "Thinking Mode";
1627
+ default:
1628
+ return "Thinking";
1629
+ }
1630
+ }
1631
+ async function handleInternalCommand(input, switchModel, switchRole, ctx) {
1632
+ const parts = input.trim().split(/\s+/);
1633
+ const command = parts[0];
1634
+ const args = parts.slice(1);
1635
+ const arg = args[0];
1636
+ switch (command) {
1637
+ case "/help": {
1638
+ const helpLines = SLASH_COMMANDS.map((cmd) => ` ${cmd.command.padEnd(17)}${cmd.description}`).join("\n");
1639
+ addSystemMessage(ctx, helpLines);
1640
+ break;
1641
+ }
1642
+ case "/model": {
1643
+ if (arg) {
1644
+ const resolvedId = resolveModelSelection(arg);
1645
+ if (!resolvedId) {
1646
+ addSystemMessage(ctx, `Unknown model: ${arg}`);
1647
+ break;
1648
+ }
1649
+ const info = SUPPORTED_MODELS[resolvedId];
1650
+ if (!info) {
1651
+ addSystemMessage(ctx, `Unknown model: ${arg}`);
1652
+ break;
1653
+ }
1654
+ switchModel(resolvedId);
1655
+ const thinkingCfg = getThinkingConfigForModel(resolvedId);
1656
+ if (thinkingCfg) {
1657
+ const isValid = thinkingCfg.options.some((o) => o.value === ctx.thinkingValue);
1658
+ if (!isValid) ctx.setThinkingValue(thinkingCfg.defaultValue);
1659
+ }
1660
+ addSystemMessage(ctx, `Switched to model: ${info.name}`);
1661
+ } else {
1662
+ ctx.setSelectionMode({ type: "model" });
1663
+ }
1664
+ break;
1665
+ }
1666
+ case "/role": {
1667
+ if (arg) {
1668
+ const validRoles = ["planning", "coding", "review", "testing", "bugfix", "documentation"];
1669
+ if (validRoles.includes(arg)) {
1670
+ switchRole(arg);
1671
+ addSystemMessage(ctx, `Switched to role: ${arg}`);
1672
+ } else {
1673
+ addSystemMessage(ctx, `Unknown role: ${arg}
1674
+ Valid roles: ${validRoles.join(", ")}`);
1675
+ }
1676
+ } else {
1677
+ addSystemMessage(ctx, `Current role: ${ctx.resolution.role ?? "default"}`);
1678
+ }
1679
+ break;
1680
+ }
1681
+ case "/cost":
1682
+ addSystemMessage(ctx, `Session cost: ${ctx.totalCost} | Tokens: ${ctx.totalTokens}`);
1683
+ break;
1684
+ case "/clear":
1685
+ ctx.setMessages([]);
1686
+ break;
1687
+ case "/compact":
1688
+ addSystemMessage(ctx, "Context compacted.");
1689
+ break;
1690
+ case "/team":
1691
+ await handleTeamCommand(args, ctx);
1692
+ break;
1693
+ case "/mcp":
1694
+ await handleMcpCommand(args, ctx);
1695
+ break;
1696
+ case "/skill":
1697
+ await handleSkillCommand(args, ctx);
1698
+ break;
1699
+ case "/panel": {
1700
+ const layout = arg;
1701
+ if (!layout) {
1702
+ addSystemMessage(ctx, "Usage: /panel <layout>\nLayouts: auto, horizontal, vertical, grid");
1703
+ } else {
1704
+ addSystemMessage(ctx, `Panel layout set to: ${layout}`);
1705
+ }
1706
+ break;
1707
+ }
1708
+ case "/auth":
1709
+ await handleAuthSlashCommand(args, ctx);
1710
+ break;
1711
+ case "/config":
1712
+ await handleConfigSlashCommand(args, ctx);
1713
+ break;
1714
+ case "/quit":
1715
+ case "/exit":
1716
+ process.exit(0);
1717
+ break;
1718
+ default:
1719
+ addSystemMessage(ctx, `Unknown command: ${command}. Type /help for available commands.`);
1720
+ }
1721
+ }
1722
+ 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.
1723
+
1724
+ You MUST respond with ONLY a JSON array (no markdown, no explanation, no code fences). Each element represents one agent with these exact fields:
1725
+ - "name": string \u2014 PascalCase name describing the agent's function (e.g. "ProjectManager", "TypeScriptDeveloper", "SecurityAuditor")
1726
+ - "agentType": string \u2014 short role type (e.g. "lead", "developer", "reviewer", "researcher", "designer", "architect", "auditor", "tester")
1727
+ - "model": string \u2014 one of the available models (provided in the user message)
1728
+ - "role": string \u2014 one of: "planning", "coding", "review", "testing", "bugfix", "documentation"
1729
+ - "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.
1730
+
1731
+ Guidelines for team design:
1732
+ - Use the MINIMUM number of agents needed to accomplish the task (typically 2-5, max 8)
1733
+ - Assign the most capable models (opus, gpt-5.2, gemini pro) to critical roles like planning and review
1734
+ - Assign efficient models (sonnet, haiku, flash) to implementation, testing, and documentation
1735
+ - Every team MUST have at least one agent with role "coding" to do actual implementation
1736
+ - For complex tasks, include a planner/lead agent and a reviewer agent
1737
+ - If only one provider's models are available, use those models for all agents
1738
+ - Each agent's taskPrompt must be highly specific to the user's request \u2014 never use generic instructions
1739
+ - Agent names should reflect their specific responsibility in this task
1740
+ `;
1741
+ var VALID_ROLES = /* @__PURE__ */ new Set([
1742
+ "planning",
1743
+ "coding",
1744
+ "review",
1745
+ "testing",
1746
+ "bugfix",
1747
+ "documentation"
1748
+ ]);
1749
+ function parseLLMTeamDesign(response, availableModels, fallbackModel) {
1750
+ let jsonStr = response.trim();
1751
+ const fenceMatch = /```(?:json)?\s*\n?([\s\S]*?)\n?```/.exec(jsonStr);
1752
+ if (fenceMatch?.[1] !== void 0) {
1753
+ jsonStr = fenceMatch[1].trim();
1754
+ }
1755
+ const arrayStart = jsonStr.indexOf("[");
1756
+ const arrayEnd = jsonStr.lastIndexOf("]");
1757
+ if (arrayStart === -1 || arrayEnd === -1 || arrayEnd <= arrayStart) {
1758
+ throw new Error("LLM response does not contain a valid JSON array for team design");
1759
+ }
1760
+ jsonStr = jsonStr.slice(arrayStart, arrayEnd + 1);
1761
+ let parsed;
1762
+ try {
1763
+ parsed = JSON.parse(jsonStr);
1764
+ } catch {
1765
+ throw new Error("Failed to parse LLM team design as JSON");
1766
+ }
1767
+ if (!Array.isArray(parsed) || parsed.length === 0) {
1768
+ throw new Error("LLM team design must be a non-empty array");
1769
+ }
1770
+ const availableSet = new Set(availableModels);
1771
+ const specs = [];
1772
+ for (const item of parsed) {
1773
+ if (typeof item !== "object" || item === null) continue;
1774
+ const record = item;
1775
+ const name = typeof record["name"] === "string" && record["name"].length > 0 ? record["name"] : `Agent${specs.length + 1}`;
1776
+ const agentType = typeof record["agentType"] === "string" && record["agentType"].length > 0 ? record["agentType"] : "developer";
1777
+ const rawModel = typeof record["model"] === "string" ? record["model"] : "";
1778
+ const rawRole = typeof record["role"] === "string" ? record["role"] : "coding";
1779
+ const taskPrompt = typeof record["taskPrompt"] === "string" ? record["taskPrompt"] : "";
1780
+ const model = availableSet.has(rawModel) ? rawModel : fallbackModel;
1781
+ const role = VALID_ROLES.has(rawRole) ? rawRole : "coding";
1782
+ specs.push({ name, agentType, model, role, taskPrompt });
1783
+ }
1784
+ if (specs.length === 0) {
1785
+ throw new Error("LLM team design produced no valid agent specifications");
1786
+ }
1787
+ return specs.slice(0, 8);
1788
+ }
1789
+ function buildTeamDesignUserPrompt(userRequest, availableModels) {
1790
+ const modelList = availableModels.map((id) => {
1791
+ const info = SUPPORTED_MODELS[id];
1792
+ if (!info) return `- ${id}`;
1793
+ return `- ${id} (${info.provider}, ${info.name})`;
1794
+ }).join("\n");
1795
+ return `Available models:
1796
+ ${modelList}
1797
+
1798
+ User request:
1799
+ ${userRequest}
1800
+
1801
+ Design the agent team. Respond with ONLY a JSON array.`;
1802
+ }
1803
+ var TEAM_CREATION_PATTERNS = [
1804
+ /\bcreate\s+(?:a\s+)?team\b/i,
1805
+ /\bstart\s+(?:a\s+)?team\b/i,
1806
+ /\bspawn\s+(?:a\s+)?(?:team|agents?)\b/i,
1807
+ /\buse\s+(?:a\s+)?team\b/i,
1808
+ /\bassemble\s+(?:a\s+)?team\b/i,
1809
+ /\blaunch\s+(?:a\s+)?team\b/i,
1810
+ /\bneed\s+(?:a\s+)?team\b/i,
1811
+ /\bwork\s+(?:as|with)\s+(?:a\s+)?team\b/i,
1812
+ /\bmulti[- ]?agent\b/i,
1813
+ /\bagent\s+team\b/i
1814
+ ];
1815
+ function detectTeamCreationIntent(input) {
1816
+ return TEAM_CREATION_PATTERNS.some((pattern) => pattern.test(input));
1817
+ }
1818
+ var activeTeamManager;
1819
+ var activeTeamName;
1820
+ var activeTmuxCleanup;
1821
+ var PROVIDER_CLI_MAP = {
1822
+ anthropic: { bin: "claude", modelFlag: true, extraArgs: ["--dangerously-skip-permissions"] },
1823
+ openai: { bin: "codex", modelFlag: true, extraArgs: ["--sandbox", "danger-full-access", "--ask-for-approval", "never"] },
1824
+ google: { bin: "gemini", modelFlag: true, extraArgs: ["--yolo"] },
1825
+ kimi: { bin: "kimi", modelFlag: false, extraArgs: ["--yolo"] }
1826
+ };
1827
+ function writeAgentLauncherScript(provider, model, promptFile, launcherFile, projectRoot, shellEscapeFn, writeFileSyncFn) {
1828
+ const cliInfo = PROVIDER_CLI_MAP[provider];
1829
+ if (cliInfo) {
1830
+ const modelArg = cliInfo.modelFlag ? ` --model ${model}` : "";
1831
+ const extraArgs = cliInfo.extraArgs.length > 0 ? ` ${cliInfo.extraArgs.join(" ")}` : "";
1832
+ const script2 = [
1833
+ "#!/bin/bash",
1834
+ `cd '${shellEscapeFn(projectRoot)}' || exit 1`,
1835
+ `${cliInfo.bin}${extraArgs}${modelArg} "$(cat '${shellEscapeFn(promptFile)}')"`
1836
+ ].join("\n");
1837
+ writeFileSyncFn(launcherFile, script2, { mode: 493 });
1838
+ return `bash '${shellEscapeFn(launcherFile)}'`;
1839
+ }
1840
+ const script = [
1841
+ "#!/bin/bash",
1842
+ `cd '${shellEscapeFn(projectRoot)}' || exit 1`,
1843
+ `export AEMEATHCLI_PROMPT_FILE='${shellEscapeFn(promptFile)}'`,
1844
+ `'${shellEscapeFn(process.execPath)}' '${shellEscapeFn(process.argv[1] ?? "aemeathcli")}' --model ${model}`
1845
+ ].join("\n");
1846
+ writeFileSyncFn(launcherFile, script, { mode: 493 });
1847
+ return `bash '${shellEscapeFn(launcherFile)}'`;
1848
+ }
1849
+ async function handlePromptBasedTeamCreation(input, setMessages, panel, getRegistry, currentModelId) {
1850
+ const teamName = `team-${Date.now()}`;
1851
+ setMessages((prev) => [
1852
+ ...prev,
1853
+ { id: v4Id(), role: "user", content: input, createdAt: /* @__PURE__ */ new Date() },
1854
+ {
1855
+ id: v4Id(),
1856
+ role: "system",
1857
+ content: "Analyzing your request to design the agent team...",
1858
+ createdAt: /* @__PURE__ */ new Date()
1859
+ }
1860
+ ]);
1861
+ try {
1862
+ const registry = await getRegistry();
1863
+ const availableModels = Object.keys(SUPPORTED_MODELS).filter(
1864
+ (id) => registry.hasModel(id)
1865
+ );
1866
+ if (availableModels.length === 0) {
1867
+ setMessages((prev) => [
1868
+ ...prev,
1869
+ {
1870
+ id: v4Id(),
1871
+ role: "system",
1872
+ content: "No models available. Please authenticate with at least one provider using 'aemeathcli auth login'.",
1873
+ createdAt: /* @__PURE__ */ new Date()
1874
+ }
1875
+ ]);
1876
+ return;
1877
+ }
1878
+ const designModel = registry.hasModel(currentModelId) ? currentModelId : availableModels[0];
1879
+ const designProvider = registry.getForModel(designModel);
1880
+ const userPrompt = buildTeamDesignUserPrompt(input, availableModels);
1881
+ const designStream = designProvider.stream({
1882
+ model: designModel,
1883
+ messages: [
1884
+ {
1885
+ id: v4Id(),
1886
+ role: "user",
1887
+ content: userPrompt,
1888
+ createdAt: /* @__PURE__ */ new Date()
1889
+ }
1890
+ ],
1891
+ system: TEAM_DESIGN_SYSTEM_PROMPT,
1892
+ maxTokens: 4e3
1893
+ });
1894
+ let designResponse = "";
1895
+ for await (const chunk of designStream) {
1896
+ if (chunk.type === "text" && chunk.content) {
1897
+ designResponse += chunk.content;
1898
+ }
1899
+ }
1900
+ const agentSpecs = parseLLMTeamDesign(
1901
+ designResponse,
1902
+ availableModels,
1903
+ designModel
1904
+ );
1905
+ const agentDefinitions = agentSpecs.map((spec) => {
1906
+ const modelInfo = SUPPORTED_MODELS[spec.model];
1907
+ const provider = modelInfo?.provider ?? "anthropic";
1908
+ return {
1909
+ name: spec.name,
1910
+ agentType: spec.agentType,
1911
+ model: spec.model,
1912
+ provider,
1913
+ role: spec.role
1914
+ };
1915
+ });
1916
+ const { writeFileSync, mkdirSync, mkdtempSync } = await import('fs');
1917
+ const { join } = await import('path');
1918
+ const { tmpdir } = await import('os');
1919
+ const { execa: execaPane } = await import('execa');
1920
+ const boardDir = join(process.cwd(), ".aemeathcli", "team-board");
1921
+ mkdirSync(boardDir, { recursive: true });
1922
+ const tempDir = mkdtempSync(join(tmpdir(), "aemeathcli-team-"));
1923
+ const shellEscape = (s) => s.replace(/'/gu, "'\\''");
1924
+ const leadSpec = agentSpecs.find((s) => s.agentType === "lead") ?? agentSpecs.find((s) => s.role === "planning") ?? agentSpecs[0];
1925
+ const teamManifest = {
1926
+ teamName,
1927
+ task: input,
1928
+ boardDir,
1929
+ leadAgent: leadSpec.name,
1930
+ agents: agentSpecs.map((s) => ({
1931
+ name: s.name,
1932
+ agentType: s.agentType,
1933
+ model: s.model,
1934
+ role: s.role,
1935
+ outputFile: join(boardDir, `${s.name}.md`)
1936
+ })),
1937
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1938
+ };
1939
+ writeFileSync(
1940
+ join(boardDir, "team-manifest.json"),
1941
+ JSON.stringify(teamManifest, null, 2),
1942
+ "utf-8"
1943
+ );
1944
+ const teamRoster = agentSpecs.map((s) => ` - ${s.name} (${s.agentType}, ${s.model}) \u2014 role: ${s.role}`).join("\n");
1945
+ const workerSpecs = agentSpecs.filter((s) => s.name !== leadSpec.name);
1946
+ const projectRoot = process.cwd();
1947
+ const agentCommands = [];
1948
+ for (const spec of [...workerSpecs]) {
1949
+ const outputFile = join(boardDir, `${spec.name}.md`);
1950
+ const promptFile = join(tempDir, `${spec.name}.txt`);
1951
+ const prompt = [
1952
+ `# Team Role: ${spec.name}`,
1953
+ `Type: ${spec.agentType} | Model: ${spec.model} | Role: ${spec.role}`,
1954
+ "",
1955
+ "## Your Task",
1956
+ spec.taskPrompt,
1957
+ "",
1958
+ "## Team Context",
1959
+ `You are part of a ${agentSpecs.length}-agent team working collaboratively.`,
1960
+ `Each agent has a specific domain. Do NOT overlap with other agents' responsibilities.`,
1961
+ "",
1962
+ "### Team Members:",
1963
+ teamRoster,
1964
+ "",
1965
+ "## Shared Workspace",
1966
+ `Team board directory: ${boardDir}`,
1967
+ `Your output file: ${outputFile}`,
1968
+ `Team manifest: ${join(boardDir, "team-manifest.json")}`,
1969
+ "",
1970
+ "## Coordination Protocol",
1971
+ `1. Write ALL your findings, analysis, and deliverables to your output file: ${outputFile}`,
1972
+ `2. You can read other agents' output files in ${boardDir}/ to check their progress and avoid duplication.`,
1973
+ `3. Focus on YOUR specific domain. Reference other agents' work when relevant to your analysis.`,
1974
+ `4. Read and analyze source files in the project directory to complete your task.`,
1975
+ `5. Be thorough and specific. Include file paths, line numbers, and code snippets in your findings.`,
1976
+ "",
1977
+ "## Coordination with Lead",
1978
+ `The team lead is ${leadSpec.name}. Check their coordination plan at: ${join(boardDir, "coordinator.md")}`,
1979
+ `After completing your work, the lead agent will read your output and synthesize findings.`,
1980
+ "",
1981
+ "## User's Original Request",
1982
+ input
1983
+ ].join("\n");
1984
+ writeFileSync(promptFile, prompt, "utf-8");
1985
+ const modelInfo = SUPPORTED_MODELS[spec.model];
1986
+ const provider = modelInfo?.provider ?? "anthropic";
1987
+ const launcherFile = join(tempDir, `${spec.name}-launch.sh`);
1988
+ const cmd = writeAgentLauncherScript(
1989
+ provider,
1990
+ spec.model,
1991
+ promptFile,
1992
+ launcherFile,
1993
+ projectRoot,
1994
+ shellEscape,
1995
+ writeFileSync
1996
+ );
1997
+ agentCommands.push({ name: spec.name, command: cmd });
1998
+ }
1999
+ const leadOutputFile = join(boardDir, `${leadSpec.name}.md`);
2000
+ const leadCoordinationTask = [
2001
+ `I am the team coordinator (${leadSpec.name}, ${leadSpec.model}).`,
2002
+ "",
2003
+ leadSpec.taskPrompt,
2004
+ "",
2005
+ `## My Responsibilities`,
2006
+ `1. Break down the user's request into clear subtasks for each team member.`,
2007
+ `2. Write my coordination plan and task assignments to: ${join(boardDir, "coordinator.md")}`,
2008
+ `3. After completing my own analysis, read other agents' output files in ${boardDir}/ to check progress.`,
2009
+ `4. Synthesize findings from all agents into a final team summary at: ${join(boardDir, "SUMMARY.md")}`,
2010
+ `5. Flag any conflicts, gaps, or overlaps between agents' work.`,
2011
+ "",
2012
+ `## Team Members Working in Parallel Panes`,
2013
+ ...workerSpecs.map((s) => `- ${s.name} (${s.model}): writing to ${join(boardDir, s.name + ".md")}`),
2014
+ "",
2015
+ `## My Output File: ${leadOutputFile}`,
2016
+ "",
2017
+ `## User's Original Request`,
2018
+ input,
2019
+ "",
2020
+ `Start by reading the codebase and writing my coordination plan to ${join(boardDir, "coordinator.md")}.`
2021
+ ].join("\n");
2022
+ const isITerm2 = process.platform === "darwin" && process.env["TERM_PROGRAM"] === "iTerm.app";
2023
+ if (isITerm2) {
2024
+ setMessages((prev) => [
2025
+ ...prev,
2026
+ {
2027
+ id: v4Id(),
2028
+ role: "system",
2029
+ content: `Designed ${agentSpecs.length}-agent team. Creating iTerm2 split panes...`,
2030
+ createdAt: /* @__PURE__ */ new Date()
2031
+ }
2032
+ ]);
2033
+ const asEscape = (s) => s.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"');
2034
+ const scriptLines = [];
2035
+ scriptLines.push('tell application "iTerm2"');
2036
+ scriptLines.push(" tell current window");
2037
+ scriptLines.push(" set leaderSession to current session of current tab");
2038
+ for (let i = 0; i < agentCommands.length; i++) {
2039
+ const agent = agentCommands[i];
2040
+ const prevVar = i === 0 ? "leaderSession" : `agent${i - 1}`;
2041
+ const curVar = `agent${i}`;
2042
+ const splitDir = i === 0 ? "vertically" : "horizontally";
2043
+ const splitTarget = prevVar;
2044
+ const escapedName = asEscape(agent.name);
2045
+ const escapedCmd = asEscape(agent.command);
2046
+ scriptLines.push(` tell ${splitTarget}`);
2047
+ scriptLines.push(` set ${curVar} to (split ${splitDir} with default profile)`);
2048
+ scriptLines.push(" end tell");
2049
+ scriptLines.push(` tell ${curVar}`);
2050
+ scriptLines.push(` set name to "${escapedName}"`);
2051
+ scriptLines.push(` write text "${escapedCmd}"`);
2052
+ scriptLines.push(" end tell");
2053
+ }
2054
+ scriptLines.push(" select leaderSession");
2055
+ scriptLines.push(" end tell");
2056
+ scriptLines.push("end tell");
2057
+ const script = scriptLines.join("\n");
2058
+ const scriptFile = join(tempDir, "create-panes.applescript");
2059
+ writeFileSync(scriptFile, script, "utf-8");
2060
+ try {
2061
+ await execaPane("osascript", [scriptFile]);
2062
+ } catch (scriptErr) {
2063
+ const errMsg = scriptErr instanceof Error ? scriptErr.message : String(scriptErr);
2064
+ setMessages((prev) => [
2065
+ ...prev,
2066
+ {
2067
+ id: v4Id(),
2068
+ role: "system",
2069
+ content: `Failed to create iTerm2 panes: ${errMsg.slice(0, 200)}`,
2070
+ createdAt: /* @__PURE__ */ new Date()
2071
+ }
2072
+ ]);
2073
+ return;
2074
+ }
2075
+ activeTeamName = teamName;
2076
+ activeTeamManager = void 0;
2077
+ activeTmuxCleanup = async () => {
2078
+ try {
2079
+ const { execSync } = await import('child_process');
2080
+ execSync(`pkill -f '${shellEscape(tempDir)}'`, { stdio: "ignore" });
2081
+ } catch {
2082
+ }
2083
+ try {
2084
+ const { rmSync } = await import('fs');
2085
+ rmSync(tempDir, { recursive: true, force: true });
2086
+ rmSync(boardDir, { recursive: true, force: true });
2087
+ } catch {
2088
+ }
2089
+ };
2090
+ const agentLines2 = agentSpecs.map(
2091
+ (spec) => spec.name === leadSpec.name ? ` ${spec.name} (${spec.model}) \u2014 ${spec.role} [LEAD \u2014 this pane]` : ` ${spec.name} (${spec.model}) \u2014 ${spec.role}`
2092
+ );
2093
+ setMessages((prev) => [
2094
+ ...prev,
2095
+ {
2096
+ id: v4Id(),
2097
+ role: "system",
2098
+ content: `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
2099
+ ${workerSpecs.length} worker panes in iTerm2 + lead coordinating here.
2100
+ ${agentLines2.join("\n")}
2101
+ /team stop to shut down all agents.`,
2102
+ createdAt: /* @__PURE__ */ new Date()
2103
+ }
2104
+ ]);
2105
+ return leadCoordinationTask;
2106
+ }
2107
+ const { TmuxManager } = await import('./tmux-manager-GPYZ3WQH.js');
2108
+ const tmux = new TmuxManager();
2109
+ const tmuxAvailable = await tmux.isAvailable();
2110
+ if (tmuxAvailable) {
2111
+ const insideTmux = typeof process.env["TMUX"] === "string" && process.env["TMUX"].length > 0;
2112
+ if (insideTmux) {
2113
+ setMessages((prev) => [
2114
+ ...prev,
2115
+ {
2116
+ id: v4Id(),
2117
+ role: "system",
2118
+ content: `Designed ${agentSpecs.length}-agent team. Creating tmux split panes...`,
2119
+ createdAt: /* @__PURE__ */ new Date()
2120
+ }
2121
+ ]);
2122
+ const currentResult = await execaPane("tmux", [
2123
+ "display-message",
2124
+ "-p",
2125
+ "#{pane_id}"
2126
+ ]);
2127
+ const leaderPaneId = currentResult.stdout.trim();
2128
+ const agentPaneIds = [];
2129
+ for (let i = 0; i < agentCommands.length; i++) {
2130
+ const agent = agentCommands[i];
2131
+ const splitResult = await execaPane("tmux", [
2132
+ "split-window",
2133
+ i % 2 === 0 ? "-h" : "-v",
2134
+ "-P",
2135
+ "-F",
2136
+ "#{pane_id}"
2137
+ ]);
2138
+ const newPaneId = splitResult.stdout.trim();
2139
+ agentPaneIds.push(newPaneId);
2140
+ await execaPane("tmux", ["send-keys", "-t", newPaneId, agent.command, "Enter"]);
2141
+ }
2142
+ try {
2143
+ await execaPane("tmux", ["select-layout", "tiled"]);
2144
+ } catch {
2145
+ }
2146
+ try {
2147
+ await execaPane("tmux", ["select-pane", "-t", leaderPaneId]);
2148
+ } catch {
2149
+ }
2150
+ activeTeamName = teamName;
2151
+ activeTeamManager = void 0;
2152
+ activeTmuxCleanup = async () => {
2153
+ const { execa: ex } = await import('execa');
2154
+ for (const pid of agentPaneIds) {
2155
+ try {
2156
+ await ex("tmux", ["kill-pane", "-t", pid]);
2157
+ } catch {
2158
+ }
2159
+ }
2160
+ try {
2161
+ const { rmSync } = await import('fs');
2162
+ rmSync(tempDir, { recursive: true, force: true });
2163
+ rmSync(boardDir, { recursive: true, force: true });
2164
+ } catch {
2165
+ }
2166
+ };
2167
+ const agentLines3 = agentSpecs.map(
2168
+ (spec) => spec.name === leadSpec.name ? ` ${spec.name} (${spec.model}) \u2014 ${spec.role} [LEAD \u2014 this pane]` : ` ${spec.name} (${spec.model}) \u2014 ${spec.role}`
2169
+ );
2170
+ setMessages((prev) => [
2171
+ ...prev,
2172
+ {
2173
+ id: v4Id(),
2174
+ role: "system",
2175
+ content: `Team "${teamName}" \u2014 ${agentSpecs.length} agents active.
2176
+ ${workerSpecs.length} worker panes in tmux + lead coordinating here.
2177
+ ${agentLines3.join("\n")}
2178
+ /team stop to shut down all agents.`,
2179
+ createdAt: /* @__PURE__ */ new Date()
2180
+ }
2181
+ ]);
2182
+ return leadCoordinationTask;
2183
+ }
2184
+ setMessages((prev) => [
2185
+ ...prev,
2186
+ {
2187
+ id: v4Id(),
2188
+ role: "system",
2189
+ content: `Designed ${agentSpecs.length}-agent team. Opening tmux split-panel view...`,
2190
+ createdAt: /* @__PURE__ */ new Date()
2191
+ }
2192
+ ]);
2193
+ const sessionName = await tmux.createSession(teamName);
2194
+ const paneConfigs = agentSpecs.map((spec, i) => ({
2195
+ paneId: `pane-${i}`,
2196
+ agentName: spec.name,
2197
+ model: spec.model,
2198
+ role: spec.role,
2199
+ title: `${spec.name} (${spec.model})`
2200
+ }));
2201
+ const layoutConfig = {
2202
+ layout: "auto",
2203
+ panes: paneConfigs,
2204
+ maxPanes: paneConfigs.length
2205
+ };
2206
+ await tmux.createPanes(layoutConfig);
2207
+ for (let i = 0; i < agentCommands.length; i++) {
2208
+ const agent = agentCommands[i];
2209
+ const paneId = `pane-${i}`;
2210
+ await tmux.sendCommand(paneId, agent.command);
2211
+ }
2212
+ activeTeamName = teamName;
2213
+ activeTeamManager = void 0;
2214
+ activeTmuxCleanup = async () => {
2215
+ await tmux.destroy();
2216
+ try {
2217
+ const { rmSync } = await import('fs');
2218
+ rmSync(tempDir, { recursive: true, force: true });
2219
+ rmSync(boardDir, { recursive: true, force: true });
2220
+ } catch {
2221
+ }
2222
+ };
2223
+ const { execFileSync } = await import('child_process');
2224
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
2225
+ process.stdin.setRawMode(false);
2226
+ }
2227
+ process.stdin.pause();
2228
+ try {
2229
+ execFileSync("tmux", ["attach-session", "-t", sessionName], {
2230
+ stdio: "inherit"
2231
+ });
2232
+ } catch {
2233
+ }
2234
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
2235
+ process.stdin.setRawMode(true);
2236
+ }
2237
+ process.stdin.resume();
2238
+ const agentLines2 = agentSpecs.map(
2239
+ (spec) => spec.name === leadSpec.name ? ` ${spec.name} (${spec.model}) \u2014 ${spec.role} [LEAD]` : ` ${spec.name} (${spec.model}) \u2014 ${spec.role}`
2240
+ );
2241
+ setMessages((prev) => [
2242
+ ...prev,
2243
+ {
2244
+ id: v4Id(),
2245
+ role: "system",
2246
+ content: `Detached from tmux. Agents may still be running.
2247
+ ${agentLines2.join("\n")}
2248
+ Re-attach: tmux attach -t ${sessionName}
2249
+ /team stop to shut down all agents.`,
2250
+ createdAt: /* @__PURE__ */ new Date()
2251
+ }
2252
+ ]);
2253
+ return leadCoordinationTask;
2254
+ }
2255
+ setMessages((prev) => [
2256
+ ...prev,
2257
+ {
2258
+ id: v4Id(),
2259
+ role: "system",
2260
+ content: `Designed ${agentSpecs.length}-agent team. Starting agents (in-process mode)...`,
2261
+ createdAt: /* @__PURE__ */ new Date()
2262
+ }
2263
+ ]);
2264
+ const { TeamManager: TM } = await import('./team-manager-HC4XGCFY.js');
2265
+ const manager = new TM();
2266
+ activeTeamManager = manager;
2267
+ activeTeamName = teamName;
2268
+ activeTmuxCleanup = void 0;
2269
+ const teamConfig = await manager.createTeam(teamName, {
2270
+ description: `Agent team for: ${input.slice(0, 120)}`,
2271
+ agents: agentDefinitions
2272
+ });
2273
+ const agentStates = teamConfig.members.map((member) => ({
2274
+ config: member,
2275
+ status: "idle"
2276
+ }));
2277
+ panel.setAgents(agentStates);
2278
+ panel.activate();
2279
+ for (const member of teamConfig.members) {
2280
+ panel.appendOutput(
2281
+ member.agentId,
2282
+ `[${member.name}] Starting (${member.model})...
2283
+ `
2284
+ );
2285
+ }
2286
+ manager.onAgentMessages(teamName, (_agentName, method, params) => {
2287
+ if (method === "agent.streamChunk") {
2288
+ const agentId = typeof params["agentId"] === "string" ? params["agentId"] : "";
2289
+ const content = typeof params["content"] === "string" ? params["content"] : "";
2290
+ if (agentId && content) {
2291
+ panel.appendOutput(agentId, content);
2292
+ }
2293
+ }
2294
+ if (method === "agent.taskUpdate") {
2295
+ const agentId = typeof params["agentId"] === "string" ? params["agentId"] : "";
2296
+ const rawStatus = typeof params["status"] === "string" ? params["status"] : "";
2297
+ if (agentId && rawStatus) {
2298
+ const statusMap = {
2299
+ in_progress: "active",
2300
+ completed: "idle"
2301
+ };
2302
+ const mapped = statusMap[rawStatus];
2303
+ if (mapped) {
2304
+ panel.updateAgentStatus(agentId, mapped);
2305
+ }
2306
+ }
2307
+ }
2308
+ });
2309
+ await manager.startAgents(teamName);
2310
+ for (let i = 0; i < teamConfig.members.length; i++) {
2311
+ const member = teamConfig.members[i];
2312
+ const spec = agentSpecs[i];
2313
+ const taskId = v4Id();
2314
+ const prompt = spec ? `You are ${spec.name} (${spec.agentType}).
2315
+
2316
+ ${spec.taskPrompt}
2317
+
2318
+ User request:
2319
+ ${input}` : `Work on the following task:
2320
+
2321
+ ${input}`;
2322
+ manager.assignTask(
2323
+ teamName,
2324
+ member.name,
2325
+ taskId,
2326
+ `${member.role}: ${input.slice(0, 80)}`,
2327
+ prompt
2328
+ );
2329
+ }
2330
+ const agentLines = agentSpecs.map(
2331
+ (spec) => ` ${spec.name} (${spec.model}) \u2014 ${spec.role}`
2332
+ );
2333
+ setMessages((prev) => [
2334
+ ...prev,
2335
+ {
2336
+ id: v4Id(),
2337
+ role: "system",
2338
+ content: `Team "${teamName}" created with ${teamConfig.members.length} agents \u2014 split-panel active.
2339
+ ${agentLines.join("\n")}
2340
+ Use Tab to switch agents. /team stop to return to single-pane.`,
2341
+ createdAt: /* @__PURE__ */ new Date()
2342
+ }
2343
+ ]);
2344
+ return void 0;
2345
+ } catch (error) {
2346
+ const msg = error instanceof Error ? error.message : String(error);
2347
+ setMessages((prev) => [
2348
+ ...prev,
2349
+ {
2350
+ id: v4Id(),
2351
+ role: "system",
2352
+ content: `Failed to create team: ${msg}`,
2353
+ createdAt: /* @__PURE__ */ new Date()
2354
+ }
2355
+ ]);
2356
+ return void 0;
2357
+ }
2358
+ }
2359
+ async function handleTeamCommand(args, ctx) {
2360
+ const subcommand = args[0];
2361
+ if (subcommand === "stop") {
2362
+ if (activeTmuxCleanup) {
2363
+ try {
2364
+ await activeTmuxCleanup();
2365
+ } catch {
2366
+ }
2367
+ activeTmuxCleanup = void 0;
2368
+ }
2369
+ if (activeTeamManager && activeTeamName) {
2370
+ try {
2371
+ await activeTeamManager.deleteTeam(activeTeamName);
2372
+ } catch {
2373
+ }
2374
+ activeTeamManager = void 0;
2375
+ }
2376
+ activeTeamName = void 0;
2377
+ ctx.panel.deactivate();
2378
+ addSystemMessage(ctx, "Team shut down. All agents stopped. Returned to single-pane mode.");
2379
+ return;
2380
+ }
2381
+ if (subcommand === "list") {
2382
+ try {
2383
+ const { TeamManager } = await import('./team-manager-HC4XGCFY.js');
2384
+ const manager = new TeamManager();
2385
+ const teams = manager.listTeams();
2386
+ if (teams.length === 0) {
2387
+ addSystemMessage(ctx, "No active teams.");
2388
+ } else {
2389
+ const lines = teams.map((t) => ` ${t.teamName} \u2014 ${t.members.length} agents (${t.status})`);
2390
+ addSystemMessage(ctx, lines.join("\n"));
2391
+ }
2392
+ } catch (error) {
2393
+ const msg = error instanceof Error ? error.message : String(error);
2394
+ addSystemMessage(ctx, `Failed to list teams: ${msg}`);
2395
+ }
2396
+ return;
2397
+ }
2398
+ addSystemMessage(
2399
+ ctx,
2400
+ '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"'
2401
+ );
2402
+ }
2403
+ async function handleMcpCommand(args, ctx) {
2404
+ const subcommand = args[0];
2405
+ if (subcommand === "list") {
2406
+ try {
2407
+ const { MCPServerManager } = await import('./server-manager-PTGBHCLS.js');
2408
+ const manager = new MCPServerManager();
2409
+ const connected = manager.getConnectedServers();
2410
+ if (connected.length === 0) {
2411
+ addSystemMessage(ctx, "No MCP servers connected.\nConfigure servers in ~/.aemeathcli/mcp.json");
2412
+ } else {
2413
+ const lines = connected.map((name) => {
2414
+ const status = manager.getServerStatus(name) ?? "unknown";
2415
+ return ` ${name} \u2014 ${status}`;
2416
+ });
2417
+ addSystemMessage(ctx, `MCP Servers:
2418
+ ${lines.join("\n")}`);
2419
+ }
2420
+ } catch (error) {
2421
+ const msg = error instanceof Error ? error.message : String(error);
2422
+ addSystemMessage(ctx, `Failed to list MCP servers: ${msg}`);
2423
+ }
2424
+ return;
2425
+ }
2426
+ if (subcommand === "add") {
2427
+ const name = args[1];
2428
+ if (!name) {
2429
+ addSystemMessage(ctx, "Usage: /mcp add <server-name>");
2430
+ return;
2431
+ }
2432
+ addSystemMessage(ctx, `To add MCP server "${name}", edit ~/.aemeathcli/mcp.json with the server configuration.`);
2433
+ return;
2434
+ }
2435
+ addSystemMessage(ctx, "Usage: /mcp list | /mcp add <name>");
2436
+ }
2437
+ async function handleSkillCommand(args, ctx) {
2438
+ const subcommand = args[0];
2439
+ if (subcommand === "list") {
2440
+ try {
2441
+ const { SkillRegistry } = await import('./registry-H7B3AHPQ.js');
2442
+ const registry = new SkillRegistry();
2443
+ await registry.initialize();
2444
+ const skills = registry.listAll();
2445
+ if (skills.length === 0) {
2446
+ addSystemMessage(ctx, "No skills found.\nAdd skills in ~/.aemeathcli/skills/ or .aemeathcli/skills/");
2447
+ } else {
2448
+ const lines = skills.map((s) => ` $${s.name.padEnd(16)} ${s.description}`);
2449
+ addSystemMessage(ctx, `Available Skills:
2450
+ ${lines.join("\n")}`);
2451
+ }
2452
+ } catch (error) {
2453
+ const msg = error instanceof Error ? error.message : String(error);
2454
+ addSystemMessage(ctx, `Failed to list skills: ${msg}`);
2455
+ }
2456
+ return;
2457
+ }
2458
+ addSystemMessage(ctx, "Usage: /skill list\nInvoke a skill with $skill-name (e.g., $review, $commit, $plan)");
2459
+ }
2460
+ async function handleAuthSlashCommand(args, ctx) {
2461
+ const subcommand = args[0];
2462
+ if (subcommand === "status") {
2463
+ try {
2464
+ const providers = ["claude", "codex", "gemini", "kimi"];
2465
+ const lines = [];
2466
+ for (const provider of providers) {
2467
+ try {
2468
+ const loginMod = await loadLoginModuleForSlash(provider);
2469
+ const status = await loginMod.getStatus();
2470
+ if (status.loggedIn) {
2471
+ lines.push(` \u2713 ${provider} \u2014 Logged in as ${status.email ?? "unknown"} (${status.plan ?? "unknown plan"})`);
2472
+ } else {
2473
+ lines.push(` \u2717 ${provider} \u2014 Not logged in`);
2474
+ }
2475
+ } catch {
2476
+ lines.push(` \u2717 ${provider} \u2014 Not configured`);
2477
+ }
2478
+ }
2479
+ addSystemMessage(ctx, lines.join("\n"));
2480
+ } catch (error) {
2481
+ const msg = error instanceof Error ? error.message : String(error);
2482
+ addSystemMessage(ctx, `Failed to get auth status: ${msg}`);
2483
+ }
2484
+ return;
2485
+ }
2486
+ if (subcommand === "login") {
2487
+ const provider = args[1];
2488
+ if (!provider) {
2489
+ addSystemMessage(ctx, "Usage: /auth login <provider>\nProviders: claude, codex, gemini, kimi");
2490
+ return;
2491
+ }
2492
+ addSystemMessage(ctx, `Use the CLI command: aemeathcli auth login ${provider}`);
2493
+ return;
2494
+ }
2495
+ if (subcommand === "logout") {
2496
+ const provider = args[1];
2497
+ if (!provider) {
2498
+ addSystemMessage(ctx, "Usage: /auth logout <provider>\nProviders: claude, codex, gemini, kimi");
2499
+ return;
2500
+ }
2501
+ addSystemMessage(ctx, `Use the CLI command: aemeathcli auth logout ${provider}`);
2502
+ return;
2503
+ }
2504
+ addSystemMessage(ctx, "Usage: /auth status | /auth login <provider> | /auth logout <provider>");
2505
+ }
2506
+ async function loadLoginModuleForSlash(provider) {
2507
+ switch (provider) {
2508
+ case "claude": {
2509
+ const mod = await import('./claude-login-5WELXPKT.js');
2510
+ return new mod.ClaudeLogin();
2511
+ }
2512
+ case "codex": {
2513
+ const mod = await import('./codex-login-7HHLJHBF.js');
2514
+ return new mod.CodexLogin();
2515
+ }
2516
+ case "gemini": {
2517
+ const mod = await import('./gemini-login-ZZLYC3J6.js');
2518
+ return new mod.GeminiLogin();
2519
+ }
2520
+ case "kimi": {
2521
+ const mod = await import('./kimi-login-CZPS63NK.js');
2522
+ return new mod.KimiLogin();
2523
+ }
2524
+ default:
2525
+ throw new Error(`Unknown provider: ${provider}`);
2526
+ }
2527
+ }
2528
+ async function handleConfigSlashCommand(args, ctx) {
2529
+ const subcommand = args[0];
2530
+ if (subcommand === "get") {
2531
+ const key = args[1];
2532
+ try {
2533
+ const { ConfigStore } = await import('./config-store-W6FBCQAQ.js');
2534
+ const store = new ConfigStore();
2535
+ const cfg = store.loadGlobal();
2536
+ if (!key) {
2537
+ addSystemMessage(ctx, JSON.stringify(cfg, null, 2));
2538
+ } else {
2539
+ const value = getNestedConfigValue(cfg, key);
2540
+ if (value === void 0) {
2541
+ addSystemMessage(ctx, `Key not found: ${key}`);
2542
+ } else {
2543
+ addSystemMessage(ctx, `${key} = ${JSON.stringify(value, null, 2)}`);
2544
+ }
2545
+ }
2546
+ } catch (error) {
2547
+ const msg = error instanceof Error ? error.message : String(error);
2548
+ addSystemMessage(ctx, `Failed to read config: ${msg}`);
2549
+ }
2550
+ return;
2551
+ }
2552
+ if (subcommand === "set") {
2553
+ const key = args[1];
2554
+ const value = args.slice(2).join(" ");
2555
+ if (!key || !value) {
2556
+ addSystemMessage(ctx, "Usage: /config set <key> <value>");
2557
+ return;
2558
+ }
2559
+ try {
2560
+ const { ConfigStore } = await import('./config-store-W6FBCQAQ.js');
2561
+ const store = new ConfigStore();
2562
+ const cfg = store.loadGlobal();
2563
+ let parsedValue;
2564
+ try {
2565
+ parsedValue = JSON.parse(value);
2566
+ } catch {
2567
+ parsedValue = value;
2568
+ }
2569
+ setNestedConfigValue(cfg, key, parsedValue);
2570
+ store.saveGlobal(cfg);
2571
+ addSystemMessage(ctx, `Set ${key} = ${JSON.stringify(parsedValue)}`);
2572
+ } catch (error) {
2573
+ const msg = error instanceof Error ? error.message : String(error);
2574
+ addSystemMessage(ctx, `Failed to set config: ${msg}`);
2575
+ }
2576
+ return;
2577
+ }
2578
+ addSystemMessage(ctx, "Usage: /config get [key] | /config set <key> <value>");
2579
+ }
2580
+ function getNestedConfigValue(obj, path) {
2581
+ const keys = path.split(".");
2582
+ let current = obj;
2583
+ for (const key of keys) {
2584
+ if (current === null || current === void 0 || typeof current !== "object") return void 0;
2585
+ current = current[key];
2586
+ }
2587
+ return current;
2588
+ }
2589
+ function setNestedConfigValue(obj, path, value) {
2590
+ const keys = path.split(".");
2591
+ let current = obj;
2592
+ for (let i = 0; i < keys.length - 1; i++) {
2593
+ const key = keys[i];
2594
+ if (!key) continue;
2595
+ if (typeof current[key] !== "object" || current[key] === null) current[key] = {};
2596
+ current = current[key];
2597
+ }
2598
+ const lastKey = keys[keys.length - 1];
2599
+ if (lastKey) current[lastKey] = value;
2600
+ }
2601
+ async function handleSkillInvocation(input, setMessages) {
2602
+ const parts = input.trim().split(/\s+/);
2603
+ const trigger = parts[0] ?? "";
2604
+ const skillName = trigger.replace(/^\$/, "");
2605
+ if (!skillName) {
2606
+ setMessages((prev) => [
2607
+ ...prev,
2608
+ { id: v4Id(), role: "system", content: "Usage: $skill-name [args]\nType /skill list to see available skills.", createdAt: /* @__PURE__ */ new Date() }
2609
+ ]);
2610
+ return;
2611
+ }
2612
+ setMessages((prev) => [
2613
+ ...prev,
2614
+ { id: v4Id(), role: "user", content: input, createdAt: /* @__PURE__ */ new Date() }
2615
+ ]);
2616
+ try {
2617
+ const { SkillRegistry } = await import('./registry-H7B3AHPQ.js');
2618
+ const { SkillExecutor } = await import('./executor-6RIKIGXK.js');
2619
+ const registry = new SkillRegistry();
2620
+ await registry.initialize();
2621
+ const executor = new SkillExecutor(registry);
2622
+ const result = await executor.activateByTrigger(trigger);
2623
+ if (!result.success) {
2624
+ setMessages((prev) => [
2625
+ ...prev,
2626
+ { id: v4Id(), role: "system", content: result.errorMessage ?? `Skill not found: "${skillName}"
2627
+ Type /skill list to see available skills.`, createdAt: /* @__PURE__ */ new Date() }
2628
+ ]);
2629
+ return;
2630
+ }
2631
+ const content = executor.getActiveSkillContent();
2632
+ const warningText = result.warnings && result.warnings.length > 0 ? `
2633
+ Warnings: ${result.warnings.join(", ")}` : "";
2634
+ setMessages((prev) => [
2635
+ ...prev,
2636
+ { id: v4Id(), role: "system", content: `Skill "$${skillName}" activated.${warningText}
2637
+ ${content ? content.slice(0, 500) : ""}`, createdAt: /* @__PURE__ */ new Date() }
2638
+ ]);
2639
+ } catch (error) {
2640
+ const msg = error instanceof Error ? error.message : String(error);
2641
+ setMessages((prev) => [
2642
+ ...prev,
2643
+ { id: v4Id(), role: "system", content: `Skill error: ${msg}`, createdAt: /* @__PURE__ */ new Date() }
2644
+ ]);
2645
+ }
2646
+ }
2647
+ async function startChatSession(options) {
2648
+ let config;
2649
+ try {
2650
+ const { ConfigStore } = await import('./config-store-W6FBCQAQ.js');
2651
+ const store = new ConfigStore();
2652
+ config = store.loadGlobal();
2653
+ } catch {
2654
+ config = DEFAULT_CONFIG;
2655
+ }
2656
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx(App, { config, options }));
2657
+ await waitUntilExit();
2658
+ }
2659
+ async function createFirstRunLogin(provider) {
2660
+ switch (provider) {
2661
+ case "claude": {
2662
+ const { ClaudeLogin } = await import('./claude-login-5WELXPKT.js');
2663
+ return new ClaudeLogin();
2664
+ }
2665
+ case "codex": {
2666
+ const { CodexLogin } = await import('./codex-login-7HHLJHBF.js');
2667
+ return new CodexLogin();
2668
+ }
2669
+ case "gemini": {
2670
+ const { GeminiLogin } = await import('./gemini-login-ZZLYC3J6.js');
2671
+ return new GeminiLogin();
2672
+ }
2673
+ case "kimi": {
2674
+ const { KimiLogin } = await import('./kimi-login-CZPS63NK.js');
2675
+ return new KimiLogin();
2676
+ }
2677
+ }
2678
+ }
2679
+ async function runFirstRunSetup() {
2680
+ const { confirm } = await import('@inquirer/prompts');
2681
+ const pc = await import('picocolors');
2682
+ process.stdout.write(
2683
+ [
2684
+ "",
2685
+ pc.default.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),
2686
+ pc.default.cyan(" \u2551 Welcome to AemeathCLI \u2551"),
2687
+ pc.default.cyan(" \u2551 Multi-Model CLI Coding Tool v1.0.0 \u2551"),
2688
+ pc.default.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),
2689
+ "",
2690
+ " Let's get you set up:",
2691
+ ""
2692
+ ].join("\n")
2693
+ );
2694
+ const providers = ["claude", "codex", "gemini", "kimi"];
2695
+ for (const provider of providers) {
2696
+ const shouldLogin = await confirm({
2697
+ message: `Log in to ${provider}?`,
2698
+ default: provider !== "kimi"
2699
+ });
2700
+ if (shouldLogin) {
2701
+ process.stdout.write(pc.default.cyan(` Logging in to ${provider}...
2702
+ `));
2703
+ try {
2704
+ const login = await createFirstRunLogin(provider);
2705
+ await login.login();
2706
+ process.stdout.write(pc.default.green(` \u2713 ${provider} - Logged in successfully
2707
+ `));
2708
+ } catch {
2709
+ process.stdout.write(pc.default.red(` \u2717 ${provider} - Login failed (you can retry later)
2710
+ `));
2711
+ }
2712
+ }
2713
+ }
2714
+ process.stdout.write(pc.default.green("\n \u2713 Configuration saved. Ready!\n\n"));
2715
+ }
2716
+
2717
+ export { runFirstRunSetup, startChatSession };
2718
+ //# sourceMappingURL=App-P4MYD4QY.js.map
2719
+ //# sourceMappingURL=App-P4MYD4QY.js.map