@oxgeneral/orch 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App-TW35IULR.js +18 -0
- package/dist/agent-FRQKL7YI.js +9 -0
- package/dist/{orchestrator-VGYKSOZJ.js → chunk-2UC4SVJB.js} +236 -71
- package/dist/chunk-2UC4SVJB.js.map +1 -0
- package/dist/chunk-5AJ4LYO5.js +8 -0
- package/dist/{chunk-45K2XID7.js → chunk-6DWHQPTE.js} +2 -1
- package/dist/chunk-6DWHQPTE.js.map +1 -0
- package/dist/{chunk-POUC4CPC.js → chunk-6MJ7V6VY.js} +2 -2
- package/dist/{chunk-HNKJ4IF7.js → chunk-B4JQM4NU.js} +34 -10
- package/dist/chunk-B4JQM4NU.js.map +1 -0
- package/dist/{chunk-6HENRUYZ.js → chunk-CDFA4IIQ.js} +2 -2
- package/dist/chunk-CHRW4CLD.js +2 -0
- package/dist/{chunk-ZU6AY2VU.js → chunk-GZ2Q56YZ.js} +2 -2
- package/dist/chunk-HMMPM7MF.js +3 -0
- package/dist/{chunk-AELEEEV3.js → chunk-HSBYJ5C5.js} +27 -7
- package/dist/chunk-HXOMNULD.js +2 -0
- package/dist/{chunk-O5AO5QIR.js → chunk-IQXRQBUK.js} +9 -2
- package/dist/chunk-IQXRQBUK.js.map +1 -0
- package/dist/chunk-L26TK7Y5.js +2 -0
- package/dist/chunk-L3FYR45M.js +2 -0
- package/dist/chunk-LXNRCJ22.js +2 -0
- package/dist/{chunk-TX7WOFCW.js → chunk-MGFMVPRD.js} +4 -7
- package/dist/chunk-MGFMVPRD.js.map +1 -0
- package/dist/chunk-MNXU3KCD.js +2 -0
- package/dist/{chunk-CHIP7O6V.js → chunk-O2MSGW3V.js} +3 -1
- package/dist/chunk-O2MSGW3V.js.map +1 -0
- package/dist/chunk-PJ5DKXGR.js +2 -0
- package/dist/{chunk-VTA74YWX.js → chunk-QEEM67OA.js} +11 -17
- package/dist/chunk-QEEM67OA.js.map +1 -0
- package/dist/chunk-UMZEA3JT.js +5 -0
- package/dist/{shell-OGTSH4RJ.js → chunk-UW6GUUE6.js} +3 -3
- package/dist/chunk-XDVMX2FO.js +8 -0
- package/dist/chunk-XDVMX2FO.js.map +1 -0
- package/dist/chunk-ZA5Z33GO.js +11 -0
- package/dist/claude-E36EGXUV.js +2 -0
- package/dist/{chunk-IRN2U2NE.js → claude-RIB3RQS5.js} +5 -2
- package/dist/claude-RIB3RQS5.js.map +1 -0
- package/dist/cli.js +1 -199
- package/dist/clipboard-service-PDTSZIR5.js +25 -0
- package/dist/codex-OTZKVESD.js +2 -0
- package/dist/{codex-U7LTJTX6.js → codex-VBUSA2GJ.js} +5 -3
- package/dist/codex-VBUSA2GJ.js.map +1 -0
- package/dist/config-CCSS2P7R.js +2 -0
- package/dist/container-OIXLFSX2.js +6 -0
- package/dist/context-GSMQHQES.js +7 -0
- package/dist/cursor-3DJA6LWS.js +2 -0
- package/dist/{cursor-3DI5GKRF.js → cursor-4QIOTDBW.js} +5 -3
- package/dist/cursor-4QIOTDBW.js.map +1 -0
- package/dist/doctor-KBK5JZBZ.js +2 -0
- package/dist/doctor-service-F2SXDWHS.js +91 -0
- package/dist/doctor-service-F2SXDWHS.js.map +1 -0
- package/dist/doctor-service-PB7YBH3F.js +2 -0
- package/dist/goal-RFKFPR7M.js +8 -0
- package/dist/index.d.ts +124 -46
- package/dist/index.js +1817 -5
- package/dist/index.js.map +1 -1
- package/dist/init-WRDFAFS2.js +53 -0
- package/dist/logs-5QHJWMEG.js +12 -0
- package/dist/msg-4SCLBO4K.js +9 -0
- package/dist/orchestrator-FGGXK3N3.js +5 -0
- package/dist/{orchestrator-TAFBYQQ5.js.map → orchestrator-FGGXK3N3.js.map} +1 -1
- package/dist/orchestrator-R7IWZUT6.js +13 -0
- package/dist/process-manager-33H27MQF.js +2 -0
- package/dist/process-manager-A36Y7LHP.js +3 -0
- package/dist/{process-manager-TLZOTO4Y.js.map → process-manager-A36Y7LHP.js.map} +1 -1
- package/dist/registry-BO2PPRNG.js +2 -0
- package/dist/registry-JXXRLJ5J.js +3 -0
- package/dist/{registry-UQAHK77P.js.map → registry-JXXRLJ5J.js.map} +1 -1
- package/dist/run-HSHRELOP.js +3 -0
- package/dist/shell-EOJBDWTH.js +2 -0
- package/dist/{chunk-CIIE6LNG.js → shell-IH2MMTVP.js} +3 -2
- package/dist/shell-IH2MMTVP.js.map +1 -0
- package/dist/status-DLBNWSWM.js +2 -0
- package/dist/task-J6ZN7ALI.js +20 -0
- package/dist/team-MSIBKOQC.js +4 -0
- package/dist/template-engine-MFL5B677.js +3 -0
- package/dist/{template-engine-322SCRR6.js.map → template-engine-MFL5B677.js.map} +1 -1
- package/dist/template-engine-ONIDVD4F.js +2 -0
- package/dist/tui-G4XUFAIP.js +2 -0
- package/dist/update-PC2ENCKU.js +2 -0
- package/dist/update-check-HGMBDYHL.js +2 -0
- package/dist/workspace-manager-KOOYTO7E.js +3 -0
- package/dist/{workspace-manager-47KI7B27.js → workspace-manager-T6AXG7XL.js} +40 -3
- package/dist/workspace-manager-T6AXG7XL.js.map +1 -0
- package/package.json +2 -1
- package/readme.md +5 -4
- package/scripts/benchmark.ts +304 -0
- package/dist/App-KDZSTAMR.js +0 -4864
- package/dist/agent-V5M2C3OC.js +0 -157
- package/dist/chunk-2B32FPEB.js +0 -11
- package/dist/chunk-2B32FPEB.js.map +0 -1
- package/dist/chunk-33QNTNR6.js +0 -46
- package/dist/chunk-6GFVB6EK.js +0 -101
- package/dist/chunk-6HENRUYZ.js.map +0 -1
- package/dist/chunk-AELEEEV3.js.map +0 -1
- package/dist/chunk-E3TCKHU6.js +0 -13
- package/dist/chunk-E3TCKHU6.js.map +0 -1
- package/dist/chunk-ED47GL3F.js +0 -29
- package/dist/chunk-HXYAZGLP.js +0 -15
- package/dist/chunk-I5WEMARW.js +0 -166
- package/dist/chunk-IZYSGYXG.js +0 -2
- package/dist/chunk-IZYSGYXG.js.map +0 -1
- package/dist/chunk-P6ATSXGL.js +0 -107
- package/dist/chunk-PBFE5V3G.js +0 -2
- package/dist/chunk-PBFE5V3G.js.map +0 -1
- package/dist/chunk-PNE6LQRF.js +0 -5
- package/dist/chunk-POUC4CPC.js.map +0 -1
- package/dist/chunk-XI4TU6VU.js +0 -50
- package/dist/chunk-ZU6AY2VU.js.map +0 -1
- package/dist/claude-GH6P2DC5.js +0 -4
- package/dist/claude-S47YTIHU.js +0 -2
- package/dist/claude-S47YTIHU.js.map +0 -1
- package/dist/codex-2CH57B7G.js +0 -2
- package/dist/codex-2CH57B7G.js.map +0 -1
- package/dist/config-LJFM55LN.js +0 -75
- package/dist/container-JV7TAUP5.js +0 -1532
- package/dist/context-EPSDCJTU.js +0 -83
- package/dist/cursor-QFUNKPCQ.js +0 -2
- package/dist/cursor-QFUNKPCQ.js.map +0 -1
- package/dist/doctor-IO4PV4D6.js +0 -67
- package/dist/doctor-service-A34DHPKI.js +0 -2
- package/dist/doctor-service-NTWBWOM2.js +0 -2
- package/dist/doctor-service-NTWBWOM2.js.map +0 -1
- package/dist/goal-I56QP7HS.js +0 -110
- package/dist/init-BE5VKWOM.js +0 -149
- package/dist/logs-IAUAS5TX.js +0 -207
- package/dist/msg-SQWQLJP6.js +0 -95
- package/dist/orchestrator-TAFBYQQ5.js +0 -2
- package/dist/process-manager-HUVNAPQV.js +0 -2
- package/dist/process-manager-TLZOTO4Y.js +0 -2
- package/dist/registry-PQWRVNF2.js +0 -2
- package/dist/registry-UQAHK77P.js +0 -2
- package/dist/run-PSZURVVL.js +0 -95
- package/dist/shell-5ZNXFGXV.js +0 -3
- package/dist/shell-OGTSH4RJ.js.map +0 -1
- package/dist/status-DTF7D3DV.js +0 -56
- package/dist/task-5OJTXW27.js +0 -209
- package/dist/team-AISPLEJB.js +0 -97
- package/dist/template-engine-322SCRR6.js +0 -2
- package/dist/template-engine-3CDRZNMJ.js +0 -3
- package/dist/tui-XDJE3IUA.js +0 -225
- package/dist/update-72GZMF65.js +0 -64
- package/dist/update-check-4RV7Z6WT.js +0 -2
- package/dist/workspace-manager-7M46ESUL.js +0 -2
- package/dist/workspace-manager-7M46ESUL.js.map +0 -1
package/dist/App-KDZSTAMR.js
DELETED
|
@@ -1,4864 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { DEFAULT_CONFIG } from './chunk-ED47GL3F.js';
|
|
3
|
-
import { GOAL_STATUS_ORDER } from './chunk-HXYAZGLP.js';
|
|
4
|
-
import { formatDuration, formatDurationSince } from './chunk-I5WEMARW.js';
|
|
5
|
-
import React5, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
6
|
-
import { Box, Text, useApp, useStdout, useInput } from 'ink';
|
|
7
|
-
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
8
|
-
|
|
9
|
-
// src/tui/colors.ts
|
|
10
|
-
var tuiColors = {
|
|
11
|
-
// Brand
|
|
12
|
-
amber: "#ffaf00",
|
|
13
|
-
// ansi256(214) — logo, selected cursor, accents
|
|
14
|
-
amberDim: "#af8700",
|
|
15
|
-
// ansi256(136) — amber at reduced intensity
|
|
16
|
-
// Semantic
|
|
17
|
-
green: "#5faf87",
|
|
18
|
-
// ansi256(72) — running, success, active
|
|
19
|
-
red: "#d75f5f",
|
|
20
|
-
// ansi256(167) — failed, P1, errors
|
|
21
|
-
blue: "#5fafd7",
|
|
22
|
-
// ansi256(74) — review, info
|
|
23
|
-
yellow: "#d7af00",
|
|
24
|
-
// ansi256(178) — retrying, P2, warning
|
|
25
|
-
cyan: "#5fd7d7",
|
|
26
|
-
// ansi256(80) — timestamps, metadata
|
|
27
|
-
purple: "#af87ff",
|
|
28
|
-
// ansi256(141) — file paths, labels
|
|
29
|
-
// Neutrals (high → low intensity)
|
|
30
|
-
white: "#eeeeee",
|
|
31
|
-
// ansi256(255) — primary text
|
|
32
|
-
silver: "#bcbcbc",
|
|
33
|
-
// ansi256(250) — secondary text
|
|
34
|
-
gray: "#808080",
|
|
35
|
-
// ansi256(244) — tertiary text
|
|
36
|
-
dim: "#585858",
|
|
37
|
-
// ansi256(240) — subtle text, deemphasized
|
|
38
|
-
ghost: "#3a3a3a",
|
|
39
|
-
// ansi256(237) — rules, separators
|
|
40
|
-
void: "#262626",
|
|
41
|
-
// ansi256(235) — deepest background elements
|
|
42
|
-
// Semantic backgrounds (for log highlights)
|
|
43
|
-
errorBg: "#3d1515",
|
|
44
|
-
// deep red background for errors
|
|
45
|
-
warnBg: "#3d2e0a",
|
|
46
|
-
// deep amber background for warnings
|
|
47
|
-
successBg: "#0f2d1f",
|
|
48
|
-
// deep green background for success
|
|
49
|
-
infoBg: "#1a1a22"};
|
|
50
|
-
var HEAVY_RULE = "\u2501";
|
|
51
|
-
var LIGHT_RULE = "\u2500";
|
|
52
|
-
var DOT = "\xB7";
|
|
53
|
-
var LOZENGE = "\u25C8";
|
|
54
|
-
var STAR = "\u2605";
|
|
55
|
-
var LOOP = "\u27F3";
|
|
56
|
-
var DIAMOND = "\u25C6";
|
|
57
|
-
var TICK_INTERVAL = 120;
|
|
58
|
-
var globalTick = 0;
|
|
59
|
-
var timer = null;
|
|
60
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
61
|
-
function startGlobal() {
|
|
62
|
-
if (timer) return;
|
|
63
|
-
timer = setInterval(() => {
|
|
64
|
-
globalTick++;
|
|
65
|
-
for (const fn of listeners) fn(globalTick);
|
|
66
|
-
}, TICK_INTERVAL);
|
|
67
|
-
}
|
|
68
|
-
function stopGlobal() {
|
|
69
|
-
if (timer && listeners.size === 0) {
|
|
70
|
-
clearInterval(timer);
|
|
71
|
-
timer = null;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function useAnimTick() {
|
|
75
|
-
const [tick, setTick] = useState(globalTick);
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
const listener = (t) => setTick(t);
|
|
78
|
-
listeners.add(listener);
|
|
79
|
-
startGlobal();
|
|
80
|
-
return () => {
|
|
81
|
-
listeners.delete(listener);
|
|
82
|
-
stopGlobal();
|
|
83
|
-
};
|
|
84
|
-
}, []);
|
|
85
|
-
return tick;
|
|
86
|
-
}
|
|
87
|
-
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
88
|
-
function Spinner({ color }) {
|
|
89
|
-
const tick = useAnimTick();
|
|
90
|
-
return /* @__PURE__ */ jsx(Text, { color, children: FRAMES[tick % FRAMES.length] });
|
|
91
|
-
}
|
|
92
|
-
var STATUS_ORDER = {
|
|
93
|
-
in_progress: 0,
|
|
94
|
-
retrying: 1,
|
|
95
|
-
review: 2,
|
|
96
|
-
todo: 3,
|
|
97
|
-
done: 4,
|
|
98
|
-
failed: 5,
|
|
99
|
-
cancelled: 6
|
|
100
|
-
};
|
|
101
|
-
var EMPTY_CIRCLE = "\u25CB";
|
|
102
|
-
var CHECK = "\u2713";
|
|
103
|
-
var CROSS = "\u2715";
|
|
104
|
-
var RETRY = "\u21BB";
|
|
105
|
-
var DASH = "\u2500";
|
|
106
|
-
var TRIANGLE = "\u25B6";
|
|
107
|
-
var chipBg = {
|
|
108
|
-
green: "#0f2d1f",
|
|
109
|
-
blue: "#0f1f2d",
|
|
110
|
-
yellow: "#2d2a0f",
|
|
111
|
-
red: "#2d0f0f",
|
|
112
|
-
neutral: "#1a1a22"};
|
|
113
|
-
var STATUS_CHIP = {
|
|
114
|
-
in_progress: { icon: TRIANGLE, label: "RUN", fg: tuiColors.green, bg: chipBg.green, bold: true, spinner: true },
|
|
115
|
-
retrying: { icon: RETRY, label: "RETRY", fg: tuiColors.yellow, bg: chipBg.yellow, spinner: true },
|
|
116
|
-
review: { icon: LOZENGE, label: "REVIEW", fg: tuiColors.blue, bg: chipBg.blue },
|
|
117
|
-
todo: { icon: EMPTY_CIRCLE, label: "TODO", fg: tuiColors.dim, bg: chipBg.neutral },
|
|
118
|
-
done: { icon: CHECK, label: "DONE", fg: tuiColors.green, bg: chipBg.green },
|
|
119
|
-
failed: { icon: CROSS, label: "FAIL", fg: tuiColors.red, bg: chipBg.red, bold: true },
|
|
120
|
-
cancelled: { icon: DASH, label: "OFF", fg: tuiColors.dim, bg: chipBg.neutral }
|
|
121
|
-
};
|
|
122
|
-
var PRIORITY_CONFIG = {
|
|
123
|
-
1: { color: tuiColors.red, label: "!!!" },
|
|
124
|
-
2: { color: tuiColors.yellow, label: "!!" },
|
|
125
|
-
3: { color: tuiColors.dim, label: "!" },
|
|
126
|
-
4: { color: tuiColors.ghost, label: DOT }
|
|
127
|
-
};
|
|
128
|
-
var TaskRow = React5.memo(function TaskRow2({ task, selected, width, agentNameMap }) {
|
|
129
|
-
const chip = STATUS_CHIP[task.status];
|
|
130
|
-
const isRunning = task.status === "in_progress" || task.status === "retrying";
|
|
131
|
-
const priConf = PRIORITY_CONFIG[task.priority] ?? { color: tuiColors.ghost, label: DOT };
|
|
132
|
-
let timeStr;
|
|
133
|
-
let timeColor;
|
|
134
|
-
if (task.status === "done") {
|
|
135
|
-
timeStr = CHECK;
|
|
136
|
-
timeColor = tuiColors.green;
|
|
137
|
-
} else if (task.status === "failed") {
|
|
138
|
-
timeStr = CROSS;
|
|
139
|
-
timeColor = tuiColors.red;
|
|
140
|
-
} else if (isRunning) {
|
|
141
|
-
const ms = Date.now() - new Date(task.updated_at).getTime();
|
|
142
|
-
timeStr = formatDuration(ms);
|
|
143
|
-
timeColor = tuiColors.cyan;
|
|
144
|
-
} else {
|
|
145
|
-
timeStr = "\u2014";
|
|
146
|
-
timeColor = void 0;
|
|
147
|
-
}
|
|
148
|
-
const cursor = selected ? "\u25B8" : " ";
|
|
149
|
-
const chipWidth = 10;
|
|
150
|
-
const priWidth = 4;
|
|
151
|
-
const assigneeWidth = 14;
|
|
152
|
-
const timeWidth = 7;
|
|
153
|
-
const fixedCols = 2 + chipWidth + priWidth + assigneeWidth + timeWidth;
|
|
154
|
-
const titleWidth = width ? Math.max(10, width - fixedCols) : 40;
|
|
155
|
-
const assigneeName = task.assignee ? agentNameMap?.get(task.assignee) ?? task.assignee : void 0;
|
|
156
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
157
|
-
/* @__PURE__ */ jsxs(Text, { color: selected ? tuiColors.amber : void 0, children: [
|
|
158
|
-
cursor,
|
|
159
|
-
" "
|
|
160
|
-
] }),
|
|
161
|
-
/* @__PURE__ */ jsx(Box, { width: chipWidth, children: /* @__PURE__ */ jsx(Text, { backgroundColor: chip.bg, color: chip.fg, bold: chip.bold, children: chip.spinner ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
162
|
-
" ",
|
|
163
|
-
/* @__PURE__ */ jsx(Spinner, { color: chip.fg }),
|
|
164
|
-
" ",
|
|
165
|
-
chip.label,
|
|
166
|
-
" "
|
|
167
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
168
|
-
" ",
|
|
169
|
-
chip.icon,
|
|
170
|
-
" ",
|
|
171
|
-
chip.label,
|
|
172
|
-
" "
|
|
173
|
-
] }) }) }),
|
|
174
|
-
/* @__PURE__ */ jsx(Box, { width: priWidth, children: /* @__PURE__ */ jsx(Text, { color: priConf.color, bold: task.priority <= 2, children: priConf.label }) }),
|
|
175
|
-
/* @__PURE__ */ jsx(Box, { width: titleWidth, children: /* @__PURE__ */ jsx(
|
|
176
|
-
Text,
|
|
177
|
-
{
|
|
178
|
-
wrap: "truncate",
|
|
179
|
-
bold: selected || isRunning,
|
|
180
|
-
color: selected ? tuiColors.white : isRunning ? tuiColors.silver : void 0,
|
|
181
|
-
children: task.title.length > titleWidth ? task.title.slice(0, titleWidth - 1) + "\u2026" : task.title
|
|
182
|
-
}
|
|
183
|
-
) }),
|
|
184
|
-
/* @__PURE__ */ jsx(Box, { width: assigneeWidth, children: assigneeName ? /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg.green, color: tuiColors.green, wrap: "truncate", children: [
|
|
185
|
-
" ",
|
|
186
|
-
assigneeName.length > assigneeWidth - 2 ? assigneeName.slice(0, assigneeWidth - 3) + "\u2026" : assigneeName,
|
|
187
|
-
" "
|
|
188
|
-
] }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2014" }) }),
|
|
189
|
-
/* @__PURE__ */ jsx(Box, { width: timeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { color: timeColor, dimColor: !timeColor, children: timeStr }) })
|
|
190
|
-
] });
|
|
191
|
-
});
|
|
192
|
-
var CROSS2 = "\u2715";
|
|
193
|
-
var EMPTY_CIRCLE2 = "\u25CB";
|
|
194
|
-
var TRIANGLE2 = "\u25B6";
|
|
195
|
-
var CHECK2 = "\u2713";
|
|
196
|
-
var chipBg2 = {
|
|
197
|
-
green: "#0f2d1f",
|
|
198
|
-
red: "#2d0f0f",
|
|
199
|
-
neutral: "#1a1a22",
|
|
200
|
-
amber: "#2d1f0a"
|
|
201
|
-
};
|
|
202
|
-
var STATUS_CHIP2 = {
|
|
203
|
-
running: { icon: TRIANGLE2, label: "ACTIVE", fg: tuiColors.green, bg: chipBg2.green, bold: true, spinner: true },
|
|
204
|
-
idle: { icon: EMPTY_CIRCLE2, label: "IDLE", fg: tuiColors.dim, bg: chipBg2.neutral },
|
|
205
|
-
error: { icon: CROSS2, label: "ERROR", fg: tuiColors.red, bg: chipBg2.red, bold: true },
|
|
206
|
-
disabled: { icon: EMPTY_CIRCLE2, label: "OFF", fg: tuiColors.ghost, bg: chipBg2.neutral }
|
|
207
|
-
};
|
|
208
|
-
var AGENT_STATUS_ORDER = {
|
|
209
|
-
running: 0,
|
|
210
|
-
idle: 1,
|
|
211
|
-
error: 2,
|
|
212
|
-
disabled: 3
|
|
213
|
-
};
|
|
214
|
-
var AgentRow = React5.memo(function AgentRow2({ agent, selected, width, runningEntry, currentTaskTitle, teamName, isLead }) {
|
|
215
|
-
const chip = STATUS_CHIP2[agent.status];
|
|
216
|
-
const isRunning = agent.status === "running";
|
|
217
|
-
let timeStr;
|
|
218
|
-
let timeColor;
|
|
219
|
-
if (isRunning && runningEntry) {
|
|
220
|
-
const ms = Date.now() - new Date(runningEntry.started_at).getTime();
|
|
221
|
-
timeStr = formatDuration(ms);
|
|
222
|
-
timeColor = tuiColors.cyan;
|
|
223
|
-
} else if (agent.stats.total_runs > 0) {
|
|
224
|
-
timeStr = `${agent.stats.tasks_completed}/${agent.stats.total_runs}`;
|
|
225
|
-
timeColor = agent.stats.tasks_completed > 0 ? tuiColors.green : tuiColors.dim;
|
|
226
|
-
} else {
|
|
227
|
-
timeStr = "\u2014";
|
|
228
|
-
timeColor = void 0;
|
|
229
|
-
}
|
|
230
|
-
const cursor = selected ? "\u25B8" : " ";
|
|
231
|
-
const chipWidth = 11;
|
|
232
|
-
const adapterWidth = 10;
|
|
233
|
-
const teamColWidth = teamName ? Math.min(teamName.length + 2, 14) : 0;
|
|
234
|
-
const roleWidth = Math.max(6, 22 - teamColWidth);
|
|
235
|
-
const timeWidth = 7;
|
|
236
|
-
const fixedCols = 2 + chipWidth + adapterWidth + teamColWidth + roleWidth + timeWidth;
|
|
237
|
-
const nameWidth = width ? Math.max(8, width - fixedCols) : 20;
|
|
238
|
-
let roleText;
|
|
239
|
-
let roleColor;
|
|
240
|
-
let roleBold = false;
|
|
241
|
-
if (isRunning && currentTaskTitle) {
|
|
242
|
-
roleText = currentTaskTitle;
|
|
243
|
-
roleColor = tuiColors.white;
|
|
244
|
-
roleBold = true;
|
|
245
|
-
} else if (agent.role) {
|
|
246
|
-
roleText = agent.role;
|
|
247
|
-
roleColor = tuiColors.dim;
|
|
248
|
-
} else {
|
|
249
|
-
roleText = "\u2014";
|
|
250
|
-
roleColor = tuiColors.ghost;
|
|
251
|
-
}
|
|
252
|
-
const hasHistory = agent.stats.total_runs > 0;
|
|
253
|
-
const successRate = hasHistory ? Math.round(agent.stats.tasks_completed / agent.stats.total_runs * 100) : 0;
|
|
254
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
255
|
-
/* @__PURE__ */ jsxs(Text, { color: selected ? tuiColors.amber : void 0, children: [
|
|
256
|
-
cursor,
|
|
257
|
-
" "
|
|
258
|
-
] }),
|
|
259
|
-
/* @__PURE__ */ jsx(Box, { width: chipWidth, children: /* @__PURE__ */ jsx(Text, { backgroundColor: chip.bg, color: chip.fg, bold: chip.bold, children: chip.spinner ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
260
|
-
" ",
|
|
261
|
-
/* @__PURE__ */ jsx(Spinner, { color: chip.fg }),
|
|
262
|
-
" ",
|
|
263
|
-
chip.label,
|
|
264
|
-
" "
|
|
265
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
266
|
-
" ",
|
|
267
|
-
chip.icon,
|
|
268
|
-
" ",
|
|
269
|
-
chip.label,
|
|
270
|
-
" "
|
|
271
|
-
] }) }) }),
|
|
272
|
-
/* @__PURE__ */ jsx(Box, { width: nameWidth, children: /* @__PURE__ */ jsxs(
|
|
273
|
-
Text,
|
|
274
|
-
{
|
|
275
|
-
wrap: "truncate",
|
|
276
|
-
bold: selected || isRunning,
|
|
277
|
-
color: selected ? tuiColors.white : isRunning ? tuiColors.green : tuiColors.silver,
|
|
278
|
-
children: [
|
|
279
|
-
agent.autonomous && /* @__PURE__ */ jsxs(Text, { color: tuiColors.cyan, children: [
|
|
280
|
-
LOOP,
|
|
281
|
-
" "
|
|
282
|
-
] }),
|
|
283
|
-
isLead && /* @__PURE__ */ jsxs(Text, { color: tuiColors.amber, children: [
|
|
284
|
-
STAR,
|
|
285
|
-
" "
|
|
286
|
-
] }),
|
|
287
|
-
agent.name
|
|
288
|
-
]
|
|
289
|
-
}
|
|
290
|
-
) }),
|
|
291
|
-
/* @__PURE__ */ jsx(Box, { width: adapterWidth, children: /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg2.neutral, color: tuiColors.dim, children: [
|
|
292
|
-
" ",
|
|
293
|
-
agent.adapter,
|
|
294
|
-
" "
|
|
295
|
-
] }) }),
|
|
296
|
-
teamName && /* @__PURE__ */ jsx(Box, { width: teamColWidth, children: /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg2.amber, color: tuiColors.amber, wrap: "truncate", children: [
|
|
297
|
-
" ",
|
|
298
|
-
teamName,
|
|
299
|
-
" "
|
|
300
|
-
] }) }),
|
|
301
|
-
/* @__PURE__ */ jsx(Box, { width: roleWidth, children: /* @__PURE__ */ jsx(Text, { color: roleColor, bold: roleBold, wrap: "truncate", children: roleText }) }),
|
|
302
|
-
/* @__PURE__ */ jsx(Box, { width: timeWidth, justifyContent: "flex-end", children: hasHistory && !isRunning ? /* @__PURE__ */ jsxs(Text, { color: successRate >= 80 ? tuiColors.green : successRate >= 50 ? tuiColors.yellow : tuiColors.red, children: [
|
|
303
|
-
timeStr,
|
|
304
|
-
" ",
|
|
305
|
-
CHECK2
|
|
306
|
-
] }) : /* @__PURE__ */ jsx(Text, { color: timeColor, dimColor: !timeColor, children: timeStr }) })
|
|
307
|
-
] });
|
|
308
|
-
});
|
|
309
|
-
function TeamSectionRow({ teamName, memberCount, leadName, width }) {
|
|
310
|
-
const count = `${memberCount} agent${memberCount !== 1 ? "s" : ""}`;
|
|
311
|
-
const leadStr = leadName ? ` ${DOT} ${STAR} ${leadName}` : "";
|
|
312
|
-
const label = ` ${LOZENGE} ${teamName.toUpperCase()} ${DOT} ${count}${leadStr} `;
|
|
313
|
-
const leftLen = 3;
|
|
314
|
-
const rightLen = Math.max(0, width - leftLen - label.length - 4);
|
|
315
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, children: [
|
|
316
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2500".repeat(leftLen) }),
|
|
317
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: chipBg2.amber, color: tuiColors.amber, bold: true, children: label }),
|
|
318
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2500".repeat(rightLen) })
|
|
319
|
-
] });
|
|
320
|
-
}
|
|
321
|
-
var EMPTY_DIAMOND = "\u25C7";
|
|
322
|
-
function UnassignedSectionRow({ memberCount, width }) {
|
|
323
|
-
const count = `${memberCount} agent${memberCount !== 1 ? "s" : ""}`;
|
|
324
|
-
const label = ` ${EMPTY_DIAMOND} UNASSIGNED ${DOT} ${count} `;
|
|
325
|
-
const leftLen = 3;
|
|
326
|
-
const rightLen = Math.max(0, width - leftLen - label.length - 4);
|
|
327
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, children: [
|
|
328
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2500".repeat(leftLen) }),
|
|
329
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: chipBg2.neutral, color: tuiColors.dim, children: label }),
|
|
330
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2500".repeat(rightLen) })
|
|
331
|
-
] });
|
|
332
|
-
}
|
|
333
|
-
var CHECK3 = "\u2713";
|
|
334
|
-
var CROSS3 = "\u2715";
|
|
335
|
-
var PAUSE = "\u2016";
|
|
336
|
-
var TARGET = "\u25C9";
|
|
337
|
-
var chipBg3 = {
|
|
338
|
-
green: "#0f2d1f",
|
|
339
|
-
amber: "#2d1f0a",
|
|
340
|
-
neutral: "#1a1a22"};
|
|
341
|
-
var STATUS_CHIP3 = {
|
|
342
|
-
active: { icon: TARGET, label: "ACTIVE", fg: tuiColors.green, bg: chipBg3.green, bold: true },
|
|
343
|
-
paused: { icon: PAUSE, label: "PAUSED", fg: tuiColors.dim, bg: chipBg3.neutral },
|
|
344
|
-
achieved: { icon: CHECK3, label: "DONE", fg: tuiColors.amber, bg: chipBg3.amber, bold: true },
|
|
345
|
-
abandoned: { icon: CROSS3, label: "DROP", fg: tuiColors.ghost, bg: chipBg3.neutral }
|
|
346
|
-
};
|
|
347
|
-
var GoalRow = React5.memo(function GoalRow2({ goal, selected, width, agentNameMap }) {
|
|
348
|
-
const chip = STATUS_CHIP3[goal.status];
|
|
349
|
-
const cursor = selected ? "\u25B8" : " ";
|
|
350
|
-
const chipWidth = 11;
|
|
351
|
-
const assigneeWidth = 14;
|
|
352
|
-
const timeWidth = 7;
|
|
353
|
-
const fixedCols = 2 + chipWidth + assigneeWidth + timeWidth;
|
|
354
|
-
const titleWidth = width ? Math.max(10, width - fixedCols) : 40;
|
|
355
|
-
const assigneeName = goal.assignee ? agentNameMap?.get(goal.assignee) ?? goal.assignee : void 0;
|
|
356
|
-
let timeStr;
|
|
357
|
-
let timeColor;
|
|
358
|
-
if (goal.status === "achieved") {
|
|
359
|
-
timeStr = CHECK3;
|
|
360
|
-
timeColor = tuiColors.amber;
|
|
361
|
-
} else if (goal.status === "abandoned") {
|
|
362
|
-
timeStr = CROSS3;
|
|
363
|
-
timeColor = tuiColors.ghost;
|
|
364
|
-
} else {
|
|
365
|
-
const ms = Date.now() - new Date(goal.created_at).getTime();
|
|
366
|
-
const days = Math.floor(ms / 864e5);
|
|
367
|
-
timeStr = days > 0 ? `${days}d` : "<1d";
|
|
368
|
-
timeColor = tuiColors.dim;
|
|
369
|
-
}
|
|
370
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
371
|
-
/* @__PURE__ */ jsxs(Text, { color: selected ? tuiColors.amber : void 0, children: [
|
|
372
|
-
cursor,
|
|
373
|
-
" "
|
|
374
|
-
] }),
|
|
375
|
-
/* @__PURE__ */ jsx(Box, { width: chipWidth, children: /* @__PURE__ */ jsxs(Text, { backgroundColor: chip.bg, color: chip.fg, bold: chip.bold, children: [
|
|
376
|
-
" ",
|
|
377
|
-
chip.icon,
|
|
378
|
-
" ",
|
|
379
|
-
chip.label,
|
|
380
|
-
" "
|
|
381
|
-
] }) }),
|
|
382
|
-
/* @__PURE__ */ jsx(Box, { width: titleWidth, children: /* @__PURE__ */ jsx(
|
|
383
|
-
Text,
|
|
384
|
-
{
|
|
385
|
-
wrap: "truncate",
|
|
386
|
-
bold: selected || goal.status === "active",
|
|
387
|
-
color: selected ? tuiColors.white : goal.status === "active" ? tuiColors.silver : void 0,
|
|
388
|
-
children: goal.title.length > titleWidth ? goal.title.slice(0, titleWidth - 1) + "\u2026" : goal.title
|
|
389
|
-
}
|
|
390
|
-
) }),
|
|
391
|
-
/* @__PURE__ */ jsx(Box, { width: assigneeWidth, children: assigneeName ? /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg3.green, color: tuiColors.green, wrap: "truncate", children: [
|
|
392
|
-
" ",
|
|
393
|
-
assigneeName.length > assigneeWidth - 2 ? assigneeName.slice(0, assigneeWidth - 3) + "\u2026" : assigneeName,
|
|
394
|
-
" "
|
|
395
|
-
] }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2014" }) }),
|
|
396
|
-
/* @__PURE__ */ jsx(Box, { width: timeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx(Text, { color: timeColor, dimColor: !timeColor, children: timeStr }) })
|
|
397
|
-
] });
|
|
398
|
-
});
|
|
399
|
-
var MSG_ICONS = {
|
|
400
|
-
system: "\u2666",
|
|
401
|
-
// ◆
|
|
402
|
-
lifecycle: "\u25B6",
|
|
403
|
-
// ▶
|
|
404
|
-
output: "\u2502",
|
|
405
|
-
// │
|
|
406
|
-
tool: "\u2699",
|
|
407
|
-
// ⚙
|
|
408
|
-
result: "\u2190",
|
|
409
|
-
// ←
|
|
410
|
-
error: "\u2715",
|
|
411
|
-
// ✕
|
|
412
|
-
file: "\u270E",
|
|
413
|
-
// ✎
|
|
414
|
-
info: "\u2502"
|
|
415
|
-
// │
|
|
416
|
-
};
|
|
417
|
-
function SectionDivider({ label, width, color }) {
|
|
418
|
-
const innerW = width - 4;
|
|
419
|
-
const labelWithSpaces = ` ${label} `;
|
|
420
|
-
const leftLen = 3;
|
|
421
|
-
const rightLen = Math.max(0, innerW - leftLen - labelWithSpaces.length);
|
|
422
|
-
return /* @__PURE__ */ jsxs(Text, { color: color ?? tuiColors.ghost, children: [
|
|
423
|
-
" ",
|
|
424
|
-
"\u2500".repeat(leftLen),
|
|
425
|
-
labelWithSpaces,
|
|
426
|
-
"\u2500".repeat(rightLen)
|
|
427
|
-
] });
|
|
428
|
-
}
|
|
429
|
-
function DetailPanel({ task, height, width, taskLogs, agentNameMap }) {
|
|
430
|
-
const statusColor = STATUS_DETAIL_COLOR[task.status] ?? tuiColors.dim;
|
|
431
|
-
const priColor = task.priority <= 2 ? task.priority === 1 ? tuiColors.red : tuiColors.yellow : void 0;
|
|
432
|
-
const col1Width = 24;
|
|
433
|
-
const hasDescription = !!task.description?.trim();
|
|
434
|
-
const hasSummary = !!task.proof?.agent_summary;
|
|
435
|
-
const hasFiles = (task.proof?.files_changed?.length ?? 0) > 0;
|
|
436
|
-
const hasLogs = (taskLogs?.length ?? 0) > 0;
|
|
437
|
-
const descLines = hasDescription ? task.description.split("\n") : [];
|
|
438
|
-
const summaryLines = hasSummary ? task.proof.agent_summary.split("\n") : [];
|
|
439
|
-
let usedRows = 3;
|
|
440
|
-
if (hasDescription) {
|
|
441
|
-
usedRows += 1;
|
|
442
|
-
usedRows += Math.min(descLines.length, Math.max(1, Math.ceil((height - 10) * 0.3)));
|
|
443
|
-
} else if (!hasSummary) {
|
|
444
|
-
usedRows += 2;
|
|
445
|
-
}
|
|
446
|
-
if (hasSummary) {
|
|
447
|
-
usedRows += 2;
|
|
448
|
-
}
|
|
449
|
-
if (hasFiles) {
|
|
450
|
-
usedRows += 1;
|
|
451
|
-
}
|
|
452
|
-
if (hasLogs) {
|
|
453
|
-
usedRows += 2;
|
|
454
|
-
}
|
|
455
|
-
const remainingRows = Math.max(0, height - usedRows);
|
|
456
|
-
let summaryMaxLines = 0;
|
|
457
|
-
let logMaxLines = 0;
|
|
458
|
-
if (hasSummary && hasLogs) {
|
|
459
|
-
summaryMaxLines = Math.max(1, Math.floor(remainingRows * 0.4));
|
|
460
|
-
logMaxLines = Math.max(1, remainingRows - summaryMaxLines);
|
|
461
|
-
} else if (hasSummary) {
|
|
462
|
-
summaryMaxLines = remainingRows;
|
|
463
|
-
} else if (hasLogs) {
|
|
464
|
-
logMaxLines = remainingRows;
|
|
465
|
-
}
|
|
466
|
-
const visibleDescLines = hasDescription ? descLines.slice(0, Math.max(1, Math.ceil((height - 10) * 0.3))) : [];
|
|
467
|
-
const visibleSummaryLines = summaryLines.slice(0, summaryMaxLines);
|
|
468
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, children: [
|
|
469
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
470
|
-
/* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
471
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " status " }),
|
|
472
|
-
/* @__PURE__ */ jsx(Text, { color: statusColor, children: task.status })
|
|
473
|
-
] }),
|
|
474
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
475
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " assignee " }),
|
|
476
|
-
/* @__PURE__ */ jsx(Text, { color: task.assignee ? tuiColors.green : tuiColors.dim, children: task.assignee ? agentNameMap?.get(task.assignee) ?? task.assignee : "\u2014" })
|
|
477
|
-
] })
|
|
478
|
-
] }),
|
|
479
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
480
|
-
/* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
481
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " priority " }),
|
|
482
|
-
/* @__PURE__ */ jsxs(Text, { color: priColor, bold: task.priority <= 2, children: [
|
|
483
|
-
"P",
|
|
484
|
-
task.priority
|
|
485
|
-
] })
|
|
486
|
-
] }),
|
|
487
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
488
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " attempts " }),
|
|
489
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
490
|
-
task.attempts,
|
|
491
|
-
"/",
|
|
492
|
-
task.max_attempts
|
|
493
|
-
] })
|
|
494
|
-
] })
|
|
495
|
-
] }),
|
|
496
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
497
|
-
/* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
498
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " labels " }),
|
|
499
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.purple, children: task.labels.length > 0 ? task.labels.join(", ") : "\u2014" })
|
|
500
|
-
] }),
|
|
501
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
502
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " depends " }),
|
|
503
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: task.depends_on.length > 0 ? task.depends_on.join(", ") : "\u2014" })
|
|
504
|
-
] })
|
|
505
|
-
] }),
|
|
506
|
-
hasDescription && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
507
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
508
|
-
visibleDescLines.map((line, i) => /* @__PURE__ */ jsxs(Text, { color: tuiColors.silver, wrap: "truncate", children: [
|
|
509
|
-
" ",
|
|
510
|
-
line
|
|
511
|
-
] }, `d${i}`))
|
|
512
|
-
] }),
|
|
513
|
-
!hasDescription && !hasSummary && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
514
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
515
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " No description." })
|
|
516
|
-
] }),
|
|
517
|
-
hasSummary && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
518
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
519
|
-
/* @__PURE__ */ jsx(SectionDivider, { label: "result", width, color: tuiColors.dim }),
|
|
520
|
-
visibleSummaryLines.map((line, i) => /* @__PURE__ */ jsxs(Text, { color: tuiColors.white, wrap: "truncate", children: [
|
|
521
|
-
" ",
|
|
522
|
-
line
|
|
523
|
-
] }, `r${i}`))
|
|
524
|
-
] }),
|
|
525
|
-
hasFiles && /* @__PURE__ */ jsxs(Box, { children: [
|
|
526
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " files " }),
|
|
527
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.cyan, children: task.proof.files_changed.length }),
|
|
528
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " changed" }),
|
|
529
|
-
task.proof.branch && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
530
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
531
|
-
" ",
|
|
532
|
-
"\xB7",
|
|
533
|
-
" "
|
|
534
|
-
] }),
|
|
535
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.cyan, children: task.proof.branch })
|
|
536
|
-
] })
|
|
537
|
-
] }),
|
|
538
|
-
hasLogs && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
539
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
540
|
-
/* @__PURE__ */ jsx(SectionDivider, { label: "activity", width, color: tuiColors.dim }),
|
|
541
|
-
taskLogs.slice(-logMaxLines).map((log, i) => {
|
|
542
|
-
const msgType = log.msgType ?? "info";
|
|
543
|
-
const icon = MSG_ICONS[msgType] ?? "\u2502";
|
|
544
|
-
let textColor = log.color;
|
|
545
|
-
if (msgType === "tool") textColor = tuiColors.cyan;
|
|
546
|
-
else if (msgType === "file") textColor = tuiColors.purple;
|
|
547
|
-
else if (msgType === "error") textColor = tuiColors.red;
|
|
548
|
-
else if (msgType === "lifecycle") textColor = tuiColors.green;
|
|
549
|
-
else if (msgType === "system") textColor = tuiColors.dim;
|
|
550
|
-
const logTextW = Math.max(10, width - 12);
|
|
551
|
-
const logDisplay = log.text.length > logTextW ? log.text.slice(0, logTextW - 1) + "\u2026" : log.text;
|
|
552
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
553
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
554
|
-
" ",
|
|
555
|
-
log.time,
|
|
556
|
-
" "
|
|
557
|
-
] }),
|
|
558
|
-
/* @__PURE__ */ jsxs(Text, { color: msgType === "error" ? tuiColors.red : tuiColors.dim, children: [
|
|
559
|
-
icon,
|
|
560
|
-
" "
|
|
561
|
-
] }),
|
|
562
|
-
/* @__PURE__ */ jsx(Text, { color: textColor, bold: msgType === "lifecycle", children: logDisplay })
|
|
563
|
-
] }, i);
|
|
564
|
-
})
|
|
565
|
-
] })
|
|
566
|
-
] });
|
|
567
|
-
}
|
|
568
|
-
var STATUS_DETAIL_COLOR = {
|
|
569
|
-
in_progress: tuiColors.green,
|
|
570
|
-
retrying: tuiColors.yellow,
|
|
571
|
-
review: tuiColors.blue,
|
|
572
|
-
todo: tuiColors.dim,
|
|
573
|
-
done: tuiColors.green,
|
|
574
|
-
failed: tuiColors.red,
|
|
575
|
-
cancelled: tuiColors.dim
|
|
576
|
-
};
|
|
577
|
-
var TABS = [
|
|
578
|
-
{ key: "G", id: "goals", label: "GOALS" },
|
|
579
|
-
{ key: "T", id: "tasks", label: "TASKS" },
|
|
580
|
-
{ key: "A", id: "agents", label: "AGENTS" },
|
|
581
|
-
{ key: "L", id: "logs", label: "ACTIONS" }
|
|
582
|
-
];
|
|
583
|
-
var FILLED_CIRCLE = "\u25CF";
|
|
584
|
-
var EMPTY_CIRCLE3 = "\u25CB";
|
|
585
|
-
var CHECK4 = "\u2713";
|
|
586
|
-
var CROSS4 = "\u2715";
|
|
587
|
-
var ARROW_UP = "\u2191";
|
|
588
|
-
var ARROW_DOWN = "\u2193";
|
|
589
|
-
var SIGMA = "\u03A3";
|
|
590
|
-
var TRIANGLE_RIGHT = "\u25B6";
|
|
591
|
-
var RETRY_ICON = "\u21BB";
|
|
592
|
-
var BRAILLE_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
593
|
-
var SPARK_CHARS = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
|
|
594
|
-
var chipBg4 = {
|
|
595
|
-
green: "#0f2d1f",
|
|
596
|
-
// dark emerald tint
|
|
597
|
-
blue: "#0f1f2d",
|
|
598
|
-
// dark sky tint
|
|
599
|
-
yellow: "#2d2a0f",
|
|
600
|
-
// dark amber tint
|
|
601
|
-
red: "#2d0f0f",
|
|
602
|
-
// dark rose tint
|
|
603
|
-
neutral: "#1a1a22",
|
|
604
|
-
// dark slate
|
|
605
|
-
amber: "#2d1f0a"
|
|
606
|
-
// dark warm
|
|
607
|
-
};
|
|
608
|
-
function MiniSpinner({ color }) {
|
|
609
|
-
const tick = useAnimTick();
|
|
610
|
-
return /* @__PURE__ */ jsx(Text, { color, children: BRAILLE_FRAMES[tick % BRAILLE_FRAMES.length] });
|
|
611
|
-
}
|
|
612
|
-
function PulsingDiamond() {
|
|
613
|
-
const tick = useAnimTick();
|
|
614
|
-
const bright = Math.floor(tick / 10) % 2 === 0;
|
|
615
|
-
return /* @__PURE__ */ jsx(Text, { color: bright ? tuiColors.amber : tuiColors.amberDim, bold: true, children: DIAMOND });
|
|
616
|
-
}
|
|
617
|
-
function ScannerBar({ width, active }) {
|
|
618
|
-
const segLen = Math.max(4, Math.floor(width * 0.08));
|
|
619
|
-
const step = 2;
|
|
620
|
-
const tick = useAnimTick();
|
|
621
|
-
const totalFrames = Math.ceil((width + segLen) / step);
|
|
622
|
-
const pos = active ? tick % (totalFrames * 2) : 0;
|
|
623
|
-
if (!active) {
|
|
624
|
-
return /* @__PURE__ */ jsx(Box, { paddingX: 1, children: /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(width) }) });
|
|
625
|
-
}
|
|
626
|
-
const rawPos = pos < totalFrames ? pos * step : (totalFrames * 2 - pos) * step;
|
|
627
|
-
const brightStart = Math.max(0, rawPos - segLen);
|
|
628
|
-
const brightEnd = Math.min(width, rawPos);
|
|
629
|
-
const beforeLen = brightStart;
|
|
630
|
-
const brightLen = Math.max(0, brightEnd - brightStart);
|
|
631
|
-
const afterLen = Math.max(0, width - brightEnd);
|
|
632
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
633
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(beforeLen) }),
|
|
634
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: HEAVY_RULE.repeat(brightLen) }),
|
|
635
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(afterLen) })
|
|
636
|
-
] });
|
|
637
|
-
}
|
|
638
|
-
function Sparkline({ data, width, color }) {
|
|
639
|
-
if (data.length === 0) return null;
|
|
640
|
-
const display = data.slice(-width);
|
|
641
|
-
const max = Math.max(...display, 1);
|
|
642
|
-
const chars = display.map((v) => {
|
|
643
|
-
const idx = Math.round(v / max * (SPARK_CHARS.length - 1));
|
|
644
|
-
return SPARK_CHARS[idx] ?? SPARK_CHARS[0];
|
|
645
|
-
}).join("");
|
|
646
|
-
return /* @__PURE__ */ jsx(Text, { color, children: chars });
|
|
647
|
-
}
|
|
648
|
-
function BrandBar({
|
|
649
|
-
projectName,
|
|
650
|
-
activeView,
|
|
651
|
-
mode,
|
|
652
|
-
stats,
|
|
653
|
-
uptime,
|
|
654
|
-
width
|
|
655
|
-
}) {
|
|
656
|
-
const isWatching = mode === "watching";
|
|
657
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, justifyContent: "space-between", width, children: [
|
|
658
|
-
/* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
659
|
-
/* @__PURE__ */ jsx(PulsingDiamond, {}),
|
|
660
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, bold: true, children: " ORCH" }),
|
|
661
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
662
|
-
" ",
|
|
663
|
-
DOT,
|
|
664
|
-
" "
|
|
665
|
-
] }),
|
|
666
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.silver, children: projectName })
|
|
667
|
-
] }),
|
|
668
|
-
/* @__PURE__ */ jsx(Box, { gap: 0, children: TABS.map((tab, i) => {
|
|
669
|
-
const isActive = activeView === tab.id;
|
|
670
|
-
return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
|
|
671
|
-
i > 0 && /* @__PURE__ */ jsx(Text, { children: " " }),
|
|
672
|
-
isActive ? (
|
|
673
|
-
// Active tab: inverted chip — amber background, dark text
|
|
674
|
-
/* @__PURE__ */ jsxs(Text, { backgroundColor: tuiColors.amber, color: "#0a0a0c", bold: true, children: [
|
|
675
|
-
" ",
|
|
676
|
-
tab.key,
|
|
677
|
-
" ",
|
|
678
|
-
tab.label,
|
|
679
|
-
" "
|
|
680
|
-
] })
|
|
681
|
-
) : (
|
|
682
|
-
// Inactive tab: ghost key + dim label
|
|
683
|
-
/* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
684
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: tab.key }),
|
|
685
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
686
|
-
" ",
|
|
687
|
-
tab.label.toLowerCase()
|
|
688
|
-
] })
|
|
689
|
-
] })
|
|
690
|
-
)
|
|
691
|
-
] }, tab.id);
|
|
692
|
-
}) }),
|
|
693
|
-
/* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
694
|
-
isWatching ? /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg4.green, color: tuiColors.green, bold: true, children: [
|
|
695
|
-
" ",
|
|
696
|
-
FILLED_CIRCLE,
|
|
697
|
-
" WATCHING",
|
|
698
|
-
" "
|
|
699
|
-
] }) : /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg4.neutral, color: tuiColors.dim, children: [
|
|
700
|
-
" ",
|
|
701
|
-
EMPTY_CIRCLE3,
|
|
702
|
-
" IDLE",
|
|
703
|
-
" "
|
|
704
|
-
] }),
|
|
705
|
-
stats.running > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
706
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
707
|
-
/* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg4.green, color: tuiColors.green, children: [
|
|
708
|
-
" ",
|
|
709
|
-
/* @__PURE__ */ jsx(MiniSpinner, { color: tuiColors.green }),
|
|
710
|
-
" ",
|
|
711
|
-
stats.running,
|
|
712
|
-
" active",
|
|
713
|
-
" "
|
|
714
|
-
] })
|
|
715
|
-
] }),
|
|
716
|
-
uptime && /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
717
|
-
" ",
|
|
718
|
-
uptime
|
|
719
|
-
] })
|
|
720
|
-
] })
|
|
721
|
-
] });
|
|
722
|
-
}
|
|
723
|
-
function StatsBar({
|
|
724
|
-
stats,
|
|
725
|
-
tokens,
|
|
726
|
-
width,
|
|
727
|
-
sparklineData
|
|
728
|
-
}) {
|
|
729
|
-
const allChips = [
|
|
730
|
-
{ icon: TRIANGLE_RIGHT, label: "RUN", count: stats.running, fg: tuiColors.green, bg: chipBg4.green, bold: true, spinner: true, show: stats.running > 0 },
|
|
731
|
-
{ icon: RETRY_ICON, label: "RETRY", count: stats.retrying, fg: tuiColors.yellow, bg: chipBg4.yellow, show: stats.retrying > 0 },
|
|
732
|
-
{ icon: LOZENGE, label: "REVIEW", count: stats.review, fg: tuiColors.blue, bg: chipBg4.blue, show: stats.review > 0 },
|
|
733
|
-
{ icon: EMPTY_CIRCLE3, label: "TODO", count: stats.todo, fg: tuiColors.dim, bg: chipBg4.neutral, show: stats.todo > 0 },
|
|
734
|
-
{ icon: CHECK4, label: "DONE", count: stats.done, fg: tuiColors.green, bg: chipBg4.green, show: stats.done > 0 },
|
|
735
|
-
{ icon: CROSS4, label: "FAIL", count: stats.failed, fg: tuiColors.red, bg: chipBg4.red, bold: true, show: stats.failed > 0 },
|
|
736
|
-
{ icon: DIAMOND, label: "TEAMS", count: stats.teams, fg: tuiColors.amber, bg: chipBg4.amber, show: stats.teams > 0 }
|
|
737
|
-
];
|
|
738
|
-
const chips = allChips.filter((c) => c.show);
|
|
739
|
-
const hasTokens = tokens.total > 0;
|
|
740
|
-
const fmtK = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
|
|
741
|
-
const sparkWidth = sparklineData && sparklineData.length > 0 ? Math.min(16, sparklineData.length) : 0;
|
|
742
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, justifyContent: "space-between", width, children: [
|
|
743
|
-
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
744
|
-
chips.map((chip) => /* @__PURE__ */ jsx(Text, { backgroundColor: chip.bg, color: chip.fg, bold: chip.bold, children: chip.spinner ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
745
|
-
" ",
|
|
746
|
-
/* @__PURE__ */ jsx(MiniSpinner, { color: chip.fg }),
|
|
747
|
-
" ",
|
|
748
|
-
chip.count,
|
|
749
|
-
" ",
|
|
750
|
-
chip.label,
|
|
751
|
-
" "
|
|
752
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
753
|
-
" ",
|
|
754
|
-
chip.icon,
|
|
755
|
-
" ",
|
|
756
|
-
chip.count,
|
|
757
|
-
" ",
|
|
758
|
-
chip.label,
|
|
759
|
-
" "
|
|
760
|
-
] }) }, chip.label)),
|
|
761
|
-
chips.length === 0 && /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg4.neutral, color: tuiColors.dim, children: [
|
|
762
|
-
" ",
|
|
763
|
-
"NO TASKS",
|
|
764
|
-
" "
|
|
765
|
-
] })
|
|
766
|
-
] }),
|
|
767
|
-
/* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
768
|
-
sparkWidth > 0 && sparklineData && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
769
|
-
/* @__PURE__ */ jsx(Sparkline, { data: sparklineData, width: sparkWidth, color: tuiColors.amberDim }),
|
|
770
|
-
/* @__PURE__ */ jsx(Text, { children: " " })
|
|
771
|
-
] }),
|
|
772
|
-
hasTokens && /* @__PURE__ */ jsxs(Text, { backgroundColor: chipBg4.amber, color: tuiColors.cyan, children: [
|
|
773
|
-
" ",
|
|
774
|
-
ARROW_UP,
|
|
775
|
-
fmtK(tokens.input),
|
|
776
|
-
" ",
|
|
777
|
-
ARROW_DOWN,
|
|
778
|
-
fmtK(tokens.output),
|
|
779
|
-
" ",
|
|
780
|
-
DOT,
|
|
781
|
-
" ",
|
|
782
|
-
SIGMA,
|
|
783
|
-
fmtK(tokens.total),
|
|
784
|
-
" "
|
|
785
|
-
] })
|
|
786
|
-
] })
|
|
787
|
-
] });
|
|
788
|
-
}
|
|
789
|
-
var Header = React5.memo(function Header2(props) {
|
|
790
|
-
const barWidth = Math.max(10, props.width - 2);
|
|
791
|
-
const isActive = props.stats.running > 0;
|
|
792
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
793
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
794
|
-
/* @__PURE__ */ jsx(
|
|
795
|
-
BrandBar,
|
|
796
|
-
{
|
|
797
|
-
projectName: props.projectName,
|
|
798
|
-
activeView: props.activeView,
|
|
799
|
-
mode: props.mode,
|
|
800
|
-
stats: props.stats,
|
|
801
|
-
uptime: props.uptime,
|
|
802
|
-
width: props.width
|
|
803
|
-
}
|
|
804
|
-
),
|
|
805
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
806
|
-
/* @__PURE__ */ jsx(
|
|
807
|
-
StatsBar,
|
|
808
|
-
{
|
|
809
|
-
stats: props.stats,
|
|
810
|
-
tokens: props.tokens,
|
|
811
|
-
width: props.width,
|
|
812
|
-
sparklineData: props.sparklineData
|
|
813
|
-
}
|
|
814
|
-
),
|
|
815
|
-
/* @__PURE__ */ jsx(ScannerBar, { width: barWidth, active: isActive })
|
|
816
|
-
] });
|
|
817
|
-
});
|
|
818
|
-
|
|
819
|
-
// src/tui/commandBar.ts
|
|
820
|
-
var COMMAND_REGISTRY = {
|
|
821
|
-
goal: { sub: ["add", "list", "show", "status", "delete"], help: "Manage goals" },
|
|
822
|
-
task: { sub: ["add", "list", "show", "cancel", "retry", "assign", "approve", "reject", "delete"], help: "Manage tasks" },
|
|
823
|
-
agent: { sub: ["add", "list", "disable", "enable", "delete", "autonomous"], help: "Manage agents" },
|
|
824
|
-
team: { sub: ["create", "list", "join", "leave", "disband", "set-lead"], help: "Manage teams" },
|
|
825
|
-
run: { args: "[id]", help: "Run task (or selected)" },
|
|
826
|
-
"run-all": { help: "Run all todo tasks" },
|
|
827
|
-
watch: { help: "Start watch mode (auto-dispatch)" },
|
|
828
|
-
pause: { help: "Pause watch mode" },
|
|
829
|
-
config: { sub: ["activity-filter", "max-concurrent"], help: "TUI settings" },
|
|
830
|
-
status: { help: "Show orchestrator status" },
|
|
831
|
-
help: { help: "List all commands" },
|
|
832
|
-
quit: { help: "Exit the TUI" }
|
|
833
|
-
};
|
|
834
|
-
function resolveCompletion(input) {
|
|
835
|
-
if (!input.startsWith("/")) return null;
|
|
836
|
-
const body = input.slice(1);
|
|
837
|
-
const spaceIdx = body.indexOf(" ");
|
|
838
|
-
if (spaceIdx === -1) {
|
|
839
|
-
const prefix = body;
|
|
840
|
-
if (!prefix) return null;
|
|
841
|
-
const match2 = Object.keys(COMMAND_REGISTRY).find(
|
|
842
|
-
(k) => k.startsWith(prefix) && k !== prefix
|
|
843
|
-
);
|
|
844
|
-
return match2 ? match2.slice(prefix.length) : null;
|
|
845
|
-
}
|
|
846
|
-
const verb = body.slice(0, spaceIdx);
|
|
847
|
-
const spec = COMMAND_REGISTRY[verb];
|
|
848
|
-
if (!spec?.sub) return null;
|
|
849
|
-
const subPrefix = body.slice(spaceIdx + 1);
|
|
850
|
-
if (!subPrefix) return null;
|
|
851
|
-
const match = spec.sub.find(
|
|
852
|
-
(s) => s.startsWith(subPrefix) && s !== subPrefix
|
|
853
|
-
);
|
|
854
|
-
return match ? match.slice(subPrefix.length) : null;
|
|
855
|
-
}
|
|
856
|
-
function resolveSuggestions(input) {
|
|
857
|
-
if (!input.startsWith("/")) return [];
|
|
858
|
-
const body = input.slice(1);
|
|
859
|
-
const spaceIdx = body.indexOf(" ");
|
|
860
|
-
if (spaceIdx === -1) {
|
|
861
|
-
const prefix = body.toLowerCase();
|
|
862
|
-
const results2 = [];
|
|
863
|
-
for (const [verb2, spec2] of Object.entries(COMMAND_REGISTRY)) {
|
|
864
|
-
if (!prefix || verb2.startsWith(prefix)) {
|
|
865
|
-
const argsHint = spec2.args ? ` ${spec2.args}` : "";
|
|
866
|
-
results2.push({
|
|
867
|
-
cmd: `/${verb2}${argsHint}`,
|
|
868
|
-
desc: spec2.help,
|
|
869
|
-
subs: spec2.sub?.join(" \xB7 ")
|
|
870
|
-
});
|
|
871
|
-
if (prefix && verb2 === prefix && spec2.sub) {
|
|
872
|
-
for (const sub of spec2.sub) {
|
|
873
|
-
results2.push({ cmd: `/${verb2} ${sub}`, desc: `${spec2.help}: ${sub}` });
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
return results2;
|
|
879
|
-
}
|
|
880
|
-
const verb = body.slice(0, spaceIdx);
|
|
881
|
-
const spec = COMMAND_REGISTRY[verb];
|
|
882
|
-
if (!spec?.sub) return [];
|
|
883
|
-
const subPrefix = body.slice(spaceIdx + 1).toLowerCase();
|
|
884
|
-
const results = [];
|
|
885
|
-
for (const sub of spec.sub) {
|
|
886
|
-
if (!subPrefix || sub.startsWith(subPrefix)) {
|
|
887
|
-
results.push({ cmd: `/${verb} ${sub}`, desc: `${spec.help}: ${sub}` });
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
return results;
|
|
891
|
-
}
|
|
892
|
-
var CommandHistory = class {
|
|
893
|
-
entries = [];
|
|
894
|
-
cursor = 0;
|
|
895
|
-
push(cmd) {
|
|
896
|
-
if (!cmd) return;
|
|
897
|
-
if (this.entries[this.entries.length - 1] !== cmd) {
|
|
898
|
-
this.entries.push(cmd);
|
|
899
|
-
if (this.entries.length > 100) this.entries.shift();
|
|
900
|
-
}
|
|
901
|
-
this.cursor = this.entries.length;
|
|
902
|
-
}
|
|
903
|
-
prev() {
|
|
904
|
-
if (this.entries.length === 0) return null;
|
|
905
|
-
if (this.cursor > 0) this.cursor--;
|
|
906
|
-
return this.entries[this.cursor] ?? null;
|
|
907
|
-
}
|
|
908
|
-
next() {
|
|
909
|
-
if (this.cursor < this.entries.length - 1) {
|
|
910
|
-
this.cursor++;
|
|
911
|
-
return this.entries[this.cursor] ?? null;
|
|
912
|
-
}
|
|
913
|
-
this.cursor = this.entries.length;
|
|
914
|
-
return null;
|
|
915
|
-
}
|
|
916
|
-
reset() {
|
|
917
|
-
this.cursor = this.entries.length;
|
|
918
|
-
}
|
|
919
|
-
};
|
|
920
|
-
var CURSOR_CHAR = "\u2588";
|
|
921
|
-
var CommandBar = React5.memo(function CommandBar2({
|
|
922
|
-
mode,
|
|
923
|
-
value,
|
|
924
|
-
completion,
|
|
925
|
-
activeView,
|
|
926
|
-
canRun,
|
|
927
|
-
canNew,
|
|
928
|
-
canApprove,
|
|
929
|
-
canReject,
|
|
930
|
-
canCancel,
|
|
931
|
-
canDelete,
|
|
932
|
-
canEdit,
|
|
933
|
-
canForceStop,
|
|
934
|
-
canToggleAuto,
|
|
935
|
-
autoActive,
|
|
936
|
-
canPause,
|
|
937
|
-
isPaused,
|
|
938
|
-
canToggleShowAll,
|
|
939
|
-
showAllActive,
|
|
940
|
-
hasDetail,
|
|
941
|
-
itemCount,
|
|
942
|
-
itemLabel,
|
|
943
|
-
width,
|
|
944
|
-
hasSuggestions
|
|
945
|
-
}) {
|
|
946
|
-
if (mode === "command") {
|
|
947
|
-
const hintText = hasSuggestions ? " \u2191\u2193 select Tab fill Esc \u2715" : " Enter exec \u2191\u2193 history Tab complete Esc \u2715";
|
|
948
|
-
const maxLen = Math.max(4, width - 6 - hintText.length - (completion?.length ?? 0) - 1);
|
|
949
|
-
const display = value.length > maxLen ? "\u2026" + value.slice(-(maxLen - 1)) : value;
|
|
950
|
-
return /* @__PURE__ */ jsx(Box, { paddingX: 2, justifyContent: "space-between", width, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
951
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: "/ " }),
|
|
952
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, children: display }),
|
|
953
|
-
completion && /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: completion }),
|
|
954
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: CURSOR_CHAR }),
|
|
955
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: hintText })
|
|
956
|
-
] }) });
|
|
957
|
-
}
|
|
958
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, justifyContent: "space-between", width, children: [
|
|
959
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
960
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "\u2191\u2193" }),
|
|
961
|
-
" ",
|
|
962
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "Tab" }),
|
|
963
|
-
"/",
|
|
964
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "\u2190\u2192" }),
|
|
965
|
-
" ",
|
|
966
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "/" }),
|
|
967
|
-
" cmd",
|
|
968
|
-
canNew && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
969
|
-
" ",
|
|
970
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "N" }),
|
|
971
|
-
" new"
|
|
972
|
-
] }),
|
|
973
|
-
canRun && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
974
|
-
" ",
|
|
975
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "R" }),
|
|
976
|
-
" run"
|
|
977
|
-
] }),
|
|
978
|
-
canCancel && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
979
|
-
" ",
|
|
980
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.amber, children: "C" }),
|
|
981
|
-
" cancel"
|
|
982
|
-
] }),
|
|
983
|
-
canApprove && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
984
|
-
" ",
|
|
985
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.green, children: "A" }),
|
|
986
|
-
" approve"
|
|
987
|
-
] }),
|
|
988
|
-
canReject && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
989
|
-
" ",
|
|
990
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.red, children: "X" }),
|
|
991
|
-
" reject"
|
|
992
|
-
] }),
|
|
993
|
-
canEdit && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
994
|
-
" ",
|
|
995
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.cyan, children: "E" }),
|
|
996
|
-
" edit"
|
|
997
|
-
] }),
|
|
998
|
-
canForceStop && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
999
|
-
" ",
|
|
1000
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.red, children: "S" }),
|
|
1001
|
-
" stop"
|
|
1002
|
-
] }),
|
|
1003
|
-
canPause && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1004
|
-
" ",
|
|
1005
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.amber, children: "P" }),
|
|
1006
|
-
isPaused ? " resume" : " pause"
|
|
1007
|
-
] }),
|
|
1008
|
-
canToggleAuto && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1009
|
-
" ",
|
|
1010
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.cyan, children: "U" }),
|
|
1011
|
-
autoActive ? " auto off" : " auto on"
|
|
1012
|
-
] }),
|
|
1013
|
-
canToggleShowAll && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1014
|
-
" ",
|
|
1015
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "S" }),
|
|
1016
|
-
showAllActive ? " collapse" : " show all"
|
|
1017
|
-
] }),
|
|
1018
|
-
canDelete && !canApprove && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1019
|
-
" ",
|
|
1020
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "D" }),
|
|
1021
|
-
" delete"
|
|
1022
|
-
] }),
|
|
1023
|
-
hasDetail && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1024
|
-
" ",
|
|
1025
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "Esc" }),
|
|
1026
|
-
" close"
|
|
1027
|
-
] }),
|
|
1028
|
-
!hasDetail && (activeView === "tasks" || activeView === "agents" || activeView === "goals") && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1029
|
-
" ",
|
|
1030
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "Enter" }),
|
|
1031
|
-
" detail"
|
|
1032
|
-
] }),
|
|
1033
|
-
" ",
|
|
1034
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "Q" }),
|
|
1035
|
-
" quit"
|
|
1036
|
-
] }),
|
|
1037
|
-
itemCount > 0 && /* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
1038
|
-
itemCount,
|
|
1039
|
-
" ",
|
|
1040
|
-
itemLabel
|
|
1041
|
-
] })
|
|
1042
|
-
] });
|
|
1043
|
-
});
|
|
1044
|
-
var CURSOR = "\u2588";
|
|
1045
|
-
function FormWizard({ title, steps, onComplete, onCancel, width, height }) {
|
|
1046
|
-
const [currentStep, setCurrentStep] = useState(0);
|
|
1047
|
-
const [values, setValues] = useState({});
|
|
1048
|
-
const [textInput, setTextInput] = useState(() => {
|
|
1049
|
-
const firstActive = steps.find((s) => !s.skip?.({}));
|
|
1050
|
-
return firstActive?.type === "text" && firstActive.defaultValue ? firstActive.defaultValue : "";
|
|
1051
|
-
});
|
|
1052
|
-
const [cursorPos, setCursorPos] = useState(() => {
|
|
1053
|
-
const firstActive = steps.find((s) => !s.skip?.({}));
|
|
1054
|
-
return firstActive?.type === "text" && firstActive.defaultValue ? firstActive.defaultValue.length : 0;
|
|
1055
|
-
});
|
|
1056
|
-
const [taLines, setTaLines] = useState(() => {
|
|
1057
|
-
const firstActive = steps.find((s) => !s.skip?.({}));
|
|
1058
|
-
if (firstActive?.type === "textarea" && firstActive.defaultValue) {
|
|
1059
|
-
return firstActive.defaultValue.split("\n");
|
|
1060
|
-
}
|
|
1061
|
-
return [""];
|
|
1062
|
-
});
|
|
1063
|
-
const [taCursorRow, setTaCursorRow] = useState(0);
|
|
1064
|
-
const [taCursorCol, setTaCursorCol] = useState(0);
|
|
1065
|
-
const [selectIndex, setSelectIndex] = useState(() => {
|
|
1066
|
-
const firstActive = steps.find((s) => !s.skip?.({}));
|
|
1067
|
-
if (firstActive?.type === "select" && firstActive.defaultValue) {
|
|
1068
|
-
const opts = firstActive.getOptions?.({}) ?? firstActive.options ?? [];
|
|
1069
|
-
const idx = opts.findIndex((o) => o.value === firstActive.defaultValue);
|
|
1070
|
-
return idx >= 0 ? idx : 0;
|
|
1071
|
-
}
|
|
1072
|
-
return 0;
|
|
1073
|
-
});
|
|
1074
|
-
const activeSteps = useMemo(() => {
|
|
1075
|
-
return steps.filter((s) => !s.skip?.(values));
|
|
1076
|
-
}, [steps, values]);
|
|
1077
|
-
const step = activeSteps[currentStep];
|
|
1078
|
-
const totalSteps = activeSteps.length;
|
|
1079
|
-
const [multiSelected, setMultiSelected] = useState(/* @__PURE__ */ new Set());
|
|
1080
|
-
const options = useMemo(() => {
|
|
1081
|
-
if (!step || step.type !== "select" && step.type !== "multiselect") return [];
|
|
1082
|
-
return step.getOptions?.(values) ?? step.options ?? [];
|
|
1083
|
-
}, [step, values]);
|
|
1084
|
-
const clampedSelectIndex = Math.min(selectIndex, Math.max(0, options.length - 1));
|
|
1085
|
-
const goToNextStep = (value) => {
|
|
1086
|
-
const newValues = { ...values, [step.id]: value };
|
|
1087
|
-
setValues(newValues);
|
|
1088
|
-
setTextInput("");
|
|
1089
|
-
setCursorPos(0);
|
|
1090
|
-
setTaLines([""]);
|
|
1091
|
-
setTaCursorRow(0);
|
|
1092
|
-
setTaCursorCol(0);
|
|
1093
|
-
setSelectIndex(0);
|
|
1094
|
-
setMultiSelected(/* @__PURE__ */ new Set());
|
|
1095
|
-
const currentStepId = step.id;
|
|
1096
|
-
const currentIdx = steps.findIndex((s) => s.id === currentStepId);
|
|
1097
|
-
let nextOrigIdx = currentIdx + 1;
|
|
1098
|
-
while (nextOrigIdx < steps.length) {
|
|
1099
|
-
const candidate = steps[nextOrigIdx];
|
|
1100
|
-
if (candidate && !candidate.skip?.(newValues)) break;
|
|
1101
|
-
nextOrigIdx++;
|
|
1102
|
-
}
|
|
1103
|
-
if (nextOrigIdx >= steps.length) {
|
|
1104
|
-
onComplete(newValues);
|
|
1105
|
-
} else {
|
|
1106
|
-
const nextStepId = steps[nextOrigIdx].id;
|
|
1107
|
-
const newActiveSteps = steps.filter((s) => !s.skip?.(newValues));
|
|
1108
|
-
const nextActiveIdx = newActiveSteps.findIndex((s) => s.id === nextStepId);
|
|
1109
|
-
setCurrentStep(nextActiveIdx >= 0 ? nextActiveIdx : 0);
|
|
1110
|
-
const nextStep = steps[nextOrigIdx];
|
|
1111
|
-
if (nextStep.type === "text") {
|
|
1112
|
-
const def = nextStep.defaultValue ?? "";
|
|
1113
|
-
setTextInput(def);
|
|
1114
|
-
setCursorPos(def.length);
|
|
1115
|
-
} else if (nextStep.type === "textarea") {
|
|
1116
|
-
const lines = nextStep.defaultValue ? nextStep.defaultValue.split("\n") : [""];
|
|
1117
|
-
setTaLines(lines);
|
|
1118
|
-
setTaCursorRow(lines.length - 1);
|
|
1119
|
-
setTaCursorCol(lines[lines.length - 1].length);
|
|
1120
|
-
} else if (nextStep.type === "select") {
|
|
1121
|
-
const opts = nextStep.getOptions?.(newValues) ?? nextStep.options ?? [];
|
|
1122
|
-
if (nextStep.defaultValue) {
|
|
1123
|
-
const idx = opts.findIndex((o) => o.value === nextStep.defaultValue);
|
|
1124
|
-
setSelectIndex(idx >= 0 ? idx : 0);
|
|
1125
|
-
} else {
|
|
1126
|
-
setSelectIndex(0);
|
|
1127
|
-
}
|
|
1128
|
-
} else if (nextStep.type === "multiselect") {
|
|
1129
|
-
setSelectIndex(0);
|
|
1130
|
-
if (nextStep.defaultValue) {
|
|
1131
|
-
setMultiSelected(new Set(nextStep.defaultValue.split(",")));
|
|
1132
|
-
} else {
|
|
1133
|
-
setMultiSelected(/* @__PURE__ */ new Set());
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
};
|
|
1138
|
-
const goToPrevStep = () => {
|
|
1139
|
-
if (currentStep === 0) {
|
|
1140
|
-
onCancel();
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
const currentStepId = step.id;
|
|
1144
|
-
const currentOrigIdx = steps.findIndex((s) => s.id === currentStepId);
|
|
1145
|
-
let prevOrigIdx = currentOrigIdx - 1;
|
|
1146
|
-
while (prevOrigIdx >= 0) {
|
|
1147
|
-
const candidate = steps[prevOrigIdx];
|
|
1148
|
-
if (candidate && !candidate.skip?.(values)) break;
|
|
1149
|
-
prevOrigIdx--;
|
|
1150
|
-
}
|
|
1151
|
-
if (prevOrigIdx < 0) {
|
|
1152
|
-
onCancel();
|
|
1153
|
-
return;
|
|
1154
|
-
}
|
|
1155
|
-
const prevStepId = steps[prevOrigIdx].id;
|
|
1156
|
-
const prevActiveIdx = activeSteps.findIndex((s) => s.id === prevStepId);
|
|
1157
|
-
setCurrentStep(prevActiveIdx >= 0 ? prevActiveIdx : 0);
|
|
1158
|
-
const prevStep = steps[prevOrigIdx];
|
|
1159
|
-
if (prevStep.type === "text") {
|
|
1160
|
-
const val = values[prevStep.id] ?? prevStep.defaultValue ?? "";
|
|
1161
|
-
setTextInput(val);
|
|
1162
|
-
setCursorPos(val.length);
|
|
1163
|
-
} else if (prevStep.type === "textarea") {
|
|
1164
|
-
const val = values[prevStep.id] ?? prevStep.defaultValue ?? "";
|
|
1165
|
-
const lines = val ? val.split("\n") : [""];
|
|
1166
|
-
setTaLines(lines);
|
|
1167
|
-
setTaCursorRow(lines.length - 1);
|
|
1168
|
-
setTaCursorCol(lines[lines.length - 1].length);
|
|
1169
|
-
} else if (prevStep.type === "multiselect") {
|
|
1170
|
-
setSelectIndex(0);
|
|
1171
|
-
const prevVal = values[prevStep.id];
|
|
1172
|
-
setMultiSelected(prevVal ? new Set(prevVal.split(",")) : /* @__PURE__ */ new Set());
|
|
1173
|
-
} else {
|
|
1174
|
-
const prevOptions = prevStep.getOptions?.(values) ?? prevStep.options ?? [];
|
|
1175
|
-
const prevVal = values[prevStep.id];
|
|
1176
|
-
const idx = prevOptions.findIndex((o) => o.value === prevVal);
|
|
1177
|
-
setSelectIndex(idx >= 0 ? idx : 0);
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
useInput((input, key) => {
|
|
1181
|
-
if (!step) return;
|
|
1182
|
-
if (key.escape) {
|
|
1183
|
-
if (currentStep === 0) {
|
|
1184
|
-
onCancel();
|
|
1185
|
-
} else {
|
|
1186
|
-
goToPrevStep();
|
|
1187
|
-
}
|
|
1188
|
-
return;
|
|
1189
|
-
}
|
|
1190
|
-
if (step.type === "text") {
|
|
1191
|
-
if (key.return) {
|
|
1192
|
-
const val = textInput.trim();
|
|
1193
|
-
if (step.required && !val) return;
|
|
1194
|
-
goToNextStep(val);
|
|
1195
|
-
return;
|
|
1196
|
-
}
|
|
1197
|
-
if (key.leftArrow) {
|
|
1198
|
-
setCursorPos((p) => Math.max(0, p - 1));
|
|
1199
|
-
return;
|
|
1200
|
-
}
|
|
1201
|
-
if (key.rightArrow) {
|
|
1202
|
-
setCursorPos((p) => Math.min(textInput.length, p + 1));
|
|
1203
|
-
return;
|
|
1204
|
-
}
|
|
1205
|
-
if (key.backspace || key.delete) {
|
|
1206
|
-
if (cursorPos === 0 && textInput.length === 0 && currentStep > 0) {
|
|
1207
|
-
goToPrevStep();
|
|
1208
|
-
return;
|
|
1209
|
-
}
|
|
1210
|
-
if (cursorPos > 0) {
|
|
1211
|
-
setTextInput((v) => v.slice(0, cursorPos - 1) + v.slice(cursorPos));
|
|
1212
|
-
setCursorPos((p) => p - 1);
|
|
1213
|
-
}
|
|
1214
|
-
return;
|
|
1215
|
-
}
|
|
1216
|
-
if (input && !key.ctrl && !key.meta && !key.escape) {
|
|
1217
|
-
setTextInput((v) => v.slice(0, cursorPos) + input + v.slice(cursorPos));
|
|
1218
|
-
setCursorPos((p) => p + input.length);
|
|
1219
|
-
}
|
|
1220
|
-
return;
|
|
1221
|
-
}
|
|
1222
|
-
if (step.type === "textarea") {
|
|
1223
|
-
if (key.return && !key.shift) {
|
|
1224
|
-
const val = taLines.join("\n").trim();
|
|
1225
|
-
if (step.required && !val) return;
|
|
1226
|
-
goToNextStep(val);
|
|
1227
|
-
return;
|
|
1228
|
-
}
|
|
1229
|
-
if (key.return && key.shift) {
|
|
1230
|
-
setTaLines((lines) => {
|
|
1231
|
-
const line = lines[taCursorRow] ?? "";
|
|
1232
|
-
const before = line.slice(0, taCursorCol);
|
|
1233
|
-
const after = line.slice(taCursorCol);
|
|
1234
|
-
const newLines = [...lines];
|
|
1235
|
-
newLines.splice(taCursorRow, 1, before, after);
|
|
1236
|
-
return newLines;
|
|
1237
|
-
});
|
|
1238
|
-
setTaCursorRow((r) => r + 1);
|
|
1239
|
-
setTaCursorCol(0);
|
|
1240
|
-
return;
|
|
1241
|
-
}
|
|
1242
|
-
if (key.upArrow) {
|
|
1243
|
-
if (taCursorRow > 0) {
|
|
1244
|
-
setTaCursorRow((r) => r - 1);
|
|
1245
|
-
setTaCursorCol((c) => Math.min(c, (taLines[taCursorRow - 1] ?? "").length));
|
|
1246
|
-
}
|
|
1247
|
-
return;
|
|
1248
|
-
}
|
|
1249
|
-
if (key.downArrow) {
|
|
1250
|
-
if (taCursorRow < taLines.length - 1) {
|
|
1251
|
-
setTaCursorRow((r) => r + 1);
|
|
1252
|
-
setTaCursorCol((c) => Math.min(c, (taLines[taCursorRow + 1] ?? "").length));
|
|
1253
|
-
}
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
if (key.leftArrow) {
|
|
1257
|
-
if (taCursorCol > 0) {
|
|
1258
|
-
setTaCursorCol((c) => c - 1);
|
|
1259
|
-
} else if (taCursorRow > 0) {
|
|
1260
|
-
setTaCursorRow((r) => r - 1);
|
|
1261
|
-
setTaCursorCol((taLines[taCursorRow - 1] ?? "").length);
|
|
1262
|
-
}
|
|
1263
|
-
return;
|
|
1264
|
-
}
|
|
1265
|
-
if (key.rightArrow) {
|
|
1266
|
-
const lineLen = (taLines[taCursorRow] ?? "").length;
|
|
1267
|
-
if (taCursorCol < lineLen) {
|
|
1268
|
-
setTaCursorCol((c) => c + 1);
|
|
1269
|
-
} else if (taCursorRow < taLines.length - 1) {
|
|
1270
|
-
setTaCursorRow((r) => r + 1);
|
|
1271
|
-
setTaCursorCol(0);
|
|
1272
|
-
}
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
if (key.backspace || key.delete) {
|
|
1276
|
-
if (taCursorCol === 0 && taCursorRow === 0) {
|
|
1277
|
-
if (taLines.length === 1 && taLines[0] === "" && currentStep > 0) {
|
|
1278
|
-
goToPrevStep();
|
|
1279
|
-
}
|
|
1280
|
-
return;
|
|
1281
|
-
}
|
|
1282
|
-
if (taCursorCol > 0) {
|
|
1283
|
-
setTaLines((lines) => {
|
|
1284
|
-
const newLines = [...lines];
|
|
1285
|
-
const line = newLines[taCursorRow] ?? "";
|
|
1286
|
-
newLines[taCursorRow] = line.slice(0, taCursorCol - 1) + line.slice(taCursorCol);
|
|
1287
|
-
return newLines;
|
|
1288
|
-
});
|
|
1289
|
-
setTaCursorCol((c) => c - 1);
|
|
1290
|
-
} else {
|
|
1291
|
-
const mergedCol = (taLines[taCursorRow - 1] ?? "").length;
|
|
1292
|
-
setTaLines((lines) => {
|
|
1293
|
-
const newLines = [...lines];
|
|
1294
|
-
const prevLine = newLines[taCursorRow - 1] ?? "";
|
|
1295
|
-
const curLine = newLines[taCursorRow] ?? "";
|
|
1296
|
-
newLines.splice(taCursorRow - 1, 2, prevLine + curLine);
|
|
1297
|
-
return newLines;
|
|
1298
|
-
});
|
|
1299
|
-
setTaCursorCol(mergedCol);
|
|
1300
|
-
setTaCursorRow((r) => r - 1);
|
|
1301
|
-
}
|
|
1302
|
-
return;
|
|
1303
|
-
}
|
|
1304
|
-
if (input && !key.ctrl && !key.meta && !key.escape) {
|
|
1305
|
-
setTaLines((lines) => {
|
|
1306
|
-
const newLines = [...lines];
|
|
1307
|
-
const line = newLines[taCursorRow] ?? "";
|
|
1308
|
-
newLines[taCursorRow] = line.slice(0, taCursorCol) + input + line.slice(taCursorCol);
|
|
1309
|
-
return newLines;
|
|
1310
|
-
});
|
|
1311
|
-
setTaCursorCol((c) => c + input.length);
|
|
1312
|
-
}
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
if (step.type === "select" || step.type === "multiselect") {
|
|
1316
|
-
if (key.upArrow || input === "k") {
|
|
1317
|
-
setSelectIndex((i) => Math.max(0, i - 1));
|
|
1318
|
-
return;
|
|
1319
|
-
}
|
|
1320
|
-
if (key.downArrow || input === "j") {
|
|
1321
|
-
setSelectIndex((i) => Math.min(options.length - 1, i + 1));
|
|
1322
|
-
return;
|
|
1323
|
-
}
|
|
1324
|
-
if (key.backspace || key.delete) {
|
|
1325
|
-
goToPrevStep();
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
if (step.type === "select") {
|
|
1329
|
-
if (key.return || key.tab) {
|
|
1330
|
-
const selected = options[clampedSelectIndex];
|
|
1331
|
-
if (selected) goToNextStep(selected.value);
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
if (input >= "1" && input <= "9") {
|
|
1335
|
-
const idx = parseInt(input, 10) - 1;
|
|
1336
|
-
if (idx < options.length) {
|
|
1337
|
-
const selected = options[idx];
|
|
1338
|
-
if (selected) goToNextStep(selected.value);
|
|
1339
|
-
}
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
} else {
|
|
1343
|
-
if (input === " ") {
|
|
1344
|
-
const opt = options[clampedSelectIndex];
|
|
1345
|
-
if (opt) {
|
|
1346
|
-
setMultiSelected((prev) => {
|
|
1347
|
-
const next = new Set(prev);
|
|
1348
|
-
if (next.has(opt.value)) {
|
|
1349
|
-
next.delete(opt.value);
|
|
1350
|
-
} else {
|
|
1351
|
-
next.add(opt.value);
|
|
1352
|
-
}
|
|
1353
|
-
return next;
|
|
1354
|
-
});
|
|
1355
|
-
}
|
|
1356
|
-
return;
|
|
1357
|
-
}
|
|
1358
|
-
if (key.return) {
|
|
1359
|
-
const selected = Array.from(multiSelected).join(",");
|
|
1360
|
-
goToNextStep(selected);
|
|
1361
|
-
return;
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
});
|
|
1366
|
-
if (!step) return null;
|
|
1367
|
-
const progressText = `${currentStep + 1}/${totalSteps}`;
|
|
1368
|
-
const optionsH = Math.max(2, height - 4);
|
|
1369
|
-
let optScrollStart = 0;
|
|
1370
|
-
if (clampedSelectIndex >= optionsH) {
|
|
1371
|
-
optScrollStart = clampedSelectIndex - optionsH + 1;
|
|
1372
|
-
}
|
|
1373
|
-
const visibleOptions = options.slice(optScrollStart, optScrollStart + optionsH);
|
|
1374
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, children: [
|
|
1375
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1376
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, bold: true, children: title }),
|
|
1377
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1378
|
-
" ",
|
|
1379
|
-
LIGHT_RULE,
|
|
1380
|
-
LIGHT_RULE,
|
|
1381
|
-
" "
|
|
1382
|
-
] }),
|
|
1383
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
1384
|
-
"step ",
|
|
1385
|
-
progressText
|
|
1386
|
-
] })
|
|
1387
|
-
] }),
|
|
1388
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1389
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1390
|
-
activeSteps.map((s, i) => /* @__PURE__ */ jsxs(Text, { color: i === currentStep ? tuiColors.amber : i < currentStep ? tuiColors.green : tuiColors.ghost, children: [
|
|
1391
|
-
i === currentStep ? "\u25CF" : i < currentStep ? "\u2713" : "\u25CB",
|
|
1392
|
-
" "
|
|
1393
|
-
] }, s.id))
|
|
1394
|
-
] }),
|
|
1395
|
-
/* @__PURE__ */ jsxs(Box, { marginTop: 0, children: [
|
|
1396
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.white, bold: true, children: [
|
|
1397
|
-
" ",
|
|
1398
|
-
step.label
|
|
1399
|
-
] }),
|
|
1400
|
-
!step.required && /* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " (optional, Enter to skip)" })
|
|
1401
|
-
] }),
|
|
1402
|
-
step.type === "text" && /* @__PURE__ */ jsxs(Box, { children: [
|
|
1403
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.amber, children: [
|
|
1404
|
-
" ",
|
|
1405
|
-
">",
|
|
1406
|
-
" "
|
|
1407
|
-
] }),
|
|
1408
|
-
textInput.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1409
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, children: textInput.slice(0, cursorPos) }),
|
|
1410
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: CURSOR }),
|
|
1411
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, children: textInput.slice(cursorPos) })
|
|
1412
|
-
] }) : step.placeholder ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1413
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: step.placeholder }),
|
|
1414
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: CURSOR })
|
|
1415
|
-
] }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: CURSOR })
|
|
1416
|
-
] }),
|
|
1417
|
-
step.type === "textarea" && (() => {
|
|
1418
|
-
const taVisibleH = Math.max(3, height - 6);
|
|
1419
|
-
let taScrollStart = 0;
|
|
1420
|
-
if (taCursorRow >= taVisibleH) {
|
|
1421
|
-
taScrollStart = taCursorRow - taVisibleH + 1;
|
|
1422
|
-
}
|
|
1423
|
-
const visibleLines = taLines.slice(taScrollStart, taScrollStart + taVisibleH);
|
|
1424
|
-
const lineNumWidth = String(taLines.length).length;
|
|
1425
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1426
|
-
visibleLines.map((line, i) => {
|
|
1427
|
-
const realRow = i + taScrollStart;
|
|
1428
|
-
const lineNum = String(realRow + 1).padStart(lineNumWidth, " ");
|
|
1429
|
-
const isCursorLine = realRow === taCursorRow;
|
|
1430
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1431
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
1432
|
-
" ",
|
|
1433
|
-
lineNum,
|
|
1434
|
-
" "
|
|
1435
|
-
] }),
|
|
1436
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1437
|
-
"\u2502",
|
|
1438
|
-
" "
|
|
1439
|
-
] }),
|
|
1440
|
-
isCursorLine ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1441
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, children: line.slice(0, taCursorCol) }),
|
|
1442
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: CURSOR }),
|
|
1443
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, children: line.slice(taCursorCol) })
|
|
1444
|
-
] }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.silver, children: line || " " })
|
|
1445
|
-
] }, realRow);
|
|
1446
|
-
}),
|
|
1447
|
-
taLines.length === 1 && taLines[0] === "" && step.placeholder && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
1448
|
-
" ",
|
|
1449
|
-
"".padStart(lineNumWidth, " "),
|
|
1450
|
-
" ",
|
|
1451
|
-
step.placeholder
|
|
1452
|
-
] }) })
|
|
1453
|
-
] });
|
|
1454
|
-
})(),
|
|
1455
|
-
step.type === "select" && /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: visibleOptions.map((opt, i) => {
|
|
1456
|
-
const realIdx = i + optScrollStart;
|
|
1457
|
-
const isSelected = realIdx === clampedSelectIndex;
|
|
1458
|
-
const numLabel = realIdx < 9 ? `${realIdx + 1}` : " ";
|
|
1459
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1460
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? tuiColors.amber : tuiColors.ghost, children: isSelected ? " \u25B8 " : ` ${numLabel} ` }),
|
|
1461
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? tuiColors.white : tuiColors.silver, bold: isSelected, children: opt.label }),
|
|
1462
|
-
opt.hint && /* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, wrap: "truncate", children: [
|
|
1463
|
-
" ",
|
|
1464
|
-
LIGHT_RULE,
|
|
1465
|
-
" ",
|
|
1466
|
-
opt.hint.replace(/\n/g, " ")
|
|
1467
|
-
] })
|
|
1468
|
-
] }, opt.value);
|
|
1469
|
-
}) }),
|
|
1470
|
-
step.type === "multiselect" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1471
|
-
visibleOptions.map((opt, i) => {
|
|
1472
|
-
const realIdx = i + optScrollStart;
|
|
1473
|
-
const isSelected = realIdx === clampedSelectIndex;
|
|
1474
|
-
const isChecked = multiSelected.has(opt.value);
|
|
1475
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1476
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? tuiColors.amber : tuiColors.ghost, children: isSelected ? " \u25B8 " : " " }),
|
|
1477
|
-
/* @__PURE__ */ jsx(Text, { color: isChecked ? tuiColors.green : tuiColors.dim, children: isChecked ? "[\u2713]" : "[ ]" }),
|
|
1478
|
-
/* @__PURE__ */ jsxs(Text, { color: isSelected ? tuiColors.white : tuiColors.silver, bold: isSelected, children: [
|
|
1479
|
-
" ",
|
|
1480
|
-
opt.label
|
|
1481
|
-
] }),
|
|
1482
|
-
opt.hint && /* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, wrap: "truncate", children: [
|
|
1483
|
-
" ",
|
|
1484
|
-
LIGHT_RULE,
|
|
1485
|
-
" ",
|
|
1486
|
-
opt.hint.replace(/\n/g, " ")
|
|
1487
|
-
] })
|
|
1488
|
-
] }, opt.value);
|
|
1489
|
-
}),
|
|
1490
|
-
multiSelected.size > 0 && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
1491
|
-
" ",
|
|
1492
|
-
"\u2514",
|
|
1493
|
-
" ",
|
|
1494
|
-
multiSelected.size,
|
|
1495
|
-
" selected"
|
|
1496
|
-
] }) })
|
|
1497
|
-
] }),
|
|
1498
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1499
|
-
" ",
|
|
1500
|
-
step.type === "select" ? "\u2191\u2193 select Enter confirm" : step.type === "multiselect" ? "\u2191\u2193 move Space toggle Enter confirm" : step.type === "textarea" ? "Shift+Enter newline Enter confirm \u2190\u2191\u2192\u2193 navigate" : "\u2190\u2192 move Enter confirm",
|
|
1501
|
-
" Esc ",
|
|
1502
|
-
currentStep > 0 ? "back" : "cancel"
|
|
1503
|
-
] }) })
|
|
1504
|
-
] });
|
|
1505
|
-
}
|
|
1506
|
-
var TL = "\u256D";
|
|
1507
|
-
var TR = "\u256E";
|
|
1508
|
-
var BL = "\u2570";
|
|
1509
|
-
var BR = "\u256F";
|
|
1510
|
-
var V = "\u2502";
|
|
1511
|
-
function Row({ children, cw }) {
|
|
1512
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1513
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: V }),
|
|
1514
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1515
|
-
" ",
|
|
1516
|
-
children.padEnd(cw),
|
|
1517
|
-
" "
|
|
1518
|
-
] }),
|
|
1519
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: V })
|
|
1520
|
-
] });
|
|
1521
|
-
}
|
|
1522
|
-
function EmptyRow({ cw }) {
|
|
1523
|
-
return /* @__PURE__ */ jsx(Row, { cw, children: "" });
|
|
1524
|
-
}
|
|
1525
|
-
function OnboardingBox({ count, config, width }) {
|
|
1526
|
-
if (count >= 3) return null;
|
|
1527
|
-
const boxW = Math.min((width ?? 44) - 4, 50);
|
|
1528
|
-
const cw = boxW - 6;
|
|
1529
|
-
const hLine = LIGHT_RULE.repeat(boxW - 2);
|
|
1530
|
-
const topBorder = /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1531
|
-
TL,
|
|
1532
|
-
hLine,
|
|
1533
|
-
TR
|
|
1534
|
-
] });
|
|
1535
|
-
const botBorder = /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1536
|
-
BL,
|
|
1537
|
-
hLine,
|
|
1538
|
-
BR
|
|
1539
|
-
] });
|
|
1540
|
-
if (count > 0) {
|
|
1541
|
-
const hint = config.hints[0];
|
|
1542
|
-
const hintSuffix = hint ? ` ${hint.key} ${hint.label}` : "";
|
|
1543
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, children: [
|
|
1544
|
-
topBorder,
|
|
1545
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1546
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1547
|
-
V,
|
|
1548
|
-
" "
|
|
1549
|
-
] }),
|
|
1550
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: DIAMOND }),
|
|
1551
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.silver, children: [
|
|
1552
|
-
" ",
|
|
1553
|
-
config.nudge.padEnd(cw - 2 - hintSuffix.length)
|
|
1554
|
-
] }),
|
|
1555
|
-
hint && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1556
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.amber, children: [
|
|
1557
|
-
" ",
|
|
1558
|
-
hint.key
|
|
1559
|
-
] }),
|
|
1560
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.gray, children: [
|
|
1561
|
-
" ",
|
|
1562
|
-
hint.label
|
|
1563
|
-
] })
|
|
1564
|
-
] }),
|
|
1565
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1566
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: V })
|
|
1567
|
-
] }),
|
|
1568
|
-
botBorder
|
|
1569
|
-
] });
|
|
1570
|
-
}
|
|
1571
|
-
const hintsLen = config.hints.reduce((acc, h, i) => acc + h.key.length + 1 + h.label.length + (i > 0 ? 3 : 0), 0);
|
|
1572
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, children: [
|
|
1573
|
-
topBorder,
|
|
1574
|
-
/* @__PURE__ */ jsx(EmptyRow, { cw }),
|
|
1575
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1576
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1577
|
-
V,
|
|
1578
|
-
" "
|
|
1579
|
-
] }),
|
|
1580
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: DIAMOND }),
|
|
1581
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.white, bold: true, children: [
|
|
1582
|
-
" ",
|
|
1583
|
-
config.title
|
|
1584
|
-
] }),
|
|
1585
|
-
/* @__PURE__ */ jsx(Text, { children: " ".repeat(Math.max(0, cw - config.title.length - 2)) }),
|
|
1586
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1587
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: V })
|
|
1588
|
-
] }),
|
|
1589
|
-
/* @__PURE__ */ jsx(EmptyRow, { cw }),
|
|
1590
|
-
config.description.map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
1591
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1592
|
-
V,
|
|
1593
|
-
" "
|
|
1594
|
-
] }),
|
|
1595
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.silver, children: line.padEnd(cw) }),
|
|
1596
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1597
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: V })
|
|
1598
|
-
] }, i)),
|
|
1599
|
-
/* @__PURE__ */ jsx(EmptyRow, { cw }),
|
|
1600
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1601
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
1602
|
-
V,
|
|
1603
|
-
" "
|
|
1604
|
-
] }),
|
|
1605
|
-
config.hints.map((h, i) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
|
|
1606
|
-
i > 0 && /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " " }),
|
|
1607
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: h.key }),
|
|
1608
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.gray, children: [
|
|
1609
|
-
" ",
|
|
1610
|
-
h.label
|
|
1611
|
-
] })
|
|
1612
|
-
] }, i)),
|
|
1613
|
-
/* @__PURE__ */ jsx(Text, { children: " ".repeat(Math.max(0, cw - hintsLen)) }),
|
|
1614
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
1615
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: V })
|
|
1616
|
-
] }),
|
|
1617
|
-
/* @__PURE__ */ jsx(EmptyRow, { cw }),
|
|
1618
|
-
botBorder
|
|
1619
|
-
] });
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
// src/tui/wizardConfigs.ts
|
|
1623
|
-
var CLAUDE_MODELS = [
|
|
1624
|
-
{ value: "claude-opus-4-6", label: "Claude Opus 4.6", hint: "most capable" },
|
|
1625
|
-
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", hint: "fast, balanced" },
|
|
1626
|
-
{ value: "claude-haiku-4-6", label: "Claude Haiku 4.6", hint: "fastest, cheapest" },
|
|
1627
|
-
{ value: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", hint: "extended thinking" },
|
|
1628
|
-
{ value: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5", hint: "legacy" }
|
|
1629
|
-
];
|
|
1630
|
-
var CODEX_MODELS = [
|
|
1631
|
-
{ value: "gpt-5.3-codex", label: "GPT-5.3 Codex", hint: "default, balanced" },
|
|
1632
|
-
{ value: "gpt-5.4", label: "GPT-5.4", hint: "latest" },
|
|
1633
|
-
{ value: "gpt-5", label: "GPT-5", hint: "capable" },
|
|
1634
|
-
{ value: "gpt-5.3-codex-spark", label: "GPT-5.3 Codex Spark", hint: "fast" },
|
|
1635
|
-
{ value: "o3", label: "o3", hint: "reasoning" },
|
|
1636
|
-
{ value: "o4-mini", label: "o4-mini", hint: "fast reasoning" },
|
|
1637
|
-
{ value: "gpt-5-mini", label: "GPT-5 Mini", hint: "light" },
|
|
1638
|
-
{ value: "gpt-5-nano", label: "GPT-5 Nano", hint: "cheapest" },
|
|
1639
|
-
{ value: "codex-mini-latest", label: "Codex Mini", hint: "legacy" }
|
|
1640
|
-
];
|
|
1641
|
-
var CURSOR_MODELS = [
|
|
1642
|
-
{ value: "auto", label: "Auto", hint: "let Cursor decide" },
|
|
1643
|
-
{ value: "composer-1.5", label: "Composer 1.5", hint: "latest agent" },
|
|
1644
|
-
{ value: "composer-1", label: "Composer 1", hint: "stable agent" },
|
|
1645
|
-
{ value: "gpt-5.3-codex", label: "GPT-5.3 Codex", hint: "OpenAI" },
|
|
1646
|
-
{ value: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", hint: "Anthropic" }
|
|
1647
|
-
];
|
|
1648
|
-
var SHELL_MODELS = [
|
|
1649
|
-
{ value: "", label: "Default", hint: "use shell adapter default" }
|
|
1650
|
-
];
|
|
1651
|
-
var ADAPTERS = [
|
|
1652
|
-
{ value: "claude", label: "Claude", hint: "Claude Code CLI" },
|
|
1653
|
-
{ value: "codex", label: "Codex", hint: "OpenAI Codex CLI" },
|
|
1654
|
-
{ value: "cursor", label: "Cursor", hint: "Cursor Agent CLI" },
|
|
1655
|
-
{ value: "shell", label: "Shell", hint: "custom shell command" }
|
|
1656
|
-
];
|
|
1657
|
-
var PRIORITY_OPTIONS = [
|
|
1658
|
-
{ value: "1", label: "P1 Critical", hint: "urgent, do first" },
|
|
1659
|
-
{ value: "2", label: "P2 High", hint: "important" },
|
|
1660
|
-
{ value: "3", label: "P3 Medium", hint: "default priority" },
|
|
1661
|
-
{ value: "4", label: "P4 Low", hint: "nice to have" }
|
|
1662
|
-
];
|
|
1663
|
-
var AGENT_HINT_MAX_LEN = 80;
|
|
1664
|
-
function mapAgentOptions(agents) {
|
|
1665
|
-
return agents.filter((a) => a.status !== "disabled").map((a) => {
|
|
1666
|
-
const raw = a.role ?? a.adapter;
|
|
1667
|
-
const hint = raw.length > AGENT_HINT_MAX_LEN ? raw.slice(0, AGENT_HINT_MAX_LEN - 1) + "\u2026" : raw;
|
|
1668
|
-
return { value: a.id, label: a.name, hint };
|
|
1669
|
-
});
|
|
1670
|
-
}
|
|
1671
|
-
function buildAgentOptions(agents, emptyLabel = "Auto-assign", emptyHint = "orchestrator picks the best agent") {
|
|
1672
|
-
return [
|
|
1673
|
-
{ value: "", label: emptyLabel, hint: emptyHint },
|
|
1674
|
-
...mapAgentOptions(agents)
|
|
1675
|
-
];
|
|
1676
|
-
}
|
|
1677
|
-
var ROLE_PRESETS = [
|
|
1678
|
-
{ value: "", label: "Skip", hint: "no role description" },
|
|
1679
|
-
{ value: "Full-stack developer", label: "Full-stack developer", hint: "general purpose" },
|
|
1680
|
-
{ value: "Frontend developer", label: "Frontend developer", hint: "React, CSS, UI" },
|
|
1681
|
-
{ value: "Backend developer", label: "Backend developer", hint: "APIs, databases, services" },
|
|
1682
|
-
{ value: "DevOps engineer", label: "DevOps engineer", hint: "CI/CD, infra, deploys" },
|
|
1683
|
-
{ value: "QA / Test engineer", label: "QA / Test engineer", hint: "testing, quality" },
|
|
1684
|
-
{ value: "Code reviewer", label: "Code reviewer", hint: "review PRs, find bugs" },
|
|
1685
|
-
{ value: "Technical writer", label: "Technical writer", hint: "docs, READMEs" },
|
|
1686
|
-
{ value: "__custom__", label: "Custom...", hint: "type your own" }
|
|
1687
|
-
];
|
|
1688
|
-
function buildTeamOptions(teams) {
|
|
1689
|
-
return [
|
|
1690
|
-
{ value: "", label: "None", hint: "no team" },
|
|
1691
|
-
...(teams ?? []).filter((t) => t.status === "active").map((t) => ({ value: t.id, label: t.name, hint: `${t.members.length} members` }))
|
|
1692
|
-
];
|
|
1693
|
-
}
|
|
1694
|
-
function getAgentWizardSteps(teams) {
|
|
1695
|
-
const teamOptions = buildTeamOptions(teams);
|
|
1696
|
-
return [
|
|
1697
|
-
{
|
|
1698
|
-
id: "name",
|
|
1699
|
-
label: "Agent name",
|
|
1700
|
-
type: "text",
|
|
1701
|
-
placeholder: "e.g. alpha, frontend-bot, reviewer",
|
|
1702
|
-
required: true
|
|
1703
|
-
},
|
|
1704
|
-
{
|
|
1705
|
-
id: "adapter",
|
|
1706
|
-
label: "Provider",
|
|
1707
|
-
type: "select",
|
|
1708
|
-
options: ADAPTERS
|
|
1709
|
-
},
|
|
1710
|
-
{
|
|
1711
|
-
id: "model",
|
|
1712
|
-
label: "Model",
|
|
1713
|
-
type: "select",
|
|
1714
|
-
getOptions: (vals) => {
|
|
1715
|
-
if (vals.adapter === "codex") return CODEX_MODELS;
|
|
1716
|
-
if (vals.adapter === "cursor") return CURSOR_MODELS;
|
|
1717
|
-
if (vals.adapter === "shell") return SHELL_MODELS;
|
|
1718
|
-
return CLAUDE_MODELS;
|
|
1719
|
-
}
|
|
1720
|
-
},
|
|
1721
|
-
{
|
|
1722
|
-
id: "role",
|
|
1723
|
-
label: "Role / specialization",
|
|
1724
|
-
type: "select",
|
|
1725
|
-
options: ROLE_PRESETS
|
|
1726
|
-
},
|
|
1727
|
-
{
|
|
1728
|
-
id: "role_custom",
|
|
1729
|
-
label: "Describe the role",
|
|
1730
|
-
type: "textarea",
|
|
1731
|
-
placeholder: "e.g. Specialist in React and TypeScript",
|
|
1732
|
-
skip: (vals) => vals.role !== "__custom__"
|
|
1733
|
-
},
|
|
1734
|
-
{
|
|
1735
|
-
id: "team",
|
|
1736
|
-
label: "Join team",
|
|
1737
|
-
type: "select",
|
|
1738
|
-
options: teamOptions,
|
|
1739
|
-
skip: () => teamOptions.length <= 1
|
|
1740
|
-
// Skip if no teams exist
|
|
1741
|
-
}
|
|
1742
|
-
];
|
|
1743
|
-
}
|
|
1744
|
-
function agentWizardToInput(vals) {
|
|
1745
|
-
const role = vals.role === "__custom__" ? vals.role_custom || void 0 : vals.role || void 0;
|
|
1746
|
-
return {
|
|
1747
|
-
name: vals.name,
|
|
1748
|
-
adapter: vals.adapter || "claude",
|
|
1749
|
-
role,
|
|
1750
|
-
model: vals.model || void 0,
|
|
1751
|
-
approval_policy: "auto",
|
|
1752
|
-
team_id: vals.team || void 0
|
|
1753
|
-
};
|
|
1754
|
-
}
|
|
1755
|
-
function getTeamWizardSteps(agents) {
|
|
1756
|
-
const agentOptions = mapAgentOptions(agents);
|
|
1757
|
-
return [
|
|
1758
|
-
{
|
|
1759
|
-
id: "name",
|
|
1760
|
-
label: "Team name",
|
|
1761
|
-
type: "text",
|
|
1762
|
-
placeholder: "e.g. frontend, backend, qa",
|
|
1763
|
-
required: true
|
|
1764
|
-
},
|
|
1765
|
-
{
|
|
1766
|
-
id: "lead",
|
|
1767
|
-
label: "Team lead",
|
|
1768
|
-
type: "select",
|
|
1769
|
-
options: agentOptions
|
|
1770
|
-
},
|
|
1771
|
-
{
|
|
1772
|
-
id: "members",
|
|
1773
|
-
label: "Team members",
|
|
1774
|
-
type: "multiselect",
|
|
1775
|
-
getOptions: (vals) => agentOptions.filter((a) => a.value !== vals.lead),
|
|
1776
|
-
skip: (vals) => !agentOptions.some((a) => a.value !== vals.lead)
|
|
1777
|
-
},
|
|
1778
|
-
{
|
|
1779
|
-
id: "description",
|
|
1780
|
-
label: "Description",
|
|
1781
|
-
type: "textarea",
|
|
1782
|
-
placeholder: "Optional team purpose..."
|
|
1783
|
-
}
|
|
1784
|
-
];
|
|
1785
|
-
}
|
|
1786
|
-
function teamWizardToInput(vals) {
|
|
1787
|
-
const memberIds = vals.members ? vals.members.split(",").filter(Boolean) : [];
|
|
1788
|
-
return {
|
|
1789
|
-
name: vals.name,
|
|
1790
|
-
lead_agent_id: vals.lead,
|
|
1791
|
-
member_agent_ids: memberIds.length > 0 ? memberIds : void 0,
|
|
1792
|
-
description: vals.description || void 0
|
|
1793
|
-
};
|
|
1794
|
-
}
|
|
1795
|
-
function getTaskWizardSteps(agents) {
|
|
1796
|
-
const agentOptions = buildAgentOptions(agents);
|
|
1797
|
-
return [
|
|
1798
|
-
{
|
|
1799
|
-
id: "title",
|
|
1800
|
-
label: "Task title",
|
|
1801
|
-
type: "text",
|
|
1802
|
-
placeholder: "What needs to be done?",
|
|
1803
|
-
required: true
|
|
1804
|
-
},
|
|
1805
|
-
{
|
|
1806
|
-
id: "priority",
|
|
1807
|
-
label: "Priority",
|
|
1808
|
-
type: "select",
|
|
1809
|
-
options: PRIORITY_OPTIONS,
|
|
1810
|
-
defaultValue: "3"
|
|
1811
|
-
},
|
|
1812
|
-
{
|
|
1813
|
-
id: "assignee",
|
|
1814
|
-
label: "Assignee",
|
|
1815
|
-
type: "select",
|
|
1816
|
-
options: agentOptions,
|
|
1817
|
-
skip: () => agentOptions.length <= 1
|
|
1818
|
-
// Skip if no agents to choose from
|
|
1819
|
-
},
|
|
1820
|
-
{
|
|
1821
|
-
id: "description",
|
|
1822
|
-
label: "Description",
|
|
1823
|
-
type: "textarea",
|
|
1824
|
-
placeholder: "Optional details, context, acceptance criteria..."
|
|
1825
|
-
}
|
|
1826
|
-
];
|
|
1827
|
-
}
|
|
1828
|
-
function taskWizardToInput(vals) {
|
|
1829
|
-
return {
|
|
1830
|
-
title: vals.title,
|
|
1831
|
-
priority: vals.priority ? parseInt(vals.priority, 10) : void 0,
|
|
1832
|
-
assignee: vals.assignee || void 0,
|
|
1833
|
-
description: vals.description || void 0
|
|
1834
|
-
};
|
|
1835
|
-
}
|
|
1836
|
-
function getEditTaskWizardSteps(task, agents) {
|
|
1837
|
-
const agentOptions = buildAgentOptions(agents, "None / Auto", "remove assignee");
|
|
1838
|
-
return [
|
|
1839
|
-
{
|
|
1840
|
-
id: "title",
|
|
1841
|
-
label: "Task title",
|
|
1842
|
-
type: "text",
|
|
1843
|
-
defaultValue: task.title,
|
|
1844
|
-
required: true
|
|
1845
|
-
},
|
|
1846
|
-
{
|
|
1847
|
-
id: "priority",
|
|
1848
|
-
label: "Priority",
|
|
1849
|
-
type: "select",
|
|
1850
|
-
options: PRIORITY_OPTIONS,
|
|
1851
|
-
defaultValue: String(task.priority)
|
|
1852
|
-
},
|
|
1853
|
-
{
|
|
1854
|
-
id: "assignee",
|
|
1855
|
-
label: "Assignee",
|
|
1856
|
-
type: "select",
|
|
1857
|
-
options: agentOptions,
|
|
1858
|
-
defaultValue: task.assignee ?? "",
|
|
1859
|
-
skip: () => agentOptions.length <= 1
|
|
1860
|
-
},
|
|
1861
|
-
{
|
|
1862
|
-
id: "description",
|
|
1863
|
-
label: "Description",
|
|
1864
|
-
type: "textarea",
|
|
1865
|
-
defaultValue: task.description || "",
|
|
1866
|
-
placeholder: "Optional details..."
|
|
1867
|
-
}
|
|
1868
|
-
];
|
|
1869
|
-
}
|
|
1870
|
-
function editTaskWizardToFields(vals) {
|
|
1871
|
-
return {
|
|
1872
|
-
title: vals.title,
|
|
1873
|
-
priority: vals.priority ? parseInt(vals.priority, 10) : void 0,
|
|
1874
|
-
assignee: vals.assignee || void 0,
|
|
1875
|
-
description: vals.description ?? ""
|
|
1876
|
-
};
|
|
1877
|
-
}
|
|
1878
|
-
function getEditAgentWizardSteps(agent, teams) {
|
|
1879
|
-
const currentRoleInPresets = ROLE_PRESETS.find((r) => r.value === agent.role);
|
|
1880
|
-
const roleDefault = currentRoleInPresets ? agent.role : agent.role ? "__custom__" : "";
|
|
1881
|
-
const modelOptions = agent.adapter === "codex" ? CODEX_MODELS : agent.adapter === "cursor" ? CURSOR_MODELS : agent.adapter === "shell" ? SHELL_MODELS : CLAUDE_MODELS;
|
|
1882
|
-
const teamOptions = buildTeamOptions(teams);
|
|
1883
|
-
const currentTeamId = teams?.find((t) => t.members.some((m) => m.agent_id === agent.id))?.id;
|
|
1884
|
-
return [
|
|
1885
|
-
{
|
|
1886
|
-
id: "name",
|
|
1887
|
-
label: "Agent name",
|
|
1888
|
-
type: "text",
|
|
1889
|
-
defaultValue: agent.name,
|
|
1890
|
-
required: true
|
|
1891
|
-
},
|
|
1892
|
-
{
|
|
1893
|
-
id: "model",
|
|
1894
|
-
label: "Model",
|
|
1895
|
-
type: "select",
|
|
1896
|
-
options: modelOptions,
|
|
1897
|
-
defaultValue: agent.config.model ?? ""
|
|
1898
|
-
},
|
|
1899
|
-
{
|
|
1900
|
-
id: "role",
|
|
1901
|
-
label: "Role / specialization",
|
|
1902
|
-
type: "select",
|
|
1903
|
-
options: ROLE_PRESETS,
|
|
1904
|
-
defaultValue: roleDefault
|
|
1905
|
-
},
|
|
1906
|
-
{
|
|
1907
|
-
id: "role_custom",
|
|
1908
|
-
label: "Describe the role",
|
|
1909
|
-
type: "textarea",
|
|
1910
|
-
defaultValue: agent.role && !currentRoleInPresets ? agent.role : "",
|
|
1911
|
-
placeholder: "e.g. Specialist in React and TypeScript",
|
|
1912
|
-
skip: (vals) => vals.role !== "__custom__"
|
|
1913
|
-
},
|
|
1914
|
-
{
|
|
1915
|
-
id: "team",
|
|
1916
|
-
label: "Team",
|
|
1917
|
-
type: "select",
|
|
1918
|
-
options: teamOptions,
|
|
1919
|
-
defaultValue: currentTeamId ?? "",
|
|
1920
|
-
skip: () => teamOptions.length <= 1
|
|
1921
|
-
}
|
|
1922
|
-
];
|
|
1923
|
-
}
|
|
1924
|
-
var MAX_CONCURRENT_OPTIONS = [
|
|
1925
|
-
{ value: "1", label: "1 agent", hint: "~0.5 GB RAM, 1 subprocess" },
|
|
1926
|
-
{ value: "2", label: "2 agents", hint: "~1 GB RAM, 2 subprocesses" },
|
|
1927
|
-
{ value: "3", label: "3 agents", hint: "~1.5 GB RAM, 3 subprocesses" },
|
|
1928
|
-
{ value: "4", label: "4 agents", hint: "~2 GB RAM, 4 subprocesses" },
|
|
1929
|
-
{ value: "6", label: "6 agents", hint: "~3 GB RAM, 6 subprocesses" },
|
|
1930
|
-
{ value: "8", label: "8 agents", hint: "~4 GB RAM, 8 subprocesses" },
|
|
1931
|
-
{ value: "10", label: "10 agents", hint: "~5 GB RAM, 10 subprocesses" }
|
|
1932
|
-
];
|
|
1933
|
-
var ACTIVITY_FILTER_OPTIONS = [
|
|
1934
|
-
{ value: "all", label: "All", hint: "show everything" },
|
|
1935
|
-
{ value: "text", label: "Text", hint: "agent output only" },
|
|
1936
|
-
{ value: "tools", label: "Tools", hint: "tool calls, results, files" },
|
|
1937
|
-
{ value: "errors", label: "Errors", hint: "errors only" },
|
|
1938
|
-
{ value: "events", label: "Events", hint: "lifecycle, system events" }
|
|
1939
|
-
];
|
|
1940
|
-
function getConfigWizardSteps(currentFilter, currentMaxConcurrent) {
|
|
1941
|
-
return [
|
|
1942
|
-
{
|
|
1943
|
-
id: "setting",
|
|
1944
|
-
label: "Setting",
|
|
1945
|
-
type: "select",
|
|
1946
|
-
options: [
|
|
1947
|
-
{ value: "activity_filter", label: "Activity filter", hint: `current: ${currentFilter}` },
|
|
1948
|
-
{ value: "max_concurrent", label: "Max concurrent agents", hint: `current: ${currentMaxConcurrent}` }
|
|
1949
|
-
]
|
|
1950
|
-
},
|
|
1951
|
-
{
|
|
1952
|
-
id: "activity_filter",
|
|
1953
|
-
label: "Activity filter preset",
|
|
1954
|
-
type: "select",
|
|
1955
|
-
options: ACTIVITY_FILTER_OPTIONS,
|
|
1956
|
-
defaultValue: currentFilter,
|
|
1957
|
-
skip: (vals) => vals.setting !== "activity_filter"
|
|
1958
|
-
},
|
|
1959
|
-
{
|
|
1960
|
-
id: "max_concurrent",
|
|
1961
|
-
label: "Max concurrent agents",
|
|
1962
|
-
type: "select",
|
|
1963
|
-
options: MAX_CONCURRENT_OPTIONS,
|
|
1964
|
-
defaultValue: String(currentMaxConcurrent),
|
|
1965
|
-
skip: (vals) => vals.setting !== "max_concurrent"
|
|
1966
|
-
}
|
|
1967
|
-
];
|
|
1968
|
-
}
|
|
1969
|
-
function editAgentWizardToFields(vals) {
|
|
1970
|
-
const role = vals.role === "__custom__" ? vals.role_custom || void 0 : vals.role || void 0;
|
|
1971
|
-
return {
|
|
1972
|
-
name: vals.name,
|
|
1973
|
-
role,
|
|
1974
|
-
model: vals.model || void 0,
|
|
1975
|
-
team_id: vals.team || void 0
|
|
1976
|
-
};
|
|
1977
|
-
}
|
|
1978
|
-
function getGoalWizardSteps(agents) {
|
|
1979
|
-
const agentOptions = buildAgentOptions(agents, "Any agent", "auto-assign to autonomous agents");
|
|
1980
|
-
return [
|
|
1981
|
-
{
|
|
1982
|
-
id: "title",
|
|
1983
|
-
label: "Goal title",
|
|
1984
|
-
type: "text",
|
|
1985
|
-
placeholder: "What should be achieved?",
|
|
1986
|
-
required: true
|
|
1987
|
-
},
|
|
1988
|
-
{
|
|
1989
|
-
id: "assignee",
|
|
1990
|
-
label: "Assignee",
|
|
1991
|
-
type: "select",
|
|
1992
|
-
options: agentOptions,
|
|
1993
|
-
skip: () => agentOptions.length <= 1
|
|
1994
|
-
},
|
|
1995
|
-
{
|
|
1996
|
-
id: "description",
|
|
1997
|
-
label: "Description",
|
|
1998
|
-
type: "textarea",
|
|
1999
|
-
placeholder: "Detailed goal description, success criteria..."
|
|
2000
|
-
}
|
|
2001
|
-
];
|
|
2002
|
-
}
|
|
2003
|
-
function goalWizardToInput(vals) {
|
|
2004
|
-
return {
|
|
2005
|
-
title: vals.title,
|
|
2006
|
-
assignee: vals.assignee || void 0,
|
|
2007
|
-
description: vals.description || void 0
|
|
2008
|
-
};
|
|
2009
|
-
}
|
|
2010
|
-
function getEditGoalWizardSteps(goal, agents) {
|
|
2011
|
-
const agentOptions = buildAgentOptions(agents, "Any agent", "auto-assign");
|
|
2012
|
-
return [
|
|
2013
|
-
{
|
|
2014
|
-
id: "title",
|
|
2015
|
-
label: "Goal title",
|
|
2016
|
-
type: "text",
|
|
2017
|
-
defaultValue: goal.title,
|
|
2018
|
-
required: true
|
|
2019
|
-
},
|
|
2020
|
-
{
|
|
2021
|
-
id: "assignee",
|
|
2022
|
-
label: "Assignee",
|
|
2023
|
-
type: "select",
|
|
2024
|
-
options: agentOptions,
|
|
2025
|
-
defaultValue: goal.assignee ?? "",
|
|
2026
|
-
skip: () => agentOptions.length <= 1
|
|
2027
|
-
},
|
|
2028
|
-
{
|
|
2029
|
-
id: "description",
|
|
2030
|
-
label: "Description",
|
|
2031
|
-
type: "textarea",
|
|
2032
|
-
defaultValue: goal.description || "",
|
|
2033
|
-
placeholder: "Detailed goal description..."
|
|
2034
|
-
}
|
|
2035
|
-
];
|
|
2036
|
-
}
|
|
2037
|
-
function editGoalWizardToFields(vals) {
|
|
2038
|
-
return {
|
|
2039
|
-
title: vals.title,
|
|
2040
|
-
assignee: vals.assignee || void 0,
|
|
2041
|
-
description: vals.description ?? ""
|
|
2042
|
-
};
|
|
2043
|
-
}
|
|
2044
|
-
var TASK_LIST_LIMIT = 10;
|
|
2045
|
-
var MAX_RUN_MAP_SIZE = 500;
|
|
2046
|
-
var MAX_DETAIL_LEN = 2048;
|
|
2047
|
-
var MAX_MESSAGES = 200;
|
|
2048
|
-
var RUNNABLE = /* @__PURE__ */ new Set(["todo", "failed", "cancelled"]);
|
|
2049
|
-
var ONBOARDING_GOALS = {
|
|
2050
|
-
title: "Goals",
|
|
2051
|
-
description: [
|
|
2052
|
-
"Define what your team should achieve.",
|
|
2053
|
-
"The orchestrator breaks goals into tasks",
|
|
2054
|
-
"and assigns them to agents automatically."
|
|
2055
|
-
],
|
|
2056
|
-
hints: [{ key: "N", label: "new goal" }, { key: "/", label: "commands" }],
|
|
2057
|
-
nudge: "Add more goals to keep your team focused."
|
|
2058
|
-
};
|
|
2059
|
-
var ONBOARDING_TASKS = {
|
|
2060
|
-
title: "Tasks",
|
|
2061
|
-
description: [
|
|
2062
|
-
"Units of work dispatched to agents.",
|
|
2063
|
-
"Create them manually or let goals",
|
|
2064
|
-
"generate them automatically."
|
|
2065
|
-
],
|
|
2066
|
-
hints: [{ key: "N", label: "new task" }, { key: "W", label: "start orchestrator" }],
|
|
2067
|
-
nudge: "Add more tasks to keep agents busy."
|
|
2068
|
-
};
|
|
2069
|
-
var ONBOARDING_AGENTS = {
|
|
2070
|
-
title: "Agents",
|
|
2071
|
-
description: [
|
|
2072
|
-
"AI workers that execute your tasks.",
|
|
2073
|
-
"Each agent uses an adapter (claude, codex,",
|
|
2074
|
-
"cursor, shell) and has its own role."
|
|
2075
|
-
],
|
|
2076
|
-
hints: [{ key: "N", label: "new agent" }, { key: "W", label: "start orchestrator" }],
|
|
2077
|
-
nudge: "Add more agents to increase parallelism."
|
|
2078
|
-
};
|
|
2079
|
-
var LIFECYCLE_TAG_RE = /^\[[\w_]+\]$/;
|
|
2080
|
-
function classifyAgentSummary(summary) {
|
|
2081
|
-
if (LIFECYCLE_TAG_RE.test(summary)) return { msgType: "lifecycle", color: tuiColors.dim };
|
|
2082
|
-
if (summary.startsWith("\u2699")) return { msgType: "tool", color: tuiColors.dim };
|
|
2083
|
-
if (summary.startsWith("\u2190")) return { msgType: "result", color: tuiColors.dim };
|
|
2084
|
-
if (summary.startsWith("\u2713")) return { msgType: "lifecycle", color: tuiColors.dim };
|
|
2085
|
-
if (summary.startsWith("\u23F3")) return { msgType: "info", color: tuiColors.silver };
|
|
2086
|
-
return { msgType: "output", color: tuiColors.silver };
|
|
2087
|
-
}
|
|
2088
|
-
var AGENT_COLORS = [
|
|
2089
|
-
"#5faf87",
|
|
2090
|
-
// green
|
|
2091
|
-
"#5fafd7",
|
|
2092
|
-
// blue
|
|
2093
|
-
"#af87ff",
|
|
2094
|
-
// purple
|
|
2095
|
-
"#d7af00",
|
|
2096
|
-
// yellow
|
|
2097
|
-
"#5fd7d7",
|
|
2098
|
-
// cyan
|
|
2099
|
-
"#d787af",
|
|
2100
|
-
// pink
|
|
2101
|
-
"#afaf5f",
|
|
2102
|
-
// olive
|
|
2103
|
-
"#d7875f"
|
|
2104
|
-
// orange
|
|
2105
|
-
];
|
|
2106
|
-
function getAgentColor(agentId, agents) {
|
|
2107
|
-
const idx = agents.findIndex((a) => a.id === agentId);
|
|
2108
|
-
return AGENT_COLORS[idx >= 0 ? idx % AGENT_COLORS.length : 0];
|
|
2109
|
-
}
|
|
2110
|
-
var AGENT_INDENT = " ".repeat(9);
|
|
2111
|
-
var MSG_ICONS2 = {
|
|
2112
|
-
system: "\u2666",
|
|
2113
|
-
// ◆
|
|
2114
|
-
lifecycle: "\u25B6",
|
|
2115
|
-
// ▶
|
|
2116
|
-
output: "\u2502",
|
|
2117
|
-
// │
|
|
2118
|
-
tool: "\u2699",
|
|
2119
|
-
// ⚙
|
|
2120
|
-
result: "\u2190",
|
|
2121
|
-
// ←
|
|
2122
|
-
error: "\u2715",
|
|
2123
|
-
// ✕
|
|
2124
|
-
file: "\u270E",
|
|
2125
|
-
// ✎
|
|
2126
|
-
info: "\u2502"
|
|
2127
|
-
// │
|
|
2128
|
-
};
|
|
2129
|
-
var ALL_MSG_TYPES = ["system", "lifecycle", "output", "tool", "result", "error", "file", "info"];
|
|
2130
|
-
var ACTIVITY_PRESETS = [
|
|
2131
|
-
{ label: "all", types: ALL_MSG_TYPES },
|
|
2132
|
-
{ label: "text", types: ["output"] },
|
|
2133
|
-
{ label: "tools", types: ["tool", "result", "file"] },
|
|
2134
|
-
{ label: "errors", types: ["error"] },
|
|
2135
|
-
{ label: "events", types: ["lifecycle", "system"] }
|
|
2136
|
-
];
|
|
2137
|
-
function cyclePreset(current) {
|
|
2138
|
-
const curIdx = ACTIVITY_PRESETS.findIndex((p) => p.types.length === current.size && p.types.every((t) => current.has(t)));
|
|
2139
|
-
const nextIdx = (curIdx + 1) % ACTIVITY_PRESETS.length;
|
|
2140
|
-
return ACTIVITY_PRESETS[nextIdx];
|
|
2141
|
-
}
|
|
2142
|
-
function App({
|
|
2143
|
-
projectName,
|
|
2144
|
-
tasks: initialTasks,
|
|
2145
|
-
agents: initialAgents = [],
|
|
2146
|
-
state: initialState,
|
|
2147
|
-
onRunTask,
|
|
2148
|
-
onCreateTask,
|
|
2149
|
-
onCancelTask,
|
|
2150
|
-
onRetryTask,
|
|
2151
|
-
onAssignTask,
|
|
2152
|
-
onRunAll,
|
|
2153
|
-
onDisableAgent,
|
|
2154
|
-
onEnableAgent,
|
|
2155
|
-
onSubscribeEvents,
|
|
2156
|
-
onRefreshTasks,
|
|
2157
|
-
onRefreshAgents,
|
|
2158
|
-
onRefreshState,
|
|
2159
|
-
onLoadHistory,
|
|
2160
|
-
onAddAgent,
|
|
2161
|
-
onDeleteAgent,
|
|
2162
|
-
onApproveTask,
|
|
2163
|
-
onRejectTask,
|
|
2164
|
-
onDeleteTask,
|
|
2165
|
-
onUpdateTask,
|
|
2166
|
-
onUpdateAgent,
|
|
2167
|
-
onForceStopAgent,
|
|
2168
|
-
onCreateTeam,
|
|
2169
|
-
onListTeams,
|
|
2170
|
-
onJoinTeam,
|
|
2171
|
-
onLeaveTeam,
|
|
2172
|
-
onDisbandTeam,
|
|
2173
|
-
onSetTeamLead,
|
|
2174
|
-
onStartWatch,
|
|
2175
|
-
onStopWatch,
|
|
2176
|
-
onToggleAutonomous,
|
|
2177
|
-
onRefreshGoals,
|
|
2178
|
-
onCreateGoal,
|
|
2179
|
-
onUpdateGoal,
|
|
2180
|
-
onUpdateGoalStatus,
|
|
2181
|
-
onDeleteGoal,
|
|
2182
|
-
initialWatchActive,
|
|
2183
|
-
watchError,
|
|
2184
|
-
messageBatchMs = process.env.VITEST ? 0 : 80,
|
|
2185
|
-
initialActivityFilter = "all",
|
|
2186
|
-
onSaveActivityFilter,
|
|
2187
|
-
initialMaxConcurrent = DEFAULT_CONFIG.scheduling.max_concurrent_agents,
|
|
2188
|
-
onSaveMaxConcurrent
|
|
2189
|
-
}) {
|
|
2190
|
-
const { exit } = useApp();
|
|
2191
|
-
const { stdout } = useStdout();
|
|
2192
|
-
const [termSize, setTermSize] = useState({ w: stdout?.columns ?? 80, h: stdout?.rows ?? 24 });
|
|
2193
|
-
useEffect(() => {
|
|
2194
|
-
if (!stdout) return;
|
|
2195
|
-
const onResize = () => setTermSize({ w: stdout.columns, h: stdout.rows });
|
|
2196
|
-
stdout.on("resize", onResize);
|
|
2197
|
-
return () => {
|
|
2198
|
-
stdout.off("resize", onResize);
|
|
2199
|
-
};
|
|
2200
|
-
}, [stdout]);
|
|
2201
|
-
const W = termSize.w;
|
|
2202
|
-
const H = termSize.h;
|
|
2203
|
-
const [liveTasks, setLiveTasks] = useState(initialTasks);
|
|
2204
|
-
const [liveAgents, setLiveAgents] = useState(initialAgents);
|
|
2205
|
-
const [liveState, setLiveState] = useState(initialState);
|
|
2206
|
-
const [watchActive, setWatchActive] = useState(initialWatchActive ?? !!initialState.pid);
|
|
2207
|
-
const [liveGoals, setLiveGoals] = useState([]);
|
|
2208
|
-
const [activeView, setActiveView] = useState("tasks");
|
|
2209
|
-
const [taskSelectedIndex, setTaskSelectedIndex] = useState(0);
|
|
2210
|
-
const [agentSelectedIndex, setAgentSelectedIndex] = useState(0);
|
|
2211
|
-
const [goalSelectedIndex, setGoalSelectedIndex] = useState(0);
|
|
2212
|
-
const [detailOpen, setDetailOpen] = useState(false);
|
|
2213
|
-
const [messages, setMessages] = useState([]);
|
|
2214
|
-
const [inputMode, setInputMode] = useState("none");
|
|
2215
|
-
const [inputValue, setInputValue] = useState("");
|
|
2216
|
-
const [wizardConfig, setWizardConfig] = useState(null);
|
|
2217
|
-
const [logFilter, setLogFilter] = useState(0);
|
|
2218
|
-
const [logTypeFilter, setLogTypeFilter] = useState(() => new Set(ALL_MSG_TYPES));
|
|
2219
|
-
const [logSelectedIndex, setLogSelectedIndex] = useState(-1);
|
|
2220
|
-
const [logScrollOffset, setLogScrollOffset] = useState(0);
|
|
2221
|
-
const [activityFilter, setActivityFilter] = useState(() => {
|
|
2222
|
-
const preset = ACTIVITY_PRESETS.find((p) => p.label === initialActivityFilter);
|
|
2223
|
-
return new Set(preset?.types ?? ALL_MSG_TYPES);
|
|
2224
|
-
});
|
|
2225
|
-
const activityFilterLabel = useMemo(() => {
|
|
2226
|
-
const preset = ACTIVITY_PRESETS.find((p) => p.types.length === activityFilter.size && p.types.every((t) => activityFilter.has(t)));
|
|
2227
|
-
return preset?.label ?? "all";
|
|
2228
|
-
}, [activityFilter]);
|
|
2229
|
-
const activityFilteredMessages = useMemo(() => {
|
|
2230
|
-
if (activityFilter.size >= ALL_MSG_TYPES.length) return messages;
|
|
2231
|
-
return messages.filter((m) => activityFilter.has(m.msgType ?? "info"));
|
|
2232
|
-
}, [messages, activityFilter]);
|
|
2233
|
-
const [maxConcurrent, setMaxConcurrent] = useState(initialMaxConcurrent);
|
|
2234
|
-
const cmdHistory = React5.useRef(new CommandHistory()).current;
|
|
2235
|
-
const [taskScrollOffset, setTaskScrollOffset] = useState(0);
|
|
2236
|
-
const [showAllTasks, setShowAllTasks] = useState(false);
|
|
2237
|
-
const [agentScrollOffset, setAgentScrollOffset] = useState(0);
|
|
2238
|
-
const [goalScrollOffset, setGoalScrollOffset] = useState(0);
|
|
2239
|
-
const [suggestionIndex, setSuggestionIndex] = useState(0);
|
|
2240
|
-
const [liveTeams, setLiveTeams] = useState([]);
|
|
2241
|
-
const liveTeamsRef = useRef(liveTeams);
|
|
2242
|
-
liveTeamsRef.current = liveTeams;
|
|
2243
|
-
const refreshAll = useCallback(async (opts) => {
|
|
2244
|
-
const [t, a, s, teams, goals] = await Promise.all([
|
|
2245
|
-
onRefreshTasks?.() ?? Promise.resolve(liveTasks),
|
|
2246
|
-
onRefreshAgents?.() ?? Promise.resolve(liveAgents),
|
|
2247
|
-
onRefreshState?.() ?? Promise.resolve(liveState),
|
|
2248
|
-
opts?.includeTeams ? onListTeams?.() ?? Promise.resolve(liveTeamsRef.current) : Promise.resolve(null),
|
|
2249
|
-
onRefreshGoals?.() ?? Promise.resolve(liveGoals)
|
|
2250
|
-
]);
|
|
2251
|
-
setLiveTasks(t);
|
|
2252
|
-
setLiveAgents(a);
|
|
2253
|
-
setLiveState(s);
|
|
2254
|
-
if (teams !== null) setLiveTeams(teams);
|
|
2255
|
-
setLiveGoals(goals);
|
|
2256
|
-
if (initialWatchActive) {
|
|
2257
|
-
setWatchActive(!!s.pid);
|
|
2258
|
-
}
|
|
2259
|
-
}, [onRefreshTasks, onRefreshAgents, onRefreshState, onListTeams, onRefreshGoals, initialWatchActive]);
|
|
2260
|
-
const sortedTasks = useMemo(
|
|
2261
|
-
() => [...liveTasks].sort((a, b) => (STATUS_ORDER[a.status] ?? 9) - (STATUS_ORDER[b.status] ?? 9)),
|
|
2262
|
-
[liveTasks]
|
|
2263
|
-
);
|
|
2264
|
-
const visibleTasks = showAllTasks ? sortedTasks : sortedTasks.slice(0, TASK_LIST_LIMIT);
|
|
2265
|
-
const hiddenTaskCount = sortedTasks.length - visibleTasks.length;
|
|
2266
|
-
const selectedTask = sortedTasks[taskSelectedIndex];
|
|
2267
|
-
const taskTitleMap = useMemo(() => {
|
|
2268
|
-
const map = /* @__PURE__ */ new Map();
|
|
2269
|
-
for (const t of liveTasks) map.set(t.id, t.title);
|
|
2270
|
-
return map;
|
|
2271
|
-
}, [liveTasks]);
|
|
2272
|
-
const agentNameMap = useMemo(() => {
|
|
2273
|
-
const map = /* @__PURE__ */ new Map();
|
|
2274
|
-
for (const a of liveAgents) map.set(a.id, a.name);
|
|
2275
|
-
return map;
|
|
2276
|
-
}, [liveAgents]);
|
|
2277
|
-
const { agentTeamMap, activeTeamCount, teamLeadSet } = useMemo(() => {
|
|
2278
|
-
const map = /* @__PURE__ */ new Map();
|
|
2279
|
-
const leads = /* @__PURE__ */ new Set();
|
|
2280
|
-
let count = 0;
|
|
2281
|
-
for (const team of liveTeams) {
|
|
2282
|
-
if (team.status !== "active") continue;
|
|
2283
|
-
count++;
|
|
2284
|
-
leads.add(team.lead_agent_id);
|
|
2285
|
-
for (const member of team.members) {
|
|
2286
|
-
map.set(member.agent_id, team.name);
|
|
2287
|
-
}
|
|
2288
|
-
}
|
|
2289
|
-
return { agentTeamMap: map, activeTeamCount: count, teamLeadSet: leads };
|
|
2290
|
-
}, [liveTeams]);
|
|
2291
|
-
const sortedAgents = useMemo(() => {
|
|
2292
|
-
const agents = [...liveAgents];
|
|
2293
|
-
agents.sort((a, b) => {
|
|
2294
|
-
const teamA = agentTeamMap.get(a.id);
|
|
2295
|
-
const teamB = agentTeamMap.get(b.id);
|
|
2296
|
-
if (teamA && !teamB) return -1;
|
|
2297
|
-
if (!teamA && teamB) return 1;
|
|
2298
|
-
if (teamA && teamB && teamA !== teamB) return teamA.localeCompare(teamB);
|
|
2299
|
-
return (AGENT_STATUS_ORDER[a.status] ?? 9) - (AGENT_STATUS_ORDER[b.status] ?? 9);
|
|
2300
|
-
});
|
|
2301
|
-
return agents;
|
|
2302
|
-
}, [liveAgents, agentTeamMap]);
|
|
2303
|
-
const selectedAgent = sortedAgents[agentSelectedIndex];
|
|
2304
|
-
const sortedGoals = useMemo(
|
|
2305
|
-
() => [...liveGoals].sort((a, b) => (GOAL_STATUS_ORDER[a.status] ?? 9) - (GOAL_STATUS_ORDER[b.status] ?? 9)),
|
|
2306
|
-
[liveGoals]
|
|
2307
|
-
);
|
|
2308
|
-
const selectedGoal = sortedGoals[goalSelectedIndex];
|
|
2309
|
-
const runIdToAgentId = useRef(/* @__PURE__ */ new Map());
|
|
2310
|
-
const runIdToTaskId = useRef(/* @__PURE__ */ new Map());
|
|
2311
|
-
useEffect(() => {
|
|
2312
|
-
for (const [taskId, entry] of Object.entries(liveState.running)) {
|
|
2313
|
-
runIdToAgentId.current.set(entry.run_id, entry.agent_id);
|
|
2314
|
-
runIdToTaskId.current.set(entry.run_id, taskId);
|
|
2315
|
-
}
|
|
2316
|
-
if (runIdToAgentId.current.size > MAX_RUN_MAP_SIZE) {
|
|
2317
|
-
const excess = runIdToAgentId.current.size - MAX_RUN_MAP_SIZE;
|
|
2318
|
-
let i = 0;
|
|
2319
|
-
for (const key of runIdToAgentId.current.keys()) {
|
|
2320
|
-
if (i++ >= excess) break;
|
|
2321
|
-
runIdToAgentId.current.delete(key);
|
|
2322
|
-
runIdToTaskId.current.delete(key);
|
|
2323
|
-
}
|
|
2324
|
-
}
|
|
2325
|
-
}, [liveState.running]);
|
|
2326
|
-
const pendingMessages = useRef([]);
|
|
2327
|
-
const flushTimer = useRef(null);
|
|
2328
|
-
const flushMessages = useCallback(() => {
|
|
2329
|
-
flushTimer.current = null;
|
|
2330
|
-
if (pendingMessages.current.length === 0) return;
|
|
2331
|
-
const batch = pendingMessages.current;
|
|
2332
|
-
pendingMessages.current = [];
|
|
2333
|
-
setMessages((prev) => {
|
|
2334
|
-
if (batch.length >= MAX_MESSAGES) return batch.slice(-MAX_MESSAGES);
|
|
2335
|
-
const keep = MAX_MESSAGES - batch.length;
|
|
2336
|
-
const trimmed = prev.length > keep ? prev.slice(-keep) : prev;
|
|
2337
|
-
return trimmed.concat(batch);
|
|
2338
|
-
});
|
|
2339
|
-
}, []);
|
|
2340
|
-
useEffect(() => {
|
|
2341
|
-
return () => {
|
|
2342
|
-
if (flushTimer.current) clearTimeout(flushTimer.current);
|
|
2343
|
-
};
|
|
2344
|
-
}, []);
|
|
2345
|
-
const addMessage = useCallback((text, color, opts) => {
|
|
2346
|
-
const now = /* @__PURE__ */ new Date();
|
|
2347
|
-
const time = now.toLocaleTimeString("en-US", {
|
|
2348
|
-
hour12: false,
|
|
2349
|
-
hour: "2-digit",
|
|
2350
|
-
minute: "2-digit",
|
|
2351
|
-
second: "2-digit"
|
|
2352
|
-
});
|
|
2353
|
-
const detail = opts?.detail && opts.detail.length > MAX_DETAIL_LEN ? opts.detail.slice(0, MAX_DETAIL_LEN) + "\u2026[truncated]" : opts?.detail;
|
|
2354
|
-
pendingMessages.current.push({ text, color, time, ts: now.getTime(), ...opts, detail });
|
|
2355
|
-
if (pendingMessages.current.length > MAX_MESSAGES * 2) {
|
|
2356
|
-
pendingMessages.current = pendingMessages.current.slice(-MAX_MESSAGES);
|
|
2357
|
-
}
|
|
2358
|
-
if (messageBatchMs === 0) {
|
|
2359
|
-
flushMessages();
|
|
2360
|
-
} else if (!flushTimer.current) {
|
|
2361
|
-
flushTimer.current = setTimeout(flushMessages, messageBatchMs);
|
|
2362
|
-
}
|
|
2363
|
-
}, [flushMessages]);
|
|
2364
|
-
useEffect(() => {
|
|
2365
|
-
if (watchError) {
|
|
2366
|
-
addMessage(`Watch mode failed: ${watchError}. Tasks will not auto-dispatch.`, tuiColors.red);
|
|
2367
|
-
}
|
|
2368
|
-
}, []);
|
|
2369
|
-
useEffect(() => {
|
|
2370
|
-
if (!onLoadHistory) return;
|
|
2371
|
-
const historyEntryToMsg = (entry) => {
|
|
2372
|
-
const time = new Date(entry.timestamp).toLocaleTimeString("en-US", {
|
|
2373
|
-
hour12: false,
|
|
2374
|
-
hour: "2-digit",
|
|
2375
|
-
minute: "2-digit",
|
|
2376
|
-
second: "2-digit"
|
|
2377
|
-
});
|
|
2378
|
-
const raw = typeof entry.data === "string" ? entry.data : JSON.stringify(entry.data);
|
|
2379
|
-
let text;
|
|
2380
|
-
let color = tuiColors.silver;
|
|
2381
|
-
let msgType = "output";
|
|
2382
|
-
if (entry.type === "error") {
|
|
2383
|
-
text = typeof entry.data === "string" ? entry.data : JSON.stringify(entry.data);
|
|
2384
|
-
text = text.slice(0, 200);
|
|
2385
|
-
color = tuiColors.red;
|
|
2386
|
-
msgType = "error";
|
|
2387
|
-
} else if (entry.type === "file_changed") {
|
|
2388
|
-
text = String(entry.data);
|
|
2389
|
-
color = tuiColors.purple;
|
|
2390
|
-
msgType = "file";
|
|
2391
|
-
} else if (entry.type === "done") {
|
|
2392
|
-
text = "Completed";
|
|
2393
|
-
color = tuiColors.green;
|
|
2394
|
-
msgType = "lifecycle";
|
|
2395
|
-
} else if (entry.type === "tool_call") {
|
|
2396
|
-
const d = entry.data;
|
|
2397
|
-
text = `\u2699 ${d?.name ?? "tool"}()`;
|
|
2398
|
-
color = tuiColors.cyan;
|
|
2399
|
-
msgType = "tool";
|
|
2400
|
-
} else {
|
|
2401
|
-
const { summary } = formatAgentOutput(raw);
|
|
2402
|
-
text = summary;
|
|
2403
|
-
const cls = classifyAgentSummary(text);
|
|
2404
|
-
msgType = cls.msgType;
|
|
2405
|
-
color = cls.color;
|
|
2406
|
-
}
|
|
2407
|
-
return { text, color, time, ts: new Date(entry.timestamp).getTime(), agentId: entry.agentId, taskId: entry.taskId, msgType };
|
|
2408
|
-
};
|
|
2409
|
-
onLoadHistory((batch) => {
|
|
2410
|
-
if (batch.length === 0) return;
|
|
2411
|
-
const histMsgs = batch.map(historyEntryToMsg);
|
|
2412
|
-
setMessages((prev) => {
|
|
2413
|
-
const combined = [...histMsgs, ...prev];
|
|
2414
|
-
return combined.length > MAX_MESSAGES ? combined.slice(-MAX_MESSAGES) : combined;
|
|
2415
|
-
});
|
|
2416
|
-
}).catch(() => {
|
|
2417
|
-
});
|
|
2418
|
-
}, []);
|
|
2419
|
-
useEffect(() => {
|
|
2420
|
-
onListTeams?.().then(setLiveTeams).catch(() => {
|
|
2421
|
-
});
|
|
2422
|
-
onRefreshGoals?.().then(setLiveGoals).catch(() => {
|
|
2423
|
-
});
|
|
2424
|
-
}, []);
|
|
2425
|
-
const launchAgentWizard = useCallback(() => {
|
|
2426
|
-
setWizardConfig({
|
|
2427
|
-
title: "NEW AGENT",
|
|
2428
|
-
steps: getAgentWizardSteps(liveTeamsRef.current),
|
|
2429
|
-
kind: "agent"
|
|
2430
|
-
});
|
|
2431
|
-
setInputMode("wizard");
|
|
2432
|
-
}, []);
|
|
2433
|
-
const launchTaskWizard = useCallback(() => {
|
|
2434
|
-
setWizardConfig({
|
|
2435
|
-
title: "NEW TASK",
|
|
2436
|
-
steps: getTaskWizardSteps(liveAgents),
|
|
2437
|
-
kind: "task"
|
|
2438
|
-
});
|
|
2439
|
-
setInputMode("wizard");
|
|
2440
|
-
}, [liveAgents]);
|
|
2441
|
-
const launchEditTaskWizard = useCallback((task) => {
|
|
2442
|
-
setWizardConfig({
|
|
2443
|
-
title: "EDIT TASK",
|
|
2444
|
-
steps: getEditTaskWizardSteps(task, liveAgents),
|
|
2445
|
-
kind: "edit_task",
|
|
2446
|
-
targetId: task.id
|
|
2447
|
-
});
|
|
2448
|
-
setInputMode("wizard");
|
|
2449
|
-
}, [liveAgents]);
|
|
2450
|
-
const launchTeamWizard = useCallback(() => {
|
|
2451
|
-
setWizardConfig({
|
|
2452
|
-
title: "NEW TEAM",
|
|
2453
|
-
steps: getTeamWizardSteps(liveAgents),
|
|
2454
|
-
kind: "team"
|
|
2455
|
-
});
|
|
2456
|
-
setInputMode("wizard");
|
|
2457
|
-
}, [liveAgents]);
|
|
2458
|
-
const launchEditAgentWizard = useCallback((agent) => {
|
|
2459
|
-
setWizardConfig({
|
|
2460
|
-
title: "EDIT AGENT",
|
|
2461
|
-
steps: getEditAgentWizardSteps(agent, liveTeams),
|
|
2462
|
-
kind: "edit_agent",
|
|
2463
|
-
targetId: agent.id
|
|
2464
|
-
});
|
|
2465
|
-
setInputMode("wizard");
|
|
2466
|
-
}, [liveTeams]);
|
|
2467
|
-
const launchConfigWizard = useCallback(() => {
|
|
2468
|
-
setWizardConfig({
|
|
2469
|
-
title: "SETTINGS",
|
|
2470
|
-
steps: getConfigWizardSteps(activityFilterLabel, maxConcurrent),
|
|
2471
|
-
kind: "config"
|
|
2472
|
-
});
|
|
2473
|
-
setInputMode("wizard");
|
|
2474
|
-
}, [activityFilterLabel, maxConcurrent]);
|
|
2475
|
-
const handleWizardComplete = useCallback((values) => {
|
|
2476
|
-
setInputMode("none");
|
|
2477
|
-
const kind = wizardConfig?.kind;
|
|
2478
|
-
const targetId = wizardConfig?.targetId;
|
|
2479
|
-
setWizardConfig(null);
|
|
2480
|
-
if (kind === "agent" && onAddAgent) {
|
|
2481
|
-
const input = agentWizardToInput(values);
|
|
2482
|
-
addMessage(`Creating agent "${input.name}"...`, tuiColors.amber);
|
|
2483
|
-
onAddAgent(input.name, input.adapter, {
|
|
2484
|
-
model: input.model,
|
|
2485
|
-
role: input.role,
|
|
2486
|
-
approval_policy: input.approval_policy
|
|
2487
|
-
}).then(
|
|
2488
|
-
(agent) => {
|
|
2489
|
-
addMessage(`\u2713 Created agent "${agent.name}" (${agent.id}, ${agent.adapter})`, tuiColors.green);
|
|
2490
|
-
if (input.team_id && onJoinTeam) {
|
|
2491
|
-
onJoinTeam(input.team_id, agent.id).then(
|
|
2492
|
-
(t) => {
|
|
2493
|
-
addMessage(`\u2713 Joined team "${t.name}"`, tuiColors.green);
|
|
2494
|
-
refreshAll({ includeTeams: true });
|
|
2495
|
-
},
|
|
2496
|
-
(err) => addMessage(`Failed to join team: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2497
|
-
);
|
|
2498
|
-
} else {
|
|
2499
|
-
refreshAll();
|
|
2500
|
-
}
|
|
2501
|
-
},
|
|
2502
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2503
|
-
);
|
|
2504
|
-
} else if (kind === "team" && onCreateTeam) {
|
|
2505
|
-
const input = teamWizardToInput(values);
|
|
2506
|
-
addMessage(`Creating team "${input.name}"...`, tuiColors.amber);
|
|
2507
|
-
onCreateTeam(input).then(
|
|
2508
|
-
(team) => {
|
|
2509
|
-
addMessage(`\u2713 Created team "${team.name}" (${team.id}, ${team.members.length} members)`, tuiColors.green);
|
|
2510
|
-
refreshAll({ includeTeams: true });
|
|
2511
|
-
},
|
|
2512
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2513
|
-
);
|
|
2514
|
-
} else if (kind === "task" && onCreateTask) {
|
|
2515
|
-
const input = taskWizardToInput(values);
|
|
2516
|
-
addMessage(`Creating "${input.title}"...`, tuiColors.amber);
|
|
2517
|
-
onCreateTask(input.title, {
|
|
2518
|
-
priority: input.priority,
|
|
2519
|
-
description: input.description
|
|
2520
|
-
}).then(
|
|
2521
|
-
(task) => {
|
|
2522
|
-
addMessage(`\u2713 Created "${task.title}" (${task.id})`, tuiColors.green);
|
|
2523
|
-
if (input.assignee && onAssignTask) {
|
|
2524
|
-
onAssignTask(task.id, input.assignee).catch(() => {
|
|
2525
|
-
});
|
|
2526
|
-
}
|
|
2527
|
-
refreshAll();
|
|
2528
|
-
},
|
|
2529
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2530
|
-
);
|
|
2531
|
-
} else if (kind === "edit_task" && targetId && onUpdateTask) {
|
|
2532
|
-
const fields = editTaskWizardToFields(values);
|
|
2533
|
-
addMessage(`Updating task...`, tuiColors.amber);
|
|
2534
|
-
onUpdateTask(targetId, fields).then(
|
|
2535
|
-
(task) => {
|
|
2536
|
-
addMessage(`\u2713 Updated "${task.title}"`, tuiColors.green);
|
|
2537
|
-
if (fields.assignee && onAssignTask) {
|
|
2538
|
-
onAssignTask(targetId, fields.assignee).catch(() => {
|
|
2539
|
-
});
|
|
2540
|
-
}
|
|
2541
|
-
refreshAll();
|
|
2542
|
-
},
|
|
2543
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2544
|
-
);
|
|
2545
|
-
} else if (kind === "edit_agent" && targetId && onUpdateAgent) {
|
|
2546
|
-
const fields = editAgentWizardToFields(values);
|
|
2547
|
-
const newTeamId = fields.team_id ?? "";
|
|
2548
|
-
const oldTeamId = liveTeams.find((t) => t.members.some((m) => m.agent_id === targetId))?.id ?? "";
|
|
2549
|
-
addMessage(`Updating agent...`, tuiColors.amber);
|
|
2550
|
-
onUpdateAgent(targetId, { name: fields.name, role: fields.role, model: fields.model }).then(
|
|
2551
|
-
(agent) => {
|
|
2552
|
-
addMessage(`\u2713 Updated agent "${agent.name}"`, tuiColors.green);
|
|
2553
|
-
const teamOps = [];
|
|
2554
|
-
if (oldTeamId && oldTeamId !== newTeamId && onLeaveTeam) {
|
|
2555
|
-
teamOps.push(
|
|
2556
|
-
onLeaveTeam(oldTeamId, targetId).then(
|
|
2557
|
-
(t) => addMessage(`\u2713 Left team "${t.name}"`, tuiColors.green),
|
|
2558
|
-
(err) => addMessage(`Failed to leave team: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2559
|
-
)
|
|
2560
|
-
);
|
|
2561
|
-
}
|
|
2562
|
-
if (newTeamId && newTeamId !== oldTeamId && onJoinTeam) {
|
|
2563
|
-
teamOps.push(
|
|
2564
|
-
onJoinTeam(newTeamId, targetId).then(
|
|
2565
|
-
(t) => addMessage(`\u2713 Joined team "${t.name}"`, tuiColors.green),
|
|
2566
|
-
(err) => addMessage(`Failed to join team: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2567
|
-
)
|
|
2568
|
-
);
|
|
2569
|
-
}
|
|
2570
|
-
Promise.all(teamOps).then(() => refreshAll({ includeTeams: teamOps.length > 0 }));
|
|
2571
|
-
},
|
|
2572
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2573
|
-
);
|
|
2574
|
-
} else if (kind === "config") {
|
|
2575
|
-
if (values.setting === "activity_filter" && values.activity_filter) {
|
|
2576
|
-
const preset = ACTIVITY_PRESETS.find((p) => p.label === values.activity_filter);
|
|
2577
|
-
if (preset) {
|
|
2578
|
-
setActivityFilter(new Set(preset.types));
|
|
2579
|
-
onSaveActivityFilter?.(preset.label);
|
|
2580
|
-
addMessage(`Activity filter: ${preset.label}`, tuiColors.amber);
|
|
2581
|
-
}
|
|
2582
|
-
} else if (values.setting === "max_concurrent" && values.max_concurrent) {
|
|
2583
|
-
const num = parseInt(values.max_concurrent, 10);
|
|
2584
|
-
if (num > 0) {
|
|
2585
|
-
setMaxConcurrent(num);
|
|
2586
|
-
onSaveMaxConcurrent?.(num);
|
|
2587
|
-
addMessage(`Max concurrent agents: ${num}`, tuiColors.amber);
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
} else if (kind === "goal" && onCreateGoal) {
|
|
2591
|
-
const input = goalWizardToInput(values);
|
|
2592
|
-
addMessage(`Creating goal "${input.title}"...`, tuiColors.amber);
|
|
2593
|
-
onCreateGoal(input).then(
|
|
2594
|
-
(goal) => {
|
|
2595
|
-
addMessage(`\u2713 Created goal "${goal.title}" (${goal.id})`, tuiColors.green);
|
|
2596
|
-
refreshAll();
|
|
2597
|
-
},
|
|
2598
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2599
|
-
);
|
|
2600
|
-
} else if (kind === "edit_goal" && targetId && onUpdateGoal) {
|
|
2601
|
-
const fields = editGoalWizardToFields(values);
|
|
2602
|
-
addMessage(`Updating goal...`, tuiColors.amber);
|
|
2603
|
-
onUpdateGoal(targetId, fields).then(
|
|
2604
|
-
(goal) => {
|
|
2605
|
-
addMessage(`\u2713 Updated goal "${goal.title}"`, tuiColors.green);
|
|
2606
|
-
refreshAll();
|
|
2607
|
-
},
|
|
2608
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
2609
|
-
);
|
|
2610
|
-
}
|
|
2611
|
-
}, [wizardConfig, onAddAgent, onCreateTask, onCreateTeam, onJoinTeam, onLeaveTeam, onAssignTask, onUpdateTask, onUpdateAgent, onToggleAutonomous, onCreateGoal, onUpdateGoal, addMessage, refreshAll, onSaveActivityFilter, onSaveMaxConcurrent, liveTeams]);
|
|
2612
|
-
const handleWizardCancel = useCallback(() => {
|
|
2613
|
-
setInputMode("none");
|
|
2614
|
-
setWizardConfig(null);
|
|
2615
|
-
}, []);
|
|
2616
|
-
useEffect(() => {
|
|
2617
|
-
if (!onSubscribeEvents) return;
|
|
2618
|
-
let refreshTimer = null;
|
|
2619
|
-
const scheduleRefresh = () => {
|
|
2620
|
-
if (refreshTimer) return;
|
|
2621
|
-
refreshTimer = setTimeout(() => {
|
|
2622
|
-
refreshTimer = null;
|
|
2623
|
-
refreshAll().catch(() => {
|
|
2624
|
-
});
|
|
2625
|
-
}, 150);
|
|
2626
|
-
};
|
|
2627
|
-
const unsubscribe = onSubscribeEvents((event) => {
|
|
2628
|
-
if (event.type === "agent:started") {
|
|
2629
|
-
runIdToAgentId.current.set(event.runId, event.agentId);
|
|
2630
|
-
runIdToTaskId.current.set(event.runId, event.taskId);
|
|
2631
|
-
}
|
|
2632
|
-
formatEvent(event, addMessage, runIdToAgentId.current, runIdToTaskId.current);
|
|
2633
|
-
if (event.type === "task:status_changed" || event.type === "task:created" || event.type === "task:assigned" || event.type === "agent:started" || event.type === "agent:completed" || event.type === "run:retry" || event.type === "goal:created" || event.type === "goal:status_changed" || event.type === "goal:updated" || event.type === "goal:deleted") {
|
|
2634
|
-
scheduleRefresh();
|
|
2635
|
-
}
|
|
2636
|
-
});
|
|
2637
|
-
return () => {
|
|
2638
|
-
unsubscribe();
|
|
2639
|
-
if (refreshTimer) clearTimeout(refreshTimer);
|
|
2640
|
-
};
|
|
2641
|
-
}, [onSubscribeEvents, addMessage, refreshAll]);
|
|
2642
|
-
const mode = watchActive ? "watching" : "idle";
|
|
2643
|
-
const uptime = liveState.started_at ? formatDurationSince(liveState.started_at) : void 0;
|
|
2644
|
-
const totalTokens = liveState.stats.total_tokens.total;
|
|
2645
|
-
const headerStats = useMemo(() => {
|
|
2646
|
-
const counts = { running: 0, retrying: 0, review: 0, todo: 0, done: 0, failed: 0, cancelled: 0 };
|
|
2647
|
-
for (const t of liveTasks) {
|
|
2648
|
-
if (t.status === "in_progress") counts.running++;
|
|
2649
|
-
else if (t.status === "retrying") counts.retrying++;
|
|
2650
|
-
else if (t.status === "review") counts.review++;
|
|
2651
|
-
else if (t.status === "todo") counts.todo++;
|
|
2652
|
-
else if (t.status === "done") counts.done++;
|
|
2653
|
-
else if (t.status === "failed") counts.failed++;
|
|
2654
|
-
else if (t.status === "cancelled") counts.cancelled++;
|
|
2655
|
-
}
|
|
2656
|
-
return { ...counts, teams: activeTeamCount };
|
|
2657
|
-
}, [liveTasks, activeTeamCount]);
|
|
2658
|
-
headerStats.running;
|
|
2659
|
-
const headerTokens = {
|
|
2660
|
-
input: liveState.stats.total_tokens.input ?? 0,
|
|
2661
|
-
output: liveState.stats.total_tokens.output ?? 0,
|
|
2662
|
-
total: totalTokens
|
|
2663
|
-
};
|
|
2664
|
-
const fixedRows = 9;
|
|
2665
|
-
const contentH = Math.max(4, H - fixedRows);
|
|
2666
|
-
const teamAgentCount = agentTeamMap.size;
|
|
2667
|
-
const hasUnassigned = liveAgents.length > teamAgentCount;
|
|
2668
|
-
const agentSectionRows = activeTeamCount > 0 ? activeTeamCount + (hasUnassigned ? 1 : 0) : 0;
|
|
2669
|
-
const listItemCount = activeView === "goals" ? sortedGoals.length + 1 : activeView === "tasks" ? visibleTasks.length + 1 + (hiddenTaskCount > 0 ? 1 : 0) : (
|
|
2670
|
-
// +1 for "+ add" row, +1 for "show all" row
|
|
2671
|
-
activeView === "agents" ? liveAgents.length + 1 + agentSectionRows : 0
|
|
2672
|
-
);
|
|
2673
|
-
const minListH = Math.min(listItemCount + 1, Math.ceil(contentH * 0.5));
|
|
2674
|
-
const mainH = activeView === "logs" ? contentH : Math.max(2, Math.min(minListH, contentH - 4));
|
|
2675
|
-
const feedH = Math.max(1, contentH - mainH);
|
|
2676
|
-
const ruleW = Math.max(10, W - 2);
|
|
2677
|
-
const suggestions = useMemo(
|
|
2678
|
-
() => inputMode === "command" ? resolveSuggestions(inputValue) : [],
|
|
2679
|
-
[inputMode, inputValue]
|
|
2680
|
-
);
|
|
2681
|
-
useEffect(() => {
|
|
2682
|
-
setTaskScrollOffset((o) => Math.min(o, Math.max(0, visibleTasks.length - mainH)));
|
|
2683
|
-
}, [visibleTasks.length, mainH]);
|
|
2684
|
-
useEffect(() => {
|
|
2685
|
-
setAgentScrollOffset((o) => Math.min(o, Math.max(0, sortedAgents.length - mainH)));
|
|
2686
|
-
}, [sortedAgents.length, mainH]);
|
|
2687
|
-
useEffect(() => {
|
|
2688
|
-
setGoalScrollOffset((o) => Math.min(o, Math.max(0, sortedGoals.length - mainH)));
|
|
2689
|
-
}, [sortedGoals.length, mainH]);
|
|
2690
|
-
const executeCommand = useCallback((raw) => {
|
|
2691
|
-
const stripped = raw.trim().replace(/^\//, "");
|
|
2692
|
-
const parts = stripped.split(/\s+/);
|
|
2693
|
-
const cmd = parts[0]?.toLowerCase();
|
|
2694
|
-
if (!cmd) return;
|
|
2695
|
-
const errMsg = (err) => err instanceof Error ? err.message : String(err);
|
|
2696
|
-
switch (cmd) {
|
|
2697
|
-
// ── Legacy shortcuts (backward compat) ──
|
|
2698
|
-
case "cancel": {
|
|
2699
|
-
if (!selectedTask) {
|
|
2700
|
-
addMessage("No task selected", tuiColors.yellow);
|
|
2701
|
-
return;
|
|
2702
|
-
}
|
|
2703
|
-
if (!onCancelTask) return;
|
|
2704
|
-
addMessage(`Cancelling "${selectedTask.title}"...`, tuiColors.amber);
|
|
2705
|
-
onCancelTask(selectedTask.id).then(
|
|
2706
|
-
() => {
|
|
2707
|
-
addMessage(`\u2713 Cancelled "${selectedTask.title}"`, tuiColors.green);
|
|
2708
|
-
refreshAll();
|
|
2709
|
-
},
|
|
2710
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2711
|
-
);
|
|
2712
|
-
return;
|
|
2713
|
-
}
|
|
2714
|
-
case "retry": {
|
|
2715
|
-
if (!selectedTask) {
|
|
2716
|
-
addMessage("No task selected", tuiColors.yellow);
|
|
2717
|
-
return;
|
|
2718
|
-
}
|
|
2719
|
-
if (!onRetryTask) return;
|
|
2720
|
-
addMessage(`Retrying "${selectedTask.title}"...`, tuiColors.amber);
|
|
2721
|
-
onRetryTask(selectedTask.id).then(
|
|
2722
|
-
() => {
|
|
2723
|
-
addMessage(`\u2713 Retried "${selectedTask.title}"`, tuiColors.green);
|
|
2724
|
-
refreshAll();
|
|
2725
|
-
},
|
|
2726
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2727
|
-
);
|
|
2728
|
-
return;
|
|
2729
|
-
}
|
|
2730
|
-
case "assign": {
|
|
2731
|
-
if (!selectedTask) {
|
|
2732
|
-
addMessage("No task selected", tuiColors.yellow);
|
|
2733
|
-
return;
|
|
2734
|
-
}
|
|
2735
|
-
if (!onAssignTask || !parts[1]) {
|
|
2736
|
-
addMessage("Usage: assign <agent>", tuiColors.yellow);
|
|
2737
|
-
return;
|
|
2738
|
-
}
|
|
2739
|
-
addMessage(`Assigning "${selectedTask.title}" to ${parts[1]}...`, tuiColors.amber);
|
|
2740
|
-
onAssignTask(selectedTask.id, parts[1]).then(
|
|
2741
|
-
() => {
|
|
2742
|
-
addMessage(`\u2713 Assigned "${selectedTask.title}" to ${parts[1]}`, tuiColors.green);
|
|
2743
|
-
refreshAll();
|
|
2744
|
-
},
|
|
2745
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2746
|
-
);
|
|
2747
|
-
return;
|
|
2748
|
-
}
|
|
2749
|
-
// ── /task group ──
|
|
2750
|
-
case "task": {
|
|
2751
|
-
const sub = parts[1]?.toLowerCase();
|
|
2752
|
-
if (sub === "add") {
|
|
2753
|
-
const title = parts.slice(2).join(" ");
|
|
2754
|
-
if (!title) {
|
|
2755
|
-
launchTaskWizard();
|
|
2756
|
-
return;
|
|
2757
|
-
}
|
|
2758
|
-
if (!onCreateTask) {
|
|
2759
|
-
addMessage("Create not available", tuiColors.yellow);
|
|
2760
|
-
return;
|
|
2761
|
-
}
|
|
2762
|
-
addMessage(`Creating "${title}"...`, tuiColors.amber);
|
|
2763
|
-
onCreateTask(title).then(
|
|
2764
|
-
(task) => {
|
|
2765
|
-
addMessage(`\u2713 Created "${task.title}" (${task.id})`, tuiColors.green);
|
|
2766
|
-
refreshAll();
|
|
2767
|
-
},
|
|
2768
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2769
|
-
);
|
|
2770
|
-
} else if (sub === "list") {
|
|
2771
|
-
const lines = sortedTasks.map((t) => ` ${t.id} ${t.status.padEnd(11)} ${t.title}`);
|
|
2772
|
-
if (lines.length === 0) addMessage("No tasks", tuiColors.dim);
|
|
2773
|
-
else for (const line of lines) addMessage(line, tuiColors.cyan);
|
|
2774
|
-
} else if (sub === "show") {
|
|
2775
|
-
const t = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : selectedTask;
|
|
2776
|
-
if (!t) {
|
|
2777
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2778
|
-
return;
|
|
2779
|
-
}
|
|
2780
|
-
addMessage(`${t.id} ${t.status} P${t.priority} "${t.title}"`, tuiColors.cyan);
|
|
2781
|
-
if (t.assignee) addMessage(` agent: ${t.assignee}`, tuiColors.dim);
|
|
2782
|
-
if (t.description) addMessage(` ${t.description.slice(0, 100)}`, tuiColors.dim);
|
|
2783
|
-
} else if (sub === "cancel") {
|
|
2784
|
-
const t = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : selectedTask;
|
|
2785
|
-
if (!t) {
|
|
2786
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2787
|
-
return;
|
|
2788
|
-
}
|
|
2789
|
-
if (!onCancelTask) return;
|
|
2790
|
-
addMessage(`Cancelling "${t.title}"...`, tuiColors.amber);
|
|
2791
|
-
onCancelTask(t.id).then(
|
|
2792
|
-
() => {
|
|
2793
|
-
addMessage(`\u2713 Cancelled "${t.title}"`, tuiColors.green);
|
|
2794
|
-
refreshAll();
|
|
2795
|
-
},
|
|
2796
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2797
|
-
);
|
|
2798
|
-
} else if (sub === "retry") {
|
|
2799
|
-
const t = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : selectedTask;
|
|
2800
|
-
if (!t) {
|
|
2801
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2802
|
-
return;
|
|
2803
|
-
}
|
|
2804
|
-
if (!onRetryTask) return;
|
|
2805
|
-
addMessage(`Retrying "${t.title}"...`, tuiColors.amber);
|
|
2806
|
-
onRetryTask(t.id).then(
|
|
2807
|
-
() => {
|
|
2808
|
-
addMessage(`\u2713 Retried "${t.title}"`, tuiColors.green);
|
|
2809
|
-
refreshAll();
|
|
2810
|
-
},
|
|
2811
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2812
|
-
);
|
|
2813
|
-
} else if (sub === "assign") {
|
|
2814
|
-
const foundByParts2 = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : void 0;
|
|
2815
|
-
const t = foundByParts2 ?? selectedTask;
|
|
2816
|
-
const agentArg = foundByParts2 ? parts[3] : parts[2];
|
|
2817
|
-
if (!t) {
|
|
2818
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2819
|
-
return;
|
|
2820
|
-
}
|
|
2821
|
-
if (!agentArg) {
|
|
2822
|
-
addMessage("Usage: /task assign [id] <agent>", tuiColors.yellow);
|
|
2823
|
-
return;
|
|
2824
|
-
}
|
|
2825
|
-
if (!onAssignTask) return;
|
|
2826
|
-
addMessage(`Assigning "${t.title}" to ${agentArg}...`, tuiColors.amber);
|
|
2827
|
-
onAssignTask(t.id, agentArg).then(
|
|
2828
|
-
() => {
|
|
2829
|
-
addMessage(`\u2713 Assigned "${t.title}" to ${agentArg}`, tuiColors.green);
|
|
2830
|
-
refreshAll();
|
|
2831
|
-
},
|
|
2832
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2833
|
-
);
|
|
2834
|
-
} else if (sub === "approve") {
|
|
2835
|
-
const t = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : selectedTask;
|
|
2836
|
-
if (!t) {
|
|
2837
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2838
|
-
return;
|
|
2839
|
-
}
|
|
2840
|
-
if (t.status !== "review") {
|
|
2841
|
-
addMessage(`Cannot approve \u2014 status is ${t.status}`, tuiColors.yellow);
|
|
2842
|
-
return;
|
|
2843
|
-
}
|
|
2844
|
-
if (!onApproveTask) return;
|
|
2845
|
-
addMessage(`Approving "${t.title}"...`, tuiColors.amber);
|
|
2846
|
-
onApproveTask(t.id).then(
|
|
2847
|
-
() => {
|
|
2848
|
-
addMessage(`\u2713 Approved "${t.title}"`, tuiColors.green);
|
|
2849
|
-
refreshAll();
|
|
2850
|
-
},
|
|
2851
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2852
|
-
);
|
|
2853
|
-
} else if (sub === "reject") {
|
|
2854
|
-
const t = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : selectedTask;
|
|
2855
|
-
if (!t) {
|
|
2856
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2857
|
-
return;
|
|
2858
|
-
}
|
|
2859
|
-
if (t.status !== "review") {
|
|
2860
|
-
addMessage(`Cannot reject \u2014 status is ${t.status}`, tuiColors.yellow);
|
|
2861
|
-
return;
|
|
2862
|
-
}
|
|
2863
|
-
if (!onRejectTask) return;
|
|
2864
|
-
const feedback = parts.slice(parts[2] && sortedTasks.find((x) => x.id === parts[2]) ? 3 : 2).join(" ").trim() || void 0;
|
|
2865
|
-
addMessage(`Rejecting "${t.title}"${feedback ? " with feedback" : ""}...`, tuiColors.amber);
|
|
2866
|
-
onRejectTask(t.id, feedback).then(
|
|
2867
|
-
() => {
|
|
2868
|
-
addMessage(`\u2713 Rejected "${t.title}" \u2192 todo`, tuiColors.green);
|
|
2869
|
-
refreshAll();
|
|
2870
|
-
},
|
|
2871
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2872
|
-
);
|
|
2873
|
-
} else if (sub === "delete") {
|
|
2874
|
-
const t = parts[2] ? sortedTasks.find((x) => x.id === parts[2]) : selectedTask;
|
|
2875
|
-
if (!t) {
|
|
2876
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
2877
|
-
return;
|
|
2878
|
-
}
|
|
2879
|
-
if (t.status === "in_progress") {
|
|
2880
|
-
addMessage(`Cannot delete \u2014 task is running`, tuiColors.yellow);
|
|
2881
|
-
return;
|
|
2882
|
-
}
|
|
2883
|
-
if (!onDeleteTask) return;
|
|
2884
|
-
addMessage(`Deleting "${t.title}"...`, tuiColors.amber);
|
|
2885
|
-
onDeleteTask(t.id).then(
|
|
2886
|
-
() => {
|
|
2887
|
-
addMessage(`\u2713 Deleted "${t.title}"`, tuiColors.green);
|
|
2888
|
-
refreshAll();
|
|
2889
|
-
},
|
|
2890
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2891
|
-
);
|
|
2892
|
-
} else {
|
|
2893
|
-
addMessage("Usage: /task add|list|show|cancel|retry|assign|approve|reject|delete", tuiColors.yellow);
|
|
2894
|
-
}
|
|
2895
|
-
return;
|
|
2896
|
-
}
|
|
2897
|
-
// ── /agent group ──
|
|
2898
|
-
case "agent": {
|
|
2899
|
-
const sub = parts[1]?.toLowerCase();
|
|
2900
|
-
if (sub === "add") {
|
|
2901
|
-
const name = parts[2];
|
|
2902
|
-
if (!name) {
|
|
2903
|
-
launchAgentWizard();
|
|
2904
|
-
return;
|
|
2905
|
-
}
|
|
2906
|
-
if (!onAddAgent) {
|
|
2907
|
-
addMessage("Agent creation not available", tuiColors.yellow);
|
|
2908
|
-
return;
|
|
2909
|
-
}
|
|
2910
|
-
const adapter = parts[3];
|
|
2911
|
-
addMessage(`Creating agent "${name}"...`, tuiColors.amber);
|
|
2912
|
-
onAddAgent(name, adapter).then(
|
|
2913
|
-
(agent) => {
|
|
2914
|
-
addMessage(`\u2713 Created agent "${agent.name}" (${agent.id}, ${agent.adapter})`, tuiColors.green);
|
|
2915
|
-
refreshAll();
|
|
2916
|
-
},
|
|
2917
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2918
|
-
);
|
|
2919
|
-
} else if (sub === "list") {
|
|
2920
|
-
const lines = sortedAgents.map((a) => ` ${a.id} ${a.status.padEnd(8)} ${a.name} (${a.adapter})`);
|
|
2921
|
-
if (lines.length === 0) addMessage("No agents", tuiColors.dim);
|
|
2922
|
-
else for (const line of lines) addMessage(line, tuiColors.cyan);
|
|
2923
|
-
} else if (sub === "disable") {
|
|
2924
|
-
const a = parts[2] ? sortedAgents.find((x) => x.id === parts[2] || x.name === parts[2]) : selectedAgent;
|
|
2925
|
-
if (!a) {
|
|
2926
|
-
addMessage("No agent selected or id given", tuiColors.yellow);
|
|
2927
|
-
return;
|
|
2928
|
-
}
|
|
2929
|
-
if (!onDisableAgent) return;
|
|
2930
|
-
addMessage(`Disabling ${a.name}...`, tuiColors.amber);
|
|
2931
|
-
onDisableAgent(a.id).then(
|
|
2932
|
-
() => {
|
|
2933
|
-
addMessage(`\u2713 Disabled ${a.name}`, tuiColors.green);
|
|
2934
|
-
refreshAll();
|
|
2935
|
-
},
|
|
2936
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2937
|
-
);
|
|
2938
|
-
} else if (sub === "enable") {
|
|
2939
|
-
const a = parts[2] ? sortedAgents.find((x) => x.id === parts[2] || x.name === parts[2]) : selectedAgent;
|
|
2940
|
-
if (!a) {
|
|
2941
|
-
addMessage("No agent selected or id given", tuiColors.yellow);
|
|
2942
|
-
return;
|
|
2943
|
-
}
|
|
2944
|
-
if (!onEnableAgent) return;
|
|
2945
|
-
addMessage(`Enabling ${a.name}...`, tuiColors.amber);
|
|
2946
|
-
onEnableAgent(a.id).then(
|
|
2947
|
-
() => {
|
|
2948
|
-
addMessage(`\u2713 Enabled ${a.name}`, tuiColors.green);
|
|
2949
|
-
refreshAll();
|
|
2950
|
-
},
|
|
2951
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2952
|
-
);
|
|
2953
|
-
} else if (sub === "delete" || sub === "remove") {
|
|
2954
|
-
const a = parts[2] ? sortedAgents.find((x) => x.id === parts[2] || x.name === parts[2]) : selectedAgent;
|
|
2955
|
-
if (!a) {
|
|
2956
|
-
addMessage("No agent selected or id given", tuiColors.yellow);
|
|
2957
|
-
return;
|
|
2958
|
-
}
|
|
2959
|
-
if (a.status === "running") {
|
|
2960
|
-
addMessage("Cannot delete \u2014 agent is running", tuiColors.yellow);
|
|
2961
|
-
return;
|
|
2962
|
-
}
|
|
2963
|
-
if (!onDeleteAgent) {
|
|
2964
|
-
addMessage("Agent deletion not available", tuiColors.yellow);
|
|
2965
|
-
return;
|
|
2966
|
-
}
|
|
2967
|
-
addMessage(`Deleting agent "${a.name}"...`, tuiColors.amber);
|
|
2968
|
-
onDeleteAgent(a.id).then(
|
|
2969
|
-
() => {
|
|
2970
|
-
addMessage(`\u2713 Deleted agent "${a.name}"`, tuiColors.green);
|
|
2971
|
-
refreshAll();
|
|
2972
|
-
},
|
|
2973
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2974
|
-
);
|
|
2975
|
-
} else if (sub === "autonomous" || sub === "auto") {
|
|
2976
|
-
const a = parts[2] ? sortedAgents.find((x) => x.id === parts[2] || x.name === parts[2]) : selectedAgent;
|
|
2977
|
-
if (!a) {
|
|
2978
|
-
addMessage("No agent selected or id given", tuiColors.yellow);
|
|
2979
|
-
return;
|
|
2980
|
-
}
|
|
2981
|
-
if (!onToggleAutonomous) {
|
|
2982
|
-
addMessage("Autonomous toggle not available", tuiColors.yellow);
|
|
2983
|
-
return;
|
|
2984
|
-
}
|
|
2985
|
-
if (a.autonomous) {
|
|
2986
|
-
addMessage(`Disabling autonomous mode for "${a.name}"...`, tuiColors.amber);
|
|
2987
|
-
onToggleAutonomous(a.id, false).then(
|
|
2988
|
-
() => {
|
|
2989
|
-
addMessage(`${LOOP} ${a.name} autonomous OFF`, tuiColors.cyan);
|
|
2990
|
-
refreshAll();
|
|
2991
|
-
},
|
|
2992
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
2993
|
-
);
|
|
2994
|
-
} else {
|
|
2995
|
-
addMessage(`Enabling autonomous mode for "${a.name}"...`, tuiColors.amber);
|
|
2996
|
-
onToggleAutonomous(a.id, true).then(
|
|
2997
|
-
() => {
|
|
2998
|
-
addMessage(`${LOOP} ${a.name} autonomous ON`, tuiColors.cyan);
|
|
2999
|
-
refreshAll();
|
|
3000
|
-
},
|
|
3001
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3002
|
-
);
|
|
3003
|
-
}
|
|
3004
|
-
} else {
|
|
3005
|
-
addMessage("Usage: /agent add|list|disable|enable|delete|autonomous", tuiColors.yellow);
|
|
3006
|
-
}
|
|
3007
|
-
return;
|
|
3008
|
-
}
|
|
3009
|
-
// ── /team group ──
|
|
3010
|
-
case "team": {
|
|
3011
|
-
const sub = parts[1]?.toLowerCase();
|
|
3012
|
-
if (sub === "create" || sub === "add") {
|
|
3013
|
-
launchTeamWizard();
|
|
3014
|
-
} else if (sub === "list") {
|
|
3015
|
-
const teams = liveTeamsRef.current;
|
|
3016
|
-
if (teams.length === 0) {
|
|
3017
|
-
addMessage("No teams", tuiColors.dim);
|
|
3018
|
-
} else for (const t of teams) {
|
|
3019
|
-
addMessage(` ${t.id} ${t.status.padEnd(8)} ${t.name} (${t.members.length} members)`, tuiColors.cyan);
|
|
3020
|
-
}
|
|
3021
|
-
} else if (sub === "join") {
|
|
3022
|
-
if (!onJoinTeam) {
|
|
3023
|
-
addMessage("Join not available", tuiColors.yellow);
|
|
3024
|
-
return;
|
|
3025
|
-
}
|
|
3026
|
-
const teamArg = parts[2];
|
|
3027
|
-
const agentArg = parts[3] ?? selectedAgent?.id;
|
|
3028
|
-
if (!teamArg || !agentArg) {
|
|
3029
|
-
addMessage("Usage: /team join <teamId> [agentId]", tuiColors.yellow);
|
|
3030
|
-
return;
|
|
3031
|
-
}
|
|
3032
|
-
addMessage(`Joining team ${teamArg}...`, tuiColors.amber);
|
|
3033
|
-
onJoinTeam(teamArg, agentArg).then(
|
|
3034
|
-
(t) => {
|
|
3035
|
-
addMessage(`\u2713 Agent joined team "${t.name}"`, tuiColors.green);
|
|
3036
|
-
refreshAll({ includeTeams: true });
|
|
3037
|
-
},
|
|
3038
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3039
|
-
);
|
|
3040
|
-
} else if (sub === "leave") {
|
|
3041
|
-
if (!onLeaveTeam) {
|
|
3042
|
-
addMessage("Leave not available", tuiColors.yellow);
|
|
3043
|
-
return;
|
|
3044
|
-
}
|
|
3045
|
-
const teamArg = parts[2];
|
|
3046
|
-
const agentArg = parts[3] ?? selectedAgent?.id;
|
|
3047
|
-
if (!teamArg || !agentArg) {
|
|
3048
|
-
addMessage("Usage: /team leave <teamId> [agentId]", tuiColors.yellow);
|
|
3049
|
-
return;
|
|
3050
|
-
}
|
|
3051
|
-
addMessage(`Leaving team ${teamArg}...`, tuiColors.amber);
|
|
3052
|
-
onLeaveTeam(teamArg, agentArg).then(
|
|
3053
|
-
(t) => {
|
|
3054
|
-
addMessage(`\u2713 Agent left team "${t.name}"`, tuiColors.green);
|
|
3055
|
-
refreshAll({ includeTeams: true });
|
|
3056
|
-
},
|
|
3057
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3058
|
-
);
|
|
3059
|
-
} else if (sub === "disband") {
|
|
3060
|
-
if (!onDisbandTeam) {
|
|
3061
|
-
addMessage("Disband not available", tuiColors.yellow);
|
|
3062
|
-
return;
|
|
3063
|
-
}
|
|
3064
|
-
const teamArg = parts[2];
|
|
3065
|
-
if (!teamArg) {
|
|
3066
|
-
addMessage("Usage: /team disband <teamId>", tuiColors.yellow);
|
|
3067
|
-
return;
|
|
3068
|
-
}
|
|
3069
|
-
addMessage(`Disbanding team ${teamArg}...`, tuiColors.amber);
|
|
3070
|
-
onDisbandTeam(teamArg).then(
|
|
3071
|
-
() => {
|
|
3072
|
-
addMessage(`\u2713 Team disbanded`, tuiColors.green);
|
|
3073
|
-
refreshAll({ includeTeams: true });
|
|
3074
|
-
},
|
|
3075
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3076
|
-
);
|
|
3077
|
-
} else if (sub === "set-lead") {
|
|
3078
|
-
if (!onSetTeamLead) {
|
|
3079
|
-
addMessage("Set-lead not available", tuiColors.yellow);
|
|
3080
|
-
return;
|
|
3081
|
-
}
|
|
3082
|
-
const teamArg = parts[2];
|
|
3083
|
-
const agentArg = parts[3];
|
|
3084
|
-
if (!teamArg || !agentArg) {
|
|
3085
|
-
addMessage("Usage: /team set-lead <teamId> <agentId>", tuiColors.yellow);
|
|
3086
|
-
return;
|
|
3087
|
-
}
|
|
3088
|
-
addMessage(`Setting lead for team ${teamArg}...`, tuiColors.amber);
|
|
3089
|
-
onSetTeamLead(teamArg, agentArg).then(
|
|
3090
|
-
(t) => {
|
|
3091
|
-
addMessage(`\u2713 New lead for team "${t.name}"`, tuiColors.green);
|
|
3092
|
-
refreshAll({ includeTeams: true });
|
|
3093
|
-
},
|
|
3094
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3095
|
-
);
|
|
3096
|
-
} else {
|
|
3097
|
-
addMessage("Usage: /team create|list|join|leave|disband|set-lead", tuiColors.yellow);
|
|
3098
|
-
}
|
|
3099
|
-
return;
|
|
3100
|
-
}
|
|
3101
|
-
// ── /run, /run-all ──
|
|
3102
|
-
case "run": {
|
|
3103
|
-
const idArg = parts[1] ?? selectedTask?.id;
|
|
3104
|
-
if (!idArg) {
|
|
3105
|
-
addMessage("No task selected or id given", tuiColors.yellow);
|
|
3106
|
-
return;
|
|
3107
|
-
}
|
|
3108
|
-
if (!onRunTask) {
|
|
3109
|
-
addMessage("Run not available", tuiColors.yellow);
|
|
3110
|
-
return;
|
|
3111
|
-
}
|
|
3112
|
-
const t = sortedTasks.find((x) => x.id === idArg);
|
|
3113
|
-
if (t && !RUNNABLE.has(t.status)) {
|
|
3114
|
-
addMessage(`Cannot run \u2014 status is ${t.status}`, tuiColors.yellow);
|
|
3115
|
-
return;
|
|
3116
|
-
}
|
|
3117
|
-
addMessage(`Running ${idArg}...`, tuiColors.amber);
|
|
3118
|
-
onRunTask(idArg).then(
|
|
3119
|
-
() => {
|
|
3120
|
-
addMessage(`\u2713 Dispatched ${idArg}`, tuiColors.green);
|
|
3121
|
-
refreshAll();
|
|
3122
|
-
},
|
|
3123
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3124
|
-
);
|
|
3125
|
-
return;
|
|
3126
|
-
}
|
|
3127
|
-
case "run-all": {
|
|
3128
|
-
if (!onRunAll) {
|
|
3129
|
-
addMessage("Run-all not available", tuiColors.yellow);
|
|
3130
|
-
return;
|
|
3131
|
-
}
|
|
3132
|
-
addMessage("Running all todo tasks...", tuiColors.amber);
|
|
3133
|
-
onRunAll().then(
|
|
3134
|
-
() => {
|
|
3135
|
-
addMessage("\u2713 Dispatched all todo tasks", tuiColors.green);
|
|
3136
|
-
refreshAll();
|
|
3137
|
-
},
|
|
3138
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3139
|
-
);
|
|
3140
|
-
return;
|
|
3141
|
-
}
|
|
3142
|
-
// ── /watch, /pause ──
|
|
3143
|
-
case "watch": {
|
|
3144
|
-
if (watchActive) {
|
|
3145
|
-
addMessage("Watch mode already active", tuiColors.yellow);
|
|
3146
|
-
return;
|
|
3147
|
-
}
|
|
3148
|
-
if (!onStartWatch) {
|
|
3149
|
-
addMessage("Watch not available", tuiColors.yellow);
|
|
3150
|
-
return;
|
|
3151
|
-
}
|
|
3152
|
-
addMessage("Starting watch mode...", tuiColors.amber);
|
|
3153
|
-
onStartWatch().then(
|
|
3154
|
-
() => {
|
|
3155
|
-
setWatchActive(true);
|
|
3156
|
-
addMessage("\u2713 Watch mode started", tuiColors.green);
|
|
3157
|
-
},
|
|
3158
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3159
|
-
);
|
|
3160
|
-
return;
|
|
3161
|
-
}
|
|
3162
|
-
case "pause": {
|
|
3163
|
-
if (!watchActive) {
|
|
3164
|
-
addMessage("Watch mode not active", tuiColors.yellow);
|
|
3165
|
-
return;
|
|
3166
|
-
}
|
|
3167
|
-
if (!onStopWatch) {
|
|
3168
|
-
addMessage("Pause not available", tuiColors.yellow);
|
|
3169
|
-
return;
|
|
3170
|
-
}
|
|
3171
|
-
addMessage("Pausing watch mode...", tuiColors.amber);
|
|
3172
|
-
onStopWatch().then(
|
|
3173
|
-
() => {
|
|
3174
|
-
setWatchActive(false);
|
|
3175
|
-
addMessage("\u2713 Watch mode paused", tuiColors.green);
|
|
3176
|
-
},
|
|
3177
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3178
|
-
);
|
|
3179
|
-
return;
|
|
3180
|
-
}
|
|
3181
|
-
// ── /config ──
|
|
3182
|
-
case "config": {
|
|
3183
|
-
const sub = parts[1]?.toLowerCase();
|
|
3184
|
-
if (sub === "activity-filter") {
|
|
3185
|
-
setActivityFilter((prev) => {
|
|
3186
|
-
const next = cyclePreset(prev);
|
|
3187
|
-
onSaveActivityFilter?.(next.label);
|
|
3188
|
-
addMessage(`Activity filter: ${next.label}`, tuiColors.amber);
|
|
3189
|
-
return new Set(next.types);
|
|
3190
|
-
});
|
|
3191
|
-
} else {
|
|
3192
|
-
launchConfigWizard();
|
|
3193
|
-
}
|
|
3194
|
-
return;
|
|
3195
|
-
}
|
|
3196
|
-
// ── /status ──
|
|
3197
|
-
case "status": {
|
|
3198
|
-
const running = liveTasks.filter((t) => t.status === "in_progress").length;
|
|
3199
|
-
addMessage(`${mode} ${running} running ${liveTasks.length} tasks ${sortedAgents.length} agents`, tuiColors.cyan);
|
|
3200
|
-
return;
|
|
3201
|
-
}
|
|
3202
|
-
// ── /help ──
|
|
3203
|
-
case "help": {
|
|
3204
|
-
for (const [verb, spec] of Object.entries(COMMAND_REGISTRY)) {
|
|
3205
|
-
const subs = spec.sub ? " " + spec.sub.join("|") : spec.args ? " " + spec.args : "";
|
|
3206
|
-
addMessage(` /${verb}${subs} \u2014 ${spec.help}`, tuiColors.silver);
|
|
3207
|
-
}
|
|
3208
|
-
return;
|
|
3209
|
-
}
|
|
3210
|
-
// ── /quit ──
|
|
3211
|
-
case "quit": {
|
|
3212
|
-
exit();
|
|
3213
|
-
return;
|
|
3214
|
-
}
|
|
3215
|
-
// ── /disable, /enable (agent shortcuts) ──
|
|
3216
|
-
case "disable": {
|
|
3217
|
-
if (!selectedAgent) {
|
|
3218
|
-
addMessage("No agent selected", tuiColors.yellow);
|
|
3219
|
-
return;
|
|
3220
|
-
}
|
|
3221
|
-
if (!onDisableAgent) return;
|
|
3222
|
-
addMessage(`Disabling ${selectedAgent.name}...`, tuiColors.amber);
|
|
3223
|
-
onDisableAgent(selectedAgent.id).then(
|
|
3224
|
-
() => {
|
|
3225
|
-
addMessage(`\u2713 Disabled ${selectedAgent.name}`, tuiColors.green);
|
|
3226
|
-
refreshAll();
|
|
3227
|
-
},
|
|
3228
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3229
|
-
);
|
|
3230
|
-
return;
|
|
3231
|
-
}
|
|
3232
|
-
case "enable": {
|
|
3233
|
-
if (!selectedAgent) {
|
|
3234
|
-
addMessage("No agent selected", tuiColors.yellow);
|
|
3235
|
-
return;
|
|
3236
|
-
}
|
|
3237
|
-
if (!onEnableAgent) return;
|
|
3238
|
-
addMessage(`Enabling ${selectedAgent.name}...`, tuiColors.amber);
|
|
3239
|
-
onEnableAgent(selectedAgent.id).then(
|
|
3240
|
-
() => {
|
|
3241
|
-
addMessage(`\u2713 Enabled ${selectedAgent.name}`, tuiColors.green);
|
|
3242
|
-
refreshAll();
|
|
3243
|
-
},
|
|
3244
|
-
(err) => addMessage(`Failed: ${errMsg(err)}`, tuiColors.red)
|
|
3245
|
-
);
|
|
3246
|
-
return;
|
|
3247
|
-
}
|
|
3248
|
-
default:
|
|
3249
|
-
addMessage(`Unknown: ${cmd}. Type /help for commands`, tuiColors.yellow);
|
|
3250
|
-
}
|
|
3251
|
-
}, [
|
|
3252
|
-
selectedTask,
|
|
3253
|
-
selectedAgent,
|
|
3254
|
-
sortedTasks,
|
|
3255
|
-
sortedAgents,
|
|
3256
|
-
liveTasks,
|
|
3257
|
-
mode,
|
|
3258
|
-
watchActive,
|
|
3259
|
-
onCancelTask,
|
|
3260
|
-
onRetryTask,
|
|
3261
|
-
onAssignTask,
|
|
3262
|
-
onRunAll,
|
|
3263
|
-
onRunTask,
|
|
3264
|
-
onCreateTask,
|
|
3265
|
-
onDisableAgent,
|
|
3266
|
-
onEnableAgent,
|
|
3267
|
-
onAddAgent,
|
|
3268
|
-
onApproveTask,
|
|
3269
|
-
onRejectTask,
|
|
3270
|
-
onDeleteTask,
|
|
3271
|
-
onJoinTeam,
|
|
3272
|
-
onLeaveTeam,
|
|
3273
|
-
onDisbandTeam,
|
|
3274
|
-
onSetTeamLead,
|
|
3275
|
-
onStartWatch,
|
|
3276
|
-
onStopWatch,
|
|
3277
|
-
addMessage,
|
|
3278
|
-
exit,
|
|
3279
|
-
refreshAll,
|
|
3280
|
-
launchTaskWizard,
|
|
3281
|
-
launchAgentWizard,
|
|
3282
|
-
launchTeamWizard,
|
|
3283
|
-
launchConfigWizard
|
|
3284
|
-
]);
|
|
3285
|
-
useInput((input, key) => {
|
|
3286
|
-
if (inputMode !== "none") {
|
|
3287
|
-
if (key.escape) {
|
|
3288
|
-
setInputMode("none");
|
|
3289
|
-
setInputValue("");
|
|
3290
|
-
cmdHistory.reset();
|
|
3291
|
-
return;
|
|
3292
|
-
}
|
|
3293
|
-
if (key.return) {
|
|
3294
|
-
const value = inputValue.trim();
|
|
3295
|
-
if (!value) return;
|
|
3296
|
-
if (inputMode === "new_task") {
|
|
3297
|
-
if (!onCreateTask) return;
|
|
3298
|
-
setInputMode("none");
|
|
3299
|
-
setInputValue("");
|
|
3300
|
-
addMessage(`Creating "${value}"...`, tuiColors.amber);
|
|
3301
|
-
onCreateTask(value).then(
|
|
3302
|
-
(task) => {
|
|
3303
|
-
addMessage(`\u2713 Created "${task.title}" (${task.id})`, tuiColors.green);
|
|
3304
|
-
refreshAll();
|
|
3305
|
-
},
|
|
3306
|
-
(err) => addMessage(`Failed to create: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3307
|
-
);
|
|
3308
|
-
} else if (inputMode === "command") {
|
|
3309
|
-
let cmdToRun = value;
|
|
3310
|
-
if (suggestions.length > 0 && suggestions[suggestionIndex]) {
|
|
3311
|
-
const sel = suggestions[suggestionIndex];
|
|
3312
|
-
const cmdPart = sel.cmd.replace(/\s+\[.*\]$/, "");
|
|
3313
|
-
if (cmdPart.startsWith(value) || value === "/") {
|
|
3314
|
-
cmdToRun = cmdPart;
|
|
3315
|
-
}
|
|
3316
|
-
if (sel.subs && !cmdPart.includes(" ")) {
|
|
3317
|
-
setInputValue(cmdPart + " ");
|
|
3318
|
-
setSuggestionIndex(0);
|
|
3319
|
-
return;
|
|
3320
|
-
}
|
|
3321
|
-
}
|
|
3322
|
-
setInputMode("none");
|
|
3323
|
-
setInputValue("");
|
|
3324
|
-
setSuggestionIndex(0);
|
|
3325
|
-
cmdHistory.push(cmdToRun);
|
|
3326
|
-
executeCommand(cmdToRun);
|
|
3327
|
-
}
|
|
3328
|
-
return;
|
|
3329
|
-
}
|
|
3330
|
-
if (key.tab && inputMode === "command") {
|
|
3331
|
-
if (suggestions.length > 0) {
|
|
3332
|
-
const sel = suggestions[suggestionIndex];
|
|
3333
|
-
if (sel) {
|
|
3334
|
-
const cmdPart = sel.cmd.replace(/\s+\[.*\]$/, "");
|
|
3335
|
-
setInputValue(cmdPart + (sel.subs ? " " : ""));
|
|
3336
|
-
setSuggestionIndex(0);
|
|
3337
|
-
}
|
|
3338
|
-
} else {
|
|
3339
|
-
const suffix = resolveCompletion(inputValue);
|
|
3340
|
-
if (suffix) setInputValue((v) => v + suffix);
|
|
3341
|
-
}
|
|
3342
|
-
return;
|
|
3343
|
-
}
|
|
3344
|
-
if (key.upArrow && inputMode === "command") {
|
|
3345
|
-
if (suggestions.length > 0) {
|
|
3346
|
-
setSuggestionIndex((i) => Math.max(0, i - 1));
|
|
3347
|
-
} else {
|
|
3348
|
-
const prev = cmdHistory.prev();
|
|
3349
|
-
if (prev !== null) setInputValue(prev);
|
|
3350
|
-
}
|
|
3351
|
-
return;
|
|
3352
|
-
}
|
|
3353
|
-
if (key.downArrow && inputMode === "command") {
|
|
3354
|
-
if (suggestions.length > 0) {
|
|
3355
|
-
setSuggestionIndex((i) => Math.min(suggestions.length - 1, i + 1));
|
|
3356
|
-
} else {
|
|
3357
|
-
const next = cmdHistory.next();
|
|
3358
|
-
setInputValue(next ?? "");
|
|
3359
|
-
}
|
|
3360
|
-
return;
|
|
3361
|
-
}
|
|
3362
|
-
if (key.backspace || key.delete) {
|
|
3363
|
-
setInputValue((v) => v.slice(0, -1));
|
|
3364
|
-
setSuggestionIndex(0);
|
|
3365
|
-
return;
|
|
3366
|
-
}
|
|
3367
|
-
if (input && !key.ctrl && !key.meta) {
|
|
3368
|
-
setInputValue((v) => v + input);
|
|
3369
|
-
setSuggestionIndex(0);
|
|
3370
|
-
}
|
|
3371
|
-
return;
|
|
3372
|
-
}
|
|
3373
|
-
if (input.toLowerCase() === "q") {
|
|
3374
|
-
exit();
|
|
3375
|
-
return;
|
|
3376
|
-
}
|
|
3377
|
-
if (key.escape) {
|
|
3378
|
-
if (detailOpen) {
|
|
3379
|
-
setDetailOpen(false);
|
|
3380
|
-
return;
|
|
3381
|
-
}
|
|
3382
|
-
if (activeView === "logs" && logSelectedIndex >= 0) {
|
|
3383
|
-
setLogSelectedIndex(-1);
|
|
3384
|
-
setLogScrollOffset(0);
|
|
3385
|
-
return;
|
|
3386
|
-
}
|
|
3387
|
-
return;
|
|
3388
|
-
}
|
|
3389
|
-
if (input === "/" && !detailOpen) {
|
|
3390
|
-
setInputMode("command");
|
|
3391
|
-
setInputValue("/");
|
|
3392
|
-
setSuggestionIndex(0);
|
|
3393
|
-
return;
|
|
3394
|
-
}
|
|
3395
|
-
if (activeView === "logs" && !detailOpen && input >= "0" && input <= "9") {
|
|
3396
|
-
setLogFilter(parseInt(input, 10));
|
|
3397
|
-
return;
|
|
3398
|
-
}
|
|
3399
|
-
if ((input === "f" || input === "F") && activeView === "logs" && !detailOpen) {
|
|
3400
|
-
setLogTypeFilter((prev) => new Set(cyclePreset(prev).types));
|
|
3401
|
-
return;
|
|
3402
|
-
}
|
|
3403
|
-
if ((input === "f" || input === "F") && (activeView === "tasks" || activeView === "agents" || activeView === "goals") && !detailOpen) {
|
|
3404
|
-
setActivityFilter((prev) => {
|
|
3405
|
-
const next = cyclePreset(prev);
|
|
3406
|
-
onSaveActivityFilter?.(next.label);
|
|
3407
|
-
return new Set(next.types);
|
|
3408
|
-
});
|
|
3409
|
-
return;
|
|
3410
|
-
}
|
|
3411
|
-
if ((input === "n" || input === "N") && activeView === "tasks" && !detailOpen && onCreateTask) {
|
|
3412
|
-
launchTaskWizard();
|
|
3413
|
-
return;
|
|
3414
|
-
}
|
|
3415
|
-
if ((input === "n" || input === "N") && activeView === "agents" && !detailOpen && onAddAgent) {
|
|
3416
|
-
launchAgentWizard();
|
|
3417
|
-
return;
|
|
3418
|
-
}
|
|
3419
|
-
if ((input === "n" || input === "N") && activeView === "goals" && !detailOpen && onCreateGoal) {
|
|
3420
|
-
const steps = getGoalWizardSteps(liveAgents);
|
|
3421
|
-
setWizardConfig({ title: "New Goal", steps, kind: "goal" });
|
|
3422
|
-
setInputMode("wizard");
|
|
3423
|
-
return;
|
|
3424
|
-
}
|
|
3425
|
-
if ((input === "e" || input === "E") && activeView === "goals" && selectedGoal && onUpdateGoal) {
|
|
3426
|
-
const steps = getEditGoalWizardSteps(selectedGoal, liveAgents);
|
|
3427
|
-
setWizardConfig({ title: `Edit Goal: ${selectedGoal.title}`, steps, kind: "edit_goal", targetId: selectedGoal.id });
|
|
3428
|
-
setInputMode("wizard");
|
|
3429
|
-
return;
|
|
3430
|
-
}
|
|
3431
|
-
if ((input === "d" || input === "D") && activeView === "goals" && selectedGoal && onDeleteGoal) {
|
|
3432
|
-
addMessage(`Deleting goal "${selectedGoal.title}"...`, tuiColors.amber);
|
|
3433
|
-
onDeleteGoal(selectedGoal.id).then(
|
|
3434
|
-
() => {
|
|
3435
|
-
addMessage(`\u2713 Deleted goal "${selectedGoal.title}"`, tuiColors.green);
|
|
3436
|
-
refreshAll();
|
|
3437
|
-
},
|
|
3438
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3439
|
-
);
|
|
3440
|
-
return;
|
|
3441
|
-
}
|
|
3442
|
-
if ((input === "c" || input === "C") && activeView === "goals" && selectedGoal && onUpdateGoalStatus) {
|
|
3443
|
-
if (selectedGoal.status === "active" || selectedGoal.status === "paused") {
|
|
3444
|
-
addMessage(`Marking goal "${selectedGoal.title}" as achieved...`, tuiColors.amber);
|
|
3445
|
-
onUpdateGoalStatus(selectedGoal.id, "achieved").then(
|
|
3446
|
-
() => {
|
|
3447
|
-
addMessage(`\u2713 Goal "${selectedGoal.title}" achieved`, tuiColors.green);
|
|
3448
|
-
refreshAll();
|
|
3449
|
-
},
|
|
3450
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3451
|
-
);
|
|
3452
|
-
}
|
|
3453
|
-
return;
|
|
3454
|
-
}
|
|
3455
|
-
if ((input === "x" || input === "X") && activeView === "goals" && selectedGoal && onUpdateGoalStatus) {
|
|
3456
|
-
if (selectedGoal.status === "active" || selectedGoal.status === "paused") {
|
|
3457
|
-
addMessage(`Abandoning goal "${selectedGoal.title}"...`, tuiColors.amber);
|
|
3458
|
-
onUpdateGoalStatus(selectedGoal.id, "abandoned").then(
|
|
3459
|
-
() => {
|
|
3460
|
-
addMessage(`\u2713 Goal "${selectedGoal.title}" abandoned`, tuiColors.dim);
|
|
3461
|
-
refreshAll();
|
|
3462
|
-
},
|
|
3463
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3464
|
-
);
|
|
3465
|
-
}
|
|
3466
|
-
return;
|
|
3467
|
-
}
|
|
3468
|
-
if ((input === "p" || input === "P") && activeView === "goals" && selectedGoal && onUpdateGoalStatus) {
|
|
3469
|
-
const newStatus = selectedGoal.status === "paused" ? "active" : "paused";
|
|
3470
|
-
if (selectedGoal.status === "active" || selectedGoal.status === "paused") {
|
|
3471
|
-
onUpdateGoalStatus(selectedGoal.id, newStatus).then(
|
|
3472
|
-
() => {
|
|
3473
|
-
addMessage(`Goal "${selectedGoal.title}" ${newStatus}`, tuiColors.cyan);
|
|
3474
|
-
refreshAll();
|
|
3475
|
-
},
|
|
3476
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3477
|
-
);
|
|
3478
|
-
}
|
|
3479
|
-
return;
|
|
3480
|
-
}
|
|
3481
|
-
if ((input === "a" || input === "A") && activeView === "tasks" && selectedTask?.status === "review" && onApproveTask) {
|
|
3482
|
-
addMessage(`Approving "${selectedTask.title}"...`, tuiColors.amber);
|
|
3483
|
-
onApproveTask(selectedTask.id).then(
|
|
3484
|
-
() => {
|
|
3485
|
-
addMessage(`\u2713 Approved "${selectedTask.title}"`, tuiColors.green);
|
|
3486
|
-
refreshAll();
|
|
3487
|
-
},
|
|
3488
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3489
|
-
);
|
|
3490
|
-
return;
|
|
3491
|
-
}
|
|
3492
|
-
if ((input === "x" || input === "X") && activeView === "tasks" && selectedTask?.status === "review" && onRejectTask) {
|
|
3493
|
-
addMessage(`Rejecting "${selectedTask.title}"...`, tuiColors.amber);
|
|
3494
|
-
onRejectTask(selectedTask.id).then(
|
|
3495
|
-
() => {
|
|
3496
|
-
addMessage(`\u2713 Rejected "${selectedTask.title}" \u2192 todo`, tuiColors.green);
|
|
3497
|
-
refreshAll();
|
|
3498
|
-
},
|
|
3499
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3500
|
-
);
|
|
3501
|
-
return;
|
|
3502
|
-
}
|
|
3503
|
-
if ((input === "c" || input === "C") && activeView === "tasks" && selectedTask && onCancelTask) {
|
|
3504
|
-
if (selectedTask.status === "done" || selectedTask.status === "failed" || selectedTask.status === "cancelled") {
|
|
3505
|
-
addMessage(`Cannot cancel \u2014 status is ${selectedTask.status}`, tuiColors.yellow);
|
|
3506
|
-
return;
|
|
3507
|
-
}
|
|
3508
|
-
addMessage(`Cancelling "${selectedTask.title}"...`, tuiColors.amber);
|
|
3509
|
-
onCancelTask(selectedTask.id).then(
|
|
3510
|
-
() => {
|
|
3511
|
-
addMessage(`\u2713 Cancelled "${selectedTask.title}"`, tuiColors.green);
|
|
3512
|
-
refreshAll();
|
|
3513
|
-
},
|
|
3514
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3515
|
-
);
|
|
3516
|
-
return;
|
|
3517
|
-
}
|
|
3518
|
-
if ((input === "e" || input === "E") && activeView === "tasks" && selectedTask && onUpdateTask) {
|
|
3519
|
-
launchEditTaskWizard(selectedTask);
|
|
3520
|
-
return;
|
|
3521
|
-
}
|
|
3522
|
-
if ((input === "e" || input === "E") && activeView === "agents" && selectedAgent && onUpdateAgent) {
|
|
3523
|
-
launchEditAgentWizard(selectedAgent);
|
|
3524
|
-
return;
|
|
3525
|
-
}
|
|
3526
|
-
if ((input === "s" || input === "S") && activeView === "tasks") {
|
|
3527
|
-
setShowAllTasks((v) => !v);
|
|
3528
|
-
setTaskSelectedIndex(0);
|
|
3529
|
-
setTaskScrollOffset(0);
|
|
3530
|
-
return;
|
|
3531
|
-
}
|
|
3532
|
-
if ((input === "s" || input === "S") && activeView === "agents" && selectedAgent && onForceStopAgent) {
|
|
3533
|
-
const isActuallyRunning = Object.values(liveState.running).some((e) => e.agent_id === selectedAgent.id);
|
|
3534
|
-
if (!isActuallyRunning && selectedAgent.status !== "running") {
|
|
3535
|
-
addMessage(`Agent "${selectedAgent.name}" is not running`, tuiColors.yellow);
|
|
3536
|
-
return;
|
|
3537
|
-
}
|
|
3538
|
-
addMessage(`Force-stopping agent "${selectedAgent.name}"...`, tuiColors.amber);
|
|
3539
|
-
onForceStopAgent(selectedAgent.id).then(
|
|
3540
|
-
() => {
|
|
3541
|
-
addMessage(`\u2713 Stopped agent "${selectedAgent.name}"`, tuiColors.green);
|
|
3542
|
-
refreshAll();
|
|
3543
|
-
},
|
|
3544
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3545
|
-
);
|
|
3546
|
-
return;
|
|
3547
|
-
}
|
|
3548
|
-
if ((input === "d" || input === "D") && activeView === "tasks" && selectedTask && selectedTask.status !== "in_progress" && onDeleteTask) {
|
|
3549
|
-
addMessage(`Deleting "${selectedTask.title}"...`, tuiColors.amber);
|
|
3550
|
-
onDeleteTask(selectedTask.id).then(
|
|
3551
|
-
() => {
|
|
3552
|
-
addMessage(`\u2713 Deleted "${selectedTask.title}"`, tuiColors.green);
|
|
3553
|
-
refreshAll();
|
|
3554
|
-
},
|
|
3555
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3556
|
-
);
|
|
3557
|
-
return;
|
|
3558
|
-
}
|
|
3559
|
-
if ((input === "d" || input === "D") && activeView === "agents" && selectedAgent && onDeleteAgent) {
|
|
3560
|
-
const isActuallyRunning = Object.values(liveState.running).some((e) => e.agent_id === selectedAgent.id);
|
|
3561
|
-
if (isActuallyRunning) {
|
|
3562
|
-
if (onForceStopAgent) {
|
|
3563
|
-
addMessage(`Stopping & deleting agent "${selectedAgent.name}"...`, tuiColors.amber);
|
|
3564
|
-
onForceStopAgent(selectedAgent.id).then(
|
|
3565
|
-
() => onDeleteAgent(selectedAgent.id)
|
|
3566
|
-
).then(
|
|
3567
|
-
() => {
|
|
3568
|
-
addMessage(`\u2713 Deleted agent "${selectedAgent.name}"`, tuiColors.green);
|
|
3569
|
-
refreshAll();
|
|
3570
|
-
},
|
|
3571
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3572
|
-
);
|
|
3573
|
-
} else {
|
|
3574
|
-
addMessage(`Cannot delete \u2014 agent "${selectedAgent.name}" is running. Press S to stop first.`, tuiColors.yellow);
|
|
3575
|
-
}
|
|
3576
|
-
return;
|
|
3577
|
-
}
|
|
3578
|
-
addMessage(`Deleting agent "${selectedAgent.name}"...`, tuiColors.amber);
|
|
3579
|
-
onDeleteAgent(selectedAgent.id).then(
|
|
3580
|
-
() => {
|
|
3581
|
-
addMessage(`\u2713 Deleted agent "${selectedAgent.name}"`, tuiColors.green);
|
|
3582
|
-
refreshAll();
|
|
3583
|
-
},
|
|
3584
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3585
|
-
);
|
|
3586
|
-
return;
|
|
3587
|
-
}
|
|
3588
|
-
if ((input === "u" || input === "U") && activeView === "agents" && selectedAgent && onToggleAutonomous) {
|
|
3589
|
-
const newAuto = !selectedAgent.autonomous;
|
|
3590
|
-
addMessage(`${newAuto ? "Enabling" : "Disabling"} autonomous mode for "${selectedAgent.name}"...`, tuiColors.amber);
|
|
3591
|
-
onToggleAutonomous(selectedAgent.id, newAuto).then(
|
|
3592
|
-
() => {
|
|
3593
|
-
addMessage(`${LOOP} ${selectedAgent.name} autonomous ${newAuto ? "ON" : "OFF"}`, tuiColors.cyan);
|
|
3594
|
-
refreshAll();
|
|
3595
|
-
},
|
|
3596
|
-
(err) => addMessage(`Failed: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3597
|
-
);
|
|
3598
|
-
return;
|
|
3599
|
-
}
|
|
3600
|
-
if (!detailOpen) {
|
|
3601
|
-
if (input === "g" || input === "G") {
|
|
3602
|
-
setActiveView("goals");
|
|
3603
|
-
return;
|
|
3604
|
-
}
|
|
3605
|
-
if (input === "t" || input === "T") {
|
|
3606
|
-
setActiveView("tasks");
|
|
3607
|
-
return;
|
|
3608
|
-
}
|
|
3609
|
-
if (input === "a" || input === "A") {
|
|
3610
|
-
setActiveView("agents");
|
|
3611
|
-
return;
|
|
3612
|
-
}
|
|
3613
|
-
if (input === "l" || input === "L") {
|
|
3614
|
-
setActiveView("logs");
|
|
3615
|
-
return;
|
|
3616
|
-
}
|
|
3617
|
-
}
|
|
3618
|
-
if (!detailOpen) {
|
|
3619
|
-
const viewOrder = TABS.map((t) => t.id);
|
|
3620
|
-
const idx = viewOrder.indexOf(activeView);
|
|
3621
|
-
if (key.tab || key.rightArrow) {
|
|
3622
|
-
setActiveView(viewOrder[(idx + 1) % viewOrder.length]);
|
|
3623
|
-
return;
|
|
3624
|
-
}
|
|
3625
|
-
if (key.leftArrow) {
|
|
3626
|
-
setActiveView(viewOrder[(idx + viewOrder.length - 1) % viewOrder.length]);
|
|
3627
|
-
return;
|
|
3628
|
-
}
|
|
3629
|
-
}
|
|
3630
|
-
if (key.return) {
|
|
3631
|
-
const showAllRowIdx = hiddenTaskCount > 0 ? visibleTasks.length : -1;
|
|
3632
|
-
if (activeView === "tasks" && taskSelectedIndex === showAllRowIdx) {
|
|
3633
|
-
setShowAllTasks((v) => !v);
|
|
3634
|
-
setTaskSelectedIndex(0);
|
|
3635
|
-
setTaskScrollOffset(0);
|
|
3636
|
-
return;
|
|
3637
|
-
}
|
|
3638
|
-
const addRowIdx = visibleTasks.length + (hiddenTaskCount > 0 ? 1 : 0);
|
|
3639
|
-
if (activeView === "tasks" && taskSelectedIndex === addRowIdx && onCreateTask) {
|
|
3640
|
-
launchTaskWizard();
|
|
3641
|
-
return;
|
|
3642
|
-
}
|
|
3643
|
-
if (activeView === "goals" && goalSelectedIndex === sortedGoals.length && onCreateGoal) {
|
|
3644
|
-
const steps = getGoalWizardSteps(liveAgents);
|
|
3645
|
-
setWizardConfig({ title: "New Goal", steps, kind: "goal" });
|
|
3646
|
-
setInputMode("wizard");
|
|
3647
|
-
return;
|
|
3648
|
-
}
|
|
3649
|
-
if (activeView === "agents" && agentSelectedIndex === sortedAgents.length && onAddAgent) {
|
|
3650
|
-
launchAgentWizard();
|
|
3651
|
-
return;
|
|
3652
|
-
}
|
|
3653
|
-
if (activeView === "goals" && selectedGoal) {
|
|
3654
|
-
setDetailOpen((prev) => !prev);
|
|
3655
|
-
return;
|
|
3656
|
-
}
|
|
3657
|
-
if (activeView === "tasks" && selectedTask) {
|
|
3658
|
-
setDetailOpen((prev) => !prev);
|
|
3659
|
-
return;
|
|
3660
|
-
}
|
|
3661
|
-
if (activeView === "agents" && selectedAgent) {
|
|
3662
|
-
setDetailOpen((prev) => !prev);
|
|
3663
|
-
return;
|
|
3664
|
-
}
|
|
3665
|
-
if (activeView === "logs" && logSelectedIndex >= 0) {
|
|
3666
|
-
setDetailOpen((prev) => !prev);
|
|
3667
|
-
return;
|
|
3668
|
-
}
|
|
3669
|
-
}
|
|
3670
|
-
if ((input === "r" || input === "R") && activeView === "tasks" && selectedTask && onRunTask) {
|
|
3671
|
-
if (!RUNNABLE.has(selectedTask.status)) {
|
|
3672
|
-
addMessage(`Cannot run "${selectedTask.title}" \u2014 status is ${selectedTask.status}`, tuiColors.yellow);
|
|
3673
|
-
return;
|
|
3674
|
-
}
|
|
3675
|
-
addMessage(`Running "${selectedTask.title}"...`, tuiColors.green);
|
|
3676
|
-
onRunTask(selectedTask.id).then(
|
|
3677
|
-
() => {
|
|
3678
|
-
addMessage(`Dispatched "${selectedTask.title}"`, tuiColors.green);
|
|
3679
|
-
refreshAll();
|
|
3680
|
-
},
|
|
3681
|
-
(err) => addMessage(`Failed to run: ${err instanceof Error ? err.message : String(err)}`, tuiColors.red)
|
|
3682
|
-
);
|
|
3683
|
-
return;
|
|
3684
|
-
}
|
|
3685
|
-
if (key.upArrow || input === "k") {
|
|
3686
|
-
if (activeView === "goals") {
|
|
3687
|
-
setGoalSelectedIndex((i) => {
|
|
3688
|
-
const next = Math.max(0, i - 1);
|
|
3689
|
-
setGoalScrollOffset((o) => next < o ? next : o);
|
|
3690
|
-
return next;
|
|
3691
|
-
});
|
|
3692
|
-
} else if (activeView === "tasks") {
|
|
3693
|
-
setTaskSelectedIndex((i) => {
|
|
3694
|
-
const next = Math.max(0, i - 1);
|
|
3695
|
-
setTaskScrollOffset((o) => next < o ? next : o);
|
|
3696
|
-
return next;
|
|
3697
|
-
});
|
|
3698
|
-
} else if (activeView === "agents") {
|
|
3699
|
-
setAgentSelectedIndex((i) => {
|
|
3700
|
-
const next = Math.max(0, i - 1);
|
|
3701
|
-
setAgentScrollOffset((o) => next < o ? next : o);
|
|
3702
|
-
return next;
|
|
3703
|
-
});
|
|
3704
|
-
} else if (activeView === "logs") {
|
|
3705
|
-
setLogSelectedIndex((i) => {
|
|
3706
|
-
if (i === -1) {
|
|
3707
|
-
const last = messages.length - 1;
|
|
3708
|
-
setLogScrollOffset(Math.max(0, last - mainH + 2));
|
|
3709
|
-
return Math.max(0, last);
|
|
3710
|
-
}
|
|
3711
|
-
const next = Math.max(0, i - 1);
|
|
3712
|
-
setLogScrollOffset((o) => next < o ? next : o);
|
|
3713
|
-
return next;
|
|
3714
|
-
});
|
|
3715
|
-
}
|
|
3716
|
-
}
|
|
3717
|
-
if (key.downArrow || input === "j") {
|
|
3718
|
-
if (activeView === "goals") {
|
|
3719
|
-
const maxIdx = sortedGoals.length + (onCreateGoal ? 1 : 0) - 1;
|
|
3720
|
-
setGoalSelectedIndex((i) => {
|
|
3721
|
-
const next = Math.min(Math.max(0, maxIdx), i + 1);
|
|
3722
|
-
setGoalScrollOffset((o) => next >= o + mainH ? next - mainH + 1 : o);
|
|
3723
|
-
return next;
|
|
3724
|
-
});
|
|
3725
|
-
} else if (activeView === "tasks") {
|
|
3726
|
-
const maxIdx = visibleTasks.length + (onCreateTask ? 1 : 0) + (hiddenTaskCount > 0 ? 1 : 0) - 1;
|
|
3727
|
-
setTaskSelectedIndex((i) => {
|
|
3728
|
-
const next = Math.min(Math.max(0, maxIdx), i + 1);
|
|
3729
|
-
setTaskScrollOffset((o) => next >= o + mainH ? next - mainH + 1 : o);
|
|
3730
|
-
return next;
|
|
3731
|
-
});
|
|
3732
|
-
} else if (activeView === "agents") {
|
|
3733
|
-
const maxIdx = sortedAgents.length + (onAddAgent ? 1 : 0) - 1;
|
|
3734
|
-
setAgentSelectedIndex((i) => {
|
|
3735
|
-
const next = Math.min(Math.max(0, maxIdx), i + 1);
|
|
3736
|
-
setAgentScrollOffset((o) => next >= o + mainH ? next - mainH + 1 : o);
|
|
3737
|
-
return next;
|
|
3738
|
-
});
|
|
3739
|
-
} else if (activeView === "logs") {
|
|
3740
|
-
setLogSelectedIndex((i) => {
|
|
3741
|
-
if (i === -1) return -1;
|
|
3742
|
-
const maxIdx = messages.length - 1;
|
|
3743
|
-
if (i >= maxIdx) {
|
|
3744
|
-
setLogScrollOffset(0);
|
|
3745
|
-
return -1;
|
|
3746
|
-
}
|
|
3747
|
-
const next = i + 1;
|
|
3748
|
-
setLogScrollOffset((o) => next >= o + mainH - 1 ? next - mainH + 2 : o);
|
|
3749
|
-
return next;
|
|
3750
|
-
});
|
|
3751
|
-
}
|
|
3752
|
-
}
|
|
3753
|
-
});
|
|
3754
|
-
const inInput = inputMode !== "none";
|
|
3755
|
-
const selectedLog = logSelectedIndex >= 0 ? messages[logSelectedIndex] : void 0;
|
|
3756
|
-
const showTaskDetail = !inInput && detailOpen && activeView === "tasks" && selectedTask;
|
|
3757
|
-
const showAgentDetail = !inInput && detailOpen && activeView === "agents" && selectedAgent;
|
|
3758
|
-
const showGoalDetail = !inInput && detailOpen && activeView === "goals" && selectedGoal;
|
|
3759
|
-
const showLogDetail = !inInput && detailOpen && activeView === "logs" && selectedLog;
|
|
3760
|
-
const canRun = !inInput && activeView === "tasks" && selectedTask && RUNNABLE.has(selectedTask.status) && !!onRunTask;
|
|
3761
|
-
const canNew = !inInput && !detailOpen && (activeView === "goals" && !!onCreateGoal || activeView === "tasks" && !!onCreateTask || activeView === "agents" && !!onAddAgent);
|
|
3762
|
-
const canApprove = !inInput && activeView === "tasks" && selectedTask?.status === "review" && !!onApproveTask;
|
|
3763
|
-
const canReject = !inInput && activeView === "tasks" && selectedTask?.status === "review" && !!onRejectTask;
|
|
3764
|
-
const agentActuallyRunning = selectedAgent ? Object.values(liveState.running).some((e) => e.agent_id === selectedAgent.id) : false;
|
|
3765
|
-
const canDelete = !inInput && (activeView === "goals" && selectedGoal && !!onDeleteGoal || activeView === "tasks" && selectedTask && selectedTask.status !== "in_progress" && !!onDeleteTask || activeView === "agents" && selectedAgent && !!onDeleteAgent);
|
|
3766
|
-
const canEdit = !inInput && !detailOpen && (activeView === "goals" && !!selectedGoal && !!onUpdateGoal || activeView === "tasks" && !!selectedTask && !!onUpdateTask || activeView === "agents" && !!selectedAgent && !!onUpdateAgent);
|
|
3767
|
-
const canForceStop = !inInput && activeView === "agents" && selectedAgent && (agentActuallyRunning || selectedAgent.status === "running") && !!onForceStopAgent;
|
|
3768
|
-
const canToggleAuto = !inInput && activeView === "agents" && !!selectedAgent && !!onToggleAutonomous;
|
|
3769
|
-
const canPause = !inInput && activeView === "goals" && !!selectedGoal && (selectedGoal.status === "active" || selectedGoal.status === "paused") && !!onUpdateGoalStatus;
|
|
3770
|
-
const showSuggestions = inputMode === "command" && suggestions.length > 0;
|
|
3771
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: W, height: H, children: [
|
|
3772
|
-
/* @__PURE__ */ jsx(
|
|
3773
|
-
Header,
|
|
3774
|
-
{
|
|
3775
|
-
projectName,
|
|
3776
|
-
activeView,
|
|
3777
|
-
mode,
|
|
3778
|
-
stats: headerStats,
|
|
3779
|
-
tokens: headerTokens,
|
|
3780
|
-
uptime,
|
|
3781
|
-
width: W
|
|
3782
|
-
}
|
|
3783
|
-
),
|
|
3784
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
3785
|
-
activeView === "goals" && /* @__PURE__ */ jsx(
|
|
3786
|
-
GoalsContent,
|
|
3787
|
-
{
|
|
3788
|
-
goals: sortedGoals,
|
|
3789
|
-
selectedIndex: goalSelectedIndex,
|
|
3790
|
-
scrollOffset: goalScrollOffset,
|
|
3791
|
-
height: mainH,
|
|
3792
|
-
width: ruleW,
|
|
3793
|
-
showAddRow: !!onCreateGoal,
|
|
3794
|
-
agentNameMap
|
|
3795
|
-
}
|
|
3796
|
-
),
|
|
3797
|
-
activeView === "tasks" && /* @__PURE__ */ jsx(
|
|
3798
|
-
TasksContent,
|
|
3799
|
-
{
|
|
3800
|
-
tasks: visibleTasks,
|
|
3801
|
-
selectedIndex: taskSelectedIndex,
|
|
3802
|
-
scrollOffset: taskScrollOffset,
|
|
3803
|
-
height: mainH,
|
|
3804
|
-
width: ruleW,
|
|
3805
|
-
showAddRow: !!onCreateTask,
|
|
3806
|
-
agentNameMap,
|
|
3807
|
-
hiddenCount: hiddenTaskCount
|
|
3808
|
-
}
|
|
3809
|
-
),
|
|
3810
|
-
activeView === "agents" && /* @__PURE__ */ jsx(
|
|
3811
|
-
AgentsContent,
|
|
3812
|
-
{
|
|
3813
|
-
agents: sortedAgents,
|
|
3814
|
-
selectedIndex: agentSelectedIndex,
|
|
3815
|
-
scrollOffset: agentScrollOffset,
|
|
3816
|
-
height: mainH,
|
|
3817
|
-
width: ruleW,
|
|
3818
|
-
state: liveState,
|
|
3819
|
-
taskTitleMap,
|
|
3820
|
-
showAddRow: !!onAddAgent,
|
|
3821
|
-
agentTeamMap,
|
|
3822
|
-
teamLeadSet,
|
|
3823
|
-
activeTeamCount
|
|
3824
|
-
}
|
|
3825
|
-
),
|
|
3826
|
-
activeView === "logs" && /* @__PURE__ */ jsx(
|
|
3827
|
-
LogsContent,
|
|
3828
|
-
{
|
|
3829
|
-
messages,
|
|
3830
|
-
height: mainH,
|
|
3831
|
-
agents: sortedAgents,
|
|
3832
|
-
logFilter,
|
|
3833
|
-
logTypeFilter,
|
|
3834
|
-
selectedIndex: logSelectedIndex,
|
|
3835
|
-
scrollOffset: logScrollOffset,
|
|
3836
|
-
agentNameMap,
|
|
3837
|
-
taskTitleMap,
|
|
3838
|
-
width: ruleW
|
|
3839
|
-
}
|
|
3840
|
-
),
|
|
3841
|
-
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
3842
|
-
inputMode === "wizard" && wizardConfig ? /* @__PURE__ */ jsx(
|
|
3843
|
-
FormWizard,
|
|
3844
|
-
{
|
|
3845
|
-
title: wizardConfig.title,
|
|
3846
|
-
steps: wizardConfig.steps,
|
|
3847
|
-
onComplete: handleWizardComplete,
|
|
3848
|
-
onCancel: handleWizardCancel,
|
|
3849
|
-
width: ruleW,
|
|
3850
|
-
height: feedH
|
|
3851
|
-
}
|
|
3852
|
-
) : showSuggestions ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3853
|
-
/* @__PURE__ */ jsx(SectionLabel, { label: "COMMANDS", width: ruleW }),
|
|
3854
|
-
/* @__PURE__ */ jsx(
|
|
3855
|
-
SuggestionsPanel,
|
|
3856
|
-
{
|
|
3857
|
-
suggestions,
|
|
3858
|
-
selectedIndex: suggestionIndex,
|
|
3859
|
-
height: Math.min(suggestions.length, feedH),
|
|
3860
|
-
width: ruleW
|
|
3861
|
-
}
|
|
3862
|
-
)
|
|
3863
|
-
] }) : inputMode === "new_task" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3864
|
-
/* @__PURE__ */ jsx(InputSectionLabel, { mode: inputMode, width: ruleW }),
|
|
3865
|
-
/* @__PURE__ */ jsx(InputPanel, { mode: inputMode, value: inputValue, width: ruleW })
|
|
3866
|
-
] }) : showTaskDetail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3867
|
-
/* @__PURE__ */ jsx(DetailSectionLabel, { task: selectedTask, width: ruleW }),
|
|
3868
|
-
/* @__PURE__ */ jsx(
|
|
3869
|
-
DetailPanel,
|
|
3870
|
-
{
|
|
3871
|
-
task: selectedTask,
|
|
3872
|
-
height: feedH,
|
|
3873
|
-
width: ruleW,
|
|
3874
|
-
taskLogs: messages.filter((m) => m.taskId === selectedTask.id),
|
|
3875
|
-
agentNameMap
|
|
3876
|
-
}
|
|
3877
|
-
)
|
|
3878
|
-
] }) : showGoalDetail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3879
|
-
/* @__PURE__ */ jsx(SectionLabel, { label: `GOAL: ${selectedGoal.title}`, width: ruleW }),
|
|
3880
|
-
/* @__PURE__ */ jsx(GoalDetailPanel, { goal: selectedGoal, height: feedH, width: ruleW, agentNameMap })
|
|
3881
|
-
] }) : showAgentDetail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3882
|
-
/* @__PURE__ */ jsx(AgentDetailSectionLabel, { agent: selectedAgent, width: ruleW }),
|
|
3883
|
-
/* @__PURE__ */ jsx(AgentDetailPanel, { agent: selectedAgent, height: feedH, state: liveState, taskTitleMap, teamName: agentTeamMap.get(selectedAgent.id) })
|
|
3884
|
-
] }) : showLogDetail ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3885
|
-
/* @__PURE__ */ jsx(SectionLabel, { label: "LOG", width: ruleW }),
|
|
3886
|
-
/* @__PURE__ */ jsx(LogDetailPanel, { message: selectedLog, height: feedH, width: ruleW, agents: sortedAgents, agentNameMap, taskTitleMap })
|
|
3887
|
-
] }) : messages.length > 0 && activeView !== "logs" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3888
|
-
(() => {
|
|
3889
|
-
const suffixText = ` F:${activityFilterLabel.toUpperCase()} \u2502 ${activityFilteredMessages.length}/${messages.length}`;
|
|
3890
|
-
return /* @__PURE__ */ jsx(SectionLabel, { label: "ACTIVITY", width: ruleW, suffixLen: suffixText.length, suffix: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3891
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " F:" }),
|
|
3892
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: activityFilterLabel.toUpperCase() }),
|
|
3893
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
3894
|
-
" ",
|
|
3895
|
-
"\u2502",
|
|
3896
|
-
" ",
|
|
3897
|
-
activityFilteredMessages.length,
|
|
3898
|
-
"/",
|
|
3899
|
-
messages.length
|
|
3900
|
-
] })
|
|
3901
|
-
] }) });
|
|
3902
|
-
})(),
|
|
3903
|
-
/* @__PURE__ */ jsx(
|
|
3904
|
-
ActivityFeed,
|
|
3905
|
-
{
|
|
3906
|
-
messages: activityFilteredMessages,
|
|
3907
|
-
height: Math.max(1, feedH - 1),
|
|
3908
|
-
width: ruleW,
|
|
3909
|
-
agents: sortedAgents,
|
|
3910
|
-
agentNameMap
|
|
3911
|
-
}
|
|
3912
|
-
)
|
|
3913
|
-
] }) : activeView === "goals" ? /* @__PURE__ */ jsx(OnboardingBox, { count: sortedGoals.length, config: ONBOARDING_GOALS, width: ruleW }) : activeView === "tasks" ? /* @__PURE__ */ jsx(OnboardingBox, { count: sortedTasks.length, config: ONBOARDING_TASKS, width: ruleW }) : activeView === "agents" ? /* @__PURE__ */ jsx(OnboardingBox, { count: sortedAgents.length, config: ONBOARDING_AGENTS, width: ruleW }) : null,
|
|
3914
|
-
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
3915
|
-
/* @__PURE__ */ jsx(
|
|
3916
|
-
CommandBar,
|
|
3917
|
-
{
|
|
3918
|
-
mode: inputMode === "command" ? "command" : "navigate",
|
|
3919
|
-
value: inputMode === "command" ? inputValue : "",
|
|
3920
|
-
completion: inputMode === "command" ? resolveCompletion(inputValue) : null,
|
|
3921
|
-
activeView,
|
|
3922
|
-
canRun: !!canRun,
|
|
3923
|
-
canNew: !!canNew,
|
|
3924
|
-
canApprove: !!canApprove,
|
|
3925
|
-
canReject: !!canReject,
|
|
3926
|
-
canCancel: activeView === "tasks" && !!selectedTask && selectedTask.status === "in_progress" && !!onCancelTask,
|
|
3927
|
-
canDelete: !!canDelete,
|
|
3928
|
-
canEdit: !!canEdit,
|
|
3929
|
-
canForceStop: !!canForceStop,
|
|
3930
|
-
canToggleAuto: !!canToggleAuto,
|
|
3931
|
-
autoActive: selectedAgent?.autonomous,
|
|
3932
|
-
canPause: !!canPause,
|
|
3933
|
-
isPaused: selectedGoal?.status === "paused",
|
|
3934
|
-
canToggleShowAll: activeView === "tasks" && sortedTasks.length > TASK_LIST_LIMIT,
|
|
3935
|
-
showAllActive: showAllTasks,
|
|
3936
|
-
hasDetail: !!(showTaskDetail || showAgentDetail || showGoalDetail),
|
|
3937
|
-
itemCount: activeView === "goals" ? sortedGoals.length : activeView === "tasks" ? sortedTasks.length : activeView === "agents" ? liveAgents.length : messages.length,
|
|
3938
|
-
itemLabel: activeView === "goals" ? "goals" : activeView === "tasks" ? "tasks" : activeView === "agents" ? "agents" : "events",
|
|
3939
|
-
width: W,
|
|
3940
|
-
hasSuggestions: showSuggestions
|
|
3941
|
-
}
|
|
3942
|
-
)
|
|
3943
|
-
] });
|
|
3944
|
-
}
|
|
3945
|
-
function SuggestionsPanel({ suggestions, selectedIndex, height, width }) {
|
|
3946
|
-
const maxVisible = height;
|
|
3947
|
-
let scrollStart = 0;
|
|
3948
|
-
if (selectedIndex >= maxVisible) {
|
|
3949
|
-
scrollStart = selectedIndex - maxVisible + 1;
|
|
3950
|
-
}
|
|
3951
|
-
const visible = suggestions.slice(scrollStart, scrollStart + maxVisible);
|
|
3952
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 2, children: visible.map((sug, i) => {
|
|
3953
|
-
const realIndex = i + scrollStart;
|
|
3954
|
-
const isSelected = realIndex === selectedIndex;
|
|
3955
|
-
const marker = isSelected ? "\u25B6" : " ";
|
|
3956
|
-
const cmdPad = Math.min(20, Math.max(14, ...suggestions.map((s) => s.cmd.length + 1)));
|
|
3957
|
-
const cmdText = sug.cmd.padEnd(cmdPad);
|
|
3958
|
-
const subsText = sug.subs ? ` ${sug.subs}` : "";
|
|
3959
|
-
const maxDescLen = Math.max(4, width - cmdPad - subsText.length - 8);
|
|
3960
|
-
const desc = sug.desc.length > maxDescLen ? sug.desc.slice(0, maxDescLen - 1) + "\u2026" : sug.desc;
|
|
3961
|
-
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate", children: [
|
|
3962
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? tuiColors.amber : tuiColors.ghost, children: ` ${marker} ` }),
|
|
3963
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? tuiColors.white : tuiColors.silver, bold: isSelected, children: cmdText }),
|
|
3964
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: desc }),
|
|
3965
|
-
subsText && /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: subsText })
|
|
3966
|
-
] }, realIndex);
|
|
3967
|
-
}) });
|
|
3968
|
-
}
|
|
3969
|
-
function GoalsContent({ goals, selectedIndex, scrollOffset = 0, height, width, showAddRow, agentNameMap }) {
|
|
3970
|
-
const addRowIndex = goals.length;
|
|
3971
|
-
const visible = goals.slice(scrollOffset, scrollOffset + height);
|
|
3972
|
-
const addRowVisible = showAddRow && addRowIndex >= scrollOffset && addRowIndex < scrollOffset + height;
|
|
3973
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height, children: [
|
|
3974
|
-
visible.map((goal, i) => /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsx(GoalRow, { goal, selected: i + scrollOffset === selectedIndex, width: width - 2, agentNameMap }) }, goal.id)),
|
|
3975
|
-
addRowVisible && /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsxs(Text, { color: selectedIndex === addRowIndex ? tuiColors.amber : tuiColors.ghost, children: [
|
|
3976
|
-
selectedIndex === addRowIndex ? " \u25B8 " : " ",
|
|
3977
|
-
/* @__PURE__ */ jsx(Text, { color: selectedIndex === addRowIndex ? tuiColors.amber : tuiColors.dim, children: "+ add goal..." })
|
|
3978
|
-
] }) }, "__add__")
|
|
3979
|
-
] });
|
|
3980
|
-
}
|
|
3981
|
-
function GoalDetailPanel({ goal, height, width, agentNameMap }) {
|
|
3982
|
-
const assigneeName = goal.assignee ? agentNameMap?.get(goal.assignee) ?? goal.assignee : "any";
|
|
3983
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height, paddingX: 2, children: [
|
|
3984
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3985
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: "Status: " }),
|
|
3986
|
-
/* @__PURE__ */ jsx(Text, { color: goal.status === "active" ? tuiColors.green : goal.status === "achieved" ? tuiColors.amber : tuiColors.dim, bold: true, children: goal.status.toUpperCase() }),
|
|
3987
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
3988
|
-
" ",
|
|
3989
|
-
"\u2502",
|
|
3990
|
-
" "
|
|
3991
|
-
] }),
|
|
3992
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: "Assignee: " }),
|
|
3993
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.silver, children: assigneeName }),
|
|
3994
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
3995
|
-
" ",
|
|
3996
|
-
"\u2502",
|
|
3997
|
-
" "
|
|
3998
|
-
] }),
|
|
3999
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: "Created: " }),
|
|
4000
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.silver, children: goal.created_at.slice(0, 10) })
|
|
4001
|
-
] }),
|
|
4002
|
-
goal.description ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: goal.description.split("\n").slice(0, Math.max(1, height - 2)).map((line, i) => /* @__PURE__ */ jsx(Text, { color: tuiColors.silver, wrap: "truncate", children: line }, i)) }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, dimColor: true, children: "No description" })
|
|
4003
|
-
] });
|
|
4004
|
-
}
|
|
4005
|
-
function TasksContent({ tasks, selectedIndex, scrollOffset = 0, height, width, showAddRow, agentNameMap, hiddenCount = 0 }) {
|
|
4006
|
-
const hasShowAll = hiddenCount > 0;
|
|
4007
|
-
const showAllIndex = hasShowAll ? tasks.length : -1;
|
|
4008
|
-
const addRowIndex = tasks.length + (hasShowAll ? 1 : 0);
|
|
4009
|
-
const visible = tasks.slice(scrollOffset, scrollOffset + height);
|
|
4010
|
-
const showAllVisible = hasShowAll && showAllIndex >= scrollOffset && showAllIndex < scrollOffset + height;
|
|
4011
|
-
const addRowVisible = showAddRow && addRowIndex >= scrollOffset && addRowIndex < scrollOffset + height;
|
|
4012
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height, children: [
|
|
4013
|
-
visible.map((task, i) => /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsx(TaskRow, { task, selected: i + scrollOffset === selectedIndex, width: width - 2, agentNameMap }) }, task.id)),
|
|
4014
|
-
showAllVisible && /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsxs(Text, { color: selectedIndex === showAllIndex ? tuiColors.amber : tuiColors.ghost, children: [
|
|
4015
|
-
selectedIndex === showAllIndex ? " \u25B8 " : " ",
|
|
4016
|
-
/* @__PURE__ */ jsxs(Text, { color: selectedIndex === showAllIndex ? tuiColors.amber : tuiColors.dim, children: [
|
|
4017
|
-
"\u25BC",
|
|
4018
|
-
" Show all (",
|
|
4019
|
-
hiddenCount,
|
|
4020
|
-
" more) \u2014 press ",
|
|
4021
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: tuiColors.gray, children: "S" })
|
|
4022
|
-
] })
|
|
4023
|
-
] }) }, "__show_all__"),
|
|
4024
|
-
addRowVisible && /* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsxs(Text, { color: selectedIndex === addRowIndex ? tuiColors.amber : tuiColors.ghost, children: [
|
|
4025
|
-
selectedIndex === addRowIndex ? " \u25B8 " : " ",
|
|
4026
|
-
/* @__PURE__ */ jsx(Text, { color: selectedIndex === addRowIndex ? tuiColors.amber : tuiColors.dim, children: "+ add task..." })
|
|
4027
|
-
] }) }, "__add__")
|
|
4028
|
-
] });
|
|
4029
|
-
}
|
|
4030
|
-
function AgentsContent({ agents, selectedIndex, scrollOffset = 0, height, width, state, taskTitleMap, showAddRow, agentTeamMap, teamLeadSet, activeTeamCount }) {
|
|
4031
|
-
const runningByAgent = /* @__PURE__ */ new Map();
|
|
4032
|
-
for (const entry of Object.values(state.running)) {
|
|
4033
|
-
runningByAgent.set(entry.agent_id, entry);
|
|
4034
|
-
}
|
|
4035
|
-
const teamMemberCounts = /* @__PURE__ */ new Map();
|
|
4036
|
-
if (activeTeamCount && activeTeamCount > 0) {
|
|
4037
|
-
for (const a of agents) {
|
|
4038
|
-
const t = agentTeamMap?.get(a.id);
|
|
4039
|
-
if (t) teamMemberCounts.set(t, (teamMemberCounts.get(t) ?? 0) + 1);
|
|
4040
|
-
}
|
|
4041
|
-
}
|
|
4042
|
-
const addRowIndex = agents.length;
|
|
4043
|
-
const visible = agents.slice(scrollOffset, scrollOffset + height);
|
|
4044
|
-
const addRowVisible = showAddRow && addRowIndex >= scrollOffset && addRowIndex < scrollOffset + height;
|
|
4045
|
-
const hasTeams = activeTeamCount != null && activeTeamCount > 0;
|
|
4046
|
-
const teamLeadNameMap = /* @__PURE__ */ new Map();
|
|
4047
|
-
if (hasTeams && teamLeadSet && agentTeamMap) {
|
|
4048
|
-
for (const a of agents) {
|
|
4049
|
-
if (teamLeadSet.has(a.id)) {
|
|
4050
|
-
const t = agentTeamMap.get(a.id);
|
|
4051
|
-
if (t) teamLeadNameMap.set(t, a.name);
|
|
4052
|
-
}
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
let teamMemberTotal = 0;
|
|
4056
|
-
for (const c of teamMemberCounts.values()) teamMemberTotal += c;
|
|
4057
|
-
const unassignedCount = agents.length - teamMemberTotal;
|
|
4058
|
-
const rows = [];
|
|
4059
|
-
let prevTeam = scrollOffset > 0 ? agentTeamMap?.get(agents[scrollOffset - 1]?.id ?? "") : void 0;
|
|
4060
|
-
for (let i = 0; i < visible.length && rows.length < height; i++) {
|
|
4061
|
-
const agent = visible[i];
|
|
4062
|
-
const team = agentTeamMap?.get(agent.id);
|
|
4063
|
-
if (hasTeams && team && team !== prevTeam) {
|
|
4064
|
-
rows.push(
|
|
4065
|
-
/* @__PURE__ */ jsx(
|
|
4066
|
-
TeamSectionRow,
|
|
4067
|
-
{
|
|
4068
|
-
teamName: team,
|
|
4069
|
-
memberCount: teamMemberCounts.get(team) ?? 0,
|
|
4070
|
-
leadName: teamLeadNameMap.get(team),
|
|
4071
|
-
width
|
|
4072
|
-
},
|
|
4073
|
-
`ts-${team}`
|
|
4074
|
-
)
|
|
4075
|
-
);
|
|
4076
|
-
if (rows.length >= height) break;
|
|
4077
|
-
}
|
|
4078
|
-
if (hasTeams && !team && prevTeam) {
|
|
4079
|
-
rows.push(
|
|
4080
|
-
/* @__PURE__ */ jsx(UnassignedSectionRow, { memberCount: unassignedCount, width }, "ts-unassigned")
|
|
4081
|
-
);
|
|
4082
|
-
if (rows.length >= height) break;
|
|
4083
|
-
}
|
|
4084
|
-
prevTeam = team;
|
|
4085
|
-
rows.push(
|
|
4086
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsx(
|
|
4087
|
-
AgentRow,
|
|
4088
|
-
{
|
|
4089
|
-
agent,
|
|
4090
|
-
selected: i + scrollOffset === selectedIndex,
|
|
4091
|
-
width: width - 2,
|
|
4092
|
-
runningEntry: runningByAgent.get(agent.id),
|
|
4093
|
-
currentTaskTitle: agent.current_task ? taskTitleMap.get(agent.current_task) : void 0,
|
|
4094
|
-
teamName: team,
|
|
4095
|
-
isLead: teamLeadSet?.has(agent.id)
|
|
4096
|
-
}
|
|
4097
|
-
) }, agent.id)
|
|
4098
|
-
);
|
|
4099
|
-
}
|
|
4100
|
-
if (addRowVisible && rows.length < height) {
|
|
4101
|
-
rows.push(
|
|
4102
|
-
/* @__PURE__ */ jsx(Box, { paddingX: 2, children: /* @__PURE__ */ jsxs(Text, { color: selectedIndex === addRowIndex ? tuiColors.amber : tuiColors.ghost, children: [
|
|
4103
|
-
selectedIndex === addRowIndex ? " \u25B8 " : " ",
|
|
4104
|
-
/* @__PURE__ */ jsx(Text, { color: selectedIndex === addRowIndex ? tuiColors.amber : tuiColors.dim, children: "+ add agent..." })
|
|
4105
|
-
] }) }, "__add__")
|
|
4106
|
-
);
|
|
4107
|
-
}
|
|
4108
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", height, children: rows });
|
|
4109
|
-
}
|
|
4110
|
-
function useNow(interval = 5e3) {
|
|
4111
|
-
const [now, setNow] = useState(Date.now());
|
|
4112
|
-
useEffect(() => {
|
|
4113
|
-
const timer2 = setInterval(() => setNow(Date.now()), interval);
|
|
4114
|
-
return () => clearInterval(timer2);
|
|
4115
|
-
}, [interval]);
|
|
4116
|
-
return now;
|
|
4117
|
-
}
|
|
4118
|
-
function relativeTime(ts, now) {
|
|
4119
|
-
const diff = Math.max(0, now - ts);
|
|
4120
|
-
if (diff < 3e3) return "now";
|
|
4121
|
-
if (diff < 6e4) return `${Math.floor(diff / 1e3)}s`;
|
|
4122
|
-
if (diff < 36e5) return `${Math.floor(diff / 6e4)}m`;
|
|
4123
|
-
return `${Math.floor(diff / 36e5)}h`;
|
|
4124
|
-
}
|
|
4125
|
-
var SPARK_CHARS2 = " \u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
4126
|
-
function buildSparkline(messages, buckets, bucketMs, now) {
|
|
4127
|
-
const counts = new Array(buckets).fill(0);
|
|
4128
|
-
const windowStart = now - buckets * bucketMs;
|
|
4129
|
-
for (const m of messages) {
|
|
4130
|
-
if (m.ts < windowStart) continue;
|
|
4131
|
-
const idx = Math.min(buckets - 1, Math.floor((m.ts - windowStart) / bucketMs));
|
|
4132
|
-
counts[idx]++;
|
|
4133
|
-
}
|
|
4134
|
-
const max = Math.max(1, ...counts);
|
|
4135
|
-
return counts.map((c) => SPARK_CHARS2[Math.round(c / max * 8)]).join("");
|
|
4136
|
-
}
|
|
4137
|
-
function getMsgBg(msgType) {
|
|
4138
|
-
switch (msgType) {
|
|
4139
|
-
case "error":
|
|
4140
|
-
return tuiColors.errorBg;
|
|
4141
|
-
default:
|
|
4142
|
-
return void 0;
|
|
4143
|
-
}
|
|
4144
|
-
}
|
|
4145
|
-
function getMsgTextColor(msgType, fallback) {
|
|
4146
|
-
switch (msgType) {
|
|
4147
|
-
case "output":
|
|
4148
|
-
return tuiColors.white;
|
|
4149
|
-
case "tool":
|
|
4150
|
-
return tuiColors.dim;
|
|
4151
|
-
case "result":
|
|
4152
|
-
return tuiColors.dim;
|
|
4153
|
-
case "file":
|
|
4154
|
-
return tuiColors.gray;
|
|
4155
|
-
case "error":
|
|
4156
|
-
return tuiColors.red;
|
|
4157
|
-
case "lifecycle":
|
|
4158
|
-
return tuiColors.dim;
|
|
4159
|
-
case "system":
|
|
4160
|
-
return tuiColors.dim;
|
|
4161
|
-
default:
|
|
4162
|
-
return fallback;
|
|
4163
|
-
}
|
|
4164
|
-
}
|
|
4165
|
-
function LogsContent({ messages, height, agents, logFilter, logTypeFilter, selectedIndex, scrollOffset, agentNameMap, taskTitleMap, width }) {
|
|
4166
|
-
const now = useNow();
|
|
4167
|
-
const filteredMessages = useMemo(() => {
|
|
4168
|
-
return messages.filter((m) => {
|
|
4169
|
-
if (logFilter !== 0) {
|
|
4170
|
-
const agent = agents[logFilter - 1];
|
|
4171
|
-
if (agent && m.agentId !== agent.id) return false;
|
|
4172
|
-
}
|
|
4173
|
-
const mt = m.msgType ?? "info";
|
|
4174
|
-
return logTypeFilter.has(mt);
|
|
4175
|
-
});
|
|
4176
|
-
}, [messages, agents, logFilter, logTypeFilter]);
|
|
4177
|
-
useMemo(() => {
|
|
4178
|
-
const counts = {};
|
|
4179
|
-
for (const m of messages) {
|
|
4180
|
-
const mt = m.msgType ?? "info";
|
|
4181
|
-
counts[mt] = (counts[mt] ?? 0) + 1;
|
|
4182
|
-
}
|
|
4183
|
-
return counts;
|
|
4184
|
-
}, [messages]);
|
|
4185
|
-
const agentMsgCounts = useMemo(() => {
|
|
4186
|
-
const counts = /* @__PURE__ */ new Map();
|
|
4187
|
-
for (const m of messages) {
|
|
4188
|
-
if (m.agentId) counts.set(m.agentId, (counts.get(m.agentId) ?? 0) + 1);
|
|
4189
|
-
}
|
|
4190
|
-
return counts;
|
|
4191
|
-
}, [messages]);
|
|
4192
|
-
const sparkline = useMemo(() => buildSparkline(filteredMessages, 30, 1e4, now), [filteredMessages, now]);
|
|
4193
|
-
const typeFilterLabel = logTypeFilter.size >= 8 ? "all" : logTypeFilter.size === 1 && logTypeFilter.has("output") ? "text" : logTypeFilter.size === 1 && logTypeFilter.has("error") ? "errors" : logTypeFilter.has("tool") && !logTypeFilter.has("output") ? "tools" : logTypeFilter.has("lifecycle") && !logTypeFilter.has("output") ? "events" : `${logTypeFilter.size} types`;
|
|
4194
|
-
const viewH = height - 3;
|
|
4195
|
-
const visible = selectedIndex === -1 ? filteredMessages.slice(-viewH) : filteredMessages.slice(scrollOffset, scrollOffset + viewH);
|
|
4196
|
-
const highlightIdx = selectedIndex === -1 ? -1 : selectedIndex - scrollOffset;
|
|
4197
|
-
const agentColW = Math.min(10, Math.max(6, ...agents.map((a) => a.name.length)));
|
|
4198
|
-
const prefixW = 11 + agentColW;
|
|
4199
|
-
const isSessionStart = (i) => {
|
|
4200
|
-
if (i === 0) return true;
|
|
4201
|
-
const curr = visible[i];
|
|
4202
|
-
const prev = visible[i - 1];
|
|
4203
|
-
if (curr.agentId !== prev.agentId) return true;
|
|
4204
|
-
if (!curr.agentId) return false;
|
|
4205
|
-
return curr.ts - prev.ts > 3e4;
|
|
4206
|
-
};
|
|
4207
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
4208
|
-
/* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
4209
|
-
logFilter === 0 ? /* @__PURE__ */ jsx(Text, { backgroundColor: tuiColors.infoBg, color: tuiColors.silver, bold: true, children: " \u25CF ALL " }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " \u25CB all " }),
|
|
4210
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " " }),
|
|
4211
|
-
agents.slice(0, 9).map((a, i) => {
|
|
4212
|
-
const ac = getAgentColor(a.id, agents);
|
|
4213
|
-
const active = logFilter === i + 1;
|
|
4214
|
-
const count = agentMsgCounts.get(a.id) ?? 0;
|
|
4215
|
-
const countStr = count > 0 ? `\xB7${count}` : "";
|
|
4216
|
-
return active ? /* @__PURE__ */ jsxs(Text, { backgroundColor: tuiColors.successBg, color: ac, bold: true, children: [
|
|
4217
|
-
" ",
|
|
4218
|
-
i + 1,
|
|
4219
|
-
":",
|
|
4220
|
-
a.name,
|
|
4221
|
-
countStr,
|
|
4222
|
-
" "
|
|
4223
|
-
] }, a.id) : /* @__PURE__ */ jsxs(Text, { color: count > 0 ? tuiColors.dim : tuiColors.ghost, children: [
|
|
4224
|
-
" ",
|
|
4225
|
-
i + 1,
|
|
4226
|
-
":",
|
|
4227
|
-
a.name,
|
|
4228
|
-
countStr
|
|
4229
|
-
] }, a.id);
|
|
4230
|
-
})
|
|
4231
|
-
] }),
|
|
4232
|
-
/* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
4233
|
-
typeFilterLabel === "all" ? /* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " F:all" }) : /* @__PURE__ */ jsxs(Text, { backgroundColor: tuiColors.warnBg, color: tuiColors.amber, bold: true, children: [
|
|
4234
|
-
" F:",
|
|
4235
|
-
typeFilterLabel.toUpperCase(),
|
|
4236
|
-
" "
|
|
4237
|
-
] }),
|
|
4238
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4239
|
-
" ",
|
|
4240
|
-
"\u2502",
|
|
4241
|
-
" "
|
|
4242
|
-
] }),
|
|
4243
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
4244
|
-
filteredMessages.length,
|
|
4245
|
-
" events"
|
|
4246
|
-
] }),
|
|
4247
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4248
|
-
" ",
|
|
4249
|
-
"\u2502",
|
|
4250
|
-
" "
|
|
4251
|
-
] }),
|
|
4252
|
-
selectedIndex === -1 ? /* @__PURE__ */ jsxs(Box, { gap: 0, children: [
|
|
4253
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: tuiColors.successBg, color: tuiColors.green, children: " " }),
|
|
4254
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: tuiColors.successBg, color: tuiColors.green, children: /* @__PURE__ */ jsx(Spinner, { color: tuiColors.green }) }),
|
|
4255
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: tuiColors.successBg, color: tuiColors.green, children: " LIVE " })
|
|
4256
|
-
] }) : /* @__PURE__ */ jsxs(Text, { backgroundColor: tuiColors.warnBg, color: tuiColors.amber, children: [
|
|
4257
|
-
" \u2191\u2193 ",
|
|
4258
|
-
selectedIndex + 1,
|
|
4259
|
-
"/",
|
|
4260
|
-
filteredMessages.length,
|
|
4261
|
-
" "
|
|
4262
|
-
] }),
|
|
4263
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " " }),
|
|
4264
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amberDim, children: sparkline }),
|
|
4265
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " 5m" })
|
|
4266
|
-
] }),
|
|
4267
|
-
visible.length === 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, paddingTop: 1, children: [
|
|
4268
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: messages.length === 0 ? " \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E" : "No events for current filter." }),
|
|
4269
|
-
messages.length === 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4270
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " \u2502 \u2502" }),
|
|
4271
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
4272
|
-
" \u2502 ",
|
|
4273
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u25C7" }),
|
|
4274
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.gray, children: " Waiting for activity " }),
|
|
4275
|
-
"\u2502"
|
|
4276
|
-
] }),
|
|
4277
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
4278
|
-
" \u2502 ",
|
|
4279
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2502" }),
|
|
4280
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " Run tasks or start " }),
|
|
4281
|
-
"\u2502"
|
|
4282
|
-
] }),
|
|
4283
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
4284
|
-
" \u2502 ",
|
|
4285
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2502" }),
|
|
4286
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " the orchestrator " }),
|
|
4287
|
-
"\u2502"
|
|
4288
|
-
] }),
|
|
4289
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
4290
|
-
" \u2502 ",
|
|
4291
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u25C7" }),
|
|
4292
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " " }),
|
|
4293
|
-
"\u2502"
|
|
4294
|
-
] }),
|
|
4295
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F" })
|
|
4296
|
-
] })
|
|
4297
|
-
] }) : visible.map((msg, i) => {
|
|
4298
|
-
const isSelected = i === highlightIdx;
|
|
4299
|
-
const msgType = msg.msgType ?? "info";
|
|
4300
|
-
const icon = MSG_ICONS2[msgType] ?? "\u2502";
|
|
4301
|
-
const agentName = msg.agentId ? agentNameMap.get(msg.agentId) ?? msg.agentId.slice(0, 8) : void 0;
|
|
4302
|
-
const agentColor = msg.agentId ? getAgentColor(msg.agentId, agents) : void 0;
|
|
4303
|
-
const sessionStart = isSessionStart(i);
|
|
4304
|
-
const prevMsg = i > 0 ? visible[i - 1] : void 0;
|
|
4305
|
-
const isContinuation = prevMsg?.agentId === msg.agentId && !!msg.agentId;
|
|
4306
|
-
const showAgentBadge = !isContinuation && !!agentName;
|
|
4307
|
-
const showConnector = isContinuation && !!agentName;
|
|
4308
|
-
const textColor = getMsgTextColor(msgType, msg.color);
|
|
4309
|
-
const rowBg = isSelected ? tuiColors.infoBg : msgType === "error" ? tuiColors.errorBg : void 0;
|
|
4310
|
-
const taskTitle = msg.taskId ? taskTitleMap.get(msg.taskId) : void 0;
|
|
4311
|
-
const relTs = relativeTime(msg.ts, now);
|
|
4312
|
-
const badgeLabel = taskTitle && width > 80 ? `#${taskTitle.slice(0, 20)}` : "";
|
|
4313
|
-
const badgeW = badgeLabel ? badgeLabel.length + 3 : 0;
|
|
4314
|
-
const textW = Math.max(10, width - 2 - prefixW - badgeW);
|
|
4315
|
-
const displayText = msg.text.length > textW ? msg.text.slice(0, textW - 1) + "\u2026" : msg.text;
|
|
4316
|
-
return /* @__PURE__ */ jsxs(Box, { backgroundColor: rowBg, children: [
|
|
4317
|
-
/* @__PURE__ */ jsx(Text, { color: agentColor ?? tuiColors.ghost, children: sessionStart && showAgentBadge ? "\u250C" : showConnector ? "\u2502" : " " }),
|
|
4318
|
-
/* @__PURE__ */ jsx(Text, { color: isSelected ? tuiColors.amber : void 0, children: isSelected ? "\u25B8" : " " }),
|
|
4319
|
-
/* @__PURE__ */ jsx(Box, { width: 5, children: /* @__PURE__ */ jsx(Text, { color: relTs === "now" ? tuiColors.green : isSelected ? tuiColors.silver : tuiColors.ghost, children: relTs.padStart(4) }) }),
|
|
4320
|
-
/* @__PURE__ */ jsx(Box, { width: agentColW + 1, children: showAgentBadge ? /* @__PURE__ */ jsxs(Text, { color: agentColor, bold: true, children: [
|
|
4321
|
-
" ",
|
|
4322
|
-
agentName.slice(0, agentColW).padEnd(agentColW)
|
|
4323
|
-
] }) : showConnector ? /* @__PURE__ */ jsxs(Text, { color: agentColor ?? tuiColors.ghost, children: [
|
|
4324
|
-
" ",
|
|
4325
|
-
"\xB7".padEnd(agentColW)
|
|
4326
|
-
] }) : /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4327
|
-
" ",
|
|
4328
|
-
" ".padEnd(agentColW)
|
|
4329
|
-
] }) }),
|
|
4330
|
-
/* @__PURE__ */ jsxs(Text, { color: msgType === "error" ? tuiColors.red : agentColor ?? tuiColors.dim, children: [
|
|
4331
|
-
" ",
|
|
4332
|
-
icon,
|
|
4333
|
-
" "
|
|
4334
|
-
] }),
|
|
4335
|
-
/* @__PURE__ */ jsx(
|
|
4336
|
-
Text,
|
|
4337
|
-
{
|
|
4338
|
-
color: isSelected ? tuiColors.white : textColor,
|
|
4339
|
-
bold: isSelected || msgType === "lifecycle",
|
|
4340
|
-
children: displayText
|
|
4341
|
-
}
|
|
4342
|
-
),
|
|
4343
|
-
badgeLabel && /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4344
|
-
" ",
|
|
4345
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, backgroundColor: tuiColors.void, children: ` ${badgeLabel} ` })
|
|
4346
|
-
] })
|
|
4347
|
-
] }, i);
|
|
4348
|
-
})
|
|
4349
|
-
] });
|
|
4350
|
-
}
|
|
4351
|
-
function ActivityFeed({ messages, height, width, agents, agentNameMap }) {
|
|
4352
|
-
const now = useNow();
|
|
4353
|
-
const visible = messages.slice(-height);
|
|
4354
|
-
const textW = Math.max(10, width - 2 - 17);
|
|
4355
|
-
const padRows = Math.max(0, height - visible.length);
|
|
4356
|
-
let groupIdx = 0;
|
|
4357
|
-
const groupIndices = [];
|
|
4358
|
-
for (let j = 0; j < visible.length; j++) {
|
|
4359
|
-
if (j > 0 && visible[j].agentId !== visible[j - 1].agentId) groupIdx++;
|
|
4360
|
-
groupIndices.push(groupIdx);
|
|
4361
|
-
}
|
|
4362
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
4363
|
-
padRows > 0 && /* @__PURE__ */ jsx(Box, { height: padRows }),
|
|
4364
|
-
visible.map((msg, i) => {
|
|
4365
|
-
const agentName = msg.agentId ? agentNameMap.get(msg.agentId) ?? msg.agentId.slice(0, 8) : void 0;
|
|
4366
|
-
const agentColor = msg.agentId ? getAgentColor(msg.agentId, agents) : void 0;
|
|
4367
|
-
const msgType = msg.msgType ?? "info";
|
|
4368
|
-
const icon = MSG_ICONS2[msgType] ?? "\u2502";
|
|
4369
|
-
const textColor = getMsgTextColor(msgType, msg.color);
|
|
4370
|
-
const prevMsg = i > 0 ? visible[i - 1] : void 0;
|
|
4371
|
-
const isContinuation = prevMsg?.agentId === msg.agentId && !!msg.agentId;
|
|
4372
|
-
const isOddGroup = (groupIndices[i] & 1) === 1;
|
|
4373
|
-
const rowBg = getMsgBg(msgType) ?? (isOddGroup ? "#1a1a1a" : void 0);
|
|
4374
|
-
const relTs = relativeTime(msg.ts, now);
|
|
4375
|
-
const displayText = msg.text.length > textW ? msg.text.slice(0, textW - 1) + "\u2026" : msg.text;
|
|
4376
|
-
return /* @__PURE__ */ jsxs(Box, { backgroundColor: rowBg, children: [
|
|
4377
|
-
/* @__PURE__ */ jsx(Text, { color: agentColor ?? tuiColors.ghost, children: !isContinuation && agentName ? "\u258D" : isContinuation ? "\u258F" : " " }),
|
|
4378
|
-
/* @__PURE__ */ jsx(Box, { width: 5, children: /* @__PURE__ */ jsx(Text, { color: isContinuation ? tuiColors.ghost : relTs === "now" ? tuiColors.green : tuiColors.dim, children: isContinuation ? " " : relTs.padStart(4) }) }),
|
|
4379
|
-
/* @__PURE__ */ jsx(Box, { width: 9, children: agentName && !isContinuation ? /* @__PURE__ */ jsxs(Text, { color: agentColor, bold: true, children: [
|
|
4380
|
-
" ",
|
|
4381
|
-
agentName.slice(0, 8)
|
|
4382
|
-
] }) : /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: AGENT_INDENT }) }),
|
|
4383
|
-
/* @__PURE__ */ jsxs(Text, { color: msgType === "error" ? tuiColors.red : isContinuation ? tuiColors.ghost : agentColor ?? tuiColors.dim, children: [
|
|
4384
|
-
icon,
|
|
4385
|
-
" "
|
|
4386
|
-
] }),
|
|
4387
|
-
/* @__PURE__ */ jsx(Text, { color: textColor, children: displayText })
|
|
4388
|
-
] }, i);
|
|
4389
|
-
})
|
|
4390
|
-
] });
|
|
4391
|
-
}
|
|
4392
|
-
function LogDetailPanel({ message, height, width, agents, agentNameMap, taskTitleMap }) {
|
|
4393
|
-
const content = message.detail ?? message.text;
|
|
4394
|
-
const msgType = message.msgType ?? "info";
|
|
4395
|
-
const agentName = message.agentId ? agentNameMap.get(message.agentId) ?? message.agentId.slice(0, 8) : void 0;
|
|
4396
|
-
const agentColor = message.agentId ? getAgentColor(message.agentId, agents) : tuiColors.dim;
|
|
4397
|
-
const taskTitle = message.taskId ? taskTitleMap.get(message.taskId) : void 0;
|
|
4398
|
-
let display;
|
|
4399
|
-
let isJson = false;
|
|
4400
|
-
try {
|
|
4401
|
-
const parsed = JSON.parse(content);
|
|
4402
|
-
display = JSON.stringify(parsed, null, 2);
|
|
4403
|
-
isJson = true;
|
|
4404
|
-
} catch {
|
|
4405
|
-
display = content;
|
|
4406
|
-
}
|
|
4407
|
-
const maxW = Math.max(4, width - 6);
|
|
4408
|
-
const bodyHeight = Math.max(1, height - 4);
|
|
4409
|
-
const lines = display.split("\n").slice(0, bodyHeight);
|
|
4410
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
4411
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4412
|
-
"\u256D",
|
|
4413
|
-
"\u2500".repeat(maxW + 2),
|
|
4414
|
-
"\u256E"
|
|
4415
|
-
] }) }),
|
|
4416
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4417
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2502 " }),
|
|
4418
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: message.time }),
|
|
4419
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " \u2502 " }),
|
|
4420
|
-
agentName && /* @__PURE__ */ jsx(Text, { color: agentColor, bold: true, children: agentName }),
|
|
4421
|
-
agentName && /* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " \u2502 " }),
|
|
4422
|
-
/* @__PURE__ */ jsxs(Text, { color: MSG_ICONS2[msgType] ? msgType === "error" ? tuiColors.red : tuiColors.dim : tuiColors.dim, children: [
|
|
4423
|
-
MSG_ICONS2[msgType] ?? "\u2502",
|
|
4424
|
-
" ",
|
|
4425
|
-
msgType
|
|
4426
|
-
] }),
|
|
4427
|
-
taskTitle && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4428
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: " \u2502 " }),
|
|
4429
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.dim, children: [
|
|
4430
|
-
"#",
|
|
4431
|
-
taskTitle.slice(0, 30)
|
|
4432
|
-
] })
|
|
4433
|
-
] })
|
|
4434
|
-
] }),
|
|
4435
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4436
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2502 " }),
|
|
4437
|
-
/* @__PURE__ */ jsx(Text, { color: message.color, bold: true, wrap: "truncate", children: message.text.slice(0, maxW) })
|
|
4438
|
-
] }),
|
|
4439
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4440
|
-
"\u251C",
|
|
4441
|
-
"\u2500".repeat(maxW + 2),
|
|
4442
|
-
"\u2524"
|
|
4443
|
-
] }) }),
|
|
4444
|
-
lines.map((line, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
4445
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: "\u2502 " }),
|
|
4446
|
-
isJson && /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4447
|
-
String(i + 1).padStart(3),
|
|
4448
|
-
" "
|
|
4449
|
-
] }),
|
|
4450
|
-
/* @__PURE__ */ jsx(
|
|
4451
|
-
Text,
|
|
4452
|
-
{
|
|
4453
|
-
wrap: "truncate",
|
|
4454
|
-
color: isJson && line.includes('"') ? tuiColors.cyan : isJson && /^\s*[}\]]/.test(line) ? tuiColors.ghost : line.startsWith("error") || line.startsWith("Error") ? tuiColors.red : tuiColors.silver,
|
|
4455
|
-
children: line.slice(0, isJson ? maxW - 4 : maxW)
|
|
4456
|
-
}
|
|
4457
|
-
)
|
|
4458
|
-
] }, i)),
|
|
4459
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4460
|
-
"\u2570",
|
|
4461
|
-
"\u2500".repeat(maxW + 2),
|
|
4462
|
-
"\u256F"
|
|
4463
|
-
] }) })
|
|
4464
|
-
] });
|
|
4465
|
-
}
|
|
4466
|
-
function SectionLabel({ label, width, suffix, suffixLen = 0 }) {
|
|
4467
|
-
const chipText = ` ${label} `;
|
|
4468
|
-
const leftRuleLen = 3;
|
|
4469
|
-
const usedLen = leftRuleLen + chipText.length + 2;
|
|
4470
|
-
if (!suffix) {
|
|
4471
|
-
const rightRuleLen = Math.max(0, width - usedLen);
|
|
4472
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
4473
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(leftRuleLen) }),
|
|
4474
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: "#1a1a22", color: tuiColors.dim, bold: true, children: chipText }),
|
|
4475
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(rightRuleLen) })
|
|
4476
|
-
] });
|
|
4477
|
-
}
|
|
4478
|
-
const gapLen = 2;
|
|
4479
|
-
const trailLen = Math.max(0, width - usedLen - gapLen - suffixLen);
|
|
4480
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
4481
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(leftRuleLen) }),
|
|
4482
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: "#1a1a22", color: tuiColors.dim, bold: true, children: chipText }),
|
|
4483
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(gapLen) }),
|
|
4484
|
-
suffix,
|
|
4485
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(trailLen) })
|
|
4486
|
-
] });
|
|
4487
|
-
}
|
|
4488
|
-
function DetailSectionLabel({ task, width }) {
|
|
4489
|
-
const chipText = " DETAIL ";
|
|
4490
|
-
const maxTitleLen = width - chipText.length - 10;
|
|
4491
|
-
const titleTrunc = task.title.length > maxTitleLen ? task.title.slice(0, maxTitleLen - 3) + "..." : task.title;
|
|
4492
|
-
const rightRuleLen = Math.max(0, width - 3 - chipText.length - titleTrunc.length - 4);
|
|
4493
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
4494
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(3) }),
|
|
4495
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: "#2d1f0a", color: tuiColors.amber, bold: true, children: chipText }),
|
|
4496
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4497
|
-
HEAVY_RULE,
|
|
4498
|
-
" "
|
|
4499
|
-
] }),
|
|
4500
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, bold: true, children: titleTrunc }),
|
|
4501
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4502
|
-
" ",
|
|
4503
|
-
HEAVY_RULE.repeat(Math.max(0, rightRuleLen))
|
|
4504
|
-
] })
|
|
4505
|
-
] });
|
|
4506
|
-
}
|
|
4507
|
-
function AgentDetailSectionLabel({ agent, width }) {
|
|
4508
|
-
const chipText = " AGENT ";
|
|
4509
|
-
const maxNameLen = width - chipText.length - 10;
|
|
4510
|
-
const nameTrunc = agent.name.length > maxNameLen ? agent.name.slice(0, maxNameLen - 3) + "..." : agent.name;
|
|
4511
|
-
const rightRuleLen = Math.max(0, width - 3 - chipText.length - nameTrunc.length - 4);
|
|
4512
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
4513
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(3) }),
|
|
4514
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: "#0f2d1f", color: tuiColors.green, bold: true, children: chipText }),
|
|
4515
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4516
|
-
HEAVY_RULE,
|
|
4517
|
-
" "
|
|
4518
|
-
] }),
|
|
4519
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.green, bold: true, children: nameTrunc }),
|
|
4520
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.ghost, children: [
|
|
4521
|
-
" ",
|
|
4522
|
-
HEAVY_RULE.repeat(Math.max(0, rightRuleLen))
|
|
4523
|
-
] })
|
|
4524
|
-
] });
|
|
4525
|
-
}
|
|
4526
|
-
function AgentDetailPanel({ agent, height, state, taskTitleMap, teamName }) {
|
|
4527
|
-
const statusColor = STATUS_DETAIL_COLOR2[agent.status] ?? tuiColors.dim;
|
|
4528
|
-
Object.values(state.running).find((e) => e.agent_id === agent.id);
|
|
4529
|
-
const taskTitle = agent.current_task ? taskTitleMap.get(agent.current_task) : void 0;
|
|
4530
|
-
const col1Width = 24;
|
|
4531
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, children: [
|
|
4532
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4533
|
-
/* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
4534
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " status " }),
|
|
4535
|
-
/* @__PURE__ */ jsx(Text, { color: statusColor, children: agent.status })
|
|
4536
|
-
] }),
|
|
4537
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4538
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " adapter " }),
|
|
4539
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.cyan, children: agent.adapter })
|
|
4540
|
-
] })
|
|
4541
|
-
] }),
|
|
4542
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4543
|
-
/* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
4544
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " model " }),
|
|
4545
|
-
/* @__PURE__ */ jsx(Text, { children: agent.config.model ?? "\u2014" })
|
|
4546
|
-
] }),
|
|
4547
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4548
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " task " }),
|
|
4549
|
-
/* @__PURE__ */ jsx(Text, { color: taskTitle ? tuiColors.white : tuiColors.dim, children: taskTitle ?? "\u2014" })
|
|
4550
|
-
] })
|
|
4551
|
-
] }),
|
|
4552
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4553
|
-
/* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
4554
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " runs " }),
|
|
4555
|
-
/* @__PURE__ */ jsx(Text, { children: agent.stats.total_runs }),
|
|
4556
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " (" }),
|
|
4557
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.green, children: agent.stats.tasks_completed }),
|
|
4558
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: "/" }),
|
|
4559
|
-
/* @__PURE__ */ jsx(Text, { color: agent.stats.tasks_failed > 0 ? tuiColors.red : tuiColors.dim, children: agent.stats.tasks_failed }),
|
|
4560
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: ")" })
|
|
4561
|
-
] }),
|
|
4562
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
4563
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " team " }),
|
|
4564
|
-
/* @__PURE__ */ jsx(Text, { color: teamName ? tuiColors.amber : tuiColors.dim, children: teamName ?? "\u2014" })
|
|
4565
|
-
] })
|
|
4566
|
-
] }),
|
|
4567
|
-
agent.autonomous && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Box, { width: col1Width, children: [
|
|
4568
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " auto " }),
|
|
4569
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.cyan, children: [
|
|
4570
|
-
LOOP,
|
|
4571
|
-
" ON"
|
|
4572
|
-
] })
|
|
4573
|
-
] }) }),
|
|
4574
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
4575
|
-
agent.role ? agent.role.split("\n").slice(0, Math.max(1, height - 4)).map((line, i) => /* @__PURE__ */ jsxs(Text, { color: tuiColors.silver, wrap: "truncate", children: [
|
|
4576
|
-
" ",
|
|
4577
|
-
line
|
|
4578
|
-
] }, i)) : /* @__PURE__ */ jsx(Text, { color: tuiColors.dim, children: " No role description." })
|
|
4579
|
-
] });
|
|
4580
|
-
}
|
|
4581
|
-
var STATUS_DETAIL_COLOR2 = {
|
|
4582
|
-
idle: tuiColors.dim,
|
|
4583
|
-
running: tuiColors.green,
|
|
4584
|
-
error: tuiColors.red,
|
|
4585
|
-
disabled: tuiColors.ghost
|
|
4586
|
-
};
|
|
4587
|
-
var CURSOR_CHAR2 = "\u2588";
|
|
4588
|
-
function InputSectionLabel({ mode, width }) {
|
|
4589
|
-
const label = mode === "command" ? "COMMAND" : "NEW TASK";
|
|
4590
|
-
const chipText = ` ${label} `;
|
|
4591
|
-
const rightRuleLen = Math.max(0, width - 3 - chipText.length - 2);
|
|
4592
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
4593
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(3) }),
|
|
4594
|
-
/* @__PURE__ */ jsx(Text, { backgroundColor: "#2d1f0a", color: tuiColors.amber, bold: true, children: chipText }),
|
|
4595
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.ghost, children: HEAVY_RULE.repeat(rightRuleLen) })
|
|
4596
|
-
] });
|
|
4597
|
-
}
|
|
4598
|
-
function InputPanel({ mode, value, width }) {
|
|
4599
|
-
const prefix = mode === "command" ? "/" : "\u25B8";
|
|
4600
|
-
const maxLen = Math.max(10, width - 8);
|
|
4601
|
-
const displayValue = value.length > maxLen ? value.slice(-maxLen) : value;
|
|
4602
|
-
return /* @__PURE__ */ jsxs(Box, { paddingX: 2, children: [
|
|
4603
|
-
/* @__PURE__ */ jsxs(Text, { color: tuiColors.amber, children: [
|
|
4604
|
-
prefix,
|
|
4605
|
-
" "
|
|
4606
|
-
] }),
|
|
4607
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.white, children: displayValue }),
|
|
4608
|
-
/* @__PURE__ */ jsx(Text, { color: tuiColors.amber, children: CURSOR_CHAR2 })
|
|
4609
|
-
] });
|
|
4610
|
-
}
|
|
4611
|
-
function formatToolInput(name, input) {
|
|
4612
|
-
if (!input || typeof input !== "object") return "";
|
|
4613
|
-
const inp = input;
|
|
4614
|
-
if (inp.file_path && typeof inp.file_path === "string") {
|
|
4615
|
-
const parts = inp.file_path.split("/");
|
|
4616
|
-
return parts.slice(-2).join("/");
|
|
4617
|
-
}
|
|
4618
|
-
if (inp.command && typeof inp.command === "string") {
|
|
4619
|
-
return inp.command.slice(0, 60);
|
|
4620
|
-
}
|
|
4621
|
-
if (inp.pattern && typeof inp.pattern === "string") {
|
|
4622
|
-
return `"${inp.pattern.slice(0, 40)}"`;
|
|
4623
|
-
}
|
|
4624
|
-
if (inp.glob && typeof inp.glob === "string") {
|
|
4625
|
-
return inp.glob.slice(0, 40);
|
|
4626
|
-
}
|
|
4627
|
-
const s = JSON.stringify(inp);
|
|
4628
|
-
return s.length > 80 ? s.slice(0, 77) + "..." : s;
|
|
4629
|
-
}
|
|
4630
|
-
function extractTextFromContent(content, maxLen = 200) {
|
|
4631
|
-
if (typeof content === "string") return content.slice(0, maxLen);
|
|
4632
|
-
if (!Array.isArray(content)) return null;
|
|
4633
|
-
const parts = [];
|
|
4634
|
-
let totalLen = 0;
|
|
4635
|
-
for (const block of content) {
|
|
4636
|
-
if (totalLen >= maxLen) break;
|
|
4637
|
-
if (block?.type === "text" && typeof block.text === "string") {
|
|
4638
|
-
const firstLine = block.text.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
4639
|
-
parts.push(firstLine.slice(0, maxLen - totalLen));
|
|
4640
|
-
totalLen += firstLine.length;
|
|
4641
|
-
} else if (block?.type === "tool_use") {
|
|
4642
|
-
const hint = formatToolInput(block.name ?? "tool", block.input);
|
|
4643
|
-
const s = `\u2699 ${block.name ?? "tool"}(${hint})`;
|
|
4644
|
-
parts.push(s);
|
|
4645
|
-
totalLen += s.length;
|
|
4646
|
-
} else if (block?.type === "tool_result") {
|
|
4647
|
-
parts.push(`\u2190 (result)`);
|
|
4648
|
-
totalLen += 10;
|
|
4649
|
-
} else if (block?.type === "thinking" && typeof block.thinking === "string") {
|
|
4650
|
-
const s = block.thinking.slice(0, 60).split("\n")[0] ?? "";
|
|
4651
|
-
parts.push(`\u{1F4AD} ${s}`);
|
|
4652
|
-
totalLen += s.length + 3;
|
|
4653
|
-
}
|
|
4654
|
-
}
|
|
4655
|
-
return parts.length > 0 ? parts.join(" ") : null;
|
|
4656
|
-
}
|
|
4657
|
-
function summarizeToolResult(content) {
|
|
4658
|
-
if (typeof content === "string") {
|
|
4659
|
-
const lines = content.split("\n").length;
|
|
4660
|
-
const firstLine = content.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
4661
|
-
if (lines > 3) return `${firstLine.slice(0, 80)}... (${lines} lines)`;
|
|
4662
|
-
return firstLine.slice(0, 120);
|
|
4663
|
-
}
|
|
4664
|
-
if (!Array.isArray(content)) return "(result)";
|
|
4665
|
-
const summaries = [];
|
|
4666
|
-
for (const block of content) {
|
|
4667
|
-
if (block?.type === "tool_result") {
|
|
4668
|
-
block.tool_use_id ? block.tool_use_id.slice(0, 8) : "";
|
|
4669
|
-
const isError = block.is_error;
|
|
4670
|
-
const inner = typeof block.content === "string" ? block.content : "";
|
|
4671
|
-
const lines = inner.split("\n").length;
|
|
4672
|
-
if (isError) {
|
|
4673
|
-
summaries.push(`\u2715 error: ${inner.slice(0, 60)}`);
|
|
4674
|
-
} else if (lines > 3) {
|
|
4675
|
-
summaries.push(`\u2713 ${lines} lines`);
|
|
4676
|
-
} else {
|
|
4677
|
-
summaries.push(`\u2713 ${inner.slice(0, 80)}`);
|
|
4678
|
-
}
|
|
4679
|
-
} else if (block?.type === "text" && typeof block.text === "string") {
|
|
4680
|
-
summaries.push(block.text.split("\n")[0]?.slice(0, 80) ?? "");
|
|
4681
|
-
}
|
|
4682
|
-
}
|
|
4683
|
-
return summaries.join(" ") || "(result)";
|
|
4684
|
-
}
|
|
4685
|
-
function formatAgentOutput(raw) {
|
|
4686
|
-
const detail = raw.length > MAX_DETAIL_LEN ? raw.slice(0, MAX_DETAIL_LEN) + "\u2026" : raw;
|
|
4687
|
-
if (LIFECYCLE_TAG_RE.test(raw.trim())) {
|
|
4688
|
-
return { summary: raw.trim(), detail };
|
|
4689
|
-
}
|
|
4690
|
-
try {
|
|
4691
|
-
const parsed = JSON.parse(raw);
|
|
4692
|
-
if (parsed.type === "message" && parsed.role === "assistant") {
|
|
4693
|
-
const text = extractTextFromContent(parsed.content);
|
|
4694
|
-
if (text) return { summary: text.slice(0, 200), detail };
|
|
4695
|
-
return { summary: "\u{1F4AC} (assistant message)", detail };
|
|
4696
|
-
}
|
|
4697
|
-
if (parsed.type === "assistant" || parsed.role === "assistant") {
|
|
4698
|
-
const content = parsed.message?.content ?? parsed.content;
|
|
4699
|
-
const text = extractTextFromContent(content);
|
|
4700
|
-
if (text) return { summary: text.slice(0, 200), detail };
|
|
4701
|
-
return { summary: "\u{1F4AC} (assistant)", detail };
|
|
4702
|
-
}
|
|
4703
|
-
if (parsed.type === "user" || parsed.role === "user") {
|
|
4704
|
-
const content = parsed.message?.content ?? parsed.content;
|
|
4705
|
-
const summary = summarizeToolResult(content);
|
|
4706
|
-
return { summary: `\u2190 ${summary.slice(0, 180)}`, detail };
|
|
4707
|
-
}
|
|
4708
|
-
if (parsed.type === "tool_use") {
|
|
4709
|
-
const name = parsed.name ?? "tool";
|
|
4710
|
-
const hint = formatToolInput(name, parsed.input);
|
|
4711
|
-
return { summary: `\u2699 ${name}(${hint})`, detail };
|
|
4712
|
-
}
|
|
4713
|
-
if (parsed.type === "tool_result") {
|
|
4714
|
-
const summary = summarizeToolResult(parsed.content);
|
|
4715
|
-
return { summary: `\u2190 ${summary.slice(0, 180)}`, detail };
|
|
4716
|
-
}
|
|
4717
|
-
if (parsed.type === "result") {
|
|
4718
|
-
const text = typeof parsed.result === "string" ? parsed.result : null;
|
|
4719
|
-
return { summary: text ? `\u2713 ${text.slice(0, 180)}` : "\u2713 Agent finished", detail };
|
|
4720
|
-
}
|
|
4721
|
-
if (parsed.type === "rate_limit_event") {
|
|
4722
|
-
return { summary: `\u23F3 Rate limited (${parsed.rate_limit_info?.rateLimitType ?? "unknown"})`, detail };
|
|
4723
|
-
}
|
|
4724
|
-
if (parsed.subtype) {
|
|
4725
|
-
if (parsed.message) {
|
|
4726
|
-
const content = parsed.message.content ?? parsed.message;
|
|
4727
|
-
const text = extractTextFromContent(content);
|
|
4728
|
-
if (text) return { summary: text.slice(0, 200), detail };
|
|
4729
|
-
}
|
|
4730
|
-
return { summary: `[${parsed.subtype}]`, detail };
|
|
4731
|
-
}
|
|
4732
|
-
if (parsed.content) {
|
|
4733
|
-
const text = extractTextFromContent(parsed.content);
|
|
4734
|
-
if (text) return { summary: text.slice(0, 200), detail };
|
|
4735
|
-
}
|
|
4736
|
-
if (parsed.type) return { summary: `[${parsed.type}]`, detail };
|
|
4737
|
-
return { summary: raw.slice(0, 150), detail };
|
|
4738
|
-
} catch {
|
|
4739
|
-
return { summary: extractSummaryFromTruncated(raw), detail };
|
|
4740
|
-
}
|
|
4741
|
-
}
|
|
4742
|
-
function extractSummaryFromTruncated(raw) {
|
|
4743
|
-
const subtypeMatch = raw.match(/"subtype"\s*:\s*"([^"]+)"/);
|
|
4744
|
-
if (subtypeMatch) return `[${subtypeMatch[1]}]`;
|
|
4745
|
-
const typeMatch = raw.match(/"type"\s*:\s*"([^"]+)"/);
|
|
4746
|
-
const roleMatch = raw.match(/"role"\s*:\s*"([^"]+)"/);
|
|
4747
|
-
const type = typeMatch?.[1];
|
|
4748
|
-
const role = roleMatch?.[1];
|
|
4749
|
-
if (!type && !role) return raw.slice(0, 200);
|
|
4750
|
-
if (type === "assistant" || type === "message" || role === "assistant") {
|
|
4751
|
-
const textMatch = raw.match(/"text"\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
|
4752
|
-
if (textMatch) {
|
|
4753
|
-
try {
|
|
4754
|
-
return JSON.parse(`"${textMatch[1]}"`).slice(0, 200);
|
|
4755
|
-
} catch {
|
|
4756
|
-
}
|
|
4757
|
-
}
|
|
4758
|
-
return "\u{1F4AC} (assistant)";
|
|
4759
|
-
}
|
|
4760
|
-
if (type === "user" || type === "tool_result" || role === "user") {
|
|
4761
|
-
return "\u2190 (tool result)";
|
|
4762
|
-
}
|
|
4763
|
-
if (type === "tool_use") {
|
|
4764
|
-
const nameMatch = raw.match(/"name"\s*:\s*"([^"]+)"/);
|
|
4765
|
-
return `\u2699 ${nameMatch?.[1] ?? "tool"}()`;
|
|
4766
|
-
}
|
|
4767
|
-
if (type === "result") {
|
|
4768
|
-
const resultMatch = raw.match(/"result"\s*:\s*"((?:[^"\\]|\\.)*)"/);
|
|
4769
|
-
if (resultMatch) {
|
|
4770
|
-
try {
|
|
4771
|
-
return `\u2713 ${JSON.parse(`"${resultMatch[1]}"`).slice(0, 180)}`;
|
|
4772
|
-
} catch {
|
|
4773
|
-
}
|
|
4774
|
-
}
|
|
4775
|
-
return "\u2713 Agent finished";
|
|
4776
|
-
}
|
|
4777
|
-
if (type === "rate_limit_event") return "\u23F3 Rate limited";
|
|
4778
|
-
return `[${type ?? role}]`;
|
|
4779
|
-
}
|
|
4780
|
-
function formatEvent(event, addMsg, runIdToAgentId, runIdToTaskId) {
|
|
4781
|
-
const resolveTask = (runId) => runIdToTaskId?.get(runId);
|
|
4782
|
-
switch (event.type) {
|
|
4783
|
-
case "agent:started":
|
|
4784
|
-
addMsg(
|
|
4785
|
-
`Started task`,
|
|
4786
|
-
tuiColors.green,
|
|
4787
|
-
{ agentId: event.agentId, taskId: event.taskId, msgType: "lifecycle" }
|
|
4788
|
-
);
|
|
4789
|
-
break;
|
|
4790
|
-
case "agent:output": {
|
|
4791
|
-
const { summary, detail } = formatAgentOutput(event.data);
|
|
4792
|
-
const cls = classifyAgentSummary(summary);
|
|
4793
|
-
addMsg(
|
|
4794
|
-
summary,
|
|
4795
|
-
cls.color,
|
|
4796
|
-
{ agentId: event.agentId, taskId: resolveTask(event.runId), detail, msgType: cls.msgType }
|
|
4797
|
-
);
|
|
4798
|
-
break;
|
|
4799
|
-
}
|
|
4800
|
-
case "agent:file_changed":
|
|
4801
|
-
addMsg(
|
|
4802
|
-
`${event.path}`,
|
|
4803
|
-
tuiColors.purple,
|
|
4804
|
-
{ agentId: event.agentId, taskId: resolveTask(event.runId), msgType: "file" }
|
|
4805
|
-
);
|
|
4806
|
-
break;
|
|
4807
|
-
case "agent:completed":
|
|
4808
|
-
addMsg(
|
|
4809
|
-
event.success ? "Completed successfully" : "Failed",
|
|
4810
|
-
event.success ? tuiColors.green : tuiColors.red,
|
|
4811
|
-
{ agentId: event.agentId, taskId: resolveTask(event.runId), msgType: "lifecycle" }
|
|
4812
|
-
);
|
|
4813
|
-
break;
|
|
4814
|
-
case "agent:error":
|
|
4815
|
-
addMsg(
|
|
4816
|
-
`${event.error.slice(0, 150)}`,
|
|
4817
|
-
tuiColors.red,
|
|
4818
|
-
{ agentId: event.agentId, taskId: resolveTask(event.runId), detail: event.error, msgType: "error" }
|
|
4819
|
-
);
|
|
4820
|
-
break;
|
|
4821
|
-
case "task:status_changed":
|
|
4822
|
-
addMsg(
|
|
4823
|
-
`${event.from} \u2192 ${event.to}`,
|
|
4824
|
-
tuiColors.cyan,
|
|
4825
|
-
{ taskId: event.taskId, msgType: "system" }
|
|
4826
|
-
);
|
|
4827
|
-
break;
|
|
4828
|
-
case "task:assigned":
|
|
4829
|
-
addMsg(
|
|
4830
|
-
`Assigned \u2192 ${event.agentId}`,
|
|
4831
|
-
tuiColors.cyan,
|
|
4832
|
-
{ taskId: event.taskId, msgType: "system" }
|
|
4833
|
-
);
|
|
4834
|
-
break;
|
|
4835
|
-
case "task:created":
|
|
4836
|
-
addMsg(
|
|
4837
|
-
`Created: ${event.task.title}`,
|
|
4838
|
-
tuiColors.amber,
|
|
4839
|
-
{ taskId: event.task.id, msgType: "system" }
|
|
4840
|
-
);
|
|
4841
|
-
break;
|
|
4842
|
-
case "run:retry":
|
|
4843
|
-
addMsg(
|
|
4844
|
-
`Retry #${event.attempt} (${Math.round(event.delay_ms / 1e3)}s delay)`,
|
|
4845
|
-
tuiColors.yellow,
|
|
4846
|
-
{ agentId: runIdToAgentId?.get(event.runId), taskId: resolveTask(event.runId), msgType: "lifecycle" }
|
|
4847
|
-
);
|
|
4848
|
-
break;
|
|
4849
|
-
case "orchestrator:tick":
|
|
4850
|
-
if (event.running > 0 || event.queued > 0) {
|
|
4851
|
-
addMsg(`${event.running} running \xB7 ${event.queued} queued`, tuiColors.ghost, { msgType: "system" });
|
|
4852
|
-
}
|
|
4853
|
-
break;
|
|
4854
|
-
case "orchestrator:stall_detected":
|
|
4855
|
-
addMsg(
|
|
4856
|
-
`Stall detected`,
|
|
4857
|
-
tuiColors.yellow,
|
|
4858
|
-
{ agentId: runIdToAgentId?.get(event.runId), taskId: resolveTask(event.runId), msgType: "error" }
|
|
4859
|
-
);
|
|
4860
|
-
break;
|
|
4861
|
-
}
|
|
4862
|
-
}
|
|
4863
|
-
|
|
4864
|
-
export { App };
|