agenttop 0.4.0 → 0.6.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/README.md +89 -7
- package/dist/{chunk-H2JOTO54.js → chunk-6N34AD6O.js} +55 -4
- package/dist/chunk-6N34AD6O.js.map +1 -0
- package/dist/index.js +1577 -327
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-H2JOTO54.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,28 +2,350 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SecurityEngine,
|
|
4
4
|
Watcher,
|
|
5
|
+
archiveSession,
|
|
5
6
|
clearNickname,
|
|
7
|
+
deleteSessionFiles,
|
|
6
8
|
discoverSessions,
|
|
9
|
+
getArchived,
|
|
7
10
|
getNicknames,
|
|
8
11
|
isFirstRun,
|
|
9
12
|
loadConfig,
|
|
13
|
+
purgeExpiredArchives,
|
|
10
14
|
resolveAlertLogPath,
|
|
11
15
|
rotateLogFile,
|
|
12
16
|
saveConfig,
|
|
13
17
|
setNickname,
|
|
14
|
-
startMcpServer
|
|
15
|
-
|
|
18
|
+
startMcpServer,
|
|
19
|
+
unarchiveSession
|
|
20
|
+
} from "./chunk-6N34AD6O.js";
|
|
16
21
|
|
|
17
22
|
// src/index.tsx
|
|
18
23
|
import { readFileSync as readFileSync4 } from "fs";
|
|
19
24
|
import { join as join4, dirname as dirname4 } from "path";
|
|
20
25
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
21
|
-
import
|
|
26
|
+
import React14 from "react";
|
|
22
27
|
import { render } from "ink";
|
|
23
28
|
|
|
24
29
|
// src/ui/App.tsx
|
|
25
|
-
import { useState as
|
|
26
|
-
import { Box as
|
|
30
|
+
import { useState as useState11, useEffect as useEffect8, useCallback as useCallback4 } from "react";
|
|
31
|
+
import { Box as Box13, Text as Text12, useApp, useStdout as useStdout3 } from "ink";
|
|
32
|
+
|
|
33
|
+
// src/config/themes.ts
|
|
34
|
+
var COLOR_KEYS = [
|
|
35
|
+
"primary",
|
|
36
|
+
"secondary",
|
|
37
|
+
"accent",
|
|
38
|
+
"warning",
|
|
39
|
+
"error",
|
|
40
|
+
"critical",
|
|
41
|
+
"muted",
|
|
42
|
+
"text",
|
|
43
|
+
"bright",
|
|
44
|
+
"border",
|
|
45
|
+
"selected",
|
|
46
|
+
"header"
|
|
47
|
+
];
|
|
48
|
+
var TOOL_COLOR_KEYS = [
|
|
49
|
+
"Bash",
|
|
50
|
+
"Read",
|
|
51
|
+
"Write",
|
|
52
|
+
"Edit",
|
|
53
|
+
"Grep",
|
|
54
|
+
"Glob",
|
|
55
|
+
"Task",
|
|
56
|
+
"WebFetch",
|
|
57
|
+
"WebSearch"
|
|
58
|
+
];
|
|
59
|
+
var deriveToolColors = (c) => ({
|
|
60
|
+
Bash: c.error,
|
|
61
|
+
Read: c.secondary,
|
|
62
|
+
Write: c.accent,
|
|
63
|
+
Edit: c.accent,
|
|
64
|
+
Grep: c.primary,
|
|
65
|
+
Glob: c.primary,
|
|
66
|
+
Task: c.warning,
|
|
67
|
+
WebFetch: c.warning,
|
|
68
|
+
WebSearch: c.warning
|
|
69
|
+
});
|
|
70
|
+
var fromTuple = ([
|
|
71
|
+
name,
|
|
72
|
+
primary,
|
|
73
|
+
secondary,
|
|
74
|
+
accent,
|
|
75
|
+
warning,
|
|
76
|
+
error,
|
|
77
|
+
critical,
|
|
78
|
+
muted,
|
|
79
|
+
text,
|
|
80
|
+
bright,
|
|
81
|
+
border,
|
|
82
|
+
selected,
|
|
83
|
+
header
|
|
84
|
+
]) => ({
|
|
85
|
+
name,
|
|
86
|
+
builtin: true,
|
|
87
|
+
colors: { primary, secondary, accent, warning, error, critical, muted, text, bright, border, selected, header },
|
|
88
|
+
toolColors: deriveToolColors({
|
|
89
|
+
primary,
|
|
90
|
+
secondary,
|
|
91
|
+
accent,
|
|
92
|
+
warning,
|
|
93
|
+
error,
|
|
94
|
+
critical,
|
|
95
|
+
muted,
|
|
96
|
+
text,
|
|
97
|
+
bright,
|
|
98
|
+
border,
|
|
99
|
+
selected,
|
|
100
|
+
header
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
var PRESETS = [
|
|
104
|
+
[
|
|
105
|
+
"one-dark",
|
|
106
|
+
"#61AFEF",
|
|
107
|
+
"#98C379",
|
|
108
|
+
"#C678DD",
|
|
109
|
+
"#E5C07B",
|
|
110
|
+
"#E06C75",
|
|
111
|
+
"#FF0000",
|
|
112
|
+
"#5C6370",
|
|
113
|
+
"#ABB2BF",
|
|
114
|
+
"#FFFFFF",
|
|
115
|
+
"#3E4451",
|
|
116
|
+
"#2C313A",
|
|
117
|
+
"#61AFEF"
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
"dracula",
|
|
121
|
+
"#BD93F9",
|
|
122
|
+
"#50FA7B",
|
|
123
|
+
"#FF79C6",
|
|
124
|
+
"#F1FA8C",
|
|
125
|
+
"#FF5555",
|
|
126
|
+
"#FF0000",
|
|
127
|
+
"#6272A4",
|
|
128
|
+
"#F8F8F2",
|
|
129
|
+
"#FFFFFF",
|
|
130
|
+
"#44475A",
|
|
131
|
+
"#383A59",
|
|
132
|
+
"#BD93F9"
|
|
133
|
+
],
|
|
134
|
+
[
|
|
135
|
+
"monokai-pro",
|
|
136
|
+
"#78DCE8",
|
|
137
|
+
"#A9DC76",
|
|
138
|
+
"#AB9DF2",
|
|
139
|
+
"#FFD866",
|
|
140
|
+
"#FF6188",
|
|
141
|
+
"#FF0000",
|
|
142
|
+
"#727072",
|
|
143
|
+
"#FCFCFA",
|
|
144
|
+
"#FFFFFF",
|
|
145
|
+
"#403E41",
|
|
146
|
+
"#2D2A2E",
|
|
147
|
+
"#78DCE8"
|
|
148
|
+
],
|
|
149
|
+
[
|
|
150
|
+
"solarized-dark",
|
|
151
|
+
"#268BD2",
|
|
152
|
+
"#859900",
|
|
153
|
+
"#D33682",
|
|
154
|
+
"#B58900",
|
|
155
|
+
"#DC322F",
|
|
156
|
+
"#FF0000",
|
|
157
|
+
"#586E75",
|
|
158
|
+
"#839496",
|
|
159
|
+
"#FDF6E3",
|
|
160
|
+
"#073642",
|
|
161
|
+
"#002B36",
|
|
162
|
+
"#268BD2"
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
"solarized-light",
|
|
166
|
+
"#268BD2",
|
|
167
|
+
"#859900",
|
|
168
|
+
"#D33682",
|
|
169
|
+
"#B58900",
|
|
170
|
+
"#DC322F",
|
|
171
|
+
"#FF0000",
|
|
172
|
+
"#93A1A1",
|
|
173
|
+
"#657B83",
|
|
174
|
+
"#002B36",
|
|
175
|
+
"#EEE8D5",
|
|
176
|
+
"#FDF6E3",
|
|
177
|
+
"#268BD2"
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
"nord",
|
|
181
|
+
"#88C0D0",
|
|
182
|
+
"#A3BE8C",
|
|
183
|
+
"#B48EAD",
|
|
184
|
+
"#EBCB8B",
|
|
185
|
+
"#BF616A",
|
|
186
|
+
"#FF0000",
|
|
187
|
+
"#4C566A",
|
|
188
|
+
"#D8DEE9",
|
|
189
|
+
"#ECEFF4",
|
|
190
|
+
"#3B4252",
|
|
191
|
+
"#2E3440",
|
|
192
|
+
"#88C0D0"
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
"gruvbox-dark",
|
|
196
|
+
"#83A598",
|
|
197
|
+
"#B8BB26",
|
|
198
|
+
"#D3869B",
|
|
199
|
+
"#FABD2F",
|
|
200
|
+
"#FB4934",
|
|
201
|
+
"#FF0000",
|
|
202
|
+
"#928374",
|
|
203
|
+
"#EBDBB2",
|
|
204
|
+
"#FBF1C7",
|
|
205
|
+
"#3C3836",
|
|
206
|
+
"#282828",
|
|
207
|
+
"#83A598"
|
|
208
|
+
],
|
|
209
|
+
[
|
|
210
|
+
"tokyo-night",
|
|
211
|
+
"#7AA2F7",
|
|
212
|
+
"#9ECE6A",
|
|
213
|
+
"#BB9AF7",
|
|
214
|
+
"#E0AF68",
|
|
215
|
+
"#F7768E",
|
|
216
|
+
"#FF0000",
|
|
217
|
+
"#565F89",
|
|
218
|
+
"#A9B1D6",
|
|
219
|
+
"#C0CAF5",
|
|
220
|
+
"#292E42",
|
|
221
|
+
"#1A1B26",
|
|
222
|
+
"#7AA2F7"
|
|
223
|
+
],
|
|
224
|
+
[
|
|
225
|
+
"catppuccin-mocha",
|
|
226
|
+
"#89B4FA",
|
|
227
|
+
"#A6E3A1",
|
|
228
|
+
"#CBA6F7",
|
|
229
|
+
"#F9E2AF",
|
|
230
|
+
"#F38BA8",
|
|
231
|
+
"#FF0000",
|
|
232
|
+
"#6C7086",
|
|
233
|
+
"#CDD6F4",
|
|
234
|
+
"#FFFFFF",
|
|
235
|
+
"#313244",
|
|
236
|
+
"#1E1E2E",
|
|
237
|
+
"#89B4FA"
|
|
238
|
+
],
|
|
239
|
+
[
|
|
240
|
+
"catppuccin-latte",
|
|
241
|
+
"#1E66F5",
|
|
242
|
+
"#40A02B",
|
|
243
|
+
"#8839EF",
|
|
244
|
+
"#DF8E1D",
|
|
245
|
+
"#D20F39",
|
|
246
|
+
"#FF0000",
|
|
247
|
+
"#9CA0B0",
|
|
248
|
+
"#4C4F69",
|
|
249
|
+
"#11111B",
|
|
250
|
+
"#E6E9EF",
|
|
251
|
+
"#EFF1F5",
|
|
252
|
+
"#1E66F5"
|
|
253
|
+
],
|
|
254
|
+
[
|
|
255
|
+
"rose-pine",
|
|
256
|
+
"#9CCFD8",
|
|
257
|
+
"#31748F",
|
|
258
|
+
"#C4A7E7",
|
|
259
|
+
"#F6C177",
|
|
260
|
+
"#EB6F92",
|
|
261
|
+
"#FF0000",
|
|
262
|
+
"#6E6A86",
|
|
263
|
+
"#E0DEF4",
|
|
264
|
+
"#E0DEF4",
|
|
265
|
+
"#26233A",
|
|
266
|
+
"#191724",
|
|
267
|
+
"#9CCFD8"
|
|
268
|
+
],
|
|
269
|
+
[
|
|
270
|
+
"rose-pine-moon",
|
|
271
|
+
"#9CCFD8",
|
|
272
|
+
"#3E8FB0",
|
|
273
|
+
"#C4A7E7",
|
|
274
|
+
"#F6C177",
|
|
275
|
+
"#EB6F92",
|
|
276
|
+
"#FF0000",
|
|
277
|
+
"#6E6A86",
|
|
278
|
+
"#E0DEF4",
|
|
279
|
+
"#E0DEF4",
|
|
280
|
+
"#2A273F",
|
|
281
|
+
"#232136",
|
|
282
|
+
"#9CCFD8"
|
|
283
|
+
],
|
|
284
|
+
[
|
|
285
|
+
"pastel-dark",
|
|
286
|
+
"#89CFF0",
|
|
287
|
+
"#77DD77",
|
|
288
|
+
"#FDCFE8",
|
|
289
|
+
"#FFD580",
|
|
290
|
+
"#FF6961",
|
|
291
|
+
"#FF0000",
|
|
292
|
+
"#7B8794",
|
|
293
|
+
"#D4D4D4",
|
|
294
|
+
"#FFFFFF",
|
|
295
|
+
"#3A3A4A",
|
|
296
|
+
"#2B2B3A",
|
|
297
|
+
"#89CFF0"
|
|
298
|
+
],
|
|
299
|
+
[
|
|
300
|
+
"kanagawa",
|
|
301
|
+
"#7E9CD8",
|
|
302
|
+
"#76946A",
|
|
303
|
+
"#957FB8",
|
|
304
|
+
"#E6C384",
|
|
305
|
+
"#C34043",
|
|
306
|
+
"#FF0000",
|
|
307
|
+
"#727169",
|
|
308
|
+
"#DCD7BA",
|
|
309
|
+
"#FFFFFF",
|
|
310
|
+
"#2A2A37",
|
|
311
|
+
"#1F1F28",
|
|
312
|
+
"#7E9CD8"
|
|
313
|
+
],
|
|
314
|
+
[
|
|
315
|
+
"everforest",
|
|
316
|
+
"#7FBBB3",
|
|
317
|
+
"#A7C080",
|
|
318
|
+
"#D699B6",
|
|
319
|
+
"#DBBC7F",
|
|
320
|
+
"#E67E80",
|
|
321
|
+
"#FF0000",
|
|
322
|
+
"#859289",
|
|
323
|
+
"#D3C6AA",
|
|
324
|
+
"#FFFFFF",
|
|
325
|
+
"#374145",
|
|
326
|
+
"#2D353B",
|
|
327
|
+
"#7FBBB3"
|
|
328
|
+
]
|
|
329
|
+
];
|
|
330
|
+
var BUILTIN_THEMES = PRESETS.map(fromTuple);
|
|
331
|
+
var getDefaultTheme = () => BUILTIN_THEMES[0];
|
|
332
|
+
var getAllThemes = (customThemes) => [
|
|
333
|
+
...BUILTIN_THEMES,
|
|
334
|
+
...Object.values(customThemes).map((t) => ({ ...t, builtin: false }))
|
|
335
|
+
];
|
|
336
|
+
var resolveTheme = (name, customThemes) => {
|
|
337
|
+
const builtin = BUILTIN_THEMES.find((t) => t.name === name);
|
|
338
|
+
if (builtin) return builtin;
|
|
339
|
+
const custom = customThemes[name];
|
|
340
|
+
if (custom) return { ...custom, builtin: false };
|
|
341
|
+
return getDefaultTheme();
|
|
342
|
+
};
|
|
343
|
+
var deriveSeverityColors = (c) => ({
|
|
344
|
+
info: c.muted,
|
|
345
|
+
warn: c.warning,
|
|
346
|
+
high: c.error,
|
|
347
|
+
critical: c.critical
|
|
348
|
+
});
|
|
27
349
|
|
|
28
350
|
// src/hooks/installer.ts
|
|
29
351
|
import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync, chmodSync } from "fs";
|
|
@@ -229,6 +551,11 @@ var toolColors = {
|
|
|
229
551
|
WebSearch: colors.warning
|
|
230
552
|
};
|
|
231
553
|
var getToolColor = (toolName) => toolColors[toolName] || colors.text;
|
|
554
|
+
var applyTheme = (theme) => {
|
|
555
|
+
Object.assign(colors, theme.colors);
|
|
556
|
+
Object.assign(toolColors, theme.toolColors);
|
|
557
|
+
Object.assign(severityColors, deriveSeverityColors(theme.colors));
|
|
558
|
+
};
|
|
232
559
|
|
|
233
560
|
// src/ui/components/StatusBar.tsx
|
|
234
561
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -286,76 +613,82 @@ var formatTokens = (n) => {
|
|
|
286
613
|
var truncate = (s, max) => s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
287
614
|
var SIDEBAR_WIDTH = 28;
|
|
288
615
|
var INNER_WIDTH = SIDEBAR_WIDTH - 4;
|
|
289
|
-
var SessionList = React2.memo(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
sessions.length === 0 && /* @__PURE__ */ jsx2(Box2, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx2(Text2, { color: colors.muted, italic: true, children: filter ? "No matches" : "No sessions" }) }),
|
|
308
|
-
sessions.map((session, i) => {
|
|
309
|
-
const isSelected = i === selectedIndex;
|
|
310
|
-
const indicator = isSelected ? ">" : " ";
|
|
311
|
-
const nameMaxLen = INNER_WIDTH - 2;
|
|
312
|
-
const displayName = truncate(session.nickname || session.slug, nameMaxLen);
|
|
313
|
-
const totalIn = session.usage.inputTokens + session.usage.cacheReadTokens;
|
|
314
|
-
const proj = formatProject(session.project, 12);
|
|
315
|
-
const model = formatModel(session.model);
|
|
316
|
-
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, paddingY: 0, children: [
|
|
317
|
-
/* @__PURE__ */ jsxs2(
|
|
318
|
-
Text2,
|
|
319
|
-
{
|
|
320
|
-
color: isSelected ? colors.bright : colors.text,
|
|
321
|
-
bold: isSelected,
|
|
322
|
-
backgroundColor: isSelected ? colors.selected : void 0,
|
|
323
|
-
wrap: "truncate",
|
|
324
|
-
children: [
|
|
325
|
-
indicator,
|
|
326
|
-
" ",
|
|
327
|
-
displayName
|
|
328
|
-
]
|
|
329
|
-
}
|
|
330
|
-
),
|
|
331
|
-
session.nickname && /* @__PURE__ */ jsxs2(Text2, { color: colors.muted, wrap: "truncate", children: [
|
|
332
|
-
" ",
|
|
333
|
-
truncate(session.slug, nameMaxLen)
|
|
334
|
-
] }),
|
|
335
|
-
/* @__PURE__ */ jsxs2(Text2, { color: colors.muted, wrap: "truncate", children: [
|
|
336
|
-
" ",
|
|
337
|
-
proj,
|
|
338
|
-
" ",
|
|
339
|
-
model,
|
|
340
|
-
" ",
|
|
341
|
-
session.agentCount,
|
|
342
|
-
"ag"
|
|
343
|
-
] }),
|
|
344
|
-
/* @__PURE__ */ jsxs2(Text2, { color: colors.muted, wrap: "truncate", children: [
|
|
345
|
-
" ",
|
|
346
|
-
formatTokens(totalIn),
|
|
347
|
-
"in ",
|
|
348
|
-
formatTokens(session.usage.outputTokens),
|
|
349
|
-
"out ",
|
|
350
|
-
session.cpu,
|
|
351
|
-
"%"
|
|
616
|
+
var SessionList = React2.memo(
|
|
617
|
+
({ sessions, selectedIndex, focused, filter, viewingArchive }) => {
|
|
618
|
+
const divider = "-".repeat(INNER_WIDTH);
|
|
619
|
+
return /* @__PURE__ */ jsxs2(
|
|
620
|
+
Box2,
|
|
621
|
+
{
|
|
622
|
+
flexDirection: "column",
|
|
623
|
+
width: SIDEBAR_WIDTH,
|
|
624
|
+
borderStyle: "single",
|
|
625
|
+
borderColor: focused ? colors.primary : colors.border,
|
|
626
|
+
overflow: "hidden",
|
|
627
|
+
children: [
|
|
628
|
+
/* @__PURE__ */ jsxs2(Box2, { paddingX: 1, children: [
|
|
629
|
+
/* @__PURE__ */ jsx2(Text2, { color: viewingArchive ? colors.warning : colors.header, bold: true, children: viewingArchive ? "ARCHIVE" : "SESSIONS" }),
|
|
630
|
+
filter && /* @__PURE__ */ jsxs2(Text2, { color: colors.muted, children: [
|
|
631
|
+
" [",
|
|
632
|
+
truncate(filter, 10),
|
|
633
|
+
"]"
|
|
352
634
|
] })
|
|
353
|
-
] },
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
635
|
+
] }),
|
|
636
|
+
sessions.length === 0 && /* @__PURE__ */ jsx2(Box2, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx2(Text2, { color: colors.muted, italic: true, children: filter ? "No matches" : viewingArchive ? "No archived sessions" : "No sessions" }) }),
|
|
637
|
+
sessions.map((session, i) => {
|
|
638
|
+
const isSelected = i === selectedIndex;
|
|
639
|
+
const indicator = isSelected ? ">" : " ";
|
|
640
|
+
const nameMaxLen = INNER_WIDTH - 2;
|
|
641
|
+
const displayName = truncate(session.nickname || session.slug, nameMaxLen);
|
|
642
|
+
const totalIn = session.usage.inputTokens + session.usage.cacheReadTokens;
|
|
643
|
+
const proj = formatProject(session.project, 12);
|
|
644
|
+
const model = formatModel(session.model);
|
|
645
|
+
const isActive = session.pid !== null;
|
|
646
|
+
const nameColor = isSelected ? colors.bright : isActive ? colors.secondary : colors.error;
|
|
647
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, paddingY: 0, children: [
|
|
648
|
+
i > 0 && /* @__PURE__ */ jsx2(Text2, { color: colors.border, wrap: "truncate", children: divider }),
|
|
649
|
+
/* @__PURE__ */ jsxs2(
|
|
650
|
+
Text2,
|
|
651
|
+
{
|
|
652
|
+
color: nameColor,
|
|
653
|
+
bold: isSelected,
|
|
654
|
+
backgroundColor: isSelected ? colors.selected : void 0,
|
|
655
|
+
wrap: "truncate",
|
|
656
|
+
children: [
|
|
657
|
+
indicator,
|
|
658
|
+
" ",
|
|
659
|
+
displayName
|
|
660
|
+
]
|
|
661
|
+
}
|
|
662
|
+
),
|
|
663
|
+
session.nickname && /* @__PURE__ */ jsxs2(Text2, { color: colors.muted, wrap: "truncate", children: [
|
|
664
|
+
" ",
|
|
665
|
+
truncate(session.slug, nameMaxLen)
|
|
666
|
+
] }),
|
|
667
|
+
/* @__PURE__ */ jsxs2(Text2, { color: colors.muted, wrap: "truncate", children: [
|
|
668
|
+
" ",
|
|
669
|
+
proj,
|
|
670
|
+
" ",
|
|
671
|
+
model,
|
|
672
|
+
" ",
|
|
673
|
+
session.agentCount,
|
|
674
|
+
"ag"
|
|
675
|
+
] }),
|
|
676
|
+
/* @__PURE__ */ jsxs2(Text2, { color: colors.muted, wrap: "truncate", children: [
|
|
677
|
+
" ",
|
|
678
|
+
formatTokens(totalIn),
|
|
679
|
+
"in ",
|
|
680
|
+
formatTokens(session.usage.outputTokens),
|
|
681
|
+
"out ",
|
|
682
|
+
session.cpu,
|
|
683
|
+
"%"
|
|
684
|
+
] })
|
|
685
|
+
] }, session.sessionId);
|
|
686
|
+
})
|
|
687
|
+
]
|
|
688
|
+
}
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
);
|
|
359
692
|
|
|
360
693
|
// src/ui/components/ActivityFeed.tsx
|
|
361
694
|
import React3 from "react";
|
|
@@ -388,7 +721,7 @@ var summarizeInput = (call) => {
|
|
|
388
721
|
}
|
|
389
722
|
};
|
|
390
723
|
var ActivityFeed = React3.memo(
|
|
391
|
-
({ events, sessionSlug, focused, height, scrollOffset }) => {
|
|
724
|
+
({ events, sessionSlug, focused, height, scrollOffset, filter }) => {
|
|
392
725
|
const viewportRows = height - 2;
|
|
393
726
|
const totalEvents = events.length;
|
|
394
727
|
const start = Math.max(0, totalEvents - viewportRows - scrollOffset);
|
|
@@ -412,6 +745,11 @@ var ActivityFeed = React3.memo(
|
|
|
412
745
|
" (",
|
|
413
746
|
sessionSlug,
|
|
414
747
|
")"
|
|
748
|
+
] }),
|
|
749
|
+
filter && /* @__PURE__ */ jsxs3(Text3, { color: colors.muted, children: [
|
|
750
|
+
" [",
|
|
751
|
+
filter.length > 10 ? filter.slice(0, 9) + "\u2026" : filter,
|
|
752
|
+
"]"
|
|
415
753
|
] })
|
|
416
754
|
] }),
|
|
417
755
|
focused && canScroll && !isAtBottom && /* @__PURE__ */ jsxs3(Text3, { color: colors.muted, children: [
|
|
@@ -662,49 +1000,81 @@ var SetupModal = React6.memo(({ steps, onComplete }) => {
|
|
|
662
1000
|
// src/ui/components/FooterBar.tsx
|
|
663
1001
|
import React7 from "react";
|
|
664
1002
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
665
|
-
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1003
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
666
1004
|
var label = (key) => {
|
|
667
1005
|
if (key === "tab") return "tab";
|
|
668
1006
|
if (key === "shift+tab") return "S-tab";
|
|
669
1007
|
if (key === "enter") return "enter";
|
|
670
1008
|
return key;
|
|
671
1009
|
};
|
|
672
|
-
var FooterBar = React7.memo(
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
] }))
|
|
1010
|
+
var FooterBar = React7.memo(
|
|
1011
|
+
({ keybindings, updateStatus, viewingArchive, splitMode }) => /* @__PURE__ */ jsxs7(Box7, { paddingX: 1, children: [
|
|
1012
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1013
|
+
label(keybindings.quit),
|
|
1014
|
+
":quit"
|
|
1015
|
+
] }) }),
|
|
1016
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1017
|
+
label(keybindings.navDown),
|
|
1018
|
+
"/",
|
|
1019
|
+
label(keybindings.navUp),
|
|
1020
|
+
":nav"
|
|
1021
|
+
] }) }),
|
|
1022
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1023
|
+
label(keybindings.panelNext),
|
|
1024
|
+
":panel"
|
|
1025
|
+
] }) }),
|
|
1026
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1027
|
+
label(keybindings.filter),
|
|
1028
|
+
":filter"
|
|
1029
|
+
] }) }),
|
|
1030
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1031
|
+
label(keybindings.nickname),
|
|
1032
|
+
":name"
|
|
1033
|
+
] }) }),
|
|
1034
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1035
|
+
label(keybindings.detail),
|
|
1036
|
+
":detail"
|
|
1037
|
+
] }) }),
|
|
1038
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1039
|
+
label(keybindings.split),
|
|
1040
|
+
":",
|
|
1041
|
+
splitMode ? "unsplit" : "split"
|
|
1042
|
+
] }) }),
|
|
1043
|
+
splitMode && /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
1044
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1045
|
+
label(keybindings.pinLeft),
|
|
1046
|
+
"/",
|
|
1047
|
+
label(keybindings.pinRight),
|
|
1048
|
+
":pin"
|
|
1049
|
+
] }) }),
|
|
1050
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1051
|
+
label(keybindings.swapPanels),
|
|
1052
|
+
":swap"
|
|
1053
|
+
] }) })
|
|
1054
|
+
] }),
|
|
1055
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1056
|
+
label(keybindings.archive),
|
|
1057
|
+
":",
|
|
1058
|
+
viewingArchive ? "restore" : "archive"
|
|
1059
|
+
] }) }),
|
|
1060
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1061
|
+
label(keybindings.delete),
|
|
1062
|
+
":delete"
|
|
1063
|
+
] }) }),
|
|
1064
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1065
|
+
label(keybindings.viewArchive),
|
|
1066
|
+
":archived"
|
|
1067
|
+
] }) }),
|
|
1068
|
+
/* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsxs7(Text7, { color: colors.muted, children: [
|
|
1069
|
+
label(keybindings.settings),
|
|
1070
|
+
":settings"
|
|
1071
|
+
] }) }),
|
|
1072
|
+
updateStatus && /* @__PURE__ */ jsx7(Box7, { marginRight: 2, children: /* @__PURE__ */ jsx7(Text7, { color: colors.secondary, children: updateStatus }) })
|
|
1073
|
+
] })
|
|
1074
|
+
);
|
|
705
1075
|
|
|
706
1076
|
// src/ui/components/SettingsMenu.tsx
|
|
707
|
-
import React8, { useState as useState3, useMemo } from "react";
|
|
1077
|
+
import React8, { useState as useState3, useMemo, useEffect as useEffect2, useRef } from "react";
|
|
708
1078
|
import { Box as Box8, Text as Text8, useInput as useInput2, useStdout } from "ink";
|
|
709
1079
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
710
1080
|
var KEYBIND_LABELS = {
|
|
@@ -715,12 +1085,20 @@ var KEYBIND_LABELS = {
|
|
|
715
1085
|
panelPrev: "Previous panel",
|
|
716
1086
|
scrollTop: "Scroll to top",
|
|
717
1087
|
scrollBottom: "Scroll to bottom",
|
|
718
|
-
filter: "Filter
|
|
1088
|
+
filter: "Filter",
|
|
719
1089
|
nickname: "Set nickname",
|
|
720
1090
|
clearNickname: "Clear nickname",
|
|
721
1091
|
detail: "Detail view",
|
|
722
1092
|
update: "Install update",
|
|
723
|
-
settings: "Settings"
|
|
1093
|
+
settings: "Settings",
|
|
1094
|
+
archive: "Archive session",
|
|
1095
|
+
delete: "Delete session",
|
|
1096
|
+
viewArchive: "View archive",
|
|
1097
|
+
split: "Toggle split view",
|
|
1098
|
+
pinLeft: "Pin to left panel",
|
|
1099
|
+
pinRight: "Pin to right panel",
|
|
1100
|
+
swapPanels: "Swap panels",
|
|
1101
|
+
closePanel: "Close panel"
|
|
724
1102
|
};
|
|
725
1103
|
var RULE_LABELS = {
|
|
726
1104
|
network: "Network detection",
|
|
@@ -729,7 +1107,32 @@ var RULE_LABELS = {
|
|
|
729
1107
|
shellEscape: "Shell escape",
|
|
730
1108
|
injection: "Prompt injection"
|
|
731
1109
|
};
|
|
1110
|
+
var DEFAULT_KEYBINDINGS = {
|
|
1111
|
+
quit: "q",
|
|
1112
|
+
navUp: "k",
|
|
1113
|
+
navDown: "j",
|
|
1114
|
+
panelNext: "tab",
|
|
1115
|
+
panelPrev: "shift+tab",
|
|
1116
|
+
scrollTop: "g",
|
|
1117
|
+
scrollBottom: "G",
|
|
1118
|
+
filter: "/",
|
|
1119
|
+
nickname: "n",
|
|
1120
|
+
clearNickname: "N",
|
|
1121
|
+
detail: "enter",
|
|
1122
|
+
update: "u",
|
|
1123
|
+
settings: "s",
|
|
1124
|
+
archive: "a",
|
|
1125
|
+
delete: "d",
|
|
1126
|
+
viewArchive: "A",
|
|
1127
|
+
split: "x",
|
|
1128
|
+
pinLeft: "1",
|
|
1129
|
+
pinRight: "2",
|
|
1130
|
+
swapPanels: "S",
|
|
1131
|
+
closePanel: "X"
|
|
1132
|
+
};
|
|
732
1133
|
var SEVERITY_OPTIONS = ["info", "warn", "high", "critical"];
|
|
1134
|
+
var ARCHIVE_EXPIRY_OPTIONS = [0, 7, 14, 30, 60, 90];
|
|
1135
|
+
var formatExpiry = (days) => days === 0 ? "never" : `${days}d`;
|
|
733
1136
|
var displayKey = (key) => {
|
|
734
1137
|
if (key === "tab") return "tab";
|
|
735
1138
|
if (key === "shift+tab") return "S-tab";
|
|
@@ -738,6 +1141,27 @@ var displayKey = (key) => {
|
|
|
738
1141
|
};
|
|
739
1142
|
var buildMenuItems = () => {
|
|
740
1143
|
const items = [];
|
|
1144
|
+
items.push({ type: "header", label: "THEMES", section: "themes", getValue: () => "", key: void 0 });
|
|
1145
|
+
items.push({
|
|
1146
|
+
type: "action",
|
|
1147
|
+
label: "Manage themes...",
|
|
1148
|
+
section: "themes",
|
|
1149
|
+
key: "manageThemes",
|
|
1150
|
+
getValue: (cfg) => cfg.theme,
|
|
1151
|
+
apply: void 0
|
|
1152
|
+
});
|
|
1153
|
+
items.push({ type: "header", label: "GENERAL", section: "general", getValue: () => "", key: void 0 });
|
|
1154
|
+
items.push({
|
|
1155
|
+
type: "cycle",
|
|
1156
|
+
label: "Archive expiry",
|
|
1157
|
+
section: "general",
|
|
1158
|
+
key: "archiveExpiryDays",
|
|
1159
|
+
getValue: (cfg) => formatExpiry(cfg.archiveExpiryDays),
|
|
1160
|
+
apply: (cfg) => {
|
|
1161
|
+
const idx = ARCHIVE_EXPIRY_OPTIONS.indexOf(cfg.archiveExpiryDays);
|
|
1162
|
+
return { ...cfg, archiveExpiryDays: ARCHIVE_EXPIRY_OPTIONS[(idx + 1) % ARCHIVE_EXPIRY_OPTIONS.length] };
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
741
1165
|
items.push({ type: "header", label: "KEYBINDINGS", section: "keybindings", getValue: () => "", key: void 0 });
|
|
742
1166
|
for (const [k, label2] of Object.entries(KEYBIND_LABELS)) {
|
|
743
1167
|
const kbKey = k;
|
|
@@ -747,12 +1171,17 @@ var buildMenuItems = () => {
|
|
|
747
1171
|
section: "keybindings",
|
|
748
1172
|
key: kbKey,
|
|
749
1173
|
getValue: (cfg) => displayKey(cfg.keybindings[kbKey]),
|
|
750
|
-
apply: (cfg, newValue) => ({
|
|
751
|
-
...cfg,
|
|
752
|
-
keybindings: { ...cfg.keybindings, [kbKey]: newValue }
|
|
753
|
-
})
|
|
1174
|
+
apply: (cfg, newValue) => ({ ...cfg, keybindings: { ...cfg.keybindings, [kbKey]: newValue } })
|
|
754
1175
|
});
|
|
755
1176
|
}
|
|
1177
|
+
items.push({
|
|
1178
|
+
type: "action",
|
|
1179
|
+
label: "Reset all keybindings",
|
|
1180
|
+
section: "keybindings",
|
|
1181
|
+
key: "resetAllKeybinds",
|
|
1182
|
+
getValue: () => "",
|
|
1183
|
+
apply: (cfg) => ({ ...cfg, keybindings: { ...DEFAULT_KEYBINDINGS } })
|
|
1184
|
+
});
|
|
756
1185
|
items.push({ type: "header", label: "SECURITY RULES", section: "security", getValue: () => "", key: void 0 });
|
|
757
1186
|
for (const [k, label2] of Object.entries(RULE_LABELS)) {
|
|
758
1187
|
const ruleKey = k;
|
|
@@ -764,30 +1193,18 @@ var buildMenuItems = () => {
|
|
|
764
1193
|
getValue: (cfg) => cfg.security.rules[ruleKey] ? "ON" : "OFF",
|
|
765
1194
|
apply: (cfg) => ({
|
|
766
1195
|
...cfg,
|
|
767
|
-
security: {
|
|
768
|
-
...cfg.security,
|
|
769
|
-
rules: { ...cfg.security.rules, [ruleKey]: !cfg.security.rules[ruleKey] }
|
|
770
|
-
}
|
|
1196
|
+
security: { ...cfg.security, rules: { ...cfg.security.rules, [ruleKey]: !cfg.security.rules[ruleKey] } }
|
|
771
1197
|
})
|
|
772
1198
|
});
|
|
773
1199
|
}
|
|
774
|
-
items.push({
|
|
775
|
-
type: "header",
|
|
776
|
-
label: "NOTIFICATIONS",
|
|
777
|
-
section: "notifications",
|
|
778
|
-
getValue: () => "",
|
|
779
|
-
key: void 0
|
|
780
|
-
});
|
|
1200
|
+
items.push({ type: "header", label: "NOTIFICATIONS", section: "notifications", getValue: () => "", key: void 0 });
|
|
781
1201
|
items.push({
|
|
782
1202
|
type: "toggle",
|
|
783
1203
|
label: "Terminal bell",
|
|
784
1204
|
section: "notifications",
|
|
785
1205
|
key: "bell",
|
|
786
1206
|
getValue: (cfg) => cfg.notifications.bell ? "ON" : "OFF",
|
|
787
|
-
apply: (cfg) => ({
|
|
788
|
-
...cfg,
|
|
789
|
-
notifications: { ...cfg.notifications, bell: !cfg.notifications.bell }
|
|
790
|
-
})
|
|
1207
|
+
apply: (cfg) => ({ ...cfg, notifications: { ...cfg.notifications, bell: !cfg.notifications.bell } })
|
|
791
1208
|
});
|
|
792
1209
|
items.push({
|
|
793
1210
|
type: "toggle",
|
|
@@ -795,10 +1212,7 @@ var buildMenuItems = () => {
|
|
|
795
1212
|
section: "notifications",
|
|
796
1213
|
key: "desktop",
|
|
797
1214
|
getValue: (cfg) => cfg.notifications.desktop ? "ON" : "OFF",
|
|
798
|
-
apply: (cfg) => ({
|
|
799
|
-
...cfg,
|
|
800
|
-
notifications: { ...cfg.notifications, desktop: !cfg.notifications.desktop }
|
|
801
|
-
})
|
|
1215
|
+
apply: (cfg) => ({ ...cfg, notifications: { ...cfg.notifications, desktop: !cfg.notifications.desktop } })
|
|
802
1216
|
});
|
|
803
1217
|
items.push({
|
|
804
1218
|
type: "cycle",
|
|
@@ -808,20 +1222,35 @@ var buildMenuItems = () => {
|
|
|
808
1222
|
getValue: (cfg) => cfg.notifications.minSeverity,
|
|
809
1223
|
apply: (cfg) => {
|
|
810
1224
|
const idx = SEVERITY_OPTIONS.indexOf(cfg.notifications.minSeverity);
|
|
811
|
-
|
|
812
|
-
|
|
1225
|
+
return {
|
|
1226
|
+
...cfg,
|
|
1227
|
+
notifications: { ...cfg.notifications, minSeverity: SEVERITY_OPTIONS[(idx + 1) % SEVERITY_OPTIONS.length] }
|
|
1228
|
+
};
|
|
813
1229
|
}
|
|
814
1230
|
});
|
|
815
1231
|
return items;
|
|
816
1232
|
};
|
|
817
1233
|
var MENU_ITEMS = buildMenuItems();
|
|
818
1234
|
var SELECTABLE_INDICES = MENU_ITEMS.map((item, i) => item.type !== "header" ? i : -1).filter((i) => i >= 0);
|
|
819
|
-
var SettingsMenu = React8.memo(({ config, onClose }) => {
|
|
1235
|
+
var SettingsMenu = React8.memo(({ config, onClose, onOpenThemeMenu }) => {
|
|
820
1236
|
const { stdout } = useStdout();
|
|
821
1237
|
const termHeight = stdout?.rows ?? 40;
|
|
822
1238
|
const [localConfig, setLocalConfig] = useState3(() => JSON.parse(JSON.stringify(config)));
|
|
823
1239
|
const [selectablePos, setSelectablePos] = useState3(0);
|
|
824
1240
|
const [rebinding, setRebinding] = useState3(false);
|
|
1241
|
+
const [toast, setToast] = useState3("");
|
|
1242
|
+
const toastTimer = useRef(null);
|
|
1243
|
+
const showToast = (msg) => {
|
|
1244
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1245
|
+
setToast(msg);
|
|
1246
|
+
toastTimer.current = setTimeout(() => setToast(""), 2500);
|
|
1247
|
+
};
|
|
1248
|
+
useEffect2(
|
|
1249
|
+
() => () => {
|
|
1250
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1251
|
+
},
|
|
1252
|
+
[]
|
|
1253
|
+
);
|
|
825
1254
|
const selectedIndex = SELECTABLE_INDICES[selectablePos];
|
|
826
1255
|
const maxLabelLen = useMemo(
|
|
827
1256
|
() => Math.max(...MENU_ITEMS.filter((i) => i.type !== "header").map((i) => i.label.length)),
|
|
@@ -837,11 +1266,24 @@ var SettingsMenu = React8.memo(({ config, onClose }) => {
|
|
|
837
1266
|
else if (key.escape) {
|
|
838
1267
|
setRebinding(false);
|
|
839
1268
|
return;
|
|
1269
|
+
} else if (key.backspace || key.delete) {
|
|
1270
|
+
const kbKey2 = item.key;
|
|
1271
|
+
const defaultVal = DEFAULT_KEYBINDINGS[kbKey2];
|
|
1272
|
+
if (item.apply) setLocalConfig((c) => item.apply(c, defaultVal));
|
|
1273
|
+
showToast(`Reset to default: ${displayKey(defaultVal)}`);
|
|
1274
|
+
setRebinding(false);
|
|
1275
|
+
return;
|
|
840
1276
|
} else if (input && input.length === 1) newKey = input;
|
|
841
1277
|
else return;
|
|
842
|
-
|
|
843
|
-
|
|
1278
|
+
const kbKey = item.key;
|
|
1279
|
+
const conflict = Object.entries(localConfig.keybindings).find(([k, v]) => k !== kbKey && v === newKey);
|
|
1280
|
+
if (conflict) {
|
|
1281
|
+
const conflictLabel = KEYBIND_LABELS[conflict[0]] || conflict[0];
|
|
1282
|
+
showToast(`'${displayKey(newKey)}' is already assigned to '${conflictLabel}'`);
|
|
1283
|
+
setRebinding(false);
|
|
1284
|
+
return;
|
|
844
1285
|
}
|
|
1286
|
+
if (item.apply) setLocalConfig((c) => item.apply(c, newKey));
|
|
845
1287
|
setRebinding(false);
|
|
846
1288
|
return;
|
|
847
1289
|
}
|
|
@@ -859,11 +1301,17 @@ var SettingsMenu = React8.memo(({ config, onClose }) => {
|
|
|
859
1301
|
}
|
|
860
1302
|
if (key.return) {
|
|
861
1303
|
const item = MENU_ITEMS[selectedIndex];
|
|
862
|
-
if (item.
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1304
|
+
if (item.key === "manageThemes") {
|
|
1305
|
+
onOpenThemeMenu();
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
if (item.key === "resetAllKeybinds") {
|
|
1309
|
+
if (item.apply) setLocalConfig((c) => item.apply(c));
|
|
1310
|
+
showToast("All keybindings reset to defaults");
|
|
1311
|
+
return;
|
|
866
1312
|
}
|
|
1313
|
+
if (item.type === "keybind") setRebinding(true);
|
|
1314
|
+
else if (item.apply) setLocalConfig((c) => item.apply(c));
|
|
867
1315
|
}
|
|
868
1316
|
});
|
|
869
1317
|
const contentHeight = termHeight - 6;
|
|
@@ -884,7 +1332,10 @@ var SettingsMenu = React8.memo(({ config, onClose }) => {
|
|
|
884
1332
|
children: [
|
|
885
1333
|
/* @__PURE__ */ jsxs8(Box8, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
886
1334
|
/* @__PURE__ */ jsx8(Text8, { color: colors.header, bold: true, children: "SETTINGS" }),
|
|
887
|
-
/* @__PURE__ */
|
|
1335
|
+
/* @__PURE__ */ jsxs8(Text8, { color: colors.muted, children: [
|
|
1336
|
+
"esc to save & close ",
|
|
1337
|
+
rebinding ? "| backspace to reset" : ""
|
|
1338
|
+
] })
|
|
888
1339
|
] }),
|
|
889
1340
|
visibleItems.map((item, vi) => {
|
|
890
1341
|
const realIndex = visibleStartIndex + vi;
|
|
@@ -896,36 +1347,460 @@ var SettingsMenu = React8.memo(({ config, onClose }) => {
|
|
|
896
1347
|
] }) }, `h-${item.label}`);
|
|
897
1348
|
}
|
|
898
1349
|
const value = item.getValue(localConfig);
|
|
899
|
-
const dots = ".".repeat(Math.max(2, maxLabelLen - item.label.length + 4));
|
|
900
1350
|
const isRebindingThis = rebinding && isSelected;
|
|
901
1351
|
const displayValue = isRebindingThis ? "[press key...]" : value;
|
|
902
1352
|
const valueColor = isRebindingThis ? colors.warning : value === "ON" ? colors.secondary : value === "OFF" ? colors.error : colors.bright;
|
|
1353
|
+
const isReset = item.key === "resetAllKeybinds";
|
|
1354
|
+
const dots = isReset ? "" : ".".repeat(Math.max(2, maxLabelLen - item.label.length + 4)) + " ";
|
|
903
1355
|
return /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
904
1356
|
/* @__PURE__ */ jsxs8(Text8, { color: isSelected ? colors.primary : colors.text, children: [
|
|
905
1357
|
isSelected ? "> " : " ",
|
|
906
|
-
"
|
|
1358
|
+
" ",
|
|
907
1359
|
item.label,
|
|
908
1360
|
" ",
|
|
909
|
-
dots
|
|
910
|
-
" "
|
|
1361
|
+
dots
|
|
911
1362
|
] }),
|
|
912
|
-
/* @__PURE__ */ jsx8(Text8, { color: valueColor, children: displayValue })
|
|
1363
|
+
!isReset && /* @__PURE__ */ jsx8(Text8, { color: valueColor, children: displayValue })
|
|
913
1364
|
] }, `${item.section}-${item.key}`);
|
|
914
|
-
})
|
|
1365
|
+
}),
|
|
1366
|
+
toast && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx8(Text8, { color: colors.warning, children: toast }) })
|
|
915
1367
|
]
|
|
916
1368
|
}
|
|
917
1369
|
) });
|
|
918
1370
|
});
|
|
919
1371
|
|
|
1372
|
+
// src/ui/components/ThemeMenu.tsx
|
|
1373
|
+
import React10, { useState as useState5, useCallback, useRef as useRef2, useEffect as useEffect3 } from "react";
|
|
1374
|
+
import { Box as Box10, Text as Text10, useInput as useInput4, useStdout as useStdout2 } from "ink";
|
|
1375
|
+
|
|
1376
|
+
// src/ui/components/ThemeEditor.tsx
|
|
1377
|
+
import React9, { useState as useState4 } from "react";
|
|
1378
|
+
import { Box as Box9, Text as Text9, useInput as useInput3 } from "ink";
|
|
1379
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1380
|
+
var ALL_KEYS = [
|
|
1381
|
+
...COLOR_KEYS.map((key) => ({ group: "colors", key })),
|
|
1382
|
+
...TOOL_COLOR_KEYS.map((key) => ({ group: "toolColors", key }))
|
|
1383
|
+
];
|
|
1384
|
+
var isValidHex = (v) => /^#[0-9A-Fa-f]{6}$/.test(v);
|
|
1385
|
+
var ThemeEditor = React9.memo(({ theme, onSave, onCancel }) => {
|
|
1386
|
+
const [editColors, setEditColors] = useState4({ ...theme.colors });
|
|
1387
|
+
const [editToolColors, setEditToolColors] = useState4({ ...theme.toolColors });
|
|
1388
|
+
const [selectedIdx, setSelectedIdx] = useState4(0);
|
|
1389
|
+
const [editing, setEditing] = useState4(false);
|
|
1390
|
+
const [inputValue, setInputValue] = useState4("");
|
|
1391
|
+
const currentTarget = ALL_KEYS[selectedIdx];
|
|
1392
|
+
const getCurrentValue = (t) => t.group === "colors" ? editColors[t.key] : editToolColors[t.key];
|
|
1393
|
+
useInput3((input, key) => {
|
|
1394
|
+
if (editing) {
|
|
1395
|
+
if (key.escape) {
|
|
1396
|
+
setEditing(false);
|
|
1397
|
+
setInputValue("");
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
if (key.return) {
|
|
1401
|
+
const val = inputValue.startsWith("#") ? inputValue : `#${inputValue}`;
|
|
1402
|
+
if (isValidHex(val)) {
|
|
1403
|
+
if (currentTarget.group === "colors") {
|
|
1404
|
+
setEditColors((c) => ({ ...c, [currentTarget.key]: val }));
|
|
1405
|
+
} else {
|
|
1406
|
+
setEditToolColors((c) => ({ ...c, [currentTarget.key]: val }));
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
setEditing(false);
|
|
1410
|
+
setInputValue("");
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (key.backspace || key.delete) {
|
|
1414
|
+
setInputValue((v) => v.slice(0, -1));
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
if (input && input.length === 1 && /[0-9A-Fa-f#]/.test(input)) {
|
|
1418
|
+
setInputValue((v) => v + input);
|
|
1419
|
+
}
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
if (key.escape) {
|
|
1423
|
+
onCancel();
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
if (key.upArrow) {
|
|
1427
|
+
setSelectedIdx((i) => Math.max(0, i - 1));
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
if (key.downArrow) {
|
|
1431
|
+
setSelectedIdx((i) => Math.min(ALL_KEYS.length - 1, i + 1));
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (key.return) {
|
|
1435
|
+
setEditing(true);
|
|
1436
|
+
setInputValue(getCurrentValue(currentTarget));
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
if (input === "s" || input === "S") {
|
|
1440
|
+
onSave({ ...theme, colors: editColors, toolColors: editToolColors });
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
|
|
1444
|
+
/* @__PURE__ */ jsxs9(Box9, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
1445
|
+
/* @__PURE__ */ jsxs9(Text9, { color: colors.header, bold: true, children: [
|
|
1446
|
+
"EDIT THEME: ",
|
|
1447
|
+
theme.name
|
|
1448
|
+
] }),
|
|
1449
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.muted, children: "enter:edit s:save esc:cancel" })
|
|
1450
|
+
] }),
|
|
1451
|
+
/* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsxs9(Text9, { color: colors.accent, bold: true, children: [
|
|
1452
|
+
" ",
|
|
1453
|
+
"COLORS"
|
|
1454
|
+
] }) }),
|
|
1455
|
+
COLOR_KEYS.map((k, i) => {
|
|
1456
|
+
const isSelected = selectedIdx === i;
|
|
1457
|
+
const value = editColors[k];
|
|
1458
|
+
const isEditingThis = editing && isSelected;
|
|
1459
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
1460
|
+
/* @__PURE__ */ jsxs9(Text9, { color: isSelected ? colors.primary : colors.text, children: [
|
|
1461
|
+
isSelected ? "> " : " ",
|
|
1462
|
+
" ",
|
|
1463
|
+
k.padEnd(12)
|
|
1464
|
+
] }),
|
|
1465
|
+
/* @__PURE__ */ jsx9(Text9, { color: value, children: isEditingThis ? inputValue + "_" : value }),
|
|
1466
|
+
/* @__PURE__ */ jsxs9(Text9, { color: value, children: [
|
|
1467
|
+
" ",
|
|
1468
|
+
"\u2588\u2588"
|
|
1469
|
+
] })
|
|
1470
|
+
] }, k);
|
|
1471
|
+
}),
|
|
1472
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsxs9(Text9, { color: colors.accent, bold: true, children: [
|
|
1473
|
+
" ",
|
|
1474
|
+
"TOOL COLORS"
|
|
1475
|
+
] }) }),
|
|
1476
|
+
TOOL_COLOR_KEYS.map((k, i) => {
|
|
1477
|
+
const realIdx = COLOR_KEYS.length + i;
|
|
1478
|
+
const isSelected = selectedIdx === realIdx;
|
|
1479
|
+
const value = editToolColors[k];
|
|
1480
|
+
const isEditingThis = editing && isSelected;
|
|
1481
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
1482
|
+
/* @__PURE__ */ jsxs9(Text9, { color: isSelected ? colors.primary : colors.text, children: [
|
|
1483
|
+
isSelected ? "> " : " ",
|
|
1484
|
+
" ",
|
|
1485
|
+
k.padEnd(12)
|
|
1486
|
+
] }),
|
|
1487
|
+
/* @__PURE__ */ jsx9(Text9, { color: value, children: isEditingThis ? inputValue + "_" : value }),
|
|
1488
|
+
/* @__PURE__ */ jsxs9(Text9, { color: value, children: [
|
|
1489
|
+
" ",
|
|
1490
|
+
"\u2588\u2588"
|
|
1491
|
+
] })
|
|
1492
|
+
] }, k);
|
|
1493
|
+
})
|
|
1494
|
+
] });
|
|
1495
|
+
});
|
|
1496
|
+
|
|
1497
|
+
// src/ui/components/ThemeMenu.tsx
|
|
1498
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1499
|
+
var ThemeMenu = React10.memo(({ config, onClose }) => {
|
|
1500
|
+
const { stdout } = useStdout2();
|
|
1501
|
+
const termHeight = stdout?.rows ?? 40;
|
|
1502
|
+
const [localConfig, setLocalConfig] = useState5(() => JSON.parse(JSON.stringify(config)));
|
|
1503
|
+
const [selectedIdx, setSelectedIdx] = useState5(0);
|
|
1504
|
+
const [view, setView] = useState5("list");
|
|
1505
|
+
const [editingTheme, setEditingTheme] = useState5(null);
|
|
1506
|
+
const [nameInput, setNameInput] = useState5("");
|
|
1507
|
+
const [namingAction, setNamingAction] = useState5("copy");
|
|
1508
|
+
const [toast, setToast] = useState5("");
|
|
1509
|
+
const toastTimer = useRef2(null);
|
|
1510
|
+
const showToast = (msg) => {
|
|
1511
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1512
|
+
setToast(msg);
|
|
1513
|
+
toastTimer.current = setTimeout(() => setToast(""), 2500);
|
|
1514
|
+
};
|
|
1515
|
+
useEffect3(
|
|
1516
|
+
() => () => {
|
|
1517
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1518
|
+
},
|
|
1519
|
+
[]
|
|
1520
|
+
);
|
|
1521
|
+
const themes = getAllThemes(localConfig.customThemes);
|
|
1522
|
+
const previewTheme = useCallback(
|
|
1523
|
+
(idx) => {
|
|
1524
|
+
const t = themes[idx];
|
|
1525
|
+
if (t) applyTheme(t);
|
|
1526
|
+
},
|
|
1527
|
+
[themes]
|
|
1528
|
+
);
|
|
1529
|
+
const updateSelection = useCallback(
|
|
1530
|
+
(newIdx) => {
|
|
1531
|
+
setSelectedIdx(newIdx);
|
|
1532
|
+
previewTheme(newIdx);
|
|
1533
|
+
},
|
|
1534
|
+
[previewTheme]
|
|
1535
|
+
);
|
|
1536
|
+
useInput4((input, key) => {
|
|
1537
|
+
if (view === "naming") {
|
|
1538
|
+
if (key.escape) {
|
|
1539
|
+
setView("list");
|
|
1540
|
+
setNameInput("");
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
if (key.return && nameInput.trim()) {
|
|
1544
|
+
const name = nameInput.trim();
|
|
1545
|
+
if (themes.some((t) => t.name === name)) {
|
|
1546
|
+
showToast(`Theme '${name}' already exists`);
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
if (namingAction === "copy") {
|
|
1550
|
+
const source = themes[selectedIdx];
|
|
1551
|
+
const newTheme = {
|
|
1552
|
+
name,
|
|
1553
|
+
colors: { ...source.colors },
|
|
1554
|
+
toolColors: { ...source.toolColors }
|
|
1555
|
+
};
|
|
1556
|
+
setLocalConfig((c) => ({
|
|
1557
|
+
...c,
|
|
1558
|
+
theme: name,
|
|
1559
|
+
customThemes: {
|
|
1560
|
+
...c.customThemes,
|
|
1561
|
+
[name]: { name, colors: newTheme.colors, toolColors: newTheme.toolColors }
|
|
1562
|
+
}
|
|
1563
|
+
}));
|
|
1564
|
+
applyTheme(newTheme);
|
|
1565
|
+
showToast(`Created '${name}'`);
|
|
1566
|
+
} else {
|
|
1567
|
+
const old = themes[selectedIdx];
|
|
1568
|
+
const updated = { ...localConfig.customThemes };
|
|
1569
|
+
delete updated[old.name];
|
|
1570
|
+
updated[name] = { name, colors: old.colors, toolColors: old.toolColors };
|
|
1571
|
+
const newActive = localConfig.theme === old.name ? name : localConfig.theme;
|
|
1572
|
+
setLocalConfig((c) => ({ ...c, theme: newActive, customThemes: updated }));
|
|
1573
|
+
showToast(`Renamed to '${name}'`);
|
|
1574
|
+
}
|
|
1575
|
+
setView("list");
|
|
1576
|
+
setNameInput("");
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (key.backspace || key.delete) {
|
|
1580
|
+
setNameInput((v) => v.slice(0, -1));
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
if (input && input.length === 1) setNameInput((v) => v + input);
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
if (view === "editor" && editingTheme) return;
|
|
1587
|
+
if (key.escape) {
|
|
1588
|
+
const restoreTheme = resolveTheme(localConfig.theme, localConfig.customThemes);
|
|
1589
|
+
applyTheme(restoreTheme);
|
|
1590
|
+
onClose(localConfig);
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1593
|
+
if (key.upArrow) {
|
|
1594
|
+
updateSelection(Math.max(0, selectedIdx - 1));
|
|
1595
|
+
return;
|
|
1596
|
+
}
|
|
1597
|
+
if (key.downArrow) {
|
|
1598
|
+
updateSelection(Math.min(themes.length - 1, selectedIdx + 1));
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
if (key.return) {
|
|
1602
|
+
setLocalConfig((c) => ({ ...c, theme: themes[selectedIdx].name }));
|
|
1603
|
+
applyTheme(themes[selectedIdx]);
|
|
1604
|
+
onClose({ ...localConfig, theme: themes[selectedIdx].name });
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
if (input === "c") {
|
|
1608
|
+
setNamingAction("copy");
|
|
1609
|
+
setNameInput(themes[selectedIdx].name + "-custom");
|
|
1610
|
+
setView("naming");
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
const selected = themes[selectedIdx];
|
|
1614
|
+
if (input === "e" && !selected.builtin) {
|
|
1615
|
+
setEditingTheme(selected);
|
|
1616
|
+
setView("editor");
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
if (input === "r" && !selected.builtin) {
|
|
1620
|
+
setNamingAction("rename");
|
|
1621
|
+
setNameInput(selected.name);
|
|
1622
|
+
setView("naming");
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
if (input === "d" && !selected.builtin) {
|
|
1626
|
+
const updated = { ...localConfig.customThemes };
|
|
1627
|
+
delete updated[selected.name];
|
|
1628
|
+
const newTheme = localConfig.theme === selected.name ? "one-dark" : localConfig.theme;
|
|
1629
|
+
setLocalConfig((c) => ({ ...c, theme: newTheme, customThemes: updated }));
|
|
1630
|
+
if (localConfig.theme === selected.name) applyTheme(getDefaultTheme());
|
|
1631
|
+
setSelectedIdx((i) => Math.min(i, themes.length - 2));
|
|
1632
|
+
showToast(`Deleted '${selected.name}'`);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
if (key.backspace || key.delete) {
|
|
1636
|
+
setLocalConfig((c) => ({ ...c, theme: "one-dark" }));
|
|
1637
|
+
applyTheme(getDefaultTheme());
|
|
1638
|
+
showToast("Restored default theme");
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
const handleEditorSave = useCallback((updated) => {
|
|
1642
|
+
setLocalConfig((c) => ({
|
|
1643
|
+
...c,
|
|
1644
|
+
customThemes: {
|
|
1645
|
+
...c.customThemes,
|
|
1646
|
+
[updated.name]: { name: updated.name, colors: updated.colors, toolColors: updated.toolColors }
|
|
1647
|
+
}
|
|
1648
|
+
}));
|
|
1649
|
+
applyTheme(updated);
|
|
1650
|
+
setView("list");
|
|
1651
|
+
setEditingTheme(null);
|
|
1652
|
+
showToast(`Saved '${updated.name}'`);
|
|
1653
|
+
}, []);
|
|
1654
|
+
const handleEditorCancel = useCallback(() => {
|
|
1655
|
+
const restoreTheme = resolveTheme(localConfig.theme, localConfig.customThemes);
|
|
1656
|
+
applyTheme(restoreTheme);
|
|
1657
|
+
setView("list");
|
|
1658
|
+
setEditingTheme(null);
|
|
1659
|
+
}, [localConfig]);
|
|
1660
|
+
if (view === "editor" && editingTheme) {
|
|
1661
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsx10(Box10, { borderStyle: "round", borderColor: colors.primary, flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsx10(ThemeEditor, { theme: editingTheme, onSave: handleEditorSave, onCancel: handleEditorCancel }) }) });
|
|
1662
|
+
}
|
|
1663
|
+
const contentHeight = termHeight - 8;
|
|
1664
|
+
const halfView = Math.floor(contentHeight / 2);
|
|
1665
|
+
const scrollStart = Math.max(0, Math.min(selectedIdx - halfView, themes.length - contentHeight));
|
|
1666
|
+
const visibleThemes = themes.slice(Math.max(0, scrollStart), Math.max(0, scrollStart) + contentHeight);
|
|
1667
|
+
const visibleStartIdx = Math.max(0, scrollStart);
|
|
1668
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsxs10(
|
|
1669
|
+
Box10,
|
|
1670
|
+
{
|
|
1671
|
+
borderStyle: "round",
|
|
1672
|
+
borderColor: colors.primary,
|
|
1673
|
+
flexDirection: "column",
|
|
1674
|
+
paddingX: 2,
|
|
1675
|
+
paddingY: 1,
|
|
1676
|
+
height: termHeight,
|
|
1677
|
+
children: [
|
|
1678
|
+
/* @__PURE__ */ jsxs10(Box10, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
1679
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.header, bold: true, children: "THEMES" }),
|
|
1680
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.muted, children: "enter:apply c:copy e:edit r:rename d:delete esc:back" })
|
|
1681
|
+
] }),
|
|
1682
|
+
view === "naming" && /* @__PURE__ */ jsxs10(Box10, { marginBottom: 1, children: [
|
|
1683
|
+
/* @__PURE__ */ jsxs10(Text10, { color: colors.warning, children: [
|
|
1684
|
+
namingAction === "copy" ? "New name" : "Rename to",
|
|
1685
|
+
": "
|
|
1686
|
+
] }),
|
|
1687
|
+
/* @__PURE__ */ jsxs10(Text10, { color: colors.bright, children: [
|
|
1688
|
+
nameInput,
|
|
1689
|
+
"_"
|
|
1690
|
+
] })
|
|
1691
|
+
] }),
|
|
1692
|
+
visibleThemes.map((theme, vi) => {
|
|
1693
|
+
const realIdx = visibleStartIdx + vi;
|
|
1694
|
+
const isSelected = realIdx === selectedIdx;
|
|
1695
|
+
const isActive = theme.name === localConfig.theme;
|
|
1696
|
+
return /* @__PURE__ */ jsxs10(Box10, { children: [
|
|
1697
|
+
/* @__PURE__ */ jsxs10(Text10, { color: isSelected ? colors.primary : colors.text, children: [
|
|
1698
|
+
isSelected ? "> " : " ",
|
|
1699
|
+
isActive ? "* " : " ",
|
|
1700
|
+
theme.name
|
|
1701
|
+
] }),
|
|
1702
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.muted, children: theme.builtin ? " (built-in)" : " (custom)" }),
|
|
1703
|
+
/* @__PURE__ */ jsx10(Text10, { children: " " }),
|
|
1704
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.colors.primary, children: "\u2588" }),
|
|
1705
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.colors.secondary, children: "\u2588" }),
|
|
1706
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.colors.accent, children: "\u2588" }),
|
|
1707
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.colors.warning, children: "\u2588" }),
|
|
1708
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.colors.error, children: "\u2588" })
|
|
1709
|
+
] }, theme.name);
|
|
1710
|
+
}),
|
|
1711
|
+
toast && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx10(Text10, { color: colors.warning, children: toast }) })
|
|
1712
|
+
]
|
|
1713
|
+
}
|
|
1714
|
+
) });
|
|
1715
|
+
});
|
|
1716
|
+
|
|
1717
|
+
// src/ui/components/ConfirmModal.tsx
|
|
1718
|
+
import React11 from "react";
|
|
1719
|
+
import { Box as Box11, Text as Text11, useInput as useInput5 } from "ink";
|
|
1720
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1721
|
+
var ConfirmModal = React11.memo(({ title, message, onConfirm, onCancel }) => {
|
|
1722
|
+
useInput5((input, key) => {
|
|
1723
|
+
if (input === "y" || input === "Y") {
|
|
1724
|
+
onConfirm();
|
|
1725
|
+
} else if (input === "n" || input === "N" || key.escape) {
|
|
1726
|
+
onCancel();
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
return /* @__PURE__ */ jsxs11(
|
|
1730
|
+
Box11,
|
|
1731
|
+
{
|
|
1732
|
+
borderStyle: "round",
|
|
1733
|
+
borderColor: colors.warning,
|
|
1734
|
+
flexDirection: "column",
|
|
1735
|
+
paddingX: 2,
|
|
1736
|
+
paddingY: 1,
|
|
1737
|
+
alignSelf: "center",
|
|
1738
|
+
children: [
|
|
1739
|
+
/* @__PURE__ */ jsx11(Text11, { color: colors.warning, bold: true, children: title }),
|
|
1740
|
+
/* @__PURE__ */ jsx11(Text11, { color: colors.text, children: message }),
|
|
1741
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: colors.muted, children: "[y] confirm [n/esc] cancel" }) })
|
|
1742
|
+
]
|
|
1743
|
+
}
|
|
1744
|
+
);
|
|
1745
|
+
});
|
|
1746
|
+
|
|
1747
|
+
// src/ui/components/SplitPanel.tsx
|
|
1748
|
+
import React12 from "react";
|
|
1749
|
+
import { Box as Box12 } from "ink";
|
|
1750
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1751
|
+
var SplitPanel = React12.memo(
|
|
1752
|
+
({
|
|
1753
|
+
activePanel,
|
|
1754
|
+
leftSession,
|
|
1755
|
+
rightSession,
|
|
1756
|
+
leftEvents,
|
|
1757
|
+
rightEvents,
|
|
1758
|
+
leftScroll,
|
|
1759
|
+
rightScroll,
|
|
1760
|
+
leftFilter,
|
|
1761
|
+
rightFilter,
|
|
1762
|
+
leftShowDetail,
|
|
1763
|
+
rightShowDetail,
|
|
1764
|
+
height
|
|
1765
|
+
}) => {
|
|
1766
|
+
const left = leftShowDetail && leftSession ? /* @__PURE__ */ jsx12(SessionDetail, { session: leftSession, focused: activePanel === "left", height }) : /* @__PURE__ */ jsx12(
|
|
1767
|
+
ActivityFeed,
|
|
1768
|
+
{
|
|
1769
|
+
events: leftEvents,
|
|
1770
|
+
sessionSlug: leftSession?.slug ?? null,
|
|
1771
|
+
focused: activePanel === "left",
|
|
1772
|
+
height,
|
|
1773
|
+
scrollOffset: leftScroll,
|
|
1774
|
+
filter: leftFilter || void 0
|
|
1775
|
+
}
|
|
1776
|
+
);
|
|
1777
|
+
const right = rightShowDetail && rightSession ? /* @__PURE__ */ jsx12(SessionDetail, { session: rightSession, focused: activePanel === "right", height }) : /* @__PURE__ */ jsx12(
|
|
1778
|
+
ActivityFeed,
|
|
1779
|
+
{
|
|
1780
|
+
events: rightEvents,
|
|
1781
|
+
sessionSlug: rightSession?.slug ?? null,
|
|
1782
|
+
focused: activePanel === "right",
|
|
1783
|
+
height,
|
|
1784
|
+
scrollOffset: rightScroll,
|
|
1785
|
+
filter: rightFilter || void 0
|
|
1786
|
+
}
|
|
1787
|
+
);
|
|
1788
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", flexGrow: 1, children: [
|
|
1789
|
+
left,
|
|
1790
|
+
right
|
|
1791
|
+
] });
|
|
1792
|
+
}
|
|
1793
|
+
);
|
|
1794
|
+
|
|
920
1795
|
// src/ui/hooks/useSessions.ts
|
|
921
|
-
import { useState as
|
|
1796
|
+
import { useState as useState6, useEffect as useEffect4, useCallback as useCallback2, useRef as useRef3 } from "react";
|
|
922
1797
|
var ACTIVE_POLL_MS = 1e4;
|
|
923
1798
|
var IDLE_POLL_MS = 3e4;
|
|
924
|
-
var useSessions = (allUsers, filter) => {
|
|
925
|
-
const [sessions, setSessions] =
|
|
926
|
-
const [selectedIndex, setSelectedIndex] =
|
|
927
|
-
const usageOverrides =
|
|
928
|
-
const refresh =
|
|
1799
|
+
var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
1800
|
+
const [sessions, setSessions] = useState6([]);
|
|
1801
|
+
const [selectedIndex, setSelectedIndex] = useState6(0);
|
|
1802
|
+
const usageOverrides = useRef3(/* @__PURE__ */ new Map());
|
|
1803
|
+
const refresh = useCallback2(() => {
|
|
929
1804
|
const found = discoverSessions(allUsers);
|
|
930
1805
|
const nicknames = getNicknames();
|
|
931
1806
|
const enriched = found.map((s) => {
|
|
@@ -942,31 +1817,40 @@ var useSessions = (allUsers, filter) => {
|
|
|
942
1817
|
};
|
|
943
1818
|
});
|
|
944
1819
|
let filtered = enriched;
|
|
1820
|
+
if (archivedIds && archivedIds.size > 0) {
|
|
1821
|
+
if (viewingArchive) {
|
|
1822
|
+
filtered = filtered.filter((s) => archivedIds.has(s.sessionId));
|
|
1823
|
+
} else {
|
|
1824
|
+
filtered = filtered.filter((s) => !archivedIds.has(s.sessionId));
|
|
1825
|
+
}
|
|
1826
|
+
} else if (viewingArchive) {
|
|
1827
|
+
filtered = [];
|
|
1828
|
+
}
|
|
945
1829
|
if (filter) {
|
|
946
1830
|
const lower = filter.toLowerCase();
|
|
947
|
-
filtered =
|
|
1831
|
+
filtered = filtered.filter(
|
|
948
1832
|
(s) => s.slug.toLowerCase().includes(lower) || s.nickname?.toLowerCase().includes(lower) || s.project.toLowerCase().includes(lower) || s.model.toLowerCase().includes(lower)
|
|
949
1833
|
);
|
|
950
1834
|
}
|
|
951
1835
|
setSessions(filtered);
|
|
952
|
-
}, [allUsers, filter]);
|
|
953
|
-
|
|
1836
|
+
}, [allUsers, filter, archivedIds, viewingArchive]);
|
|
1837
|
+
useEffect4(() => {
|
|
954
1838
|
refresh();
|
|
955
1839
|
const pollMs = sessions.length > 0 ? ACTIVE_POLL_MS : IDLE_POLL_MS;
|
|
956
1840
|
const interval = setInterval(refresh, pollMs);
|
|
957
1841
|
return () => clearInterval(interval);
|
|
958
1842
|
}, [refresh, sessions.length > 0]);
|
|
959
1843
|
const selectedSession = sessions[selectedIndex] ?? null;
|
|
960
|
-
const selectNext =
|
|
1844
|
+
const selectNext = useCallback2(() => {
|
|
961
1845
|
setSelectedIndex((i) => Math.min(i + 1, Math.max(0, sessions.length - 1)));
|
|
962
1846
|
}, [sessions.length]);
|
|
963
|
-
const selectPrev =
|
|
1847
|
+
const selectPrev = useCallback2(() => {
|
|
964
1848
|
setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
965
1849
|
}, []);
|
|
966
|
-
const selectIndex =
|
|
1850
|
+
const selectIndex = useCallback2((i) => {
|
|
967
1851
|
setSelectedIndex(i);
|
|
968
1852
|
}, []);
|
|
969
|
-
const addUsage =
|
|
1853
|
+
const addUsage = useCallback2((sessionId, usage) => {
|
|
970
1854
|
const existing = usageOverrides.current.get(sessionId);
|
|
971
1855
|
if (existing) {
|
|
972
1856
|
usageOverrides.current.set(sessionId, {
|
|
@@ -983,12 +1867,12 @@ var useSessions = (allUsers, filter) => {
|
|
|
983
1867
|
};
|
|
984
1868
|
|
|
985
1869
|
// src/ui/hooks/useActivityStream.ts
|
|
986
|
-
import { useState as
|
|
1870
|
+
import { useState as useState7, useEffect as useEffect5, useRef as useRef4 } from "react";
|
|
987
1871
|
var MAX_EVENTS = 200;
|
|
988
1872
|
var useActivityStream = (session, allUsers) => {
|
|
989
|
-
const [events, setEvents] =
|
|
990
|
-
const watcherRef =
|
|
991
|
-
|
|
1873
|
+
const [events, setEvents] = useState7([]);
|
|
1874
|
+
const watcherRef = useRef4(null);
|
|
1875
|
+
useEffect5(() => {
|
|
992
1876
|
setEvents([]);
|
|
993
1877
|
if (!session) return;
|
|
994
1878
|
const existingCalls = [];
|
|
@@ -1014,8 +1898,19 @@ var useActivityStream = (session, allUsers) => {
|
|
|
1014
1898
|
return events;
|
|
1015
1899
|
};
|
|
1016
1900
|
|
|
1901
|
+
// src/ui/hooks/useFilteredEvents.ts
|
|
1902
|
+
import { useMemo as useMemo2 } from "react";
|
|
1903
|
+
var applyFilter = (events, filter) => {
|
|
1904
|
+
if (!filter) return events;
|
|
1905
|
+
const lower = filter.toLowerCase();
|
|
1906
|
+
return events.filter(
|
|
1907
|
+
(e) => e.toolName.toLowerCase().includes(lower) || JSON.stringify(e.toolInput).toLowerCase().includes(lower)
|
|
1908
|
+
);
|
|
1909
|
+
};
|
|
1910
|
+
var useFilteredEvents = (rawEvents, filter) => useMemo2(() => applyFilter(rawEvents, filter), [rawEvents, filter]);
|
|
1911
|
+
|
|
1017
1912
|
// src/ui/hooks/useAlerts.ts
|
|
1018
|
-
import { useState as
|
|
1913
|
+
import { useState as useState8, useEffect as useEffect6, useRef as useRef5 } from "react";
|
|
1019
1914
|
|
|
1020
1915
|
// src/notifications.ts
|
|
1021
1916
|
import { exec as exec2 } from "child_process";
|
|
@@ -1083,11 +1978,11 @@ var AlertLogger = class {
|
|
|
1083
1978
|
// src/ui/hooks/useAlerts.ts
|
|
1084
1979
|
var MAX_ALERTS = 100;
|
|
1085
1980
|
var useAlerts = (enabled, alertLevel, allUsers, config) => {
|
|
1086
|
-
const [alerts, setAlerts] =
|
|
1087
|
-
const engineRef =
|
|
1088
|
-
const watcherRef =
|
|
1089
|
-
const loggerRef =
|
|
1090
|
-
|
|
1981
|
+
const [alerts, setAlerts] = useState8([]);
|
|
1982
|
+
const engineRef = useRef5(new SecurityEngine(alertLevel));
|
|
1983
|
+
const watcherRef = useRef5(null);
|
|
1984
|
+
const loggerRef = useRef5(null);
|
|
1985
|
+
useEffect6(() => {
|
|
1091
1986
|
if (!enabled) return;
|
|
1092
1987
|
engineRef.current = new SecurityEngine(alertLevel);
|
|
1093
1988
|
if (config?.alerts.enabled) {
|
|
@@ -1123,27 +2018,27 @@ var useAlerts = (enabled, alertLevel, allUsers, config) => {
|
|
|
1123
2018
|
};
|
|
1124
2019
|
|
|
1125
2020
|
// src/ui/hooks/useTextInput.ts
|
|
1126
|
-
import { useState as
|
|
2021
|
+
import { useState as useState9, useCallback as useCallback3 } from "react";
|
|
1127
2022
|
var useTextInput = (onConfirm, onCancel) => {
|
|
1128
|
-
const [value, setValue] =
|
|
1129
|
-
const [isActive, setIsActive] =
|
|
1130
|
-
const start =
|
|
2023
|
+
const [value, setValue] = useState9("");
|
|
2024
|
+
const [isActive, setIsActive] = useState9(false);
|
|
2025
|
+
const start = useCallback3((initial = "") => {
|
|
1131
2026
|
setValue(initial);
|
|
1132
2027
|
setIsActive(true);
|
|
1133
2028
|
}, []);
|
|
1134
|
-
const cancel =
|
|
2029
|
+
const cancel = useCallback3(() => {
|
|
1135
2030
|
setValue("");
|
|
1136
2031
|
setIsActive(false);
|
|
1137
2032
|
onCancel?.();
|
|
1138
2033
|
}, [onCancel]);
|
|
1139
|
-
const confirm =
|
|
2034
|
+
const confirm = useCallback3(() => {
|
|
1140
2035
|
const result = value;
|
|
1141
2036
|
setIsActive(false);
|
|
1142
2037
|
setValue("");
|
|
1143
2038
|
onConfirm?.(result);
|
|
1144
2039
|
return result;
|
|
1145
2040
|
}, [value, onConfirm]);
|
|
1146
|
-
const handleInput =
|
|
2041
|
+
const handleInput = useCallback3(
|
|
1147
2042
|
(input, key) => {
|
|
1148
2043
|
if (!isActive) return false;
|
|
1149
2044
|
if (key.escape) {
|
|
@@ -1175,34 +2070,297 @@ var useTextInput = (onConfirm, onCancel) => {
|
|
|
1175
2070
|
return { value, isActive, start, cancel, confirm, handleInput };
|
|
1176
2071
|
};
|
|
1177
2072
|
|
|
1178
|
-
// src/ui/
|
|
1179
|
-
import {
|
|
2073
|
+
// src/ui/hooks/useKeyHandler.ts
|
|
2074
|
+
import { useInput as useInput6 } from "ink";
|
|
1180
2075
|
var matchKey = (binding, input, key) => {
|
|
1181
2076
|
if (binding === "tab") return Boolean(key.tab);
|
|
1182
2077
|
if (binding === "shift+tab") return Boolean(key.shift && key.tab);
|
|
1183
2078
|
if (binding === "enter") return Boolean(key.return);
|
|
1184
2079
|
return input === binding;
|
|
1185
2080
|
};
|
|
2081
|
+
var useKeyHandler = (deps) => {
|
|
2082
|
+
const d = deps;
|
|
2083
|
+
useInput6((input, key) => {
|
|
2084
|
+
if (d.showSetup || d.showSettings || d.confirmAction) return;
|
|
2085
|
+
if (d.inputMode === "nickname") {
|
|
2086
|
+
d.nicknameInput.handleInput(input, key);
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
if (d.inputMode === "filter") {
|
|
2090
|
+
if (key.escape) {
|
|
2091
|
+
if (d.activePanel === "sessions") d.setFilter("");
|
|
2092
|
+
else if (d.activePanel === "left") d.setLeftFilter("");
|
|
2093
|
+
else if (d.activePanel === "right") d.setRightFilter("");
|
|
2094
|
+
else d.setActivityFilter("");
|
|
2095
|
+
d.setInputMode("normal");
|
|
2096
|
+
d.filterInput.cancel();
|
|
2097
|
+
return;
|
|
2098
|
+
}
|
|
2099
|
+
d.filterInput.handleInput(input, key);
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2102
|
+
if (matchKey(d.kb.quit, input, key)) {
|
|
2103
|
+
d.exit();
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
if (d.showDetail && !d.splitMode) {
|
|
2107
|
+
if (key.escape || key.return || key.leftArrow) d.setShowDetail(false);
|
|
2108
|
+
return;
|
|
2109
|
+
}
|
|
2110
|
+
if (d.splitMode && (d.leftShowDetail || d.rightShowDetail)) {
|
|
2111
|
+
if (key.escape || key.return) {
|
|
2112
|
+
if (d.activePanel === "left") d.setLeftShowDetail(false);
|
|
2113
|
+
else if (d.activePanel === "right") d.setRightShowDetail(false);
|
|
2114
|
+
else {
|
|
2115
|
+
d.setLeftShowDetail(false);
|
|
2116
|
+
d.setRightShowDetail(false);
|
|
2117
|
+
}
|
|
2118
|
+
return;
|
|
2119
|
+
}
|
|
2120
|
+
if (key.leftArrow) {
|
|
2121
|
+
if (d.activePanel === "left") d.setLeftShowDetail(false);
|
|
2122
|
+
else if (d.activePanel === "right") d.setRightShowDetail(false);
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
if (matchKey(d.kb.split, input, key)) {
|
|
2127
|
+
if (d.splitMode) {
|
|
2128
|
+
d.clearSplitState();
|
|
2129
|
+
} else {
|
|
2130
|
+
d.setSplitMode(true);
|
|
2131
|
+
d.setLeftSession(d.selectedSession);
|
|
2132
|
+
d.setActivePanel("left");
|
|
2133
|
+
}
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
if (d.splitMode && d.activePanel === "sessions" && d.selectedSession) {
|
|
2137
|
+
if (matchKey(d.kb.pinLeft, input, key)) {
|
|
2138
|
+
d.resetPanel("left");
|
|
2139
|
+
d.setLeftSession(d.selectedSession);
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2142
|
+
if (matchKey(d.kb.pinRight, input, key)) {
|
|
2143
|
+
d.resetPanel("right");
|
|
2144
|
+
d.setRightSession(d.selectedSession);
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
if (d.splitMode && matchKey(d.kb.swapPanels, input, key)) {
|
|
2149
|
+
const tmpLs = d.leftSession;
|
|
2150
|
+
const tmpRs = d.rightSession;
|
|
2151
|
+
d.setLeftSession(tmpRs);
|
|
2152
|
+
d.setRightSession(tmpLs);
|
|
2153
|
+
const tmpScroll = d.leftScroll;
|
|
2154
|
+
d.setLeftScroll(d.rightScroll);
|
|
2155
|
+
d.setRightScroll(tmpScroll);
|
|
2156
|
+
const tmpFilt = d.leftFilter;
|
|
2157
|
+
d.setLeftFilter(d.rightFilter);
|
|
2158
|
+
d.setRightFilter(tmpFilt);
|
|
2159
|
+
const tmpDetail = d.leftShowDetail;
|
|
2160
|
+
d.setLeftShowDetail(d.rightShowDetail);
|
|
2161
|
+
d.setRightShowDetail(tmpDetail);
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
if (d.splitMode && matchKey(d.kb.closePanel, input, key)) {
|
|
2165
|
+
if (d.activePanel === "left") {
|
|
2166
|
+
d.resetPanel("left");
|
|
2167
|
+
if (!d.rightSession) d.clearSplitState();
|
|
2168
|
+
} else if (d.activePanel === "right") {
|
|
2169
|
+
d.resetPanel("right");
|
|
2170
|
+
if (!d.leftSession) d.clearSplitState();
|
|
2171
|
+
}
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
if (matchKey(d.kb.detail, input, key) && d.selectedSession) {
|
|
2175
|
+
if (d.splitMode) {
|
|
2176
|
+
if (d.activePanel === "left") {
|
|
2177
|
+
d.setLeftShowDetail((v) => !v);
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
if (d.activePanel === "right") {
|
|
2181
|
+
d.setRightShowDetail((v) => !v);
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
if (d.activePanel === "sessions") {
|
|
2185
|
+
if (!d.leftSession) {
|
|
2186
|
+
d.setLeftSession(d.selectedSession);
|
|
2187
|
+
d.setLeftShowDetail(true);
|
|
2188
|
+
d.setActivePanel("left");
|
|
2189
|
+
} else if (!d.rightSession) {
|
|
2190
|
+
d.setRightSession(d.selectedSession);
|
|
2191
|
+
d.setRightShowDetail(true);
|
|
2192
|
+
d.setActivePanel("right");
|
|
2193
|
+
}
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
2196
|
+
} else if (d.activePanel === "sessions") {
|
|
2197
|
+
d.setShowDetail(true);
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
if (matchKey(d.kb.panelNext, input, key) || key.rightArrow) {
|
|
2202
|
+
d.switchPanel("next");
|
|
2203
|
+
return;
|
|
2204
|
+
}
|
|
2205
|
+
if (matchKey(d.kb.panelPrev, input, key) || key.leftArrow) {
|
|
2206
|
+
d.switchPanel("prev");
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
if (matchKey(d.kb.nickname, input, key) && d.selectedSession) {
|
|
2210
|
+
d.setInputMode("nickname");
|
|
2211
|
+
d.nicknameInput.start(d.selectedSession.nickname || "");
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
if (matchKey(d.kb.clearNickname, input, key) && d.selectedSession) {
|
|
2215
|
+
d.onClearNickname(d.selectedSession.sessionId);
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
if (matchKey(d.kb.filter, input, key)) {
|
|
2219
|
+
d.setInputMode("filter");
|
|
2220
|
+
d.filterInput.start(d.getActiveFilter());
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
if (key.escape) {
|
|
2224
|
+
if (d.activePanel === "sessions" && d.filter) {
|
|
2225
|
+
d.setFilter("");
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
2228
|
+
if (d.activePanel === "activity" && d.activityFilter) {
|
|
2229
|
+
d.setActivityFilter("");
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2232
|
+
if (d.activePanel === "left" && d.leftFilter) {
|
|
2233
|
+
d.setLeftFilter("");
|
|
2234
|
+
return;
|
|
2235
|
+
}
|
|
2236
|
+
if (d.activePanel === "right" && d.rightFilter) {
|
|
2237
|
+
d.setRightFilter("");
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
return;
|
|
2241
|
+
}
|
|
2242
|
+
if (matchKey(d.kb.settings, input, key)) {
|
|
2243
|
+
d.setShowSettings(true);
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
if (matchKey(d.kb.viewArchive, input, key)) {
|
|
2247
|
+
d.setViewingArchive((v) => !v);
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
if (matchKey(d.kb.archive, input, key) && d.selectedSession) {
|
|
2251
|
+
if (d.viewingArchive) d.onUnarchive(d.selectedSession.sessionId);
|
|
2252
|
+
else d.onArchive(d.selectedSession.sessionId);
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
if (matchKey(d.kb.delete, input, key) && d.selectedSession) {
|
|
2256
|
+
d.onDelete(d.selectedSession);
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
if (matchKey(d.kb.update, input, key) && d.updateInfo?.available) {
|
|
2260
|
+
d.onUpdate();
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2263
|
+
if (d.activePanel === "sessions") {
|
|
2264
|
+
if (matchKey(d.kb.navDown, input, key) || key.downArrow) d.selectNext();
|
|
2265
|
+
if (matchKey(d.kb.navUp, input, key) || key.upArrow) d.selectPrev();
|
|
2266
|
+
}
|
|
2267
|
+
if (d.activePanel === "activity") {
|
|
2268
|
+
if (matchKey(d.kb.navUp, input, key) || key.upArrow) d.setActivityScroll((s) => Math.min(s + 1, d.maxScroll));
|
|
2269
|
+
if (matchKey(d.kb.navDown, input, key) || key.downArrow) d.setActivityScroll((s) => Math.max(s - 1, 0));
|
|
2270
|
+
if (matchKey(d.kb.scrollBottom, input, key)) d.setActivityScroll(0);
|
|
2271
|
+
if (matchKey(d.kb.scrollTop, input, key)) d.setActivityScroll(d.maxScroll);
|
|
2272
|
+
}
|
|
2273
|
+
if (d.activePanel === "left") {
|
|
2274
|
+
if (matchKey(d.kb.navUp, input, key) || key.upArrow) d.setLeftScroll((s) => Math.min(s + 1, d.leftMaxScroll));
|
|
2275
|
+
if (matchKey(d.kb.navDown, input, key) || key.downArrow) d.setLeftScroll((s) => Math.max(s - 1, 0));
|
|
2276
|
+
if (matchKey(d.kb.scrollBottom, input, key)) d.setLeftScroll(0);
|
|
2277
|
+
if (matchKey(d.kb.scrollTop, input, key)) d.setLeftScroll(d.leftMaxScroll);
|
|
2278
|
+
}
|
|
2279
|
+
if (d.activePanel === "right") {
|
|
2280
|
+
if (matchKey(d.kb.navUp, input, key) || key.upArrow) d.setRightScroll((s) => Math.min(s + 1, d.rightMaxScroll));
|
|
2281
|
+
if (matchKey(d.kb.navDown, input, key) || key.downArrow) d.setRightScroll((s) => Math.max(s - 1, 0));
|
|
2282
|
+
if (matchKey(d.kb.scrollBottom, input, key)) d.setRightScroll(0);
|
|
2283
|
+
if (matchKey(d.kb.scrollTop, input, key)) d.setRightScroll(d.rightMaxScroll);
|
|
2284
|
+
}
|
|
2285
|
+
});
|
|
2286
|
+
};
|
|
2287
|
+
|
|
2288
|
+
// src/ui/hooks/useUpdateChecker.ts
|
|
2289
|
+
import { useState as useState10, useEffect as useEffect7 } from "react";
|
|
2290
|
+
var useUpdateChecker = (disabled, checkOnLaunch, checkInterval) => {
|
|
2291
|
+
const [updateInfo, setUpdateInfo] = useState10(null);
|
|
2292
|
+
useEffect7(() => {
|
|
2293
|
+
if (disabled || !checkOnLaunch) return;
|
|
2294
|
+
try {
|
|
2295
|
+
const i = checkForUpdate();
|
|
2296
|
+
if (i.available) setUpdateInfo(i);
|
|
2297
|
+
} catch {
|
|
2298
|
+
}
|
|
2299
|
+
const iv = setInterval(() => {
|
|
2300
|
+
try {
|
|
2301
|
+
const i = checkForUpdate();
|
|
2302
|
+
if (i.available) setUpdateInfo(i);
|
|
2303
|
+
} catch {
|
|
2304
|
+
}
|
|
2305
|
+
}, checkInterval);
|
|
2306
|
+
return () => clearInterval(iv);
|
|
2307
|
+
}, []);
|
|
2308
|
+
return updateInfo;
|
|
2309
|
+
};
|
|
2310
|
+
|
|
2311
|
+
// src/ui/App.tsx
|
|
2312
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1186
2313
|
var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
1187
2314
|
const { exit } = useApp();
|
|
1188
|
-
const { stdout } =
|
|
2315
|
+
const { stdout } = useStdout3();
|
|
1189
2316
|
const termHeight = stdout?.rows ?? 40;
|
|
1190
|
-
const [liveConfig, setLiveConfig] =
|
|
2317
|
+
const [liveConfig, setLiveConfig] = useState11(initialConfig);
|
|
1191
2318
|
const kb = liveConfig.keybindings;
|
|
1192
|
-
const [activePanel, setActivePanel] =
|
|
1193
|
-
const [activityScroll, setActivityScroll] =
|
|
1194
|
-
const [inputMode, setInputMode] =
|
|
1195
|
-
const [showSetup, setShowSetup] =
|
|
1196
|
-
const [filter, setFilter] =
|
|
1197
|
-
const [
|
|
1198
|
-
const [updateStatus, setUpdateStatus] =
|
|
1199
|
-
const [showDetail, setShowDetail] =
|
|
1200
|
-
const [showSettings, setShowSettings] =
|
|
2319
|
+
const [activePanel, setActivePanel] = useState11("sessions");
|
|
2320
|
+
const [activityScroll, setActivityScroll] = useState11(0);
|
|
2321
|
+
const [inputMode, setInputMode] = useState11("normal");
|
|
2322
|
+
const [showSetup, setShowSetup] = useState11(firstRun);
|
|
2323
|
+
const [filter, setFilter] = useState11("");
|
|
2324
|
+
const [activityFilter, setActivityFilter] = useState11("");
|
|
2325
|
+
const [updateStatus, setUpdateStatus] = useState11("");
|
|
2326
|
+
const [showDetail, setShowDetail] = useState11(false);
|
|
2327
|
+
const [showSettings, setShowSettings] = useState11(false);
|
|
2328
|
+
const [showThemeMenu, setShowThemeMenu] = useState11(false);
|
|
2329
|
+
const [viewingArchive, setViewingArchive] = useState11(false);
|
|
2330
|
+
const [confirmAction, setConfirmAction] = useState11(
|
|
2331
|
+
null
|
|
2332
|
+
);
|
|
2333
|
+
const [archivedIds, setArchivedIds] = useState11(() => new Set(Object.keys(getArchived())));
|
|
2334
|
+
const [splitMode, setSplitMode] = useState11(false);
|
|
2335
|
+
const [leftSession, setLeftSession] = useState11(null);
|
|
2336
|
+
const [rightSession, setRightSession] = useState11(null);
|
|
2337
|
+
const [leftScroll, setLeftScroll] = useState11(0);
|
|
2338
|
+
const [rightScroll, setRightScroll] = useState11(0);
|
|
2339
|
+
const [leftFilter, setLeftFilter] = useState11("");
|
|
2340
|
+
const [rightFilter, setRightFilter] = useState11("");
|
|
2341
|
+
const [leftShowDetail, setLeftShowDetail] = useState11(false);
|
|
2342
|
+
const [rightShowDetail, setRightShowDetail] = useState11(false);
|
|
2343
|
+
const refreshArchived = useCallback4(() => setArchivedIds(new Set(Object.keys(getArchived()))), []);
|
|
2344
|
+
const updateInfo = useUpdateChecker(
|
|
2345
|
+
options.noUpdates,
|
|
2346
|
+
liveConfig.updates.checkOnLaunch,
|
|
2347
|
+
liveConfig.updates.checkInterval
|
|
2348
|
+
);
|
|
2349
|
+
useEffect8(() => {
|
|
2350
|
+
applyTheme(resolveTheme(liveConfig.theme, liveConfig.customThemes));
|
|
2351
|
+
}, [liveConfig.theme, liveConfig.customThemes]);
|
|
1201
2352
|
const { sessions, selectedSession, selectedIndex, selectNext, selectPrev, refresh } = useSessions(
|
|
1202
2353
|
options.allUsers,
|
|
1203
|
-
filter || void 0
|
|
2354
|
+
filter || void 0,
|
|
2355
|
+
archivedIds,
|
|
2356
|
+
viewingArchive
|
|
1204
2357
|
);
|
|
1205
|
-
const
|
|
2358
|
+
const rawEvents = useActivityStream(splitMode ? null : selectedSession, options.allUsers);
|
|
2359
|
+
const leftRawEvents = useActivityStream(splitMode ? leftSession : null, options.allUsers);
|
|
2360
|
+
const rightRawEvents = useActivityStream(splitMode ? rightSession : null, options.allUsers);
|
|
2361
|
+
const events = useFilteredEvents(rawEvents, activityFilter);
|
|
2362
|
+
const leftEvents = useFilteredEvents(leftRawEvents, leftFilter);
|
|
2363
|
+
const rightEvents = useFilteredEvents(rightRawEvents, rightFilter);
|
|
1206
2364
|
const { alerts } = useAlerts(!options.noSecurity, options.alertLevel, options.allUsers, liveConfig);
|
|
1207
2365
|
const nicknameInput = useTextInput(
|
|
1208
2366
|
(value) => {
|
|
@@ -1216,43 +2374,43 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
1216
2374
|
);
|
|
1217
2375
|
const filterInput = useTextInput(
|
|
1218
2376
|
(value) => {
|
|
1219
|
-
setFilter(value);
|
|
2377
|
+
if (activePanel === "sessions") setFilter(value);
|
|
2378
|
+
else if (activePanel === "left") setLeftFilter(value);
|
|
2379
|
+
else if (activePanel === "right") setRightFilter(value);
|
|
2380
|
+
else setActivityFilter(value);
|
|
1220
2381
|
setInputMode("normal");
|
|
1221
2382
|
},
|
|
1222
2383
|
() => {
|
|
1223
|
-
setFilter("");
|
|
2384
|
+
if (activePanel === "sessions") setFilter("");
|
|
2385
|
+
else if (activePanel === "left") setLeftFilter("");
|
|
2386
|
+
else if (activePanel === "right") setRightFilter("");
|
|
2387
|
+
else setActivityFilter("");
|
|
1224
2388
|
setInputMode("normal");
|
|
1225
2389
|
}
|
|
1226
2390
|
);
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
const i = checkForUpdate();
|
|
1231
|
-
if (i.available) setUpdateInfo(i);
|
|
1232
|
-
} catch {
|
|
1233
|
-
}
|
|
1234
|
-
const iv = setInterval(() => {
|
|
1235
|
-
try {
|
|
1236
|
-
const i = checkForUpdate();
|
|
1237
|
-
if (i.available) setUpdateInfo(i);
|
|
1238
|
-
} catch {
|
|
1239
|
-
}
|
|
1240
|
-
}, liveConfig.updates.checkInterval);
|
|
1241
|
-
return () => clearInterval(iv);
|
|
2391
|
+
useEffect8(() => {
|
|
2392
|
+
purgeExpiredArchives();
|
|
2393
|
+
refreshArchived();
|
|
1242
2394
|
}, []);
|
|
2395
|
+
useEffect8(() => {
|
|
2396
|
+
setActivityScroll(0);
|
|
2397
|
+
}, [selectedSession?.sessionId]);
|
|
1243
2398
|
const alertHeight = options.noSecurity ? 0 : 6;
|
|
1244
2399
|
const mainHeight = termHeight - 3 - alertHeight - 1 - (inputMode !== "normal" ? 1 : 0);
|
|
1245
2400
|
const viewportRows = mainHeight - 2;
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}, [selectedSession?.sessionId]);
|
|
1250
|
-
const handleSettingsClose = useCallback3((updatedConfig) => {
|
|
1251
|
-
setLiveConfig(updatedConfig);
|
|
1252
|
-
saveConfig(updatedConfig);
|
|
2401
|
+
const handleSettingsClose = useCallback4((c) => {
|
|
2402
|
+
setLiveConfig(c);
|
|
2403
|
+
saveConfig(c);
|
|
1253
2404
|
setShowSettings(false);
|
|
1254
2405
|
}, []);
|
|
1255
|
-
const
|
|
2406
|
+
const handleThemeMenuClose = useCallback4((c) => {
|
|
2407
|
+
setLiveConfig(c);
|
|
2408
|
+
saveConfig(c);
|
|
2409
|
+
setShowThemeMenu(false);
|
|
2410
|
+
setShowSettings(true);
|
|
2411
|
+
}, []);
|
|
2412
|
+
const handleOpenThemeMenu = useCallback4(() => setShowThemeMenu(true), []);
|
|
2413
|
+
const handleSetupComplete = useCallback4(
|
|
1256
2414
|
(results) => {
|
|
1257
2415
|
const nc = { ...liveConfig };
|
|
1258
2416
|
const [hc, mc] = results;
|
|
@@ -1275,143 +2433,235 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
1275
2433
|
},
|
|
1276
2434
|
[liveConfig]
|
|
1277
2435
|
);
|
|
1278
|
-
const switchPanel =
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
setFilter("");
|
|
1290
|
-
setInputMode("normal");
|
|
1291
|
-
filterInput.cancel();
|
|
1292
|
-
return;
|
|
1293
|
-
}
|
|
1294
|
-
filterInput.handleInput(input, key);
|
|
1295
|
-
return;
|
|
1296
|
-
}
|
|
1297
|
-
if (matchKey(kb.quit, input, key)) {
|
|
1298
|
-
exit();
|
|
1299
|
-
return;
|
|
1300
|
-
}
|
|
1301
|
-
if (showDetail) {
|
|
1302
|
-
if (key.escape || key.return || key.leftArrow) {
|
|
1303
|
-
setShowDetail(false);
|
|
2436
|
+
const switchPanel = useCallback4(
|
|
2437
|
+
(dir) => {
|
|
2438
|
+
if (splitMode) {
|
|
2439
|
+
const order = ["sessions", "left", "right"];
|
|
2440
|
+
setActivePanel((p) => {
|
|
2441
|
+
const idx = order.indexOf(p);
|
|
2442
|
+
if (idx === -1) return "sessions";
|
|
2443
|
+
return dir === "next" ? order[(idx + 1) % order.length] : order[(idx - 1 + order.length) % order.length];
|
|
2444
|
+
});
|
|
2445
|
+
} else {
|
|
2446
|
+
setActivePanel((p) => p === "sessions" ? "activity" : "sessions");
|
|
1304
2447
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
if (
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
2448
|
+
},
|
|
2449
|
+
[splitMode]
|
|
2450
|
+
);
|
|
2451
|
+
const getActiveFilter = useCallback4(() => {
|
|
2452
|
+
if (activePanel === "sessions") return filter;
|
|
2453
|
+
if (activePanel === "left") return leftFilter;
|
|
2454
|
+
if (activePanel === "right") return rightFilter;
|
|
2455
|
+
return activityFilter;
|
|
2456
|
+
}, [activePanel, filter, leftFilter, rightFilter, activityFilter]);
|
|
2457
|
+
const clearSplitState = useCallback4(() => {
|
|
2458
|
+
setSplitMode(false);
|
|
2459
|
+
setLeftSession(null);
|
|
2460
|
+
setRightSession(null);
|
|
2461
|
+
setLeftScroll(0);
|
|
2462
|
+
setRightScroll(0);
|
|
2463
|
+
setLeftFilter("");
|
|
2464
|
+
setRightFilter("");
|
|
2465
|
+
setLeftShowDetail(false);
|
|
2466
|
+
setRightShowDetail(false);
|
|
2467
|
+
setActivePanel("sessions");
|
|
2468
|
+
}, []);
|
|
2469
|
+
const resetPanel = useCallback4((side) => {
|
|
2470
|
+
if (side === "left") {
|
|
2471
|
+
setLeftSession(null);
|
|
2472
|
+
setLeftScroll(0);
|
|
2473
|
+
setLeftFilter("");
|
|
2474
|
+
setLeftShowDetail(false);
|
|
2475
|
+
} else {
|
|
2476
|
+
setRightSession(null);
|
|
2477
|
+
setRightScroll(0);
|
|
2478
|
+
setRightFilter("");
|
|
2479
|
+
setRightShowDetail(false);
|
|
1323
2480
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
2481
|
+
}, []);
|
|
2482
|
+
useKeyHandler({
|
|
2483
|
+
kb,
|
|
2484
|
+
activePanel,
|
|
2485
|
+
splitMode,
|
|
2486
|
+
inputMode,
|
|
2487
|
+
showSetup,
|
|
2488
|
+
showSettings: showSettings || showThemeMenu,
|
|
2489
|
+
showDetail,
|
|
2490
|
+
leftShowDetail,
|
|
2491
|
+
rightShowDetail,
|
|
2492
|
+
confirmAction,
|
|
2493
|
+
selectedSession,
|
|
2494
|
+
leftSession,
|
|
2495
|
+
rightSession,
|
|
2496
|
+
leftScroll,
|
|
2497
|
+
rightScroll,
|
|
2498
|
+
leftFilter,
|
|
2499
|
+
rightFilter,
|
|
2500
|
+
filter,
|
|
2501
|
+
activityFilter,
|
|
2502
|
+
viewingArchive,
|
|
2503
|
+
archivedIds,
|
|
2504
|
+
updateInfo,
|
|
2505
|
+
maxScroll: Math.max(0, events.length - viewportRows),
|
|
2506
|
+
leftMaxScroll: Math.max(0, leftEvents.length - viewportRows),
|
|
2507
|
+
rightMaxScroll: Math.max(0, rightEvents.length - viewportRows),
|
|
2508
|
+
exit,
|
|
2509
|
+
selectNext,
|
|
2510
|
+
selectPrev,
|
|
2511
|
+
refresh,
|
|
2512
|
+
switchPanel,
|
|
2513
|
+
clearSplitState,
|
|
2514
|
+
resetPanel,
|
|
2515
|
+
getActiveFilter,
|
|
2516
|
+
setActivePanel,
|
|
2517
|
+
setInputMode,
|
|
2518
|
+
setFilter,
|
|
2519
|
+
setActivityFilter,
|
|
2520
|
+
setLeftFilter,
|
|
2521
|
+
setRightFilter,
|
|
2522
|
+
setShowDetail,
|
|
2523
|
+
setLeftShowDetail,
|
|
2524
|
+
setRightShowDetail,
|
|
2525
|
+
setShowSettings,
|
|
2526
|
+
setViewingArchive,
|
|
2527
|
+
setSplitMode,
|
|
2528
|
+
setLeftSession,
|
|
2529
|
+
setRightSession,
|
|
2530
|
+
setLeftScroll,
|
|
2531
|
+
setRightScroll,
|
|
2532
|
+
setActivityScroll,
|
|
2533
|
+
setConfirmAction,
|
|
2534
|
+
setUpdateStatus,
|
|
2535
|
+
nicknameInput,
|
|
2536
|
+
filterInput,
|
|
2537
|
+
onNickname: (id) => {
|
|
2538
|
+
clearNickname(id);
|
|
1326
2539
|
refresh();
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
}
|
|
1342
|
-
|
|
2540
|
+
},
|
|
2541
|
+
onClearNickname: (id) => {
|
|
2542
|
+
clearNickname(id);
|
|
2543
|
+
refresh();
|
|
2544
|
+
},
|
|
2545
|
+
onArchive: (id) => {
|
|
2546
|
+
archiveSession(id);
|
|
2547
|
+
refreshArchived();
|
|
2548
|
+
refresh();
|
|
2549
|
+
},
|
|
2550
|
+
onUnarchive: (id) => {
|
|
2551
|
+
unarchiveSession(id);
|
|
2552
|
+
refreshArchived();
|
|
2553
|
+
refresh();
|
|
2554
|
+
},
|
|
2555
|
+
onDelete: (sess) => setConfirmAction({
|
|
2556
|
+
title: "Delete session?",
|
|
2557
|
+
message: `Delete ${sess.nickname || sess.slug}? Output files will be removed.`,
|
|
2558
|
+
onConfirm: () => {
|
|
2559
|
+
deleteSessionFiles(sess.outputFiles);
|
|
2560
|
+
clearNickname(sess.sessionId);
|
|
2561
|
+
if (archivedIds.has(sess.sessionId)) {
|
|
2562
|
+
unarchiveSession(sess.sessionId);
|
|
2563
|
+
refreshArchived();
|
|
2564
|
+
}
|
|
2565
|
+
refresh();
|
|
2566
|
+
setConfirmAction(null);
|
|
2567
|
+
}
|
|
2568
|
+
}),
|
|
2569
|
+
onUpdate: () => {
|
|
1343
2570
|
setUpdateStatus("updating...");
|
|
1344
|
-
installUpdate().then(() => setUpdateStatus(`updated to v${updateInfo
|
|
1345
|
-
return;
|
|
1346
|
-
}
|
|
1347
|
-
if (activePanel === "sessions") {
|
|
1348
|
-
if (matchKey(kb.navDown, input, key) || key.downArrow) selectNext();
|
|
1349
|
-
if (matchKey(kb.navUp, input, key) || key.upArrow) selectPrev();
|
|
1350
|
-
}
|
|
1351
|
-
if (activePanel === "activity") {
|
|
1352
|
-
if (matchKey(kb.navUp, input, key) || key.upArrow) setActivityScroll((s) => Math.min(s + 1, maxScroll));
|
|
1353
|
-
if (matchKey(kb.navDown, input, key) || key.downArrow) setActivityScroll((s) => Math.max(s - 1, 0));
|
|
1354
|
-
if (matchKey(kb.scrollBottom, input, key) || key.end) setActivityScroll(0);
|
|
1355
|
-
if (matchKey(kb.scrollTop, input, key) || key.home) setActivityScroll(maxScroll);
|
|
2571
|
+
installUpdate().then(() => setUpdateStatus(`updated to v${updateInfo?.latest} \u2014 restart to apply`)).catch(() => setUpdateStatus("update failed"));
|
|
1356
2572
|
}
|
|
1357
2573
|
});
|
|
1358
2574
|
if (showSetup) {
|
|
1359
|
-
const steps = [
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
2575
|
+
const steps = [
|
|
2576
|
+
...liveConfig.prompts.hook === "pending" ? [
|
|
2577
|
+
{
|
|
2578
|
+
title: "Install Claude Code hook?",
|
|
2579
|
+
description: "Adds a PostToolUse hook that blocks prompt injection attempts in real-time."
|
|
2580
|
+
}
|
|
2581
|
+
] : [],
|
|
2582
|
+
...liveConfig.prompts.mcp === "pending" ? [
|
|
2583
|
+
{
|
|
2584
|
+
title: "Install MCP server?",
|
|
2585
|
+
description: "Registers agenttop as an MCP server so Claude Code can query session status and alerts."
|
|
2586
|
+
}
|
|
2587
|
+
] : []
|
|
2588
|
+
];
|
|
1370
2589
|
if (steps.length === 0) {
|
|
1371
2590
|
setShowSetup(false);
|
|
1372
2591
|
return null;
|
|
1373
2592
|
}
|
|
1374
|
-
return /* @__PURE__ */
|
|
2593
|
+
return /* @__PURE__ */ jsx13(SetupModal, { steps, onComplete: handleSetupComplete });
|
|
1375
2594
|
}
|
|
1376
|
-
if (
|
|
1377
|
-
|
|
2595
|
+
if (showThemeMenu) return /* @__PURE__ */ jsx13(ThemeMenu, { config: liveConfig, onClose: handleThemeMenuClose });
|
|
2596
|
+
if (showSettings)
|
|
2597
|
+
return /* @__PURE__ */ jsx13(SettingsMenu, { config: liveConfig, onClose: handleSettingsClose, onOpenThemeMenu: handleOpenThemeMenu });
|
|
2598
|
+
if (confirmAction) {
|
|
2599
|
+
return /* @__PURE__ */ jsx13(Box13, { flexDirection: "column", height: termHeight, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx13(
|
|
2600
|
+
ConfirmModal,
|
|
2601
|
+
{
|
|
2602
|
+
title: confirmAction.title,
|
|
2603
|
+
message: confirmAction.message,
|
|
2604
|
+
onConfirm: confirmAction.onConfirm,
|
|
2605
|
+
onCancel: () => setConfirmAction(null)
|
|
2606
|
+
}
|
|
2607
|
+
) });
|
|
1378
2608
|
}
|
|
1379
|
-
const
|
|
2609
|
+
const filterLabel = activePanel === "sessions" ? "sessions" : activePanel === "left" ? "left" : activePanel === "right" ? "right" : "activity";
|
|
2610
|
+
const rightPanel = splitMode ? /* @__PURE__ */ jsx13(
|
|
2611
|
+
SplitPanel,
|
|
2612
|
+
{
|
|
2613
|
+
activePanel,
|
|
2614
|
+
leftSession,
|
|
2615
|
+
rightSession,
|
|
2616
|
+
leftEvents,
|
|
2617
|
+
rightEvents,
|
|
2618
|
+
leftScroll,
|
|
2619
|
+
rightScroll,
|
|
2620
|
+
leftFilter,
|
|
2621
|
+
rightFilter,
|
|
2622
|
+
leftShowDetail,
|
|
2623
|
+
rightShowDetail,
|
|
2624
|
+
height: mainHeight
|
|
2625
|
+
}
|
|
2626
|
+
) : showDetail && selectedSession ? /* @__PURE__ */ jsx13(SessionDetail, { session: selectedSession, focused: activePanel === "activity", height: mainHeight }) : /* @__PURE__ */ jsx13(
|
|
1380
2627
|
ActivityFeed,
|
|
1381
2628
|
{
|
|
1382
2629
|
events,
|
|
1383
2630
|
sessionSlug: selectedSession?.slug ?? null,
|
|
1384
2631
|
focused: activePanel === "activity",
|
|
1385
2632
|
height: mainHeight,
|
|
1386
|
-
scrollOffset: activityScroll
|
|
2633
|
+
scrollOffset: activityScroll,
|
|
2634
|
+
filter: activityFilter || void 0
|
|
1387
2635
|
}
|
|
1388
2636
|
);
|
|
1389
|
-
return /* @__PURE__ */
|
|
1390
|
-
/* @__PURE__ */
|
|
1391
|
-
/* @__PURE__ */
|
|
1392
|
-
/* @__PURE__ */
|
|
2637
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", height: termHeight, children: [
|
|
2638
|
+
/* @__PURE__ */ jsx13(StatusBar, { sessionCount: sessions.length, alertCount: alerts.length, version, updateInfo }),
|
|
2639
|
+
/* @__PURE__ */ jsxs13(Box13, { flexGrow: 1, height: mainHeight, children: [
|
|
2640
|
+
/* @__PURE__ */ jsx13(
|
|
1393
2641
|
SessionList,
|
|
1394
2642
|
{
|
|
1395
2643
|
sessions,
|
|
1396
2644
|
selectedIndex,
|
|
1397
2645
|
focused: activePanel === "sessions",
|
|
1398
|
-
filter: filter || void 0
|
|
2646
|
+
filter: filter || void 0,
|
|
2647
|
+
viewingArchive
|
|
1399
2648
|
}
|
|
1400
2649
|
),
|
|
1401
2650
|
rightPanel
|
|
1402
2651
|
] }),
|
|
1403
|
-
!options.noSecurity && /* @__PURE__ */
|
|
1404
|
-
inputMode === "nickname" && /* @__PURE__ */
|
|
1405
|
-
/* @__PURE__ */
|
|
1406
|
-
/* @__PURE__ */
|
|
1407
|
-
/* @__PURE__ */
|
|
2652
|
+
!options.noSecurity && /* @__PURE__ */ jsx13(AlertBar, { alerts }),
|
|
2653
|
+
inputMode === "nickname" && /* @__PURE__ */ jsxs13(Box13, { paddingX: 1, children: [
|
|
2654
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.primary, children: "nickname: " }),
|
|
2655
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.bright, children: nicknameInput.value }),
|
|
2656
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.muted, children: "_" })
|
|
1408
2657
|
] }),
|
|
1409
|
-
inputMode === "filter" && /* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
2658
|
+
inputMode === "filter" && /* @__PURE__ */ jsxs13(Box13, { paddingX: 1, children: [
|
|
2659
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.muted, children: filterLabel }),
|
|
2660
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.primary, children: "/" }),
|
|
2661
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.bright, children: filterInput.value }),
|
|
2662
|
+
/* @__PURE__ */ jsx13(Text12, { color: colors.muted, children: "_" })
|
|
1413
2663
|
] }),
|
|
1414
|
-
inputMode === "normal" && /* @__PURE__ */
|
|
2664
|
+
inputMode === "normal" && /* @__PURE__ */ jsx13(FooterBar, { keybindings: kb, updateStatus, viewingArchive, splitMode })
|
|
1415
2665
|
] });
|
|
1416
2666
|
};
|
|
1417
2667
|
|
|
@@ -1648,7 +2898,7 @@ var main = () => {
|
|
|
1648
2898
|
if (options.noUpdates) config.updates.checkOnLaunch = false;
|
|
1649
2899
|
if (options.noSecurity) config.security.enabled = false;
|
|
1650
2900
|
if (firstRun) saveConfig(config);
|
|
1651
|
-
render(
|
|
2901
|
+
render(React14.createElement(App, { options, config, version: VERSION, firstRun }));
|
|
1652
2902
|
};
|
|
1653
2903
|
main();
|
|
1654
2904
|
//# sourceMappingURL=index.js.map
|