@maestroai/cli 0.1.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.
@@ -0,0 +1,2393 @@
1
+ // src/tui/App.tsx
2
+ import React9 from "react";
3
+ import path2 from "path";
4
+ import { render, Box as Box14, Text as Text13, useInput as useInput6, useApp, useStdout } from "ink";
5
+
6
+ // src/tui/components/Header.tsx
7
+ import { Box, Text } from "ink";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function formatUptime(ms) {
10
+ const totalSeconds = Math.floor(ms / 1e3);
11
+ const hours = Math.floor(totalSeconds / 3600);
12
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
13
+ const seconds = totalSeconds % 60;
14
+ const parts = [];
15
+ if (hours > 0) parts.push(`${hours}h`);
16
+ if (minutes > 0 || hours > 0) parts.push(`${minutes}m`);
17
+ parts.push(`${seconds}s`);
18
+ return parts.join(" ");
19
+ }
20
+ function Header({
21
+ projectName,
22
+ completedTasks,
23
+ totalTasks,
24
+ totalCost,
25
+ uptimeMs
26
+ }) {
27
+ const progress = totalTasks > 0 ? Math.round(completedTasks / totalTasks * 100) : 0;
28
+ return /* @__PURE__ */ jsxs(
29
+ Box,
30
+ {
31
+ flexDirection: "row",
32
+ justifyContent: "space-between",
33
+ paddingX: 1,
34
+ borderStyle: "single",
35
+ borderColor: "cyan",
36
+ children: [
37
+ /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
38
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MAESTRO" }),
39
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
40
+ /* @__PURE__ */ jsx(Text, { children: projectName })
41
+ ] }),
42
+ /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
43
+ /* @__PURE__ */ jsxs(Text, { children: [
44
+ "Tasks: ",
45
+ /* @__PURE__ */ jsx(Text, { color: "green", children: completedTasks }),
46
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
47
+ "/",
48
+ totalTasks
49
+ ] }),
50
+ " ",
51
+ /* @__PURE__ */ jsxs(Text, { color: progress === 100 ? "green" : "yellow", children: [
52
+ "(",
53
+ progress,
54
+ "%)"
55
+ ] })
56
+ ] }),
57
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
58
+ /* @__PURE__ */ jsxs(Text, { children: [
59
+ "Cost: ",
60
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
61
+ "$",
62
+ totalCost.toFixed(4)
63
+ ] })
64
+ ] }),
65
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
66
+ /* @__PURE__ */ jsxs(Text, { children: [
67
+ "Uptime: ",
68
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: formatUptime(uptimeMs) })
69
+ ] })
70
+ ] })
71
+ ]
72
+ }
73
+ );
74
+ }
75
+
76
+ // src/tui/components/Dashboard.tsx
77
+ import { Box as Box9 } from "ink";
78
+
79
+ // src/tui/components/AgentPanel.tsx
80
+ import { Box as Box3, Text as Text3 } from "ink";
81
+ import figures from "figures";
82
+
83
+ // src/tui/hooks/useAgentPool.ts
84
+ import React from "react";
85
+
86
+ // src/tui/components/LogViewer.tsx
87
+ import { Box as Box2, Text as Text2 } from "ink";
88
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
89
+ var MAX_LOG_LINES = 20;
90
+ var agentLogs = /* @__PURE__ */ new Map();
91
+ function addLogLine(agentId, line) {
92
+ let logs = agentLogs.get(agentId);
93
+ if (!logs) {
94
+ logs = [];
95
+ agentLogs.set(agentId, logs);
96
+ }
97
+ logs.push(line);
98
+ if (logs.length > MAX_LOG_LINES * 2) {
99
+ agentLogs.set(agentId, logs.slice(-MAX_LOG_LINES));
100
+ }
101
+ }
102
+ function getLogLines(agentId) {
103
+ return (agentLogs.get(agentId) ?? []).slice(-MAX_LOG_LINES);
104
+ }
105
+ var KIND_COLORS = {
106
+ "task-delegated": "cyan",
107
+ "task-completed": "green",
108
+ "task-blocked": "red",
109
+ "task-failed": "red",
110
+ "agent-spawned": "green",
111
+ "agent-stopped": "gray",
112
+ "agent-error": "red",
113
+ "phase-changed": "magenta",
114
+ "pipeline-handoff": "yellow",
115
+ "plan-created": "blue",
116
+ "plan-approved": "green",
117
+ "plan-rejected": "red",
118
+ "budget-warning": "yellow",
119
+ "rate-limit": "red",
120
+ "project-completed": "green",
121
+ "cycle-summary": "gray",
122
+ "gap-detected": "yellow",
123
+ "pm-scan": "cyan",
124
+ "info": "blue"
125
+ };
126
+ function formatTime(iso) {
127
+ const d = new Date(iso);
128
+ return d.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
129
+ }
130
+ function LogViewer({ agent, orchestratorActivities }) {
131
+ if (orchestratorActivities) {
132
+ const recent = orchestratorActivities.slice(-MAX_LOG_LINES);
133
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
134
+ /* @__PURE__ */ jsx2(Text2, { bold: true, underline: true, color: "yellow", children: "Orchestrator Log" }),
135
+ /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: recent.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No activity yet..." }) : recent.map((activity) => {
136
+ const color = KIND_COLORS[activity.kind] ?? "white";
137
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", gap: 1, children: [
138
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: formatTime(activity.timestamp) }),
139
+ /* @__PURE__ */ jsx2(Text2, { color, wrap: "truncate", children: activity.message })
140
+ ] }, activity.id);
141
+ }) })
142
+ ] });
143
+ }
144
+ if (!agent) {
145
+ return /* @__PURE__ */ jsx2(Box2, { paddingY: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Select an agent to view logs." }) });
146
+ }
147
+ const lines = getLogLines(agent.config.id);
148
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
149
+ /* @__PURE__ */ jsxs2(Text2, { bold: true, underline: true, children: [
150
+ "Logs: ",
151
+ agent.config.name
152
+ ] }),
153
+ /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: lines.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No output yet..." }) : lines.map((line, i) => /* @__PURE__ */ jsx2(Text2, { wrap: "truncate", children: line }, i)) })
154
+ ] });
155
+ }
156
+
157
+ // src/tui/hooks/useAgentPool.ts
158
+ var agentTokens = /* @__PURE__ */ new Map();
159
+ function getAgentTokenUsage(agentId) {
160
+ return agentTokens.get(agentId) ?? { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0 };
161
+ }
162
+ function accumulateTokens(agentId, data) {
163
+ const usage = data?.usage;
164
+ if (!usage || typeof usage !== "object") return;
165
+ const current = agentTokens.get(agentId) ?? { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0 };
166
+ if (typeof usage.input_tokens === "number") current.inputTokens += usage.input_tokens;
167
+ if (typeof usage.output_tokens === "number") current.outputTokens += usage.output_tokens;
168
+ if (typeof usage.cache_read_input_tokens === "number") current.cacheReadTokens += usage.cache_read_input_tokens;
169
+ agentTokens.set(agentId, current);
170
+ }
171
+ function extractToolResults(data) {
172
+ const results = [];
173
+ const message = data?.message;
174
+ if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
175
+ return results;
176
+ }
177
+ for (const block of message.content) {
178
+ if (block.type !== "tool_result") continue;
179
+ if (typeof block.content === "string" && block.content.trim()) {
180
+ results.push(block.content.trim());
181
+ } else if (Array.isArray(block.content)) {
182
+ for (const sub of block.content) {
183
+ if (sub.type === "text" && typeof sub.text === "string" && sub.text.trim()) {
184
+ results.push(sub.text.trim());
185
+ }
186
+ }
187
+ }
188
+ }
189
+ return results;
190
+ }
191
+ function formatUsage(data) {
192
+ const usage = data?.usage;
193
+ if (!usage || typeof usage !== "object") return "";
194
+ const parts = [];
195
+ if (typeof usage.input_tokens === "number") parts.push(`in:${usage.input_tokens}`);
196
+ if (typeof usage.output_tokens === "number") parts.push(`out:${usage.output_tokens}`);
197
+ if (typeof usage.cache_read_input_tokens === "number" && usage.cache_read_input_tokens > 0) {
198
+ parts.push(`cache:${usage.cache_read_input_tokens}`);
199
+ }
200
+ return parts.length > 0 ? parts.join(" ") : "";
201
+ }
202
+ function useAgentPool(orchestrator) {
203
+ const [agents, setAgents] = React.useState([]);
204
+ React.useEffect(() => {
205
+ const handleSpawned = (state) => {
206
+ setAgents((prev) => {
207
+ const existing = prev.findIndex((a) => a.config.id === state.config.id);
208
+ if (existing >= 0) {
209
+ const next = [...prev];
210
+ next[existing] = state;
211
+ return next;
212
+ }
213
+ return [...prev, state];
214
+ });
215
+ addLogLine(state.config.id, `[system] Agent spawned: ${state.config.name}`);
216
+ };
217
+ const handleStatusChanged = (agentId, _oldStatus, newStatus) => {
218
+ setAgents(
219
+ (prev) => prev.map(
220
+ (a) => a.config.id === agentId ? { ...a, status: newStatus } : a
221
+ )
222
+ );
223
+ addLogLine(agentId, `[system] Status changed to: ${newStatus}`);
224
+ };
225
+ const handleOutput = (event) => {
226
+ if (event.type === "user") {
227
+ const toolResults = extractToolResults(event.data);
228
+ for (const result of toolResults) {
229
+ const truncated2 = result.length > 200 ? result.slice(0, 200) + "..." : result;
230
+ const firstLine = truncated2.split("\n")[0];
231
+ addLogLine(event.agentId, `[tool] ${firstLine}`);
232
+ }
233
+ return;
234
+ }
235
+ let text = "";
236
+ if (event.type === "assistant") {
237
+ const message = event.data?.message;
238
+ if (message && typeof message === "object" && Array.isArray(message.content)) {
239
+ text = message.content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text).join("");
240
+ } else if (typeof event.data?.content === "string") {
241
+ text = event.data.content;
242
+ } else if (typeof message === "string") {
243
+ text = message;
244
+ }
245
+ } else if (event.type === "result") {
246
+ accumulateTokens(event.agentId, event.data);
247
+ const cost = typeof event.data?.cost_usd === "number" ? `$${event.data.cost_usd.toFixed(4)}` : "";
248
+ const turns = typeof event.data?.num_turns === "number" ? `${event.data.num_turns} turns` : "";
249
+ const usage = formatUsage(event.data);
250
+ text = `done ${[cost, turns, usage].filter(Boolean).join(" | ")}`;
251
+ setAgents((prev) => [...prev]);
252
+ } else if (event.type === "error") {
253
+ text = event.data?.error ?? JSON.stringify(event.data);
254
+ } else if (event.type === "tool_use") {
255
+ const toolName = event.data?.tool ?? event.data?.name ?? "tool";
256
+ text = `[${toolName}]`;
257
+ } else {
258
+ text = event.data?.message ?? "";
259
+ }
260
+ if (!text) return;
261
+ const truncated = text.length > 200 ? text.slice(0, 200) + "..." : text;
262
+ addLogLine(event.agentId, `[${event.type}] ${truncated}`);
263
+ };
264
+ const handleError = (agentId, error) => {
265
+ setAgents(
266
+ (prev) => prev.map(
267
+ (a) => a.config.id === agentId ? { ...a, status: "error", error: error.message } : a
268
+ )
269
+ );
270
+ addLogLine(agentId, `[error] ${error.message}`);
271
+ };
272
+ const handleStopped = (agentId, exitCode) => {
273
+ setAgents(
274
+ (prev) => prev.map(
275
+ (a) => a.config.id === agentId ? { ...a, status: "stopped", currentTask: null } : a
276
+ )
277
+ );
278
+ addLogLine(agentId, `[system] Agent stopped (exit code: ${exitCode})`);
279
+ };
280
+ const handleTaskAssigned = (task, agentId) => {
281
+ setAgents(
282
+ (prev) => prev.map(
283
+ (a) => a.config.id === agentId ? { ...a, currentTask: `${task.id}: ${task.title}` } : a
284
+ )
285
+ );
286
+ };
287
+ const handleTaskCompleted = (task) => {
288
+ if (task.assignee) {
289
+ setAgents(
290
+ (prev) => prev.map(
291
+ (a) => a.config.id === task.assignee ? { ...a, currentTask: null } : a
292
+ )
293
+ );
294
+ }
295
+ };
296
+ orchestrator.on("agent:spawned", handleSpawned);
297
+ orchestrator.on("agent:status-changed", handleStatusChanged);
298
+ orchestrator.on("agent:output", handleOutput);
299
+ orchestrator.on("agent:error", handleError);
300
+ orchestrator.on("agent:stopped", handleStopped);
301
+ orchestrator.on("task:assigned", handleTaskAssigned);
302
+ orchestrator.on("task:completed", handleTaskCompleted);
303
+ return () => {
304
+ orchestrator.off("agent:spawned", handleSpawned);
305
+ orchestrator.off("agent:status-changed", handleStatusChanged);
306
+ orchestrator.off("agent:output", handleOutput);
307
+ orchestrator.off("agent:error", handleError);
308
+ orchestrator.off("agent:stopped", handleStopped);
309
+ orchestrator.off("task:assigned", handleTaskAssigned);
310
+ orchestrator.off("task:completed", handleTaskCompleted);
311
+ };
312
+ }, [orchestrator]);
313
+ return agents;
314
+ }
315
+
316
+ // src/tui/components/AgentPanel.tsx
317
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
318
+ var ROLE_ICONS = {
319
+ orchestrator: figures.star,
320
+ "project-manager": figures.bullet,
321
+ architect: figures.hamburger,
322
+ developer: figures.pointer,
323
+ designer: figures.heart,
324
+ "qa-engineer": figures.tick,
325
+ devops: figures.arrowRight,
326
+ "technical-writer": figures.info,
327
+ "code-reviewer": figures.warning
328
+ };
329
+ function getStatusColor(status) {
330
+ switch (status) {
331
+ case "running":
332
+ return "green";
333
+ case "idle":
334
+ case "starting":
335
+ return "yellow";
336
+ case "error":
337
+ return "red";
338
+ case "stopped":
339
+ case "stopping":
340
+ return "gray";
341
+ default:
342
+ return "white";
343
+ }
344
+ }
345
+ function getStatusIcon(status) {
346
+ switch (status) {
347
+ case "running":
348
+ case "starting":
349
+ return figures.play;
350
+ case "idle":
351
+ return figures.bullet;
352
+ case "error":
353
+ return figures.cross;
354
+ case "stopped":
355
+ case "stopping":
356
+ return figures.circleFilled;
357
+ default:
358
+ return figures.bullet;
359
+ }
360
+ }
361
+ function formatTokenCount(n) {
362
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
363
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
364
+ return String(n);
365
+ }
366
+ function AgentPanel({
367
+ agent,
368
+ isSelected
369
+ }) {
370
+ if (!agent) {
371
+ return /* @__PURE__ */ jsx3(Box3, { paddingY: 1, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "No agents running. Waiting for orchestrator..." }) });
372
+ }
373
+ const roleIcon = ROLE_ICONS[agent.config.role] ?? figures.bullet;
374
+ const borderColor = isSelected ? "cyan" : "gray";
375
+ const tokens = getAgentTokenUsage(agent.config.id);
376
+ const hasTokens = tokens.inputTokens > 0 || tokens.outputTokens > 0;
377
+ return /* @__PURE__ */ jsxs3(
378
+ Box3,
379
+ {
380
+ flexDirection: "column",
381
+ borderStyle: isSelected ? "bold" : "single",
382
+ borderColor,
383
+ paddingX: 1,
384
+ marginBottom: 0,
385
+ children: [
386
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", justifyContent: "space-between", children: [
387
+ /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
388
+ /* @__PURE__ */ jsx3(Text3, { children: roleIcon }),
389
+ /* @__PURE__ */ jsx3(Text3, { bold: true, children: agent.config.name }),
390
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
391
+ "(",
392
+ agent.config.role,
393
+ ")"
394
+ ] })
395
+ ] }),
396
+ /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
397
+ /* @__PURE__ */ jsx3(Text3, { color: getStatusColor(agent.status), children: getStatusIcon(agent.status) }),
398
+ /* @__PURE__ */ jsx3(Text3, { color: getStatusColor(agent.status), children: agent.status })
399
+ ] })
400
+ ] }),
401
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", justifyContent: "space-between", marginTop: 0, children: [
402
+ /* @__PURE__ */ jsx3(Box3, { flexShrink: 1, children: agent.currentTask ? /* @__PURE__ */ jsxs3(Text3, { children: [
403
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Task: " }),
404
+ /* @__PURE__ */ jsx3(Text3, { wrap: "truncate-end", children: agent.currentTask })
405
+ ] }) : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "No active task" }) }),
406
+ /* @__PURE__ */ jsxs3(Box3, { gap: 2, flexShrink: 0, children: [
407
+ /* @__PURE__ */ jsxs3(Text3, { children: [
408
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Cost: " }),
409
+ /* @__PURE__ */ jsxs3(Text3, { color: "yellow", children: [
410
+ "$",
411
+ agent.totalCostUsd.toFixed(4)
412
+ ] })
413
+ ] }),
414
+ hasTokens && /* @__PURE__ */ jsxs3(Text3, { children: [
415
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Tokens: " }),
416
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: formatTokenCount(tokens.inputTokens) }),
417
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "/" }),
418
+ /* @__PURE__ */ jsx3(Text3, { color: "green", children: formatTokenCount(tokens.outputTokens) }),
419
+ tokens.cacheReadTokens > 0 && /* @__PURE__ */ jsxs3(Fragment, { children: [
420
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: " cache:" }),
421
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: formatTokenCount(tokens.cacheReadTokens) })
422
+ ] })
423
+ ] })
424
+ ] })
425
+ ] }),
426
+ agent.error && /* @__PURE__ */ jsx3(Box3, { marginTop: 0, children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
427
+ figures.cross,
428
+ " ",
429
+ agent.error
430
+ ] }) })
431
+ ]
432
+ }
433
+ );
434
+ }
435
+
436
+ // src/tui/components/OrchestratorPanel.tsx
437
+ import { Box as Box4, Text as Text4 } from "ink";
438
+ import figures2 from "figures";
439
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
440
+ var KIND_ICONS = {
441
+ "task-delegated": { icon: figures2.arrowRight, color: "cyan" },
442
+ "task-completed": { icon: figures2.tick, color: "green" },
443
+ "task-blocked": { icon: figures2.cross, color: "red" },
444
+ "task-failed": { icon: figures2.cross, color: "red" },
445
+ "agent-spawned": { icon: figures2.play, color: "green" },
446
+ "agent-stopped": { icon: figures2.circleFilled, color: "gray" },
447
+ "agent-error": { icon: figures2.warning, color: "red" },
448
+ "phase-changed": { icon: figures2.pointer, color: "magenta" },
449
+ "pipeline-handoff": { icon: figures2.arrowRight, color: "yellow" },
450
+ "plan-created": { icon: figures2.info, color: "blue" },
451
+ "plan-approved": { icon: figures2.tick, color: "green" },
452
+ "plan-rejected": { icon: figures2.cross, color: "red" },
453
+ "budget-warning": { icon: figures2.warning, color: "yellow" },
454
+ "rate-limit": { icon: figures2.warning, color: "red" },
455
+ "project-completed": { icon: figures2.star, color: "green" },
456
+ "cycle-summary": { icon: figures2.bullet, color: "gray" },
457
+ "gap-detected": { icon: figures2.warning, color: "yellow" },
458
+ "pm-scan": { icon: figures2.pointer, color: "cyan" },
459
+ "info": { icon: figures2.info, color: "blue" }
460
+ };
461
+ var MAX_VISIBLE_ACTIVITIES = 6;
462
+ function formatTime2(iso) {
463
+ const d = new Date(iso);
464
+ return d.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
465
+ }
466
+ function OrchestratorPanel({
467
+ activities,
468
+ isSelected,
469
+ phase,
470
+ activeAgents,
471
+ totalTasks,
472
+ completedTasks
473
+ }) {
474
+ const borderColor = isSelected ? "cyan" : "yellow";
475
+ const recentActivities = activities.slice(-MAX_VISIBLE_ACTIVITIES);
476
+ return /* @__PURE__ */ jsxs4(
477
+ Box4,
478
+ {
479
+ flexDirection: "column",
480
+ borderStyle: isSelected ? "bold" : "double",
481
+ borderColor,
482
+ paddingX: 1,
483
+ marginBottom: 0,
484
+ children: [
485
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", justifyContent: "space-between", children: [
486
+ /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
487
+ /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: figures2.star }),
488
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: "yellow", children: "Orchestrator" })
489
+ ] }),
490
+ /* @__PURE__ */ jsx4(Box4, { gap: 1, children: /* @__PURE__ */ jsxs4(Text4, { color: "green", children: [
491
+ figures2.play,
492
+ " active"
493
+ ] }) })
494
+ ] }),
495
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", gap: 2, marginTop: 0, children: [
496
+ /* @__PURE__ */ jsxs4(Text4, { children: [
497
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Phase: " }),
498
+ /* @__PURE__ */ jsx4(Text4, { color: "magenta", bold: true, children: phase })
499
+ ] }),
500
+ /* @__PURE__ */ jsxs4(Text4, { children: [
501
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Agents: " }),
502
+ /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: activeAgents })
503
+ ] }),
504
+ /* @__PURE__ */ jsxs4(Text4, { children: [
505
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Tasks: " }),
506
+ /* @__PURE__ */ jsx4(Text4, { color: "green", children: completedTasks }),
507
+ /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
508
+ "/",
509
+ totalTasks
510
+ ] })
511
+ ] })
512
+ ] }),
513
+ /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginTop: 1, children: recentActivities.length === 0 ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Waiting for activity..." }) : recentActivities.map((activity) => {
514
+ const kindStyle = KIND_ICONS[activity.kind] ?? KIND_ICONS["info"];
515
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", gap: 1, children: [
516
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: formatTime2(activity.timestamp) }),
517
+ /* @__PURE__ */ jsx4(Text4, { color: kindStyle.color, children: kindStyle.icon }),
518
+ /* @__PURE__ */ jsx4(Text4, { wrap: "truncate-end", children: activity.message })
519
+ ] }, activity.id);
520
+ }) })
521
+ ]
522
+ }
523
+ );
524
+ }
525
+
526
+ // src/tui/components/AgentDetailView.tsx
527
+ import React2 from "react";
528
+ import fs from "fs";
529
+ import path from "path";
530
+ import { Box as Box5, Text as Text5 } from "ink";
531
+ import figures3 from "figures";
532
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
533
+ function formatTokenCount2(n) {
534
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
535
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
536
+ return String(n);
537
+ }
538
+ function parseLogLine(line) {
539
+ if (!line.trim()) return null;
540
+ const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z)\s+\[(\w+)\]\s+([\s\S]*)$/);
541
+ if (!match) {
542
+ return { timestamp: "", type: "raw", content: line, json: null };
543
+ }
544
+ const [, timestamp, type, content] = match;
545
+ let json = null;
546
+ if (content.startsWith("{")) {
547
+ try {
548
+ json = JSON.parse(content);
549
+ } catch {
550
+ }
551
+ }
552
+ return { timestamp, type, content, json };
553
+ }
554
+ function useFileLog(logPath) {
555
+ const [entries, setEntries] = React2.useState([]);
556
+ const lastSizeRef = React2.useRef(0);
557
+ React2.useEffect(() => {
558
+ let cancelled = false;
559
+ const readLog = () => {
560
+ try {
561
+ const stat = fs.statSync(logPath);
562
+ if (stat.size === lastSizeRef.current) return;
563
+ lastSizeRef.current = stat.size;
564
+ const content = fs.readFileSync(logPath, "utf-8");
565
+ if (cancelled) return;
566
+ const parsed = content.split("\n").map(parseLogLine).filter((e) => e !== null);
567
+ setEntries(parsed);
568
+ } catch {
569
+ }
570
+ };
571
+ readLog();
572
+ const interval = setInterval(readLog, 2e3);
573
+ return () => {
574
+ cancelled = true;
575
+ clearInterval(interval);
576
+ };
577
+ }, [logPath]);
578
+ return entries;
579
+ }
580
+ function extractAssistantText(json) {
581
+ const msg = json.message;
582
+ const contentBlocks = msg?.content;
583
+ if (!Array.isArray(contentBlocks)) return [];
584
+ const texts = [];
585
+ for (const block of contentBlocks) {
586
+ if (block.type === "text" && typeof block.text === "string") {
587
+ texts.push(block.text);
588
+ }
589
+ }
590
+ return texts;
591
+ }
592
+ function extractToolUses(json) {
593
+ const msg = json.message;
594
+ const contentBlocks = msg?.content;
595
+ if (!Array.isArray(contentBlocks)) return [];
596
+ const tools = [];
597
+ for (const block of contentBlocks) {
598
+ if (block.type === "tool_use" && typeof block.name === "string") {
599
+ const input = block.input;
600
+ const filePath = input?.file_path ?? input?.path ?? input?.command;
601
+ tools.push({ name: block.name, filePath: filePath ?? void 0, input: input ?? void 0 });
602
+ }
603
+ }
604
+ return tools;
605
+ }
606
+ function extractStandaloneToolUse(json) {
607
+ const tool = json.tool;
608
+ const name = tool?.name ?? json.name;
609
+ if (!name) return null;
610
+ const input = tool?.input ?? json.input;
611
+ const filePath = input?.file_path ?? input?.path ?? input?.command;
612
+ return { name, filePath: filePath ?? void 0 };
613
+ }
614
+ function formatToolCall(name, filePath) {
615
+ const FILE_TOOLS = ["Read", "Write", "Edit", "Glob", "Grep", "NotebookEdit"];
616
+ if (FILE_TOOLS.includes(name) && filePath) {
617
+ return `${name} ${filePath}`;
618
+ }
619
+ if (name === "Bash" && filePath) {
620
+ const cmd = filePath.length > 80 ? filePath.slice(0, 77) + "..." : filePath;
621
+ return `Bash: ${cmd}`;
622
+ }
623
+ if (name === "TodoWrite") return "TodoWrite";
624
+ if (name === "Task") return "Task (subagent)";
625
+ if (filePath) return `${name} ${filePath}`;
626
+ return name;
627
+ }
628
+ function formatTime3(iso) {
629
+ if (!iso) return " ";
630
+ const d = new Date(iso);
631
+ return d.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
632
+ }
633
+ function SystemEntry({ entry }) {
634
+ const msg = entry.json ? entry.json.message ?? (entry.json.session_id ? `Session: ${entry.json.session_id}` : entry.content) : entry.content;
635
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
636
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
637
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: msg })
638
+ ] });
639
+ }
640
+ function AssistantEntry({ entry }) {
641
+ if (!entry.json) {
642
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
643
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
644
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
645
+ /* @__PURE__ */ jsxs5(Text5, { color: "blue", bold: true, children: [
646
+ figures3.pointer,
647
+ " Assistant"
648
+ ] })
649
+ ] }),
650
+ /* @__PURE__ */ jsx5(Box5, { paddingLeft: 10, children: /* @__PURE__ */ jsx5(Text5, { wrap: "truncate-end", children: entry.content }) })
651
+ ] });
652
+ }
653
+ const texts = extractAssistantText(entry.json);
654
+ const toolUses = extractToolUses(entry.json);
655
+ const elements = [];
656
+ if (texts.length > 0) {
657
+ const combined = texts.join("\n");
658
+ const displayLines = combined.split("\n");
659
+ const maxLines = 6;
660
+ const truncated = displayLines.length > maxLines;
661
+ const shown = displayLines.slice(0, maxLines).join("\n");
662
+ elements.push(
663
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
664
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
665
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
666
+ /* @__PURE__ */ jsxs5(Text5, { color: "blue", bold: true, children: [
667
+ figures3.pointer,
668
+ " Assistant"
669
+ ] })
670
+ ] }),
671
+ /* @__PURE__ */ jsxs5(Box5, { paddingLeft: 10, children: [
672
+ /* @__PURE__ */ jsx5(Text5, { wrap: "truncate-end", children: shown }),
673
+ truncated && /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
674
+ " ... (",
675
+ displayLines.length - maxLines,
676
+ " more lines)"
677
+ ] })
678
+ ] })
679
+ ] }, "text")
680
+ );
681
+ }
682
+ for (const tool of toolUses) {
683
+ elements.push(
684
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
685
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: texts.length > 0 ? " " : formatTime3(entry.timestamp) }),
686
+ /* @__PURE__ */ jsxs5(Text5, { color: "cyan", children: [
687
+ figures3.arrowRight,
688
+ " ",
689
+ formatToolCall(tool.name, tool.filePath)
690
+ ] })
691
+ ] }, `tool-${tool.name}-${tool.filePath}`)
692
+ );
693
+ }
694
+ if (elements.length === 0) {
695
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
696
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
697
+ /* @__PURE__ */ jsx5(Text5, { color: "blue", children: "[assistant] " }),
698
+ /* @__PURE__ */ jsx5(Text5, { wrap: "truncate-end", children: entry.content.slice(0, 120) })
699
+ ] });
700
+ }
701
+ return /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: elements });
702
+ }
703
+ function ToolUseEntry({ entry }) {
704
+ if (entry.json) {
705
+ const tool = extractStandaloneToolUse(entry.json);
706
+ if (tool) {
707
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
708
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
709
+ /* @__PURE__ */ jsxs5(Text5, { color: "cyan", children: [
710
+ figures3.arrowRight,
711
+ " ",
712
+ formatToolCall(tool.name, tool.filePath)
713
+ ] })
714
+ ] });
715
+ }
716
+ }
717
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
718
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
719
+ /* @__PURE__ */ jsxs5(Text5, { color: "cyan", children: [
720
+ figures3.arrowRight,
721
+ " ",
722
+ entry.content.slice(0, 120)
723
+ ] })
724
+ ] });
725
+ }
726
+ function ToolResultEntry({ entry }) {
727
+ let content = entry.content;
728
+ if (entry.json) {
729
+ const resultContent = entry.json.content ?? entry.json.tool_result?.content;
730
+ if (typeof resultContent === "string") {
731
+ content = resultContent;
732
+ }
733
+ }
734
+ const lines = content.split("\n");
735
+ const lineCount = lines.length;
736
+ const truncated = lineCount > 3 ? lines.slice(0, 3).join("\n") + `
737
+ ... (${lineCount - 3} more lines)` : content;
738
+ const display = truncated.length > 200 ? truncated.slice(0, 200) + "..." : truncated;
739
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
740
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
741
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
742
+ figures3.ellipsis,
743
+ " ",
744
+ display
745
+ ] })
746
+ ] });
747
+ }
748
+ function ResultEntry({ entry }) {
749
+ if (entry.json) {
750
+ const costUsd = entry.json.cost_usd;
751
+ const numTurns = entry.json.num_turns;
752
+ const parts = [];
753
+ if (costUsd !== void 0) parts.push(`$${costUsd.toFixed(4)}`);
754
+ if (numTurns !== void 0) parts.push(`${numTurns} turns`);
755
+ const detail = parts.length > 0 ? ` (${parts.join(", ")})` : "";
756
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
757
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
758
+ /* @__PURE__ */ jsxs5(Text5, { color: "green", bold: true, children: [
759
+ figures3.tick,
760
+ " Task complete",
761
+ detail
762
+ ] })
763
+ ] });
764
+ }
765
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
766
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
767
+ /* @__PURE__ */ jsxs5(Text5, { color: "green", bold: true, children: [
768
+ figures3.tick,
769
+ " ",
770
+ entry.content
771
+ ] })
772
+ ] });
773
+ }
774
+ function ErrorEntry({ entry }) {
775
+ let msg = entry.content;
776
+ if (entry.json) {
777
+ msg = entry.json.error ?? entry.json.message ?? entry.content;
778
+ }
779
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
780
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
781
+ /* @__PURE__ */ jsxs5(Text5, { color: "red", children: [
782
+ figures3.cross,
783
+ " ",
784
+ msg
785
+ ] })
786
+ ] });
787
+ }
788
+ function LogEntry({ entry }) {
789
+ switch (entry.type) {
790
+ case "system":
791
+ return /* @__PURE__ */ jsx5(SystemEntry, { entry });
792
+ case "assistant":
793
+ return /* @__PURE__ */ jsx5(AssistantEntry, { entry });
794
+ case "tool_use":
795
+ return /* @__PURE__ */ jsx5(ToolUseEntry, { entry });
796
+ case "tool_result":
797
+ return /* @__PURE__ */ jsx5(ToolResultEntry, { entry });
798
+ case "result":
799
+ return /* @__PURE__ */ jsx5(ResultEntry, { entry });
800
+ case "error":
801
+ return /* @__PURE__ */ jsx5(ErrorEntry, { entry });
802
+ default:
803
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
804
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(entry.timestamp) }),
805
+ /* @__PURE__ */ jsx5(Text5, { wrap: "truncate-end", children: entry.content })
806
+ ] });
807
+ }
808
+ }
809
+ var MAX_DETAIL_LOG_LINES = 80;
810
+ function getStatusColor2(status) {
811
+ switch (status) {
812
+ case "running":
813
+ return "green";
814
+ case "idle":
815
+ case "starting":
816
+ return "yellow";
817
+ case "error":
818
+ return "red";
819
+ case "stopped":
820
+ case "stopping":
821
+ return "gray";
822
+ default:
823
+ return "white";
824
+ }
825
+ }
826
+ var KIND_COLORS2 = {
827
+ "task-delegated": "cyan",
828
+ "task-completed": "green",
829
+ "task-blocked": "red",
830
+ "task-failed": "red",
831
+ "agent-spawned": "green",
832
+ "agent-stopped": "gray",
833
+ "agent-error": "red",
834
+ "phase-changed": "magenta",
835
+ "pipeline-handoff": "yellow",
836
+ "plan-created": "blue",
837
+ "plan-approved": "green",
838
+ "plan-rejected": "red",
839
+ "budget-warning": "yellow",
840
+ "rate-limit": "red",
841
+ "project-completed": "green",
842
+ "cycle-summary": "gray",
843
+ "gap-detected": "yellow",
844
+ "pm-scan": "cyan",
845
+ "info": "blue"
846
+ };
847
+ function AgentDetailView({
848
+ agent,
849
+ orchestratorActivities,
850
+ isOrchestrator,
851
+ phase,
852
+ logsDir
853
+ }) {
854
+ if (isOrchestrator && orchestratorActivities) {
855
+ const logPath2 = path.join(logsDir, "orchestrator.log");
856
+ const entries2 = useFileLog(logPath2);
857
+ const displayEntries2 = entries2.slice(-MAX_DETAIL_LOG_LINES);
858
+ if (displayEntries2.length === 0) {
859
+ const activities = orchestratorActivities.slice(-MAX_DETAIL_LOG_LINES);
860
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
861
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, children: [
862
+ /* @__PURE__ */ jsxs5(Box5, { gap: 1, children: [
863
+ /* @__PURE__ */ jsxs5(Text5, { color: "yellow", bold: true, children: [
864
+ figures3.star,
865
+ " Orchestrator Detail View"
866
+ ] }),
867
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "| Phase: " }),
868
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", bold: true, children: phase ?? "unknown" })
869
+ ] }),
870
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Press ESC to return to agents list" })
871
+ ] }),
872
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, flexGrow: 1, children: [
873
+ /* @__PURE__ */ jsx5(Text5, { bold: true, underline: true, color: "yellow", children: "Activity Log" }),
874
+ /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginTop: 1, children: activities.length === 0 ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "No activity yet..." }) : activities.map((activity) => {
875
+ const color = KIND_COLORS2[activity.kind] ?? "white";
876
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
877
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: formatTime3(activity.timestamp) }),
878
+ /* @__PURE__ */ jsxs5(Text5, { color, bold: true, children: [
879
+ "[",
880
+ activity.kind,
881
+ "]"
882
+ ] }),
883
+ /* @__PURE__ */ jsx5(Text5, { wrap: "truncate-end", children: activity.message })
884
+ ] }, activity.id);
885
+ }) })
886
+ ] })
887
+ ] });
888
+ }
889
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
890
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, children: [
891
+ /* @__PURE__ */ jsxs5(Box5, { gap: 1, children: [
892
+ /* @__PURE__ */ jsxs5(Text5, { color: "yellow", bold: true, children: [
893
+ figures3.star,
894
+ " Orchestrator Detail View"
895
+ ] }),
896
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "| Phase: " }),
897
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", bold: true, children: phase ?? "unknown" })
898
+ ] }),
899
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Press ESC to return to agents list" })
900
+ ] }),
901
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", paddingX: 1, flexGrow: 1, children: [
902
+ /* @__PURE__ */ jsx5(Text5, { bold: true, underline: true, color: "yellow", children: "Developer Log" }),
903
+ /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginTop: 1, children: displayEntries2.map((entry, i) => /* @__PURE__ */ jsx5(LogEntry, { entry }, i)) })
904
+ ] })
905
+ ] });
906
+ }
907
+ if (!agent) {
908
+ return /* @__PURE__ */ jsx5(Box5, { paddingY: 1, paddingX: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "No agent selected. Press ESC to return." }) });
909
+ }
910
+ const logPath = path.join(logsDir, `${agent.config.id}.log`);
911
+ const entries = useFileLog(logPath);
912
+ const displayEntries = entries.slice(-MAX_DETAIL_LOG_LINES);
913
+ const statusColor = getStatusColor2(agent.status);
914
+ const tokens = getAgentTokenUsage(agent.config.id);
915
+ const hasTokens = tokens.inputTokens > 0 || tokens.outputTokens > 0;
916
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
917
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, children: [
918
+ /* @__PURE__ */ jsxs5(Box5, { gap: 1, children: [
919
+ /* @__PURE__ */ jsx5(Text5, { bold: true, children: agent.config.name }),
920
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
921
+ "(",
922
+ agent.config.role,
923
+ ")"
924
+ ] }),
925
+ /* @__PURE__ */ jsxs5(Text5, { color: statusColor, children: [
926
+ agent.status === "running" || agent.status === "starting" ? `${figures3.play} ` : "",
927
+ agent.status
928
+ ] })
929
+ ] }),
930
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Press ESC to return to agents list" })
931
+ ] }),
932
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 3, marginBottom: 1, children: [
933
+ agent.currentTask && /* @__PURE__ */ jsxs5(Text5, { children: [
934
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Task: " }),
935
+ /* @__PURE__ */ jsx5(Text5, { children: agent.currentTask })
936
+ ] }),
937
+ /* @__PURE__ */ jsxs5(Text5, { children: [
938
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Cost: " }),
939
+ /* @__PURE__ */ jsxs5(Text5, { color: "yellow", children: [
940
+ "$",
941
+ agent.totalCostUsd.toFixed(4)
942
+ ] })
943
+ ] }),
944
+ /* @__PURE__ */ jsxs5(Text5, { children: [
945
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Turns: " }),
946
+ /* @__PURE__ */ jsx5(Text5, { children: agent.turnCount })
947
+ ] }),
948
+ hasTokens && /* @__PURE__ */ jsxs5(Text5, { children: [
949
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "In: " }),
950
+ /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: formatTokenCount2(tokens.inputTokens) }),
951
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " Out: " }),
952
+ /* @__PURE__ */ jsx5(Text5, { color: "green", children: formatTokenCount2(tokens.outputTokens) }),
953
+ tokens.cacheReadTokens > 0 && /* @__PURE__ */ jsxs5(Fragment2, { children: [
954
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " Cache: " }),
955
+ /* @__PURE__ */ jsx5(Text5, { children: formatTokenCount2(tokens.cacheReadTokens) })
956
+ ] })
957
+ ] }),
958
+ agent.sessionId && /* @__PURE__ */ jsxs5(Text5, { children: [
959
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Session: " }),
960
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
961
+ agent.sessionId.slice(0, 12),
962
+ "..."
963
+ ] })
964
+ ] })
965
+ ] }),
966
+ agent.error && /* @__PURE__ */ jsx5(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsxs5(Text5, { color: "red", children: [
967
+ figures3.cross,
968
+ " ",
969
+ agent.error
970
+ ] }) }),
971
+ /* @__PURE__ */ jsxs5(
972
+ Box5,
973
+ {
974
+ flexDirection: "column",
975
+ borderStyle: "single",
976
+ borderColor: "gray",
977
+ paddingX: 1,
978
+ flexGrow: 1,
979
+ children: [
980
+ /* @__PURE__ */ jsxs5(Text5, { bold: true, underline: true, children: [
981
+ "Developer Log ",
982
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
983
+ "(",
984
+ logPath,
985
+ ")"
986
+ ] })
987
+ ] }),
988
+ /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginTop: 1, children: displayEntries.length === 0 ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "No log entries yet..." }) : displayEntries.map((entry, i) => /* @__PURE__ */ jsx5(LogEntry, { entry }, i)) })
989
+ ]
990
+ }
991
+ )
992
+ ] });
993
+ }
994
+
995
+ // src/tui/components/TaskList.tsx
996
+ import { Box as Box6, Text as Text6 } from "ink";
997
+ import figures4 from "figures";
998
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
999
+ function getStatusIcon2(status) {
1000
+ switch (status) {
1001
+ case "done":
1002
+ return figures4.tick;
1003
+ case "in-progress":
1004
+ return figures4.play;
1005
+ case "blocked":
1006
+ return figures4.cross;
1007
+ case "cancelled":
1008
+ return figures4.line;
1009
+ case "pending":
1010
+ default:
1011
+ return figures4.circle;
1012
+ }
1013
+ }
1014
+ function getStatusColor3(status) {
1015
+ switch (status) {
1016
+ case "done":
1017
+ return "green";
1018
+ case "in-progress":
1019
+ return "cyan";
1020
+ case "blocked":
1021
+ return "red";
1022
+ case "cancelled":
1023
+ return "gray";
1024
+ case "pending":
1025
+ default:
1026
+ return "white";
1027
+ }
1028
+ }
1029
+ function getPriorityIndicator(priority) {
1030
+ switch (priority) {
1031
+ case "critical":
1032
+ return { text: "!!!", color: "red" };
1033
+ case "high":
1034
+ return { text: "!! ", color: "yellow" };
1035
+ case "medium":
1036
+ return { text: "! ", color: "white" };
1037
+ case "low":
1038
+ return { text: " ", color: "gray" };
1039
+ }
1040
+ }
1041
+ function TaskRow({ task, isSelected }) {
1042
+ const icon = getStatusIcon2(task.status);
1043
+ const color = getStatusColor3(task.status);
1044
+ const priority = getPriorityIndicator(task.priority);
1045
+ const isDone = task.status === "done" || task.status === "cancelled";
1046
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", gap: 1, children: [
1047
+ /* @__PURE__ */ jsx6(Text6, { color: isSelected ? "cyan" : void 0, children: isSelected ? figures4.pointer : " " }),
1048
+ /* @__PURE__ */ jsx6(Text6, { color, children: icon }),
1049
+ /* @__PURE__ */ jsx6(Text6, { color: priority.color, children: priority.text }),
1050
+ /* @__PURE__ */ jsx6(Text6, { color: isSelected ? "cyan" : color, dimColor: isDone, bold: isSelected, children: task.id }),
1051
+ /* @__PURE__ */ jsx6(Text6, { color: isSelected ? "cyan" : color, dimColor: isDone, bold: isSelected, wrap: "truncate", children: task.title }),
1052
+ task.assignee && /* @__PURE__ */ jsxs6(Text6, { dimColor: isDone, color: task.status === "in-progress" ? "green" : void 0, children: [
1053
+ "@",
1054
+ task.assignee
1055
+ ] })
1056
+ ] });
1057
+ }
1058
+ function sortTasks(tasks) {
1059
+ const statusOrder = {
1060
+ "in-progress": 0,
1061
+ "pending": 1,
1062
+ "blocked": 2,
1063
+ "done": 3,
1064
+ "cancelled": 4
1065
+ };
1066
+ return [...tasks].sort((a, b) => {
1067
+ const sa = statusOrder[a.status] ?? 5;
1068
+ const sb = statusOrder[b.status] ?? 5;
1069
+ if (sa !== sb) return sa - sb;
1070
+ const priorityOrder = {
1071
+ critical: 0,
1072
+ high: 1,
1073
+ medium: 2,
1074
+ low: 3
1075
+ };
1076
+ return (priorityOrder[a.priority] ?? 4) - (priorityOrder[b.priority] ?? 4);
1077
+ });
1078
+ }
1079
+ function TaskList({ tasks, selectedIndex }) {
1080
+ if (tasks.length === 0) {
1081
+ return /* @__PURE__ */ jsx6(Box6, { paddingY: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "No tasks found." }) });
1082
+ }
1083
+ const sorted = sortTasks(tasks);
1084
+ const inProgress = sorted.filter((t) => t.status === "in-progress").length;
1085
+ const pending = sorted.filter((t) => t.status === "pending").length;
1086
+ const done = sorted.filter((t) => t.status === "done").length;
1087
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1088
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", gap: 2, children: [
1089
+ /* @__PURE__ */ jsxs6(Text6, { bold: true, underline: true, children: [
1090
+ "Tasks (",
1091
+ tasks.length,
1092
+ ")"
1093
+ ] }),
1094
+ /* @__PURE__ */ jsxs6(Text6, { children: [
1095
+ /* @__PURE__ */ jsxs6(Text6, { color: "cyan", children: [
1096
+ inProgress,
1097
+ " active"
1098
+ ] }),
1099
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " | " }),
1100
+ /* @__PURE__ */ jsxs6(Text6, { children: [
1101
+ pending,
1102
+ " pending"
1103
+ ] }),
1104
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " | " }),
1105
+ /* @__PURE__ */ jsxs6(Text6, { color: "green", children: [
1106
+ done,
1107
+ " done"
1108
+ ] })
1109
+ ] })
1110
+ ] }),
1111
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Use arrows to select, Enter for details, Esc to go back" }),
1112
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, flexDirection: "column", children: sorted.map((task, i) => /* @__PURE__ */ jsx6(
1113
+ TaskRow,
1114
+ {
1115
+ task,
1116
+ isSelected: i === selectedIndex
1117
+ },
1118
+ task.id
1119
+ )) })
1120
+ ] });
1121
+ }
1122
+
1123
+ // src/tui/components/TaskDetailView.tsx
1124
+ import React3 from "react";
1125
+ import { Box as Box7, Text as Text7 } from "ink";
1126
+ import figures5 from "figures";
1127
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1128
+ function getStatusColor4(status) {
1129
+ switch (status) {
1130
+ case "done":
1131
+ return "green";
1132
+ case "in-progress":
1133
+ return "cyan";
1134
+ case "blocked":
1135
+ return "red";
1136
+ case "cancelled":
1137
+ return "gray";
1138
+ case "pending":
1139
+ default:
1140
+ return "white";
1141
+ }
1142
+ }
1143
+ function getStatusIcon3(status) {
1144
+ switch (status) {
1145
+ case "done":
1146
+ return figures5.tick;
1147
+ case "in-progress":
1148
+ return figures5.play;
1149
+ case "blocked":
1150
+ return figures5.cross;
1151
+ case "cancelled":
1152
+ return figures5.line;
1153
+ default:
1154
+ return figures5.circle;
1155
+ }
1156
+ }
1157
+ function formatTime4(iso) {
1158
+ const d = new Date(iso);
1159
+ return d.toLocaleTimeString("en-US", {
1160
+ hour12: false,
1161
+ hour: "2-digit",
1162
+ minute: "2-digit",
1163
+ second: "2-digit"
1164
+ });
1165
+ }
1166
+ function getTypeIcon(type) {
1167
+ switch (type) {
1168
+ case "task-assignment":
1169
+ return { icon: figures5.arrowRight, color: "cyan" };
1170
+ case "task-result":
1171
+ return { icon: figures5.tick, color: "green" };
1172
+ case "feedback-request":
1173
+ return { icon: figures5.warning, color: "yellow" };
1174
+ case "feedback-response":
1175
+ return { icon: figures5.info, color: "blue" };
1176
+ default:
1177
+ return { icon: figures5.bullet, color: "white" };
1178
+ }
1179
+ }
1180
+ function MessageRow({ envelope }) {
1181
+ const msg = envelope.message;
1182
+ const { icon, color } = getTypeIcon(msg.type);
1183
+ const bodyLines = msg.body ? msg.body.split("\n").filter((l) => l.trim()).slice(0, 4) : [];
1184
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
1185
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", gap: 1, children: [
1186
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: formatTime4(msg.timestamp) }),
1187
+ /* @__PURE__ */ jsx7(Text7, { color, children: icon }),
1188
+ /* @__PURE__ */ jsx7(Text7, { color, bold: true, children: msg.type }),
1189
+ /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
1190
+ msg.from,
1191
+ " ",
1192
+ figures5.arrowRight,
1193
+ " ",
1194
+ msg.to
1195
+ ] })
1196
+ ] }),
1197
+ msg.subject && /* @__PURE__ */ jsx7(Box7, { paddingLeft: 2, children: /* @__PURE__ */ jsx7(Text7, { wrap: "truncate-end", children: msg.subject }) }),
1198
+ bodyLines.length > 0 && /* @__PURE__ */ jsxs7(Box7, { paddingLeft: 2, flexDirection: "column", children: [
1199
+ bodyLines.map((line, i) => /* @__PURE__ */ jsx7(Text7, { wrap: "truncate-end", dimColor: true, children: line }, i)),
1200
+ msg.body && msg.body.split("\n").filter((l) => l.trim()).length > 4 && /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " ..." })
1201
+ ] })
1202
+ ] });
1203
+ }
1204
+ function TaskDetailView({ task, orchestrator }) {
1205
+ const [messages, setMessages] = React3.useState([]);
1206
+ const [loading, setLoading] = React3.useState(true);
1207
+ React3.useEffect(() => {
1208
+ setLoading(true);
1209
+ orchestrator.getTaskMessages(task.id).then((msgs) => {
1210
+ setMessages(msgs);
1211
+ setLoading(false);
1212
+ }).catch(() => {
1213
+ setLoading(false);
1214
+ });
1215
+ }, [task.id, orchestrator]);
1216
+ const statusColor = getStatusColor4(task.status);
1217
+ const statusIcon = getStatusIcon3(task.status);
1218
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
1219
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, children: [
1220
+ /* @__PURE__ */ jsxs7(Box7, { gap: 1, children: [
1221
+ /* @__PURE__ */ jsx7(Text7, { color: statusColor, children: statusIcon }),
1222
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: task.id }),
1223
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: task.title })
1224
+ ] }),
1225
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "ESC: back | arrows: navigate" })
1226
+ ] }),
1227
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", gap: 3, marginBottom: 1, children: [
1228
+ /* @__PURE__ */ jsxs7(Text7, { children: [
1229
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Status: " }),
1230
+ /* @__PURE__ */ jsx7(Text7, { color: statusColor, bold: true, children: task.status })
1231
+ ] }),
1232
+ /* @__PURE__ */ jsxs7(Text7, { children: [
1233
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Priority: " }),
1234
+ /* @__PURE__ */ jsx7(Text7, { children: task.priority })
1235
+ ] }),
1236
+ /* @__PURE__ */ jsxs7(Text7, { children: [
1237
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Assignee: " }),
1238
+ /* @__PURE__ */ jsx7(Text7, { color: task.assignee ? "green" : "gray", children: task.assignee ?? "unassigned" })
1239
+ ] }),
1240
+ task.dependencies.length > 0 && /* @__PURE__ */ jsxs7(Text7, { children: [
1241
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Deps: " }),
1242
+ /* @__PURE__ */ jsx7(Text7, { children: task.dependencies.join(", ") })
1243
+ ] }),
1244
+ task.tags.length > 0 && /* @__PURE__ */ jsxs7(Text7, { children: [
1245
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Tags: " }),
1246
+ /* @__PURE__ */ jsx7(Text7, { children: task.tags.join(", ") })
1247
+ ] })
1248
+ ] }),
1249
+ task.description && /* @__PURE__ */ jsx7(Box7, { marginBottom: 1, children: /* @__PURE__ */ jsx7(Text7, { dimColor: true, wrap: "truncate-end", children: task.description }) }),
1250
+ /* @__PURE__ */ jsxs7(
1251
+ Box7,
1252
+ {
1253
+ flexDirection: "column",
1254
+ borderStyle: "single",
1255
+ borderColor: "gray",
1256
+ paddingX: 1,
1257
+ flexGrow: 1,
1258
+ overflow: "hidden",
1259
+ children: [
1260
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, children: [
1261
+ "Messages (",
1262
+ messages.length,
1263
+ ")"
1264
+ ] }),
1265
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginTop: 1, overflow: "hidden", children: loading ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "Loading messages..." }) : messages.length === 0 ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "No messages for this task." }) : messages.map((envelope) => /* @__PURE__ */ jsx7(MessageRow, { envelope }, envelope.message.id)) })
1266
+ ]
1267
+ }
1268
+ )
1269
+ ] });
1270
+ }
1271
+
1272
+ // src/tui/components/InstructionsPanel.tsx
1273
+ import React4 from "react";
1274
+ import { Box as Box8, Text as Text8, useInput } from "ink";
1275
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1276
+ function InstructionsPanel({
1277
+ isPaused,
1278
+ isDecomposing,
1279
+ onSubmit,
1280
+ onPause,
1281
+ onResume
1282
+ }) {
1283
+ const [lines, setLines] = React4.useState([""]);
1284
+ const [cursorLine, setCursorLine] = React4.useState(0);
1285
+ const [cursorCol, setCursorCol] = React4.useState(0);
1286
+ const [submitted, setSubmitted] = React4.useState(false);
1287
+ useInput((input, key) => {
1288
+ if (isDecomposing) return;
1289
+ if (input === "s" && key.ctrl) {
1290
+ const text = lines.join("\n").trim();
1291
+ if (text.length > 0) {
1292
+ setSubmitted(true);
1293
+ onSubmit(text);
1294
+ setTimeout(() => {
1295
+ setLines([""]);
1296
+ setCursorLine(0);
1297
+ setCursorCol(0);
1298
+ setSubmitted(false);
1299
+ }, 500);
1300
+ }
1301
+ return;
1302
+ }
1303
+ if (input === "x" && key.ctrl) {
1304
+ setLines([""]);
1305
+ setCursorLine(0);
1306
+ setCursorCol(0);
1307
+ return;
1308
+ }
1309
+ if (input === "p" && key.ctrl) {
1310
+ if (isPaused) {
1311
+ onResume();
1312
+ } else {
1313
+ onPause();
1314
+ }
1315
+ return;
1316
+ }
1317
+ if (key.return) {
1318
+ const currentLine = lines[cursorLine] ?? "";
1319
+ const before = currentLine.slice(0, cursorCol);
1320
+ const after = currentLine.slice(cursorCol);
1321
+ const newLines = [...lines];
1322
+ newLines[cursorLine] = before;
1323
+ newLines.splice(cursorLine + 1, 0, after);
1324
+ setLines(newLines);
1325
+ setCursorLine(cursorLine + 1);
1326
+ setCursorCol(0);
1327
+ return;
1328
+ }
1329
+ if (key.backspace || key.delete) {
1330
+ if (cursorCol > 0) {
1331
+ const currentLine = lines[cursorLine] ?? "";
1332
+ const newLine = currentLine.slice(0, cursorCol - 1) + currentLine.slice(cursorCol);
1333
+ const newLines = [...lines];
1334
+ newLines[cursorLine] = newLine;
1335
+ setLines(newLines);
1336
+ setCursorCol(cursorCol - 1);
1337
+ } else if (cursorLine > 0) {
1338
+ const prevLine = lines[cursorLine - 1] ?? "";
1339
+ const currentLine = lines[cursorLine] ?? "";
1340
+ const newLines = [...lines];
1341
+ newLines[cursorLine - 1] = prevLine + currentLine;
1342
+ newLines.splice(cursorLine, 1);
1343
+ setLines(newLines);
1344
+ setCursorLine(cursorLine - 1);
1345
+ setCursorCol(prevLine.length);
1346
+ }
1347
+ return;
1348
+ }
1349
+ if (key.leftArrow) {
1350
+ if (cursorCol > 0) {
1351
+ setCursorCol(cursorCol - 1);
1352
+ } else if (cursorLine > 0) {
1353
+ setCursorLine(cursorLine - 1);
1354
+ setCursorCol((lines[cursorLine - 1] ?? "").length);
1355
+ }
1356
+ return;
1357
+ }
1358
+ if (key.rightArrow) {
1359
+ const currentLine = lines[cursorLine] ?? "";
1360
+ if (cursorCol < currentLine.length) {
1361
+ setCursorCol(cursorCol + 1);
1362
+ } else if (cursorLine < lines.length - 1) {
1363
+ setCursorLine(cursorLine + 1);
1364
+ setCursorCol(0);
1365
+ }
1366
+ return;
1367
+ }
1368
+ if (key.upArrow) {
1369
+ if (cursorLine > 0) {
1370
+ setCursorLine(cursorLine - 1);
1371
+ const prevLen = (lines[cursorLine - 1] ?? "").length;
1372
+ setCursorCol(Math.min(cursorCol, prevLen));
1373
+ }
1374
+ return;
1375
+ }
1376
+ if (key.downArrow) {
1377
+ if (cursorLine < lines.length - 1) {
1378
+ setCursorLine(cursorLine + 1);
1379
+ const nextLen = (lines[cursorLine + 1] ?? "").length;
1380
+ setCursorCol(Math.min(cursorCol, nextLen));
1381
+ }
1382
+ return;
1383
+ }
1384
+ if (key.ctrl || key.meta) return;
1385
+ if (key.escape) return;
1386
+ if (key.tab) {
1387
+ const currentLine = lines[cursorLine] ?? "";
1388
+ const newLine = currentLine.slice(0, cursorCol) + " " + currentLine.slice(cursorCol);
1389
+ const newLines = [...lines];
1390
+ newLines[cursorLine] = newLine;
1391
+ setLines(newLines);
1392
+ setCursorCol(cursorCol + 2);
1393
+ return;
1394
+ }
1395
+ if (input && input.length > 0) {
1396
+ const currentLine = lines[cursorLine] ?? "";
1397
+ const newLine = currentLine.slice(0, cursorCol) + input + currentLine.slice(cursorCol);
1398
+ const newLines = [...lines];
1399
+ newLines[cursorLine] = newLine;
1400
+ setLines(newLines);
1401
+ setCursorCol(cursorCol + input.length);
1402
+ }
1403
+ });
1404
+ const hasContent = lines.some((l) => l.trim().length > 0);
1405
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
1406
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", justifyContent: "space-between", marginBottom: 1, children: [
1407
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: "cyan", children: "New Instructions" }),
1408
+ /* @__PURE__ */ jsx8(Box8, { gap: 2, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: isPaused ? /* @__PURE__ */ jsx8(Text8, { color: "yellow", bold: true, children: "PAUSED" }) : /* @__PURE__ */ jsx8(Text8, { color: "green", children: "RUNNING" }) }) })
1409
+ ] }),
1410
+ /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
1411
+ "Orchestrator: ",
1412
+ isPaused ? /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "Paused \u2014 agents stopped. " }) : /* @__PURE__ */ jsx8(Text8, { color: "green", children: "Running. " }),
1413
+ "Press ",
1414
+ /* @__PURE__ */ jsx8(Text8, { bold: true, children: "ctrl+p" }),
1415
+ " to ",
1416
+ isPaused ? "resume" : "pause",
1417
+ "."
1418
+ ] }) }),
1419
+ /* @__PURE__ */ jsxs8(
1420
+ Box8,
1421
+ {
1422
+ flexDirection: "column",
1423
+ borderStyle: "round",
1424
+ borderColor: isDecomposing ? "yellow" : submitted ? "green" : "gray",
1425
+ paddingX: 1,
1426
+ paddingY: 0,
1427
+ flexGrow: 1,
1428
+ overflow: "hidden",
1429
+ children: [
1430
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: isDecomposing ? "Decomposing instructions into tasks..." : "Type or paste instructions below. Press ctrl+s to submit, ctrl+x to clear." }),
1431
+ /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", marginTop: 1, children: lines.map((line, idx) => {
1432
+ if (idx === cursorLine && !isDecomposing) {
1433
+ const before = line.slice(0, cursorCol);
1434
+ const cursorChar = line[cursorCol] ?? " ";
1435
+ const after = line.slice(cursorCol + 1);
1436
+ return /* @__PURE__ */ jsxs8(Box8, { children: [
1437
+ /* @__PURE__ */ jsx8(Text8, { children: before }),
1438
+ /* @__PURE__ */ jsx8(Text8, { inverse: true, children: cursorChar }),
1439
+ /* @__PURE__ */ jsx8(Text8, { children: after })
1440
+ ] }, idx);
1441
+ }
1442
+ return /* @__PURE__ */ jsx8(Text8, { children: line || " " }, idx);
1443
+ }) })
1444
+ ]
1445
+ }
1446
+ ),
1447
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, gap: 3, children: [
1448
+ /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
1449
+ lines.length,
1450
+ " line",
1451
+ lines.length !== 1 ? "s" : "",
1452
+ " | col ",
1453
+ cursorCol + 1
1454
+ ] }),
1455
+ hasContent && !isDecomposing && /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: "ctrl+s: Submit" }),
1456
+ hasContent && !isDecomposing && /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "ctrl+x: Clear" }),
1457
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "esc: Back" })
1458
+ ] })
1459
+ ] });
1460
+ }
1461
+
1462
+ // src/tui/components/Dashboard.tsx
1463
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1464
+ function Dashboard({
1465
+ agents,
1466
+ tasks,
1467
+ selectedAgentIndex,
1468
+ selectedTaskIndex,
1469
+ viewMode,
1470
+ onSelectAgent,
1471
+ orchestratorActivities,
1472
+ orchestrator,
1473
+ phase,
1474
+ logsDir,
1475
+ isPaused,
1476
+ isDecomposing,
1477
+ onSubmitInstructions,
1478
+ onPause,
1479
+ onResume
1480
+ }) {
1481
+ const isOrchestratorSelected = selectedAgentIndex === 0;
1482
+ const actualAgentIndex = selectedAgentIndex - 1;
1483
+ const selectedAgent = actualAgentIndex >= 0 ? agents[actualAgentIndex] ?? null : null;
1484
+ const activeAgentCount = agents.filter(
1485
+ (a) => a.status === "running" || a.status === "starting"
1486
+ ).length;
1487
+ const completedTasks = tasks.filter((t) => t.status === "done").length;
1488
+ const sortedTasks = [...tasks].sort((a, b) => {
1489
+ const statusOrder = {
1490
+ "in-progress": 0,
1491
+ pending: 1,
1492
+ blocked: 2,
1493
+ done: 3,
1494
+ cancelled: 4
1495
+ };
1496
+ const sa = statusOrder[a.status] ?? 5;
1497
+ const sb = statusOrder[b.status] ?? 5;
1498
+ if (sa !== sb) return sa - sb;
1499
+ const priorityOrder = {
1500
+ critical: 0,
1501
+ high: 1,
1502
+ medium: 2,
1503
+ low: 3
1504
+ };
1505
+ return (priorityOrder[a.priority] ?? 4) - (priorityOrder[b.priority] ?? 4);
1506
+ });
1507
+ if (viewMode === "instructions") {
1508
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(
1509
+ InstructionsPanel,
1510
+ {
1511
+ isPaused,
1512
+ isDecomposing,
1513
+ onSubmit: onSubmitInstructions,
1514
+ onPause,
1515
+ onResume
1516
+ }
1517
+ ) });
1518
+ }
1519
+ if (viewMode === "tasks") {
1520
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(TaskList, { tasks, selectedIndex: selectedTaskIndex }) });
1521
+ }
1522
+ if (viewMode === "task-detail") {
1523
+ const selectedTask = sortedTasks[selectedTaskIndex] ?? null;
1524
+ if (!selectedTask) {
1525
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(TaskList, { tasks, selectedIndex: selectedTaskIndex }) });
1526
+ }
1527
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(TaskDetailView, { task: selectedTask, orchestrator }) });
1528
+ }
1529
+ if (viewMode === "logs") {
1530
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(LogViewer, { agent: selectedAgent }) });
1531
+ }
1532
+ if (viewMode === "agent-detail") {
1533
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", paddingX: 1, flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(
1534
+ AgentDetailView,
1535
+ {
1536
+ agent: selectedAgent,
1537
+ orchestratorActivities,
1538
+ isOrchestrator: isOrchestratorSelected,
1539
+ phase,
1540
+ logsDir
1541
+ }
1542
+ ) });
1543
+ }
1544
+ const sortedAgents = [...agents].sort((a, b) => {
1545
+ const rank = (s) => {
1546
+ if (s === "running" || s === "starting") return 0;
1547
+ if (s === "idle") return 1;
1548
+ if (s === "error") return 2;
1549
+ return 3;
1550
+ };
1551
+ return rank(a.status) - rank(b.status);
1552
+ });
1553
+ const sortedWithOrigIndex = sortedAgents.map((agent) => ({
1554
+ agent,
1555
+ originalIndex: agents.indexOf(agent) + 1
1556
+ // +1 because orchestrator is index 0
1557
+ }));
1558
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", paddingX: 1, flexGrow: 1, overflow: "hidden", children: [
1559
+ /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: [
1560
+ /* @__PURE__ */ jsx9(
1561
+ OrchestratorPanel,
1562
+ {
1563
+ activities: orchestratorActivities,
1564
+ isSelected: isOrchestratorSelected,
1565
+ phase,
1566
+ activeAgents: activeAgentCount,
1567
+ totalTasks: tasks.length,
1568
+ completedTasks
1569
+ }
1570
+ ),
1571
+ sortedWithOrigIndex.length === 0 ? /* @__PURE__ */ jsx9(Box9, { paddingY: 1, paddingX: 1, children: /* @__PURE__ */ jsx9(AgentPanel, { agent: null, isSelected: false }) }) : sortedWithOrigIndex.map(({ agent, originalIndex }) => /* @__PURE__ */ jsx9(
1572
+ AgentPanel,
1573
+ {
1574
+ agent,
1575
+ isSelected: originalIndex === selectedAgentIndex
1576
+ },
1577
+ agent.config.id
1578
+ ))
1579
+ ] }),
1580
+ /* @__PURE__ */ jsx9(
1581
+ Box9,
1582
+ {
1583
+ flexDirection: "column",
1584
+ width: "40%",
1585
+ borderStyle: "single",
1586
+ borderColor: "gray",
1587
+ paddingX: 1,
1588
+ overflow: "hidden",
1589
+ children: isOrchestratorSelected ? /* @__PURE__ */ jsx9(LogViewer, { agent: null, orchestratorActivities }) : selectedAgent ? /* @__PURE__ */ jsx9(LogViewer, { agent: selectedAgent }) : /* @__PURE__ */ jsx9(LogViewer, { agent: null })
1590
+ }
1591
+ )
1592
+ ] });
1593
+ }
1594
+
1595
+ // src/tui/components/StatusBar.tsx
1596
+ import { Box as Box10, Text as Text9 } from "ink";
1597
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1598
+ function StatusBar({ viewMode, isPaused }) {
1599
+ const isDetail = viewMode === "agent-detail" || viewMode === "task-detail";
1600
+ const hints = viewMode === "instructions" ? [
1601
+ { key: "esc", label: "Back", active: true },
1602
+ { key: "ctrl+s", label: "Submit" },
1603
+ { key: "ctrl+p", label: isPaused ? "Resume" : "Pause" },
1604
+ { key: "ctrl+x", label: "Clear" }
1605
+ ] : isDetail ? [
1606
+ { key: "esc", label: "Back to list", active: true },
1607
+ ...viewMode === "agent-detail" ? [{ key: "tab", label: "Switch agent" }] : [],
1608
+ ...viewMode === "task-detail" ? [{ key: "arrows", label: "Navigate tasks" }] : [],
1609
+ { key: "q", label: "Quit" }
1610
+ ] : [
1611
+ { key: "q", label: "Quit" },
1612
+ { key: "enter", label: "View detail" },
1613
+ ...viewMode === "agents" ? [{ key: "tab", label: "Switch agent" }] : [],
1614
+ ...viewMode === "tasks" ? [{ key: "arrows", label: "Navigate" }] : [],
1615
+ { key: "a", label: "Agents", active: viewMode === "agents" },
1616
+ { key: "t", label: "Tasks", active: viewMode === "tasks" },
1617
+ { key: "l", label: "Logs", active: viewMode === "logs" },
1618
+ { key: "i", label: "Instructions" },
1619
+ { key: "p", label: isPaused ? "Resume" : "Pause" }
1620
+ ];
1621
+ return /* @__PURE__ */ jsx10(
1622
+ Box10,
1623
+ {
1624
+ flexDirection: "row",
1625
+ paddingX: 1,
1626
+ borderStyle: "single",
1627
+ borderColor: "gray",
1628
+ justifyContent: "center",
1629
+ gap: 2,
1630
+ children: hints.map((hint) => /* @__PURE__ */ jsxs10(Box10, { gap: 0, children: [
1631
+ /* @__PURE__ */ jsx10(Text9, { bold: true, color: hint.active ? "cyan" : "white", children: hint.key }),
1632
+ /* @__PURE__ */ jsxs10(Text9, { dimColor: !hint.active, children: [
1633
+ ": ",
1634
+ hint.label
1635
+ ] })
1636
+ ] }, hint.key))
1637
+ }
1638
+ );
1639
+ }
1640
+
1641
+ // src/tui/hooks/useTaskManager.ts
1642
+ import React5 from "react";
1643
+ function useTaskManager(orchestrator) {
1644
+ const [tasks, setTasks] = React5.useState([]);
1645
+ React5.useEffect(() => {
1646
+ const handleLoaded = (loadedTasks) => {
1647
+ setTasks(loadedTasks);
1648
+ };
1649
+ const handleCreated = (task) => {
1650
+ setTasks((prev) => {
1651
+ const existing = prev.findIndex((t) => t.id === task.id);
1652
+ if (existing >= 0) {
1653
+ const next = [...prev];
1654
+ next[existing] = task;
1655
+ return next;
1656
+ }
1657
+ return [...prev, task];
1658
+ });
1659
+ };
1660
+ const handleUpdated = (task, _changes) => {
1661
+ setTasks(
1662
+ (prev) => prev.map((t) => t.id === task.id ? task : t)
1663
+ );
1664
+ };
1665
+ const handleCompleted = (task) => {
1666
+ setTasks(
1667
+ (prev) => prev.map((t) => t.id === task.id ? { ...task, status: "done" } : t)
1668
+ );
1669
+ };
1670
+ const handleAssigned = (task, agentId) => {
1671
+ setTasks(
1672
+ (prev) => prev.map((t) => t.id === task.id ? { ...task, status: "in-progress", assignee: agentId } : t)
1673
+ );
1674
+ };
1675
+ orchestrator.on("tasks:loaded", handleLoaded);
1676
+ orchestrator.on("task:created", handleCreated);
1677
+ orchestrator.on("task:updated", handleUpdated);
1678
+ orchestrator.on("task:completed", handleCompleted);
1679
+ orchestrator.on("task:assigned", handleAssigned);
1680
+ orchestrator.getTasks().then((existing) => {
1681
+ if (existing.length > 0) {
1682
+ setTasks(existing);
1683
+ }
1684
+ }).catch(() => {
1685
+ });
1686
+ return () => {
1687
+ orchestrator.off("tasks:loaded", handleLoaded);
1688
+ orchestrator.off("task:created", handleCreated);
1689
+ orchestrator.off("task:updated", handleUpdated);
1690
+ orchestrator.off("task:completed", handleCompleted);
1691
+ orchestrator.off("task:assigned", handleAssigned);
1692
+ };
1693
+ }, [orchestrator]);
1694
+ return tasks;
1695
+ }
1696
+
1697
+ // src/tui/hooks/useKeyboard.ts
1698
+ import React6 from "react";
1699
+ import { useInput as useInput2 } from "ink";
1700
+ function useKeyboard(agentCount, taskCount = 0) {
1701
+ const [selectedAgentIndex, setSelectedAgentIndex] = React6.useState(0);
1702
+ const [selectedTaskIndex, setSelectedTaskIndex] = React6.useState(0);
1703
+ const [viewMode, setViewMode] = React6.useState("agents");
1704
+ useInput2((input, key) => {
1705
+ if (viewMode === "instructions") {
1706
+ if (key.escape) {
1707
+ setViewMode("agents");
1708
+ }
1709
+ return;
1710
+ }
1711
+ if (key.return) {
1712
+ if (viewMode === "agents") {
1713
+ setViewMode("agent-detail");
1714
+ return;
1715
+ }
1716
+ if (viewMode === "tasks" && taskCount > 0) {
1717
+ setViewMode("task-detail");
1718
+ return;
1719
+ }
1720
+ }
1721
+ if (key.escape) {
1722
+ if (viewMode === "agent-detail") {
1723
+ setViewMode("agents");
1724
+ return;
1725
+ }
1726
+ if (viewMode === "task-detail") {
1727
+ setViewMode("tasks");
1728
+ return;
1729
+ }
1730
+ }
1731
+ if (key.tab && (viewMode === "agents" || viewMode === "agent-detail")) {
1732
+ setSelectedAgentIndex((prev) => {
1733
+ if (agentCount === 0) return 0;
1734
+ return (prev + 1) % agentCount;
1735
+ });
1736
+ }
1737
+ if (key.upArrow) {
1738
+ if (viewMode === "agents" || viewMode === "agent-detail") {
1739
+ setSelectedAgentIndex((prev) => {
1740
+ if (agentCount === 0) return 0;
1741
+ return prev > 0 ? prev - 1 : agentCount - 1;
1742
+ });
1743
+ }
1744
+ if (viewMode === "tasks" || viewMode === "task-detail") {
1745
+ setSelectedTaskIndex((prev) => {
1746
+ if (taskCount === 0) return 0;
1747
+ return prev > 0 ? prev - 1 : taskCount - 1;
1748
+ });
1749
+ }
1750
+ }
1751
+ if (key.downArrow) {
1752
+ if (viewMode === "agents" || viewMode === "agent-detail") {
1753
+ setSelectedAgentIndex((prev) => {
1754
+ if (agentCount === 0) return 0;
1755
+ return (prev + 1) % agentCount;
1756
+ });
1757
+ }
1758
+ if (viewMode === "tasks" || viewMode === "task-detail") {
1759
+ setSelectedTaskIndex((prev) => {
1760
+ if (taskCount === 0) return 0;
1761
+ return (prev + 1) % taskCount;
1762
+ });
1763
+ }
1764
+ }
1765
+ if (viewMode !== "agent-detail" && viewMode !== "task-detail") {
1766
+ if (input === "a") {
1767
+ setViewMode("agents");
1768
+ }
1769
+ if (input === "t") {
1770
+ setViewMode("tasks");
1771
+ }
1772
+ if (input === "l") {
1773
+ setViewMode("logs");
1774
+ }
1775
+ if (input === "i") {
1776
+ setViewMode("instructions");
1777
+ }
1778
+ }
1779
+ });
1780
+ React6.useEffect(() => {
1781
+ if (agentCount > 0 && selectedAgentIndex >= agentCount) {
1782
+ setSelectedAgentIndex(agentCount - 1);
1783
+ }
1784
+ }, [agentCount, selectedAgentIndex]);
1785
+ React6.useEffect(() => {
1786
+ if (taskCount > 0 && selectedTaskIndex >= taskCount) {
1787
+ setSelectedTaskIndex(taskCount - 1);
1788
+ }
1789
+ }, [taskCount, selectedTaskIndex]);
1790
+ return {
1791
+ selectedAgentIndex,
1792
+ selectedTaskIndex,
1793
+ viewMode,
1794
+ setSelectedAgentIndex,
1795
+ setSelectedTaskIndex,
1796
+ setViewMode
1797
+ };
1798
+ }
1799
+
1800
+ // src/tui/hooks/useFeedback.ts
1801
+ import { useState, useEffect } from "react";
1802
+ function useFeedback(orchestrator) {
1803
+ const [pendingPlan, setPendingPlan] = useState(null);
1804
+ const [questions, setQuestions] = useState([]);
1805
+ const [latestReport, setLatestReport] = useState(null);
1806
+ const [milestone, setMilestone] = useState(null);
1807
+ const [interactionMode, setInteractionMode] = useState("supervised");
1808
+ useEffect(() => {
1809
+ const onPlan = (proposal) => setPendingPlan(proposal);
1810
+ const onPlanDecided = () => setPendingPlan(null);
1811
+ const onQuestion = (q) => setQuestions((prev) => [...prev, q]);
1812
+ const onQuestionAnswered = (qId) => setQuestions((prev) => prev.filter((q) => q.id !== qId));
1813
+ const onProgress = (report) => setLatestReport(report);
1814
+ const onMilestone = (m) => setMilestone(m);
1815
+ const onMilestoneAck = () => setMilestone(null);
1816
+ const onModeChanged = (mode) => setInteractionMode(mode);
1817
+ orchestrator.on("plan:proposed", onPlan);
1818
+ orchestrator.on("plan:decided", onPlanDecided);
1819
+ orchestrator.on("question:asked", onQuestion);
1820
+ orchestrator.on("question:answered", onQuestionAnswered);
1821
+ orchestrator.on("progress:report", onProgress);
1822
+ orchestrator.on("milestone:reached", onMilestone);
1823
+ orchestrator.on("milestone:acknowledged", onMilestoneAck);
1824
+ orchestrator.on("interaction-mode:changed", onModeChanged);
1825
+ const existingPlan = orchestrator.getPendingPlan();
1826
+ if (existingPlan) setPendingPlan(existingPlan);
1827
+ const existingQuestions = orchestrator.getPendingQuestions();
1828
+ if (existingQuestions.length > 0) setQuestions(existingQuestions);
1829
+ return () => {
1830
+ orchestrator.off("plan:proposed", onPlan);
1831
+ orchestrator.off("plan:decided", onPlanDecided);
1832
+ orchestrator.off("question:asked", onQuestion);
1833
+ orchestrator.off("question:answered", onQuestionAnswered);
1834
+ orchestrator.off("progress:report", onProgress);
1835
+ orchestrator.off("milestone:reached", onMilestone);
1836
+ orchestrator.off("milestone:acknowledged", onMilestoneAck);
1837
+ orchestrator.off("interaction-mode:changed", onModeChanged);
1838
+ };
1839
+ }, [orchestrator]);
1840
+ const decidePlan = (proposalId, decision) => {
1841
+ orchestrator.decidePlan(proposalId, decision);
1842
+ };
1843
+ const answerQuestion = (questionId, answer) => {
1844
+ orchestrator.answerQuestion(questionId, answer);
1845
+ };
1846
+ const ackMilestone = (milestoneId) => {
1847
+ orchestrator.acknowledgeMilestone(milestoneId);
1848
+ setMilestone(null);
1849
+ };
1850
+ return {
1851
+ pendingPlan,
1852
+ questions,
1853
+ latestReport,
1854
+ milestone,
1855
+ interactionMode,
1856
+ decidePlan,
1857
+ answerQuestion,
1858
+ acknowledgeMilestone: ackMilestone
1859
+ };
1860
+ }
1861
+
1862
+ // src/tui/hooks/useOrchestratorActivity.ts
1863
+ import React7 from "react";
1864
+ var MAX_ACTIVITIES = 200;
1865
+ function useOrchestratorActivity(orchestrator) {
1866
+ const [activities, setActivities] = React7.useState([]);
1867
+ React7.useEffect(() => {
1868
+ const handleActivity = (activity) => {
1869
+ setActivities((prev) => {
1870
+ const next = [...prev, activity];
1871
+ if (next.length > MAX_ACTIVITIES) {
1872
+ return next.slice(-MAX_ACTIVITIES);
1873
+ }
1874
+ return next;
1875
+ });
1876
+ };
1877
+ orchestrator.on("orchestrator:activity", handleActivity);
1878
+ return () => {
1879
+ orchestrator.off("orchestrator:activity", handleActivity);
1880
+ };
1881
+ }, [orchestrator]);
1882
+ return activities;
1883
+ }
1884
+
1885
+ // src/tui/components/PlanReview.tsx
1886
+ import { Box as Box11, Text as Text10, useInput as useInput3 } from "ink";
1887
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1888
+ function PlanReview({ proposal, onDecide }) {
1889
+ useInput3((input) => {
1890
+ if (input === "y" || input === "Y") {
1891
+ onDecide(proposal.id, "approved");
1892
+ } else if (input === "n" || input === "N") {
1893
+ onDecide(proposal.id, "rejected");
1894
+ }
1895
+ });
1896
+ const priorityColor = (p) => {
1897
+ switch (p) {
1898
+ case "critical":
1899
+ return "red";
1900
+ case "high":
1901
+ return "yellow";
1902
+ case "medium":
1903
+ return "cyan";
1904
+ default:
1905
+ return "gray";
1906
+ }
1907
+ };
1908
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", paddingX: 1, children: [
1909
+ /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text10, { bold: true, color: "cyan", children: "Plan Review" }) }),
1910
+ /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
1911
+ /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "Goal: " }),
1912
+ /* @__PURE__ */ jsxs11(Text10, { children: [
1913
+ proposal.projectGoal.slice(0, 80),
1914
+ proposal.projectGoal.length > 80 ? "..." : ""
1915
+ ] })
1916
+ ] }),
1917
+ /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Text10, { bold: true, children: [
1918
+ "Proposed Tasks (",
1919
+ proposal.tasks.length,
1920
+ "):"
1921
+ ] }) }),
1922
+ proposal.tasks.map((task, i) => /* @__PURE__ */ jsxs11(Box11, { paddingLeft: 1, children: [
1923
+ /* @__PURE__ */ jsxs11(Text10, { dimColor: true, children: [
1924
+ String(i + 1).padStart(2, " "),
1925
+ ". "
1926
+ ] }),
1927
+ /* @__PURE__ */ jsxs11(Text10, { color: priorityColor(task.priority), children: [
1928
+ "[",
1929
+ task.priority.slice(0, 4).toUpperCase(),
1930
+ "] "
1931
+ ] }),
1932
+ /* @__PURE__ */ jsx11(Text10, { children: task.title }),
1933
+ task.tags.length > 0 && /* @__PURE__ */ jsxs11(Text10, { dimColor: true, children: [
1934
+ " (",
1935
+ task.tags.join(", "),
1936
+ ")"
1937
+ ] })
1938
+ ] }, i)),
1939
+ /* @__PURE__ */ jsx11(Box11, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: /* @__PURE__ */ jsxs11(Text10, { children: [
1940
+ "Press ",
1941
+ /* @__PURE__ */ jsx11(Text10, { bold: true, color: "green", children: "y" }),
1942
+ " to approve, ",
1943
+ /* @__PURE__ */ jsx11(Text10, { bold: true, color: "red", children: "n" }),
1944
+ " to reject"
1945
+ ] }) })
1946
+ ] });
1947
+ }
1948
+
1949
+ // src/tui/components/QuestionPrompt.tsx
1950
+ import { useState as useState2 } from "react";
1951
+ import { Box as Box12, Text as Text11, useInput as useInput4 } from "ink";
1952
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1953
+ function QuestionPrompt({ question, onAnswer, onSkip }) {
1954
+ const [selectedOption, setSelectedOption] = useState2(0);
1955
+ const [freeText, setFreeText] = useState2("");
1956
+ const [mode, setMode] = useState2(
1957
+ question.options && question.options.length > 0 ? "options" : "freetext"
1958
+ );
1959
+ useInput4((input, key) => {
1960
+ if (mode === "options" && question.options) {
1961
+ if (key.upArrow) {
1962
+ setSelectedOption((prev) => Math.max(0, prev - 1));
1963
+ } else if (key.downArrow) {
1964
+ setSelectedOption((prev) => Math.min(question.options.length - 1, prev + 1));
1965
+ } else if (key.return) {
1966
+ onAnswer(question.id, question.options[selectedOption]);
1967
+ } else if (input === "t" || input === "T") {
1968
+ setMode("freetext");
1969
+ } else if (input === "s" || input === "S") {
1970
+ onSkip(question.id);
1971
+ }
1972
+ } else if (mode === "freetext") {
1973
+ if (key.return && freeText.trim()) {
1974
+ onAnswer(question.id, freeText.trim());
1975
+ } else if (key.escape) {
1976
+ if (question.options && question.options.length > 0) {
1977
+ setMode("options");
1978
+ }
1979
+ } else if (key.backspace || key.delete) {
1980
+ setFreeText((prev) => prev.slice(0, -1));
1981
+ } else if (input && !key.ctrl && !key.meta) {
1982
+ setFreeText((prev) => prev + input);
1983
+ }
1984
+ }
1985
+ });
1986
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
1987
+ /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Text11, { bold: true, color: "yellow", children: [
1988
+ "Question from ",
1989
+ question.fromAgent
1990
+ ] }) }),
1991
+ /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text11, { children: question.question }) }),
1992
+ question.context && /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Text11, { dimColor: true, children: [
1993
+ "Context: ",
1994
+ question.context
1995
+ ] }) }),
1996
+ mode === "options" && question.options && /* @__PURE__ */ jsxs12(Fragment3, { children: [
1997
+ question.options.map((opt, i) => /* @__PURE__ */ jsx12(Box12, { paddingLeft: 1, children: /* @__PURE__ */ jsxs12(Text11, { color: i === selectedOption ? "cyan" : void 0, children: [
1998
+ i === selectedOption ? "> " : " ",
1999
+ opt
2000
+ ] }) }, i)),
2001
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "Up/Down to select, Enter to confirm, t for free text, s to skip" }) })
2002
+ ] }),
2003
+ mode === "freetext" && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, children: [
2004
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "> " }),
2005
+ /* @__PURE__ */ jsxs12(Text11, { children: [
2006
+ freeText,
2007
+ /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "_" })
2008
+ ] }),
2009
+ /* @__PURE__ */ jsx12(Box12, { marginLeft: 2, children: /* @__PURE__ */ jsxs12(Text11, { dimColor: true, children: [
2010
+ "Enter to submit",
2011
+ question.options ? ", Esc for options" : ""
2012
+ ] }) })
2013
+ ] })
2014
+ ] });
2015
+ }
2016
+
2017
+ // src/tui/components/ProgressSummary.tsx
2018
+ import { Box as Box13, Text as Text12, useInput as useInput5 } from "ink";
2019
+ import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
2020
+ function ProgressSummary({ report, milestone, onAcknowledge }) {
2021
+ useInput5((input) => {
2022
+ if (milestone && milestone.requiresAck && (input === "c" || input === "C" || input === " ")) {
2023
+ onAcknowledge(milestone.id);
2024
+ }
2025
+ });
2026
+ if (!report && !milestone) {
2027
+ return /* @__PURE__ */ jsx13(Box13, {});
2028
+ }
2029
+ const percent = report?.percentComplete ?? 0;
2030
+ const barWidth = 30;
2031
+ const filled = Math.round(percent / 100 * barWidth);
2032
+ const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
2033
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "single", borderColor: milestone ? "green" : "blue", paddingX: 1, children: [
2034
+ milestone && /* @__PURE__ */ jsxs13(Box13, { marginBottom: 1, children: [
2035
+ /* @__PURE__ */ jsx13(Text12, { bold: true, color: "green", children: milestone.name }),
2036
+ /* @__PURE__ */ jsx13(Text12, { children: " -- " }),
2037
+ /* @__PURE__ */ jsx13(Text12, { children: milestone.message })
2038
+ ] }),
2039
+ report && /* @__PURE__ */ jsxs13(Fragment4, { children: [
2040
+ /* @__PURE__ */ jsxs13(Box13, { children: [
2041
+ /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: "Phase: " }),
2042
+ /* @__PURE__ */ jsx13(Text12, { bold: true, children: report.phase }),
2043
+ /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: " | " }),
2044
+ /* @__PURE__ */ jsxs13(Text12, { children: [
2045
+ report.completedTasks,
2046
+ "/",
2047
+ report.totalTasks,
2048
+ " tasks"
2049
+ ] }),
2050
+ /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: " | " }),
2051
+ /* @__PURE__ */ jsxs13(Text12, { children: [
2052
+ "$",
2053
+ report.totalCostUsd.toFixed(4)
2054
+ ] })
2055
+ ] }),
2056
+ /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
2057
+ /* @__PURE__ */ jsx13(Text12, { color: "cyan", children: bar }),
2058
+ /* @__PURE__ */ jsxs13(Text12, { children: [
2059
+ " ",
2060
+ percent.toFixed(0),
2061
+ "%"
2062
+ ] })
2063
+ ] }),
2064
+ report.blockers.length > 0 && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
2065
+ /* @__PURE__ */ jsx13(Text12, { color: "red", bold: true, children: "Blockers:" }),
2066
+ report.blockers.map((b, i) => /* @__PURE__ */ jsxs13(Text12, { color: "red", children: [
2067
+ " * ",
2068
+ b
2069
+ ] }, i))
2070
+ ] })
2071
+ ] }),
2072
+ milestone && milestone.requiresAck && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text12, { dimColor: true, children: [
2073
+ "Press ",
2074
+ /* @__PURE__ */ jsx13(Text12, { bold: true, children: "c" }),
2075
+ " or ",
2076
+ /* @__PURE__ */ jsx13(Text12, { bold: true, children: "space" }),
2077
+ " to continue"
2078
+ ] }) })
2079
+ ] });
2080
+ }
2081
+
2082
+ // src/tui/App.tsx
2083
+ import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
2084
+ function formatDuration(ms) {
2085
+ const seconds = Math.floor(ms / 1e3);
2086
+ const minutes = Math.floor(seconds / 60);
2087
+ const hours = Math.floor(minutes / 60);
2088
+ if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
2089
+ if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
2090
+ return `${seconds}s`;
2091
+ }
2092
+ function useTerminalHeight() {
2093
+ const { stdout } = useStdout();
2094
+ const [height, setHeight] = React9.useState(stdout?.rows ?? 24);
2095
+ React9.useEffect(() => {
2096
+ if (!stdout) return;
2097
+ const onResize = () => setHeight(stdout.rows);
2098
+ stdout.on("resize", onResize);
2099
+ return () => {
2100
+ stdout.off("resize", onResize);
2101
+ };
2102
+ }, [stdout]);
2103
+ return height;
2104
+ }
2105
+ function App({ orchestrator, projectConfig }) {
2106
+ const { exit } = useApp();
2107
+ const termHeight = useTerminalHeight();
2108
+ const agents = useAgentPool(orchestrator);
2109
+ const tasks = useTaskManager(orchestrator);
2110
+ const orchestratorActivities = useOrchestratorActivity(orchestrator);
2111
+ const selectableCount = 1 + agents.length;
2112
+ const { selectedAgentIndex, selectedTaskIndex, viewMode, setSelectedAgentIndex, setSelectedTaskIndex, setViewMode } = useKeyboard(selectableCount, tasks.length);
2113
+ const feedback = useFeedback(orchestrator);
2114
+ const [totalCost, setTotalCost] = React9.useState(0);
2115
+ const [startTime] = React9.useState(Date.now());
2116
+ const [uptime, setUptime] = React9.useState(0);
2117
+ const [phase, setPhase] = React9.useState("planning");
2118
+ const [archReady, setArchReady] = React9.useState(null);
2119
+ const [completionSummary, setCompletionSummary] = React9.useState(null);
2120
+ const [isPaused, setIsPaused] = React9.useState(false);
2121
+ const [isDecomposing, setIsDecomposing] = React9.useState(false);
2122
+ const [quitConfirm, setQuitConfirm] = React9.useState(false);
2123
+ React9.useEffect(() => {
2124
+ const timer = setInterval(() => {
2125
+ setUptime(Date.now() - startTime);
2126
+ }, 5e3);
2127
+ return () => clearInterval(timer);
2128
+ }, [startTime]);
2129
+ React9.useEffect(() => {
2130
+ const handler = (stats) => {
2131
+ setTotalCost(stats.totalCostUsd);
2132
+ };
2133
+ orchestrator.on("orchestrator:cycle", handler);
2134
+ return () => {
2135
+ orchestrator.off("orchestrator:cycle", handler);
2136
+ };
2137
+ }, [orchestrator]);
2138
+ React9.useEffect(() => {
2139
+ const handlePhase = (p) => setPhase(p);
2140
+ const handleArchReady = (archTasks) => setArchReady(archTasks);
2141
+ const handleCompleted = (summary) => setCompletionSummary(summary);
2142
+ orchestrator.on("phase:changed", handlePhase);
2143
+ orchestrator.on("architecture:ready", handleArchReady);
2144
+ orchestrator.on("project:completed", handleCompleted);
2145
+ return () => {
2146
+ orchestrator.off("phase:changed", handlePhase);
2147
+ orchestrator.off("architecture:ready", handleArchReady);
2148
+ orchestrator.off("project:completed", handleCompleted);
2149
+ };
2150
+ }, [orchestrator]);
2151
+ React9.useEffect(() => {
2152
+ const handlePaused = () => setIsPaused(true);
2153
+ const handleResumed = () => setIsPaused(false);
2154
+ orchestrator.on("orchestrator:paused", handlePaused);
2155
+ orchestrator.on("orchestrator:resumed", handleResumed);
2156
+ return () => {
2157
+ orchestrator.off("orchestrator:paused", handlePaused);
2158
+ orchestrator.off("orchestrator:resumed", handleResumed);
2159
+ };
2160
+ }, [orchestrator]);
2161
+ const handlePause = React9.useCallback(() => {
2162
+ orchestrator.pause();
2163
+ }, [orchestrator]);
2164
+ const handleResume = React9.useCallback(() => {
2165
+ orchestrator.resume();
2166
+ }, [orchestrator]);
2167
+ const handleSubmitInstructions = React9.useCallback((instructions) => {
2168
+ setIsDecomposing(true);
2169
+ orchestrator.addInstructions(instructions).catch(() => {
2170
+ }).finally(() => {
2171
+ setIsDecomposing(false);
2172
+ });
2173
+ }, [orchestrator]);
2174
+ useInput6((input, key) => {
2175
+ if (quitConfirm) {
2176
+ if (input === "y" || input === "Y") {
2177
+ const forceExit = setTimeout(() => exit(), 15e3);
2178
+ orchestrator.stop().then(() => {
2179
+ clearTimeout(forceExit);
2180
+ exit();
2181
+ }).catch(() => exit());
2182
+ } else {
2183
+ setQuitConfirm(false);
2184
+ }
2185
+ return;
2186
+ }
2187
+ if (viewMode === "instructions") {
2188
+ return;
2189
+ }
2190
+ if (input === "q") {
2191
+ setQuitConfirm(true);
2192
+ return;
2193
+ }
2194
+ if (input === "p" && viewMode !== "agent-detail" && viewMode !== "task-detail") {
2195
+ if (isPaused) {
2196
+ handleResume();
2197
+ } else {
2198
+ handlePause();
2199
+ }
2200
+ }
2201
+ if (input === "a" && archReady && viewMode !== "agent-detail" && viewMode !== "task-detail") {
2202
+ orchestrator.approveArchitecture();
2203
+ setArchReady(null);
2204
+ }
2205
+ });
2206
+ const completedTasks = tasks.filter((t) => t.status === "done").length;
2207
+ const logsDir = path2.resolve(projectConfig.settings.workingDirectory, projectConfig.settings.logsDirectory);
2208
+ let overlayLines = 0;
2209
+ if (completionSummary) {
2210
+ const activeAgentCount = completionSummary.agentSummaries.filter((a) => a.tasksCompleted > 0).length;
2211
+ overlayLines += 18 + activeAgentCount;
2212
+ }
2213
+ if (archReady && !completionSummary) overlayLines += 4 + archReady.length;
2214
+ if (feedback.pendingPlan) overlayLines += 12;
2215
+ if (feedback.questions.length > 0 && !feedback.pendingPlan) overlayLines += 6;
2216
+ if (feedback.milestone && !feedback.pendingPlan && feedback.questions.length === 0) overlayLines += 6;
2217
+ const chromeHeight = 6 + overlayLines;
2218
+ const dashboardHeight = Math.max(8, termHeight - chromeHeight);
2219
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", width: "100%", height: termHeight, children: [
2220
+ completionSummary && (() => {
2221
+ const totalTokens = completionSummary.totalInputTokens + completionSummary.totalOutputTokens + completionSummary.totalCacheReadTokens + completionSummary.totalCacheCreationTokens;
2222
+ const activeAgents = completionSummary.agentSummaries.filter((a) => a.tasksCompleted > 0);
2223
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, paddingX: 2, borderStyle: "bold", borderColor: "green", children: [
2224
+ /* @__PURE__ */ jsxs14(Text13, { bold: true, color: "green", children: [
2225
+ "\u2605",
2226
+ " PROJECT COMPLETED ",
2227
+ "\u2605"
2228
+ ] }),
2229
+ /* @__PURE__ */ jsx14(Text13, { children: " " }),
2230
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "Tasks" }),
2231
+ /* @__PURE__ */ jsxs14(Text13, { children: [
2232
+ " Completed: ",
2233
+ /* @__PURE__ */ jsx14(Text13, { color: "green", children: completionSummary.doneTasks }),
2234
+ " / ",
2235
+ completionSummary.totalTasks
2236
+ ] }),
2237
+ completionSummary.cancelledTasks > 0 && /* @__PURE__ */ jsxs14(Text13, { children: [
2238
+ " Cancelled: ",
2239
+ /* @__PURE__ */ jsx14(Text13, { color: "yellow", children: completionSummary.cancelledTasks })
2240
+ ] }),
2241
+ /* @__PURE__ */ jsx14(Text13, { children: " " }),
2242
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "Usage" }),
2243
+ /* @__PURE__ */ jsxs14(Text13, { children: [
2244
+ " Cost: ",
2245
+ /* @__PURE__ */ jsxs14(Text13, { color: "cyan", children: [
2246
+ "$",
2247
+ completionSummary.totalCostUsd.toFixed(4)
2248
+ ] })
2249
+ ] }),
2250
+ totalTokens > 0 && /* @__PURE__ */ jsxs14(Fragment5, { children: [
2251
+ /* @__PURE__ */ jsxs14(Text13, { children: [
2252
+ " Tokens: ",
2253
+ totalTokens.toLocaleString(),
2254
+ " total"
2255
+ ] }),
2256
+ /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2257
+ " in: ",
2258
+ completionSummary.totalInputTokens.toLocaleString(),
2259
+ " | out: ",
2260
+ completionSummary.totalOutputTokens.toLocaleString(),
2261
+ " | cache-r: ",
2262
+ completionSummary.totalCacheReadTokens.toLocaleString(),
2263
+ " | cache-w: ",
2264
+ completionSummary.totalCacheCreationTokens.toLocaleString()
2265
+ ] })
2266
+ ] }),
2267
+ /* @__PURE__ */ jsxs14(Text13, { children: [
2268
+ " Duration: ",
2269
+ formatDuration(completionSummary.uptimeMs)
2270
+ ] }),
2271
+ activeAgents.length > 0 && /* @__PURE__ */ jsxs14(Fragment5, { children: [
2272
+ /* @__PURE__ */ jsx14(Text13, { children: " " }),
2273
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "Agent Breakdown" }),
2274
+ activeAgents.map((a) => {
2275
+ const agentTokens2 = a.inputTokens + a.outputTokens;
2276
+ const tokenInfo = agentTokens2 > 0 ? `, ${agentTokens2.toLocaleString()} tokens` : "";
2277
+ return /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2278
+ " ",
2279
+ a.name,
2280
+ " (",
2281
+ a.role,
2282
+ "): ",
2283
+ a.tasksCompleted,
2284
+ " tasks, $",
2285
+ a.costUsd.toFixed(4),
2286
+ tokenInfo
2287
+ ] }, a.agentId);
2288
+ })
2289
+ ] }),
2290
+ /* @__PURE__ */ jsx14(Text13, { children: " " }),
2291
+ /* @__PURE__ */ jsx14(Text13, { bold: true, children: "Next Steps" }),
2292
+ /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2293
+ " ",
2294
+ "\u2192",
2295
+ " Review the completed work in your project directory"
2296
+ ] }),
2297
+ /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2298
+ " ",
2299
+ "\u2192",
2300
+ " Run your test suite to verify the changes"
2301
+ ] }),
2302
+ /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2303
+ " ",
2304
+ "\u2192",
2305
+ " Check git diff to review all modifications"
2306
+ ] }),
2307
+ /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2308
+ " ",
2309
+ "\u2192",
2310
+ " Commit and push when ready"
2311
+ ] })
2312
+ ] });
2313
+ })(),
2314
+ archReady && !completionSummary && /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, paddingX: 2, borderStyle: "round", borderColor: "cyan", children: [
2315
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: "cyan", children: "Architecture Phase Complete" }),
2316
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "Review ARCHITECTURE.md and architecture-related files." }),
2317
+ archReady.map((t) => /* @__PURE__ */ jsxs14(Text13, { dimColor: true, children: [
2318
+ " - ",
2319
+ t.title
2320
+ ] }, t.id)),
2321
+ /* @__PURE__ */ jsx14(Text13, { color: "yellow", children: "Press 'a' to approve and advance to development" })
2322
+ ] }),
2323
+ feedback.pendingPlan && /* @__PURE__ */ jsx14(
2324
+ PlanReview,
2325
+ {
2326
+ proposal: feedback.pendingPlan,
2327
+ onDecide: feedback.decidePlan
2328
+ }
2329
+ ),
2330
+ feedback.questions.length > 0 && !feedback.pendingPlan && /* @__PURE__ */ jsx14(
2331
+ QuestionPrompt,
2332
+ {
2333
+ question: feedback.questions[0],
2334
+ onAnswer: feedback.answerQuestion,
2335
+ onSkip: (qId) => feedback.answerQuestion(qId, "")
2336
+ }
2337
+ ),
2338
+ feedback.milestone && !feedback.pendingPlan && feedback.questions.length === 0 && /* @__PURE__ */ jsx14(
2339
+ ProgressSummary,
2340
+ {
2341
+ report: feedback.latestReport,
2342
+ milestone: feedback.milestone,
2343
+ onAcknowledge: feedback.acknowledgeMilestone
2344
+ }
2345
+ ),
2346
+ /* @__PURE__ */ jsx14(
2347
+ Header,
2348
+ {
2349
+ projectName: projectConfig.name,
2350
+ completedTasks,
2351
+ totalTasks: tasks.length,
2352
+ totalCost,
2353
+ uptimeMs: uptime
2354
+ }
2355
+ ),
2356
+ /* @__PURE__ */ jsx14(Box14, { height: dashboardHeight, children: /* @__PURE__ */ jsx14(
2357
+ Dashboard,
2358
+ {
2359
+ agents,
2360
+ tasks,
2361
+ selectedAgentIndex,
2362
+ selectedTaskIndex,
2363
+ viewMode,
2364
+ onSelectAgent: setSelectedAgentIndex,
2365
+ orchestratorActivities,
2366
+ orchestrator,
2367
+ phase,
2368
+ logsDir,
2369
+ isPaused,
2370
+ isDecomposing,
2371
+ onSubmitInstructions: handleSubmitInstructions,
2372
+ onPause: handlePause,
2373
+ onResume: handleResume
2374
+ }
2375
+ ) }),
2376
+ quitConfirm && /* @__PURE__ */ jsxs14(Box14, { paddingX: 1, justifyContent: "center", children: [
2377
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: "yellow", children: "Quit Maestro? " }),
2378
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: "white", children: "y" }),
2379
+ /* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "/" }),
2380
+ /* @__PURE__ */ jsx14(Text13, { bold: true, color: "white", children: "n" })
2381
+ ] }),
2382
+ /* @__PURE__ */ jsx14(StatusBar, { viewMode, onChangeView: setViewMode, isPaused })
2383
+ ] });
2384
+ }
2385
+ function renderApp(orchestrator, projectConfig) {
2386
+ render(
2387
+ /* @__PURE__ */ jsx14(App, { orchestrator, projectConfig })
2388
+ );
2389
+ }
2390
+ export {
2391
+ renderApp
2392
+ };
2393
+ //# sourceMappingURL=App.js.map