agenttop 0.10.7 → 0.11.1
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 +158 -20
- package/dist/{chunk-CXXCDFJ5.js → chunk-27WRQSJY.js} +571 -54
- package/dist/chunk-27WRQSJY.js.map +1 -0
- package/dist/index.js +1149 -341
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-CXXCDFJ5.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
STATUS_PRIORITY,
|
|
3
4
|
SecurityEngine,
|
|
4
5
|
Watcher,
|
|
5
6
|
archiveSession,
|
|
@@ -7,30 +8,34 @@ import {
|
|
|
7
8
|
deleteSessionFiles,
|
|
8
9
|
discoverSessions,
|
|
9
10
|
getArchived,
|
|
11
|
+
getClaudeProcessesAsync,
|
|
10
12
|
getNicknames,
|
|
11
13
|
getProjectsDirs,
|
|
12
14
|
getTaskDirs,
|
|
13
15
|
isFirstRun,
|
|
14
16
|
loadConfig,
|
|
17
|
+
movePinned,
|
|
18
|
+
pinSession,
|
|
15
19
|
purgeExpiredArchives,
|
|
16
20
|
resolveAlertLogPath,
|
|
17
21
|
rotateLogFile,
|
|
18
22
|
saveConfig,
|
|
19
23
|
setNickname,
|
|
20
24
|
startMcpServer,
|
|
21
|
-
unarchiveSession
|
|
22
|
-
|
|
25
|
+
unarchiveSession,
|
|
26
|
+
unpinSession
|
|
27
|
+
} from "./chunk-27WRQSJY.js";
|
|
23
28
|
|
|
24
29
|
// src/index.tsx
|
|
25
30
|
import { readFileSync as readFileSync3 } from "fs";
|
|
26
31
|
import { join as join5, dirname as dirname4 } from "path";
|
|
27
32
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
28
|
-
import
|
|
33
|
+
import React19 from "react";
|
|
29
34
|
import { render } from "ink";
|
|
30
35
|
|
|
31
36
|
// src/ui/App.tsx
|
|
32
|
-
import { useState as
|
|
33
|
-
import { Box as
|
|
37
|
+
import { useState as useState18, useEffect as useEffect10, useCallback as useCallback8 } from "react";
|
|
38
|
+
import { Box as Box18, Text as Text17, useApp, useStdout as useStdout4 } from "ink";
|
|
34
39
|
|
|
35
40
|
// src/config/themes.ts
|
|
36
41
|
var COLOR_KEYS = [
|
|
@@ -45,7 +50,9 @@ var COLOR_KEYS = [
|
|
|
45
50
|
"bright",
|
|
46
51
|
"border",
|
|
47
52
|
"selected",
|
|
48
|
-
"header"
|
|
53
|
+
"header",
|
|
54
|
+
"waiting",
|
|
55
|
+
"stale"
|
|
49
56
|
];
|
|
50
57
|
var TOOL_COLOR_KEYS = [
|
|
51
58
|
"Bash",
|
|
@@ -82,11 +89,28 @@ var fromTuple = ([
|
|
|
82
89
|
bright,
|
|
83
90
|
border,
|
|
84
91
|
selected,
|
|
85
|
-
header
|
|
92
|
+
header,
|
|
93
|
+
waiting,
|
|
94
|
+
stale
|
|
86
95
|
]) => ({
|
|
87
96
|
name,
|
|
88
97
|
builtin: true,
|
|
89
|
-
colors: {
|
|
98
|
+
colors: {
|
|
99
|
+
primary,
|
|
100
|
+
secondary,
|
|
101
|
+
accent,
|
|
102
|
+
warning,
|
|
103
|
+
error,
|
|
104
|
+
critical,
|
|
105
|
+
muted,
|
|
106
|
+
text,
|
|
107
|
+
bright,
|
|
108
|
+
border,
|
|
109
|
+
selected,
|
|
110
|
+
header,
|
|
111
|
+
waiting,
|
|
112
|
+
stale
|
|
113
|
+
},
|
|
90
114
|
toolColors: deriveToolColors({
|
|
91
115
|
primary,
|
|
92
116
|
secondary,
|
|
@@ -99,7 +123,9 @@ var fromTuple = ([
|
|
|
99
123
|
bright,
|
|
100
124
|
border,
|
|
101
125
|
selected,
|
|
102
|
-
header
|
|
126
|
+
header,
|
|
127
|
+
waiting,
|
|
128
|
+
stale
|
|
103
129
|
})
|
|
104
130
|
});
|
|
105
131
|
var PRESETS = [
|
|
@@ -116,7 +142,9 @@ var PRESETS = [
|
|
|
116
142
|
"#FFFFFF",
|
|
117
143
|
"#3E4451",
|
|
118
144
|
"#2C313A",
|
|
119
|
-
"#61AFEF"
|
|
145
|
+
"#61AFEF",
|
|
146
|
+
"#E5C07B",
|
|
147
|
+
"#D19A66"
|
|
120
148
|
],
|
|
121
149
|
[
|
|
122
150
|
"dracula",
|
|
@@ -131,7 +159,9 @@ var PRESETS = [
|
|
|
131
159
|
"#FFFFFF",
|
|
132
160
|
"#44475A",
|
|
133
161
|
"#383A59",
|
|
134
|
-
"#BD93F9"
|
|
162
|
+
"#BD93F9",
|
|
163
|
+
"#F1FA8C",
|
|
164
|
+
"#FFB86C"
|
|
135
165
|
],
|
|
136
166
|
[
|
|
137
167
|
"monokai-pro",
|
|
@@ -146,7 +176,9 @@ var PRESETS = [
|
|
|
146
176
|
"#FFFFFF",
|
|
147
177
|
"#403E41",
|
|
148
178
|
"#2D2A2E",
|
|
149
|
-
"#78DCE8"
|
|
179
|
+
"#78DCE8",
|
|
180
|
+
"#FFD866",
|
|
181
|
+
"#FC9867"
|
|
150
182
|
],
|
|
151
183
|
[
|
|
152
184
|
"solarized-dark",
|
|
@@ -161,7 +193,9 @@ var PRESETS = [
|
|
|
161
193
|
"#FDF6E3",
|
|
162
194
|
"#073642",
|
|
163
195
|
"#002B36",
|
|
164
|
-
"#268BD2"
|
|
196
|
+
"#268BD2",
|
|
197
|
+
"#B58900",
|
|
198
|
+
"#CB4B16"
|
|
165
199
|
],
|
|
166
200
|
[
|
|
167
201
|
"solarized-light",
|
|
@@ -176,7 +210,9 @@ var PRESETS = [
|
|
|
176
210
|
"#002B36",
|
|
177
211
|
"#EEE8D5",
|
|
178
212
|
"#FDF6E3",
|
|
179
|
-
"#268BD2"
|
|
213
|
+
"#268BD2",
|
|
214
|
+
"#B58900",
|
|
215
|
+
"#CB4B16"
|
|
180
216
|
],
|
|
181
217
|
[
|
|
182
218
|
"nord",
|
|
@@ -191,7 +227,9 @@ var PRESETS = [
|
|
|
191
227
|
"#ECEFF4",
|
|
192
228
|
"#3B4252",
|
|
193
229
|
"#2E3440",
|
|
194
|
-
"#88C0D0"
|
|
230
|
+
"#88C0D0",
|
|
231
|
+
"#EBCB8B",
|
|
232
|
+
"#D08770"
|
|
195
233
|
],
|
|
196
234
|
[
|
|
197
235
|
"gruvbox-dark",
|
|
@@ -206,7 +244,9 @@ var PRESETS = [
|
|
|
206
244
|
"#FBF1C7",
|
|
207
245
|
"#3C3836",
|
|
208
246
|
"#282828",
|
|
209
|
-
"#83A598"
|
|
247
|
+
"#83A598",
|
|
248
|
+
"#FABD2F",
|
|
249
|
+
"#FE8019"
|
|
210
250
|
],
|
|
211
251
|
[
|
|
212
252
|
"tokyo-night",
|
|
@@ -221,7 +261,9 @@ var PRESETS = [
|
|
|
221
261
|
"#C0CAF5",
|
|
222
262
|
"#292E42",
|
|
223
263
|
"#1A1B26",
|
|
224
|
-
"#7AA2F7"
|
|
264
|
+
"#7AA2F7",
|
|
265
|
+
"#E0AF68",
|
|
266
|
+
"#FF9E64"
|
|
225
267
|
],
|
|
226
268
|
[
|
|
227
269
|
"catppuccin-mocha",
|
|
@@ -236,7 +278,9 @@ var PRESETS = [
|
|
|
236
278
|
"#FFFFFF",
|
|
237
279
|
"#313244",
|
|
238
280
|
"#1E1E2E",
|
|
239
|
-
"#89B4FA"
|
|
281
|
+
"#89B4FA",
|
|
282
|
+
"#F9E2AF",
|
|
283
|
+
"#FAB387"
|
|
240
284
|
],
|
|
241
285
|
[
|
|
242
286
|
"catppuccin-latte",
|
|
@@ -251,7 +295,9 @@ var PRESETS = [
|
|
|
251
295
|
"#11111B",
|
|
252
296
|
"#E6E9EF",
|
|
253
297
|
"#EFF1F5",
|
|
254
|
-
"#1E66F5"
|
|
298
|
+
"#1E66F5",
|
|
299
|
+
"#DF8E1D",
|
|
300
|
+
"#FE640B"
|
|
255
301
|
],
|
|
256
302
|
[
|
|
257
303
|
"rose-pine",
|
|
@@ -266,7 +312,9 @@ var PRESETS = [
|
|
|
266
312
|
"#E0DEF4",
|
|
267
313
|
"#26233A",
|
|
268
314
|
"#191724",
|
|
269
|
-
"#9CCFD8"
|
|
315
|
+
"#9CCFD8",
|
|
316
|
+
"#F6C177",
|
|
317
|
+
"#EA9D34"
|
|
270
318
|
],
|
|
271
319
|
[
|
|
272
320
|
"rose-pine-moon",
|
|
@@ -281,7 +329,9 @@ var PRESETS = [
|
|
|
281
329
|
"#E0DEF4",
|
|
282
330
|
"#2A273F",
|
|
283
331
|
"#232136",
|
|
284
|
-
"#9CCFD8"
|
|
332
|
+
"#9CCFD8",
|
|
333
|
+
"#F6C177",
|
|
334
|
+
"#EA9D34"
|
|
285
335
|
],
|
|
286
336
|
[
|
|
287
337
|
"pastel-dark",
|
|
@@ -296,7 +346,9 @@ var PRESETS = [
|
|
|
296
346
|
"#FFFFFF",
|
|
297
347
|
"#3A3A4A",
|
|
298
348
|
"#2B2B3A",
|
|
299
|
-
"#89CFF0"
|
|
349
|
+
"#89CFF0",
|
|
350
|
+
"#FFD580",
|
|
351
|
+
"#FFAA5E"
|
|
300
352
|
],
|
|
301
353
|
[
|
|
302
354
|
"kanagawa",
|
|
@@ -311,7 +363,9 @@ var PRESETS = [
|
|
|
311
363
|
"#FFFFFF",
|
|
312
364
|
"#2A2A37",
|
|
313
365
|
"#1F1F28",
|
|
314
|
-
"#7E9CD8"
|
|
366
|
+
"#7E9CD8",
|
|
367
|
+
"#E6C384",
|
|
368
|
+
"#FFA066"
|
|
315
369
|
],
|
|
316
370
|
[
|
|
317
371
|
"everforest",
|
|
@@ -326,7 +380,213 @@ var PRESETS = [
|
|
|
326
380
|
"#FFFFFF",
|
|
327
381
|
"#374145",
|
|
328
382
|
"#2D353B",
|
|
329
|
-
"#7FBBB3"
|
|
383
|
+
"#7FBBB3",
|
|
384
|
+
"#DBBC7F",
|
|
385
|
+
"#E69875"
|
|
386
|
+
],
|
|
387
|
+
[
|
|
388
|
+
"hi-feline",
|
|
389
|
+
"#FF6B8A",
|
|
390
|
+
"#FFB3C6",
|
|
391
|
+
"#FF1744",
|
|
392
|
+
"#FFE082",
|
|
393
|
+
"#FF5252",
|
|
394
|
+
"#FF0000",
|
|
395
|
+
"#C48B9F",
|
|
396
|
+
"#FFE4EC",
|
|
397
|
+
"#FFFFFF",
|
|
398
|
+
"#4A2030",
|
|
399
|
+
"#3A1525",
|
|
400
|
+
"#FF6B8A",
|
|
401
|
+
"#FFE082",
|
|
402
|
+
"#FFA726"
|
|
403
|
+
],
|
|
404
|
+
[
|
|
405
|
+
"plumber-bros",
|
|
406
|
+
"#4CAF50",
|
|
407
|
+
"#F44336",
|
|
408
|
+
"#2196F3",
|
|
409
|
+
"#FFD700",
|
|
410
|
+
"#FF5722",
|
|
411
|
+
"#FF0000",
|
|
412
|
+
"#795548",
|
|
413
|
+
"#EFEBE9",
|
|
414
|
+
"#FFFFFF",
|
|
415
|
+
"#1B5E20",
|
|
416
|
+
"#0D3010",
|
|
417
|
+
"#4CAF50",
|
|
418
|
+
"#FFD700",
|
|
419
|
+
"#FF9800"
|
|
420
|
+
],
|
|
421
|
+
[
|
|
422
|
+
"hedgehog-speed",
|
|
423
|
+
"#1565C0",
|
|
424
|
+
"#FFD700",
|
|
425
|
+
"#4CAF50",
|
|
426
|
+
"#FFEB3B",
|
|
427
|
+
"#F44336",
|
|
428
|
+
"#FF0000",
|
|
429
|
+
"#5C6BC0",
|
|
430
|
+
"#E8EAF6",
|
|
431
|
+
"#FFFFFF",
|
|
432
|
+
"#0D47A1",
|
|
433
|
+
"#0A2E6E",
|
|
434
|
+
"#1565C0",
|
|
435
|
+
"#FFEB3B",
|
|
436
|
+
"#FF9800"
|
|
437
|
+
],
|
|
438
|
+
[
|
|
439
|
+
"block-craft",
|
|
440
|
+
"#4CAF50",
|
|
441
|
+
"#8D6E63",
|
|
442
|
+
"#795548",
|
|
443
|
+
"#FFEB3B",
|
|
444
|
+
"#F44336",
|
|
445
|
+
"#FF0000",
|
|
446
|
+
"#78909C",
|
|
447
|
+
"#BCAAA4",
|
|
448
|
+
"#FFFFFF",
|
|
449
|
+
"#33691E",
|
|
450
|
+
"#1B4400",
|
|
451
|
+
"#4CAF50",
|
|
452
|
+
"#FFEB3B",
|
|
453
|
+
"#FF9800"
|
|
454
|
+
],
|
|
455
|
+
[
|
|
456
|
+
"galaxy-conflicts",
|
|
457
|
+
"#F44336",
|
|
458
|
+
"#2196F3",
|
|
459
|
+
"#9C27B0",
|
|
460
|
+
"#FFD54F",
|
|
461
|
+
"#FF1744",
|
|
462
|
+
"#FF0000",
|
|
463
|
+
"#546E7A",
|
|
464
|
+
"#ECEFF1",
|
|
465
|
+
"#FFFFFF",
|
|
466
|
+
"#1A1A2E",
|
|
467
|
+
"#0D0D1A",
|
|
468
|
+
"#F44336",
|
|
469
|
+
"#FFD54F",
|
|
470
|
+
"#FF6D00"
|
|
471
|
+
],
|
|
472
|
+
[
|
|
473
|
+
"pocket-creatures",
|
|
474
|
+
"#F44336",
|
|
475
|
+
"#FFFFFF",
|
|
476
|
+
"#FFEB3B",
|
|
477
|
+
"#FFC107",
|
|
478
|
+
"#E53935",
|
|
479
|
+
"#FF0000",
|
|
480
|
+
"#90A4AE",
|
|
481
|
+
"#ECEFF1",
|
|
482
|
+
"#FFFFFF",
|
|
483
|
+
"#B71C1C",
|
|
484
|
+
"#7F0000",
|
|
485
|
+
"#F44336",
|
|
486
|
+
"#FFC107",
|
|
487
|
+
"#FF9800"
|
|
488
|
+
],
|
|
489
|
+
[
|
|
490
|
+
"brick-wizard",
|
|
491
|
+
"#7B1FA2",
|
|
492
|
+
"#FFD700",
|
|
493
|
+
"#880E4F",
|
|
494
|
+
"#FFC107",
|
|
495
|
+
"#F44336",
|
|
496
|
+
"#FF0000",
|
|
497
|
+
"#6A1B9A",
|
|
498
|
+
"#E1BEE7",
|
|
499
|
+
"#FFFFFF",
|
|
500
|
+
"#311B92",
|
|
501
|
+
"#1A0A52",
|
|
502
|
+
"#7B1FA2",
|
|
503
|
+
"#FFC107",
|
|
504
|
+
"#FF9800"
|
|
505
|
+
],
|
|
506
|
+
[
|
|
507
|
+
"caped-knight",
|
|
508
|
+
"#616161",
|
|
509
|
+
"#FDD835",
|
|
510
|
+
"#424242",
|
|
511
|
+
"#FFC107",
|
|
512
|
+
"#F44336",
|
|
513
|
+
"#FF0000",
|
|
514
|
+
"#757575",
|
|
515
|
+
"#E0E0E0",
|
|
516
|
+
"#FFFFFF",
|
|
517
|
+
"#212121",
|
|
518
|
+
"#0A0A0A",
|
|
519
|
+
"#616161",
|
|
520
|
+
"#FFC107",
|
|
521
|
+
"#FF9800"
|
|
522
|
+
],
|
|
523
|
+
[
|
|
524
|
+
"web-crawler",
|
|
525
|
+
"#F44336",
|
|
526
|
+
"#1565C0",
|
|
527
|
+
"#FFFFFF",
|
|
528
|
+
"#FFEB3B",
|
|
529
|
+
"#D50000",
|
|
530
|
+
"#FF0000",
|
|
531
|
+
"#78909C",
|
|
532
|
+
"#E3F2FD",
|
|
533
|
+
"#FFFFFF",
|
|
534
|
+
"#B71C1C",
|
|
535
|
+
"#7F0000",
|
|
536
|
+
"#F44336",
|
|
537
|
+
"#FFEB3B",
|
|
538
|
+
"#FF9800"
|
|
539
|
+
],
|
|
540
|
+
[
|
|
541
|
+
"frozen-kingdom",
|
|
542
|
+
"#81D4FA",
|
|
543
|
+
"#CE93D8",
|
|
544
|
+
"#B3E5FC",
|
|
545
|
+
"#FFF9C4",
|
|
546
|
+
"#EF9A9A",
|
|
547
|
+
"#FF0000",
|
|
548
|
+
"#90CAF9",
|
|
549
|
+
"#E1F5FE",
|
|
550
|
+
"#FFFFFF",
|
|
551
|
+
"#1A237E",
|
|
552
|
+
"#0D1252",
|
|
553
|
+
"#81D4FA",
|
|
554
|
+
"#FFF9C4",
|
|
555
|
+
"#FFCC80"
|
|
556
|
+
],
|
|
557
|
+
[
|
|
558
|
+
"coral-reef",
|
|
559
|
+
"#FF7043",
|
|
560
|
+
"#29B6F6",
|
|
561
|
+
"#AB47BC",
|
|
562
|
+
"#FFEE58",
|
|
563
|
+
"#EF5350",
|
|
564
|
+
"#FF0000",
|
|
565
|
+
"#4DB6AC",
|
|
566
|
+
"#E0F7FA",
|
|
567
|
+
"#FFFFFF",
|
|
568
|
+
"#BF360C",
|
|
569
|
+
"#7F2008",
|
|
570
|
+
"#FF7043",
|
|
571
|
+
"#FFEE58",
|
|
572
|
+
"#FFA726"
|
|
573
|
+
],
|
|
574
|
+
[
|
|
575
|
+
"toy-ranch",
|
|
576
|
+
"#8D6E63",
|
|
577
|
+
"#7CB342",
|
|
578
|
+
"#7E57C2",
|
|
579
|
+
"#FFEE58",
|
|
580
|
+
"#EF5350",
|
|
581
|
+
"#FF0000",
|
|
582
|
+
"#90A4AE",
|
|
583
|
+
"#EFEBE9",
|
|
584
|
+
"#FFFFFF",
|
|
585
|
+
"#4E342E",
|
|
586
|
+
"#2E1C15",
|
|
587
|
+
"#8D6E63",
|
|
588
|
+
"#FFEE58",
|
|
589
|
+
"#FFA726"
|
|
330
590
|
]
|
|
331
591
|
];
|
|
332
592
|
var BUILTIN_THEMES = PRESETS.map(fromTuple);
|
|
@@ -350,7 +610,7 @@ var deriveSeverityColors = (c) => ({
|
|
|
350
610
|
});
|
|
351
611
|
|
|
352
612
|
// src/updates.ts
|
|
353
|
-
import { execFile,
|
|
613
|
+
import { execFile, spawn } from "child_process";
|
|
354
614
|
import { readFile } from "fs/promises";
|
|
355
615
|
import { join, dirname } from "path";
|
|
356
616
|
import { fileURLToPath } from "url";
|
|
@@ -366,7 +626,7 @@ var getPackageVersion = async () => {
|
|
|
366
626
|
};
|
|
367
627
|
var getNpmPath = () => {
|
|
368
628
|
const nodeDir = dirname(process.execPath);
|
|
369
|
-
return join(nodeDir, "npm");
|
|
629
|
+
return join(nodeDir, process.platform === "win32" ? "npm.cmd" : "npm");
|
|
370
630
|
};
|
|
371
631
|
var checkForUpdate = () => new Promise((resolve) => {
|
|
372
632
|
const npm = getNpmPath();
|
|
@@ -388,7 +648,7 @@ var checkForUpdate = () => new Promise((resolve) => {
|
|
|
388
648
|
var installUpdate = () => {
|
|
389
649
|
const npm = getNpmPath();
|
|
390
650
|
return new Promise((resolve, reject) => {
|
|
391
|
-
|
|
651
|
+
execFile(npm, ["install", "-g", "agenttop@latest"], { timeout: 6e4 }, (err, stdout) => {
|
|
392
652
|
if (err) {
|
|
393
653
|
reject(err);
|
|
394
654
|
} else {
|
|
@@ -418,7 +678,7 @@ var compareVersions = (a, b) => {
|
|
|
418
678
|
};
|
|
419
679
|
|
|
420
680
|
// src/ui/components/StatusBar.tsx
|
|
421
|
-
import React, { useState, useEffect } from "react";
|
|
681
|
+
import React, { useState, useEffect, useRef } from "react";
|
|
422
682
|
import { Box, Text } from "ink";
|
|
423
683
|
|
|
424
684
|
// src/ui/theme.ts
|
|
@@ -429,12 +689,15 @@ var colors = {
|
|
|
429
689
|
warning: "#E5C07B",
|
|
430
690
|
error: "#E06C75",
|
|
431
691
|
critical: "#FF0000",
|
|
692
|
+
success: "#98C379",
|
|
432
693
|
muted: "#5C6370",
|
|
433
694
|
text: "#ABB2BF",
|
|
434
695
|
bright: "#FFFFFF",
|
|
435
696
|
border: "#3E4451",
|
|
436
697
|
selected: "#2C313A",
|
|
437
|
-
header: "#61AFEF"
|
|
698
|
+
header: "#61AFEF",
|
|
699
|
+
waiting: "#E5C07B",
|
|
700
|
+
stale: "#D19A66"
|
|
438
701
|
};
|
|
439
702
|
var severityColors = {
|
|
440
703
|
info: colors.muted,
|
|
@@ -456,19 +719,27 @@ var toolColors = {
|
|
|
456
719
|
var getToolColor = (toolName) => toolColors[toolName] || colors.text;
|
|
457
720
|
var applyTheme = (theme) => {
|
|
458
721
|
Object.assign(colors, theme.colors);
|
|
722
|
+
colors.success = theme.colors.secondary;
|
|
459
723
|
Object.assign(toolColors, theme.toolColors);
|
|
460
724
|
Object.assign(severityColors, deriveSeverityColors(theme.colors));
|
|
461
725
|
};
|
|
462
726
|
|
|
463
727
|
// src/ui/components/StatusBar.tsx
|
|
464
728
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
729
|
+
var formatTime = () => (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
|
|
465
730
|
var StatusBar = React.memo(({ sessionCount, alertCount, version, updateInfo }) => {
|
|
466
|
-
const [
|
|
731
|
+
const [timeStr, setTimeStr] = useState(formatTime);
|
|
732
|
+
const lastRef = useRef(timeStr);
|
|
467
733
|
useEffect(() => {
|
|
468
|
-
const interval = setInterval(() =>
|
|
734
|
+
const interval = setInterval(() => {
|
|
735
|
+
const next = formatTime();
|
|
736
|
+
if (next !== lastRef.current) {
|
|
737
|
+
lastRef.current = next;
|
|
738
|
+
setTimeStr(next);
|
|
739
|
+
}
|
|
740
|
+
}, 1e3);
|
|
469
741
|
return () => clearInterval(interval);
|
|
470
742
|
}, []);
|
|
471
|
-
const timeStr = time.toLocaleTimeString("en-GB", { hour12: false });
|
|
472
743
|
return /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: colors.border, paddingX: 1, justifyContent: "space-between", children: [
|
|
473
744
|
/* @__PURE__ */ jsxs(Text, { color: colors.header, bold: true, children: [
|
|
474
745
|
"agenttop v",
|
|
@@ -496,18 +767,32 @@ var StatusBar = React.memo(({ sessionCount, alertCount, version, updateInfo }) =
|
|
|
496
767
|
// src/ui/components/SessionList.tsx
|
|
497
768
|
import React2 from "react";
|
|
498
769
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
499
|
-
|
|
770
|
+
|
|
771
|
+
// src/ui/format.ts
|
|
772
|
+
var formatTokens = (n) => {
|
|
773
|
+
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
774
|
+
if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
|
|
775
|
+
return String(n);
|
|
776
|
+
};
|
|
777
|
+
var formatTime2 = (ts) => {
|
|
778
|
+
const d = new Date(ts);
|
|
779
|
+
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
780
|
+
};
|
|
500
781
|
var formatModel = (model) => {
|
|
782
|
+
if (model.includes("opus")) return "opus";
|
|
783
|
+
if (model.includes("sonnet")) return "sonnet";
|
|
784
|
+
if (model.includes("haiku")) return "haiku";
|
|
785
|
+
return model.slice(0, 4);
|
|
786
|
+
};
|
|
787
|
+
var formatModelShort = (model) => {
|
|
501
788
|
if (model.includes("opus")) return "opus";
|
|
502
789
|
if (model.includes("sonnet")) return "son";
|
|
503
790
|
if (model.includes("haiku")) return "hai";
|
|
504
791
|
return model.slice(0, 4);
|
|
505
792
|
};
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
return String(n);
|
|
510
|
-
};
|
|
793
|
+
|
|
794
|
+
// src/ui/components/SessionList.tsx
|
|
795
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
511
796
|
var truncate = (s, max) => s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
512
797
|
var getDisplayName = (s) => {
|
|
513
798
|
if (s.nickname) return s.nickname;
|
|
@@ -567,11 +852,14 @@ var SessionList = React2.memo(
|
|
|
567
852
|
if (item.type === "group") {
|
|
568
853
|
const g = item.group;
|
|
569
854
|
const arrow = g.expanded ? "\u25BE" : "\u25B8";
|
|
570
|
-
const dotColor2 = g.
|
|
571
|
-
const statusDot2 = g.
|
|
572
|
-
const nameColor2 = isSelected ? colors.bright : g.
|
|
573
|
-
const
|
|
574
|
-
const
|
|
855
|
+
const dotColor2 = g.status === "waiting" ? colors.waiting : g.status === "stale" ? colors.stale : g.status === "active" ? colors.success : colors.muted;
|
|
856
|
+
const statusDot2 = g.status === "inactive" ? "\u25CB" : "\u25CF";
|
|
857
|
+
const nameColor2 = isSelected ? colors.bright : g.status !== "inactive" ? colors.secondary : colors.text;
|
|
858
|
+
const groupPinned = g.sessions.some((s) => s.pinned);
|
|
859
|
+
const pinMarker2 = groupPinned ? "* " : " ";
|
|
860
|
+
const statusTag2 = g.status === "waiting" ? " [waiting]" : g.status === "stale" ? " [stale]" : "";
|
|
861
|
+
const label2 = truncate(`${g.key} (${g.sessions.length})${statusTag2}`, INNER_WIDTH - 4);
|
|
862
|
+
const model2 = formatModelShort(g.latestModel);
|
|
575
863
|
return /* @__PURE__ */ jsxs2(
|
|
576
864
|
Box2,
|
|
577
865
|
{
|
|
@@ -584,6 +872,7 @@ var SessionList = React2.memo(
|
|
|
584
872
|
" ",
|
|
585
873
|
/* @__PURE__ */ jsx2(Text2, { color: dotColor2, children: statusDot2 }),
|
|
586
874
|
" ",
|
|
875
|
+
pinMarker2,
|
|
587
876
|
label2
|
|
588
877
|
] }),
|
|
589
878
|
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? colors.text : colors.muted, wrap: "truncate", children: [
|
|
@@ -602,14 +891,15 @@ var SessionList = React2.memo(
|
|
|
602
891
|
);
|
|
603
892
|
}
|
|
604
893
|
const session = item.type === "session" ? item.session : item.session;
|
|
605
|
-
const
|
|
606
|
-
const statusDot =
|
|
607
|
-
const
|
|
894
|
+
const dotColor = session.status === "waiting" ? colors.waiting : session.status === "stale" ? colors.stale : session.status === "active" ? colors.success : colors.muted;
|
|
895
|
+
const statusDot = session.status === "inactive" ? "\u25CB" : "\u25CF";
|
|
896
|
+
const pinMarker = session.pinned ? "* " : " ";
|
|
897
|
+
const statusTag = session.status === "waiting" ? " [waiting]" : session.status === "stale" ? " [stale]" : "";
|
|
608
898
|
const totalIn = session.usage.inputTokens + session.usage.cacheReadTokens;
|
|
609
|
-
const model =
|
|
899
|
+
const model = formatModelShort(session.model);
|
|
610
900
|
if (item.type === "session") {
|
|
611
|
-
const nameColor2 = isSelected ? colors.bright :
|
|
612
|
-
const displayName2 = truncate(session.nickname || session.slug
|
|
901
|
+
const nameColor2 = isSelected ? colors.bright : session.status !== "inactive" ? colors.secondary : colors.muted;
|
|
902
|
+
const displayName2 = truncate(`${session.nickname || session.slug}${statusTag}`, INNER_WIDTH - 6);
|
|
613
903
|
return /* @__PURE__ */ jsxs2(
|
|
614
904
|
Box2,
|
|
615
905
|
{
|
|
@@ -622,6 +912,7 @@ var SessionList = React2.memo(
|
|
|
622
912
|
" ",
|
|
623
913
|
/* @__PURE__ */ jsx2(Text2, { color: dotColor, children: statusDot }),
|
|
624
914
|
" ",
|
|
915
|
+
pinMarker,
|
|
625
916
|
displayName2
|
|
626
917
|
] }),
|
|
627
918
|
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? colors.text : colors.muted, wrap: "truncate", children: [
|
|
@@ -640,8 +931,8 @@ var SessionList = React2.memo(
|
|
|
640
931
|
);
|
|
641
932
|
}
|
|
642
933
|
const indicator = isSelected ? "\u25B8" : " ";
|
|
643
|
-
const nameColor = isSelected ? colors.bright :
|
|
644
|
-
const displayName = truncate(getDisplayName(session)
|
|
934
|
+
const nameColor = isSelected ? colors.bright : session.status !== "inactive" ? colors.secondary : colors.text;
|
|
935
|
+
const displayName = truncate(`${getDisplayName(session)}${statusTag}`, INNER_WIDTH - 4);
|
|
645
936
|
return /* @__PURE__ */ jsxs2(
|
|
646
937
|
Box2,
|
|
647
938
|
{
|
|
@@ -654,6 +945,7 @@ var SessionList = React2.memo(
|
|
|
654
945
|
" ",
|
|
655
946
|
/* @__PURE__ */ jsx2(Text2, { color: dotColor, children: statusDot }),
|
|
656
947
|
" ",
|
|
948
|
+
pinMarker,
|
|
657
949
|
displayName
|
|
658
950
|
] }),
|
|
659
951
|
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? colors.text : colors.muted, wrap: "truncate", children: [
|
|
@@ -682,10 +974,6 @@ import React3 from "react";
|
|
|
682
974
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
683
975
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
684
976
|
var TAG_COLORS = ["#61AFEF", "#98C379", "#C678DD", "#E5C07B", "#E06C75", "#56B6C2", "#D19A66", "#BE5046"];
|
|
685
|
-
var formatTime = (ts) => {
|
|
686
|
-
const d = new Date(ts);
|
|
687
|
-
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
688
|
-
};
|
|
689
977
|
var summarizeInput = (call) => {
|
|
690
978
|
const input = call.toolInput;
|
|
691
979
|
switch (call.toolName) {
|
|
@@ -713,7 +1001,7 @@ var ActivityFeed = React3.memo(
|
|
|
713
1001
|
events,
|
|
714
1002
|
sessionSlug,
|
|
715
1003
|
sessionId,
|
|
716
|
-
|
|
1004
|
+
status,
|
|
717
1005
|
focused,
|
|
718
1006
|
height,
|
|
719
1007
|
scrollOffset,
|
|
@@ -780,7 +1068,7 @@ var ActivityFeed = React3.memo(
|
|
|
780
1068
|
const tagColor = merged ? slugColorMap.get(call.sessionId) || colors.muted : void 0;
|
|
781
1069
|
return /* @__PURE__ */ jsx3(Box3, { paddingX: 1, overflow: "hidden", children: /* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
782
1070
|
tag && /* @__PURE__ */ jsx3(Text3, { color: tagColor, children: tag.padEnd(5) }),
|
|
783
|
-
/* @__PURE__ */ jsx3(Text3, { color: isSelected ? colors.bright : colors.muted, underline: isSelected, children:
|
|
1071
|
+
/* @__PURE__ */ jsx3(Text3, { color: isSelected ? colors.bright : colors.muted, underline: isSelected, children: formatTime2(call.timestamp) }),
|
|
784
1072
|
" ",
|
|
785
1073
|
/* @__PURE__ */ jsx3(Text3, { color: getToolColor(call.toolName), bold: true, underline: isSelected, children: call.toolName.padEnd(8) }),
|
|
786
1074
|
/* @__PURE__ */ jsxs3(Text3, { color: isSelected ? colors.bright : colors.text, underline: isSelected, children: [
|
|
@@ -790,7 +1078,7 @@ var ActivityFeed = React3.memo(
|
|
|
790
1078
|
] }) }, `${call.timestamp}-${i}`);
|
|
791
1079
|
}),
|
|
792
1080
|
focused && canScroll && !isAtTop && visible.length > 0 && /* @__PURE__ */ jsx3(Box3, { paddingX: 1, justifyContent: "flex-end", children: /* @__PURE__ */ jsx3(Text3, { color: colors.muted, children: isAtBottom ? "" : "G:bottom " }) }),
|
|
793
|
-
!merged && sessionId &&
|
|
1081
|
+
!merged && sessionId && status === "inactive" && /* @__PURE__ */ jsxs3(Box3, { paddingX: 1, flexDirection: "column", children: [
|
|
794
1082
|
/* @__PURE__ */ jsx3(Text3, { color: colors.muted, children: " " }),
|
|
795
1083
|
/* @__PURE__ */ jsxs3(Text3, { color: colors.muted, children: [
|
|
796
1084
|
"resume: ",
|
|
@@ -815,10 +1103,6 @@ var ActivityFeed = React3.memo(
|
|
|
815
1103
|
import React4 from "react";
|
|
816
1104
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
817
1105
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
818
|
-
var formatTime2 = (ts) => {
|
|
819
|
-
const d = new Date(ts);
|
|
820
|
-
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
821
|
-
};
|
|
822
1106
|
var severityIcon = {
|
|
823
1107
|
info: "i",
|
|
824
1108
|
warn: "!",
|
|
@@ -856,11 +1140,6 @@ var AlertBar = React4.memo(({ alerts, maxVisible = 4 }) => {
|
|
|
856
1140
|
import React5 from "react";
|
|
857
1141
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
858
1142
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
859
|
-
var formatTokens2 = (n) => {
|
|
860
|
-
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
861
|
-
if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
|
|
862
|
-
return String(n);
|
|
863
|
-
};
|
|
864
1143
|
var formatUptime = (startTime) => {
|
|
865
1144
|
const ms = Date.now() - startTime;
|
|
866
1145
|
const secs = Math.floor(ms / 1e3);
|
|
@@ -870,12 +1149,6 @@ var formatUptime = (startTime) => {
|
|
|
870
1149
|
if (mins > 0) return `${mins}m ${secs % 60}s`;
|
|
871
1150
|
return `${secs}s`;
|
|
872
1151
|
};
|
|
873
|
-
var formatModel2 = (model) => {
|
|
874
|
-
if (model.includes("opus")) return "opus";
|
|
875
|
-
if (model.includes("sonnet")) return "sonnet";
|
|
876
|
-
if (model.includes("haiku")) return "haiku";
|
|
877
|
-
return model.slice(0, 20);
|
|
878
|
-
};
|
|
879
1152
|
var SessionDetail = React5.memo(({ session, focused }) => {
|
|
880
1153
|
const totalInput = session.usage.inputTokens + session.usage.cacheCreationTokens + session.usage.cacheReadTokens;
|
|
881
1154
|
const totalTokens = totalInput + session.usage.outputTokens;
|
|
@@ -903,7 +1176,7 @@ var SessionDetail = React5.memo(({ session, focused }) => {
|
|
|
903
1176
|
] }),
|
|
904
1177
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
905
1178
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: "model: " }),
|
|
906
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1179
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatModel(session.model) })
|
|
907
1180
|
] }),
|
|
908
1181
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
909
1182
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: "cwd: " }),
|
|
@@ -946,19 +1219,19 @@ var SessionDetail = React5.memo(({ session, focused }) => {
|
|
|
946
1219
|
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: colors.header, bold: true, children: "Token usage" }) }),
|
|
947
1220
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
948
1221
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " input: " }),
|
|
949
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1222
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.inputTokens) })
|
|
950
1223
|
] }),
|
|
951
1224
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
952
1225
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " output: " }),
|
|
953
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1226
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.outputTokens) })
|
|
954
1227
|
] }),
|
|
955
1228
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
956
1229
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " cache write: " }),
|
|
957
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1230
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.cacheCreationTokens) })
|
|
958
1231
|
] }),
|
|
959
1232
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
960
1233
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " cache read: " }),
|
|
961
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1234
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.cacheReadTokens) })
|
|
962
1235
|
] }),
|
|
963
1236
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
964
1237
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " cache hit: " }),
|
|
@@ -969,7 +1242,7 @@ var SessionDetail = React5.memo(({ session, focused }) => {
|
|
|
969
1242
|
] }),
|
|
970
1243
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
971
1244
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " total: " }),
|
|
972
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.bright, bold: true, children:
|
|
1245
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.bright, bold: true, children: formatTokens(totalTokens) })
|
|
973
1246
|
] })
|
|
974
1247
|
] })
|
|
975
1248
|
]
|
|
@@ -1109,10 +1382,6 @@ var FooterBar = React7.memo(
|
|
|
1109
1382
|
import React8, { useState as useState3 } from "react";
|
|
1110
1383
|
import { Box as Box8, Text as Text8, useInput as useInput2 } from "ink";
|
|
1111
1384
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1112
|
-
var formatTime3 = (ts) => {
|
|
1113
|
-
const d = new Date(ts);
|
|
1114
|
-
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
1115
|
-
};
|
|
1116
1385
|
var renderBash = (event) => {
|
|
1117
1386
|
const lines = [];
|
|
1118
1387
|
const cmd = String(event.call.toolInput.command || "");
|
|
@@ -1286,7 +1555,7 @@ var ToolCallDetail = React8.memo(({ event, focused, height }) => {
|
|
|
1286
1555
|
/* @__PURE__ */ jsx8(Text8, { color: getToolColor(event.call.toolName), bold: true, children: event.call.toolName }),
|
|
1287
1556
|
/* @__PURE__ */ jsxs8(Text8, { color: colors.muted, children: [
|
|
1288
1557
|
" ",
|
|
1289
|
-
|
|
1558
|
+
formatTime2(event.call.timestamp)
|
|
1290
1559
|
] }),
|
|
1291
1560
|
/* @__PURE__ */ jsxs8(Text8, { color: colors.muted, children: [
|
|
1292
1561
|
" ",
|
|
@@ -1320,7 +1589,7 @@ var ToolCallDetail = React8.memo(({ event, focused, height }) => {
|
|
|
1320
1589
|
});
|
|
1321
1590
|
|
|
1322
1591
|
// src/ui/components/SettingsMenu.tsx
|
|
1323
|
-
import React9, { useState as useState4, useMemo, useEffect as useEffect2, useRef } from "react";
|
|
1592
|
+
import React9, { useState as useState4, useMemo, useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
1324
1593
|
import { Box as Box9, Text as Text9, useInput as useInput3, useStdout } from "ink";
|
|
1325
1594
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1326
1595
|
var KEYBIND_LABELS = {
|
|
@@ -1489,7 +1758,7 @@ var SettingsMenu = React9.memo(({ config, onClose, onOpenThemeMenu }) => {
|
|
|
1489
1758
|
const [selectablePos, setSelectablePos] = useState4(0);
|
|
1490
1759
|
const [rebinding, setRebinding] = useState4(false);
|
|
1491
1760
|
const [toast, setToast] = useState4("");
|
|
1492
|
-
const toastTimer =
|
|
1761
|
+
const toastTimer = useRef2(null);
|
|
1493
1762
|
const showToast = (msg) => {
|
|
1494
1763
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1495
1764
|
setToast(msg);
|
|
@@ -1620,7 +1889,7 @@ var SettingsMenu = React9.memo(({ config, onClose, onOpenThemeMenu }) => {
|
|
|
1620
1889
|
});
|
|
1621
1890
|
|
|
1622
1891
|
// src/ui/components/ThemeMenu.tsx
|
|
1623
|
-
import React11, { useState as useState6, useCallback, useRef as
|
|
1892
|
+
import React11, { useState as useState6, useCallback, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
1624
1893
|
import { Box as Box11, Text as Text11, useInput as useInput5, useStdout as useStdout2 } from "ink";
|
|
1625
1894
|
|
|
1626
1895
|
// src/ui/components/ThemeEditor.tsx
|
|
@@ -1756,7 +2025,7 @@ var ThemeMenu = React11.memo(({ config, onClose }) => {
|
|
|
1756
2025
|
const [nameInput, setNameInput] = useState6("");
|
|
1757
2026
|
const [namingAction, setNamingAction] = useState6("copy");
|
|
1758
2027
|
const [toast, setToast] = useState6("");
|
|
1759
|
-
const toastTimer =
|
|
2028
|
+
const toastTimer = useRef3(null);
|
|
1760
2029
|
const showToast = (msg) => {
|
|
1761
2030
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1762
2031
|
setToast(msg);
|
|
@@ -1970,23 +2239,451 @@ var ThemeMenu = React11.memo(({ config, onClose }) => {
|
|
|
1970
2239
|
/* @__PURE__ */ jsx11(Text11, { color: theme.colors.error, children: "\u2588" })
|
|
1971
2240
|
] }, theme.name);
|
|
1972
2241
|
}),
|
|
1973
|
-
toast && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx11(Text11, { color: colors.warning, children: toast }) })
|
|
2242
|
+
toast && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx11(Text11, { color: colors.warning, children: toast }) }),
|
|
2243
|
+
/* @__PURE__ */ jsx11(Box11, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: colors.muted, dimColor: true, italic: true, wrap: "truncate", children: "Some themes were inspired by pop culture. Names have been changed to protect the innocent (and our legal team)." }) })
|
|
1974
2244
|
]
|
|
1975
2245
|
}
|
|
1976
2246
|
) });
|
|
1977
2247
|
});
|
|
1978
2248
|
|
|
1979
|
-
// src/ui/components/
|
|
1980
|
-
import React12, { useState as useState7, useEffect as useEffect4 } from "react";
|
|
1981
|
-
import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
|
|
2249
|
+
// src/ui/components/AlertRulesMenu.tsx
|
|
2250
|
+
import React12, { useState as useState7, useRef as useRef4, useEffect as useEffect4 } from "react";
|
|
2251
|
+
import { Box as Box12, Text as Text12, useInput as useInput6, useStdout as useStdout3 } from "ink";
|
|
1982
2252
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1983
|
-
var
|
|
1984
|
-
|
|
2253
|
+
var MATCH_OPTIONS = ["input", "output", "toolName", "all"];
|
|
2254
|
+
var SEVERITY_OPTIONS2 = ["info", "warn", "high", "critical"];
|
|
2255
|
+
var RULE_LABELS2 = {
|
|
2256
|
+
network: "Network detection",
|
|
2257
|
+
exfiltration: "Exfiltration detection",
|
|
2258
|
+
sensitiveFiles: "Sensitive files",
|
|
2259
|
+
shellEscape: "Shell escape",
|
|
2260
|
+
injection: "Prompt injection"
|
|
2261
|
+
};
|
|
2262
|
+
var BUILTIN_RULE_KEYS = Object.keys(RULE_LABELS2);
|
|
2263
|
+
var FORM_FIELDS = ["name", "pattern", "match", "severity", "message"];
|
|
2264
|
+
var FORM_LABELS = {
|
|
2265
|
+
name: "Name",
|
|
2266
|
+
pattern: "Pattern (regex)",
|
|
2267
|
+
match: "Match target",
|
|
2268
|
+
severity: "Severity",
|
|
2269
|
+
message: "Message"
|
|
2270
|
+
};
|
|
2271
|
+
var emptyForm = () => ({
|
|
2272
|
+
name: "",
|
|
2273
|
+
pattern: "",
|
|
2274
|
+
match: "all",
|
|
2275
|
+
severity: "warn",
|
|
2276
|
+
message: ""
|
|
2277
|
+
});
|
|
2278
|
+
var formFromRule = (rule) => ({
|
|
2279
|
+
name: rule.name,
|
|
2280
|
+
pattern: rule.pattern,
|
|
2281
|
+
match: rule.match,
|
|
2282
|
+
severity: rule.severity,
|
|
2283
|
+
message: rule.message
|
|
2284
|
+
});
|
|
2285
|
+
var validatePattern = (pattern) => {
|
|
2286
|
+
if (!pattern.trim()) return "Pattern cannot be empty";
|
|
2287
|
+
try {
|
|
2288
|
+
new RegExp(pattern);
|
|
2289
|
+
return null;
|
|
2290
|
+
} catch {
|
|
2291
|
+
return "Invalid regex";
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
var AlertRulesMenu = React12.memo(({ config, onClose, onSave }) => {
|
|
2295
|
+
const { stdout } = useStdout3();
|
|
2296
|
+
const termHeight = stdout?.rows ?? 40;
|
|
2297
|
+
const [localConfig, setLocalConfig] = useState7(() => JSON.parse(JSON.stringify(config)));
|
|
2298
|
+
const [selectedIdx, setSelectedIdx] = useState7(0);
|
|
2299
|
+
const [view, setView] = useState7("list");
|
|
2300
|
+
const [toast, setToast] = useState7("");
|
|
2301
|
+
const toastTimer = useRef4(null);
|
|
2302
|
+
const [formData, setFormData] = useState7(emptyForm());
|
|
2303
|
+
const [formField, setFormField] = useState7(0);
|
|
2304
|
+
const [formError, setFormError] = useState7("");
|
|
2305
|
+
const [editingIndex, setEditingIndex] = useState7(null);
|
|
2306
|
+
useEffect4(
|
|
2307
|
+
() => () => {
|
|
2308
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2309
|
+
},
|
|
2310
|
+
[]
|
|
2311
|
+
);
|
|
2312
|
+
const showToast = (msg) => {
|
|
2313
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2314
|
+
setToast(msg);
|
|
2315
|
+
toastTimer.current = setTimeout(() => setToast(""), 2500);
|
|
2316
|
+
};
|
|
2317
|
+
const customRules = localConfig.alerts.custom || [];
|
|
2318
|
+
const totalItems = 1 + BUILTIN_RULE_KEYS.length + customRules.length;
|
|
2319
|
+
const isStaleRow = (idx) => idx === 0;
|
|
2320
|
+
const isBuiltinRow = (idx) => idx >= 1 && idx <= BUILTIN_RULE_KEYS.length;
|
|
2321
|
+
const isCustomRow = (idx) => idx > BUILTIN_RULE_KEYS.length;
|
|
2322
|
+
const getBuiltinKey = (idx) => BUILTIN_RULE_KEYS[idx - 1];
|
|
2323
|
+
const getCustomIndex = (idx) => idx - BUILTIN_RULE_KEYS.length - 1;
|
|
2324
|
+
useInput6((input, key) => {
|
|
2325
|
+
if (view === "form") {
|
|
2326
|
+
const currentField = FORM_FIELDS[formField];
|
|
2327
|
+
if (key.escape) {
|
|
2328
|
+
setView("list");
|
|
2329
|
+
setFormError("");
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
if (currentField === "match") {
|
|
2333
|
+
if (key.return || input === " ") {
|
|
2334
|
+
const idx = MATCH_OPTIONS.indexOf(formData.match);
|
|
2335
|
+
setFormData((f) => ({ ...f, match: MATCH_OPTIONS[(idx + 1) % MATCH_OPTIONS.length] }));
|
|
2336
|
+
return;
|
|
2337
|
+
}
|
|
2338
|
+
if (key.downArrow) {
|
|
2339
|
+
setFormField((f) => Math.min(f + 1, FORM_FIELDS.length - 1));
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2342
|
+
if (key.upArrow) {
|
|
2343
|
+
setFormField((f) => Math.max(f - 1, 0));
|
|
2344
|
+
return;
|
|
2345
|
+
}
|
|
2346
|
+
if (key.tab) {
|
|
2347
|
+
if (formField < FORM_FIELDS.length - 1) {
|
|
2348
|
+
setFormField((f) => f + 1);
|
|
2349
|
+
}
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
return;
|
|
2353
|
+
}
|
|
2354
|
+
if (currentField === "severity") {
|
|
2355
|
+
if (key.return || input === " ") {
|
|
2356
|
+
const idx = SEVERITY_OPTIONS2.indexOf(formData.severity);
|
|
2357
|
+
setFormData((f) => ({ ...f, severity: SEVERITY_OPTIONS2[(idx + 1) % SEVERITY_OPTIONS2.length] }));
|
|
2358
|
+
return;
|
|
2359
|
+
}
|
|
2360
|
+
if (key.downArrow) {
|
|
2361
|
+
setFormField((f) => Math.min(f + 1, FORM_FIELDS.length - 1));
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
if (key.upArrow) {
|
|
2365
|
+
setFormField((f) => Math.max(f - 1, 0));
|
|
2366
|
+
return;
|
|
2367
|
+
}
|
|
2368
|
+
if (key.tab) {
|
|
2369
|
+
if (formField < FORM_FIELDS.length - 1) {
|
|
2370
|
+
setFormField((f) => f + 1);
|
|
2371
|
+
}
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
if (key.return) {
|
|
2377
|
+
if (currentField === "pattern") {
|
|
2378
|
+
const err = validatePattern(formData.pattern);
|
|
2379
|
+
if (err) {
|
|
2380
|
+
setFormError(err);
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
setFormError("");
|
|
2384
|
+
}
|
|
2385
|
+
if (formField < FORM_FIELDS.length - 1) {
|
|
2386
|
+
setFormField((f) => f + 1);
|
|
2387
|
+
return;
|
|
2388
|
+
}
|
|
2389
|
+
if (!formData.name.trim()) {
|
|
2390
|
+
setFormError("Name cannot be empty");
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
const patErr = validatePattern(formData.pattern);
|
|
2394
|
+
if (patErr) {
|
|
2395
|
+
setFormError(patErr);
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
const newRule = {
|
|
2399
|
+
name: formData.name.trim(),
|
|
2400
|
+
pattern: formData.pattern,
|
|
2401
|
+
match: formData.match,
|
|
2402
|
+
severity: formData.severity,
|
|
2403
|
+
message: formData.message.trim(),
|
|
2404
|
+
enabled: true
|
|
2405
|
+
};
|
|
2406
|
+
setLocalConfig((c) => {
|
|
2407
|
+
const customs = [...c.alerts.custom || []];
|
|
2408
|
+
if (editingIndex !== null) {
|
|
2409
|
+
newRule.enabled = customs[editingIndex].enabled;
|
|
2410
|
+
customs[editingIndex] = newRule;
|
|
2411
|
+
} else {
|
|
2412
|
+
customs.push(newRule);
|
|
2413
|
+
}
|
|
2414
|
+
const updated = { ...c, alerts: { ...c.alerts, custom: customs } };
|
|
2415
|
+
onSave(updated);
|
|
2416
|
+
return updated;
|
|
2417
|
+
});
|
|
2418
|
+
showToast(editingIndex !== null ? `Updated '${newRule.name}'` : `Added '${newRule.name}'`);
|
|
2419
|
+
setView("list");
|
|
2420
|
+
setFormError("");
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
if (key.backspace || key.delete) {
|
|
2424
|
+
setFormData((f) => ({ ...f, [currentField]: f[currentField].slice(0, -1) }));
|
|
2425
|
+
setFormError("");
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
if (key.upArrow) {
|
|
2429
|
+
setFormField((f) => Math.max(f - 1, 0));
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
if (key.downArrow || key.tab) {
|
|
2433
|
+
if (currentField === "pattern") {
|
|
2434
|
+
const err = validatePattern(formData.pattern);
|
|
2435
|
+
if (err && formData.pattern.trim()) {
|
|
2436
|
+
setFormError(err);
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
setFormField((f) => Math.min(f + 1, FORM_FIELDS.length - 1));
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
if (input && input.length === 1) {
|
|
2444
|
+
setFormData((f) => ({ ...f, [currentField]: f[currentField] + input }));
|
|
2445
|
+
setFormError("");
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
return;
|
|
2449
|
+
}
|
|
2450
|
+
if (key.escape) {
|
|
2451
|
+
onSave(localConfig);
|
|
2452
|
+
onClose();
|
|
2453
|
+
return;
|
|
2454
|
+
}
|
|
2455
|
+
if (key.upArrow) {
|
|
2456
|
+
setSelectedIdx((i) => Math.max(0, i - 1));
|
|
2457
|
+
return;
|
|
2458
|
+
}
|
|
2459
|
+
if (key.downArrow) {
|
|
2460
|
+
setSelectedIdx((i) => Math.min(totalItems - 1, i + 1));
|
|
2461
|
+
return;
|
|
2462
|
+
}
|
|
2463
|
+
if (input === " ") {
|
|
2464
|
+
if (isStaleRow(selectedIdx)) return;
|
|
2465
|
+
if (isBuiltinRow(selectedIdx)) {
|
|
2466
|
+
const ruleKey = getBuiltinKey(selectedIdx);
|
|
2467
|
+
setLocalConfig((c) => {
|
|
2468
|
+
const updated = {
|
|
2469
|
+
...c,
|
|
2470
|
+
security: { ...c.security, rules: { ...c.security.rules, [ruleKey]: !c.security.rules[ruleKey] } }
|
|
2471
|
+
};
|
|
2472
|
+
onSave(updated);
|
|
2473
|
+
return updated;
|
|
2474
|
+
});
|
|
2475
|
+
return;
|
|
2476
|
+
}
|
|
2477
|
+
if (isCustomRow(selectedIdx)) {
|
|
2478
|
+
const ci = getCustomIndex(selectedIdx);
|
|
2479
|
+
setLocalConfig((c) => {
|
|
2480
|
+
const customs = [...c.alerts.custom || []];
|
|
2481
|
+
customs[ci] = { ...customs[ci], enabled: !customs[ci].enabled };
|
|
2482
|
+
const updated = { ...c, alerts: { ...c.alerts, custom: customs } };
|
|
2483
|
+
onSave(updated);
|
|
2484
|
+
return updated;
|
|
2485
|
+
});
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2490
|
+
if (isStaleRow(selectedIdx)) {
|
|
2491
|
+
if (input === "+" || input === "=") {
|
|
2492
|
+
setLocalConfig((c) => {
|
|
2493
|
+
const updated = { ...c, alerts: { ...c.alerts, staleTimeout: c.alerts.staleTimeout + 15 } };
|
|
2494
|
+
onSave(updated);
|
|
2495
|
+
return updated;
|
|
2496
|
+
});
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2499
|
+
if (input === "-" || input === "_") {
|
|
2500
|
+
setLocalConfig((c) => {
|
|
2501
|
+
const newTimeout = Math.max(15, c.alerts.staleTimeout - 15);
|
|
2502
|
+
const updated = { ...c, alerts: { ...c.alerts, staleTimeout: newTimeout } };
|
|
2503
|
+
onSave(updated);
|
|
2504
|
+
return updated;
|
|
2505
|
+
});
|
|
2506
|
+
return;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
if (input === "n") {
|
|
2510
|
+
setFormData(emptyForm());
|
|
2511
|
+
setFormField(0);
|
|
2512
|
+
setEditingIndex(null);
|
|
2513
|
+
setFormError("");
|
|
2514
|
+
setView("form");
|
|
2515
|
+
return;
|
|
2516
|
+
}
|
|
2517
|
+
if (input === "e" && isCustomRow(selectedIdx)) {
|
|
2518
|
+
const ci = getCustomIndex(selectedIdx);
|
|
2519
|
+
const rule = customRules[ci];
|
|
2520
|
+
setFormData(formFromRule(rule));
|
|
2521
|
+
setFormField(0);
|
|
2522
|
+
setEditingIndex(ci);
|
|
2523
|
+
setFormError("");
|
|
2524
|
+
setView("form");
|
|
2525
|
+
return;
|
|
2526
|
+
}
|
|
2527
|
+
if (input === "d" && isCustomRow(selectedIdx)) {
|
|
2528
|
+
const ci = getCustomIndex(selectedIdx);
|
|
2529
|
+
const name = customRules[ci].name;
|
|
2530
|
+
setLocalConfig((c) => {
|
|
2531
|
+
const customs = [...c.alerts.custom || []];
|
|
2532
|
+
customs.splice(ci, 1);
|
|
2533
|
+
const updated = { ...c, alerts: { ...c.alerts, custom: customs } };
|
|
2534
|
+
onSave(updated);
|
|
2535
|
+
return updated;
|
|
2536
|
+
});
|
|
2537
|
+
setSelectedIdx((i) => Math.min(i, totalItems - 2));
|
|
2538
|
+
showToast(`Deleted '${name}'`);
|
|
2539
|
+
return;
|
|
2540
|
+
}
|
|
2541
|
+
});
|
|
2542
|
+
if (view === "form") {
|
|
2543
|
+
const currentField = FORM_FIELDS[formField];
|
|
2544
|
+
return /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsxs12(
|
|
2545
|
+
Box12,
|
|
2546
|
+
{
|
|
2547
|
+
borderStyle: "round",
|
|
2548
|
+
borderColor: colors.primary,
|
|
2549
|
+
flexDirection: "column",
|
|
2550
|
+
paddingX: 2,
|
|
2551
|
+
paddingY: 1,
|
|
2552
|
+
height: termHeight,
|
|
2553
|
+
children: [
|
|
2554
|
+
/* @__PURE__ */ jsxs12(Box12, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
2555
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.header, bold: true, children: editingIndex !== null ? "EDIT RULE" : "NEW RULE" }),
|
|
2556
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: "enter:next/save esc:cancel" })
|
|
2557
|
+
] }),
|
|
2558
|
+
FORM_FIELDS.map((field, fi) => {
|
|
2559
|
+
const isCurrent = fi === formField;
|
|
2560
|
+
const value = formData[field];
|
|
2561
|
+
const isTextInput = field === "name" || field === "pattern" || field === "message";
|
|
2562
|
+
const displayValue = isTextInput ? isCurrent ? `${value}_` : value || "(empty)" : field === "match" ? `${value} (space to cycle)` : `${value} (space to cycle)`;
|
|
2563
|
+
return /* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2564
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isCurrent ? colors.primary : colors.text, children: [
|
|
2565
|
+
isCurrent ? "> " : " ",
|
|
2566
|
+
FORM_LABELS[field],
|
|
2567
|
+
":",
|
|
2568
|
+
" "
|
|
2569
|
+
] }),
|
|
2570
|
+
/* @__PURE__ */ jsx12(Text12, { color: isCurrent ? colors.bright : colors.muted, children: displayValue })
|
|
2571
|
+
] }, field);
|
|
2572
|
+
}),
|
|
2573
|
+
formError && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx12(Text12, { color: colors.error, children: formError }) }),
|
|
2574
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: currentField === "match" || currentField === "severity" ? "space/enter: cycle options | up/down: move fields" : "type to edit | enter: next field | up/down: move fields" }) })
|
|
2575
|
+
]
|
|
2576
|
+
}
|
|
2577
|
+
) });
|
|
2578
|
+
}
|
|
2579
|
+
const contentHeight = termHeight - 6;
|
|
2580
|
+
const halfView = Math.floor(contentHeight / 2);
|
|
2581
|
+
const scrollStart = Math.max(0, Math.min(selectedIdx - halfView, totalItems - contentHeight));
|
|
2582
|
+
const visibleStart = Math.max(0, scrollStart);
|
|
2583
|
+
const visibleEnd = Math.min(totalItems, visibleStart + contentHeight);
|
|
2584
|
+
return /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsxs12(
|
|
2585
|
+
Box12,
|
|
2586
|
+
{
|
|
2587
|
+
borderStyle: "round",
|
|
2588
|
+
borderColor: colors.primary,
|
|
2589
|
+
flexDirection: "column",
|
|
2590
|
+
paddingX: 2,
|
|
2591
|
+
paddingY: 1,
|
|
2592
|
+
height: termHeight,
|
|
2593
|
+
children: [
|
|
2594
|
+
/* @__PURE__ */ jsxs12(Box12, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
2595
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.header, bold: true, children: "ALERT RULES" }),
|
|
2596
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: "space:toggle n:new e:edit d:delete esc:close" })
|
|
2597
|
+
] }),
|
|
2598
|
+
visibleStart === 0 && /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text12, { color: colors.accent, bold: true, children: [
|
|
2599
|
+
" ",
|
|
2600
|
+
"STALE SESSION"
|
|
2601
|
+
] }) }) }),
|
|
2602
|
+
Array.from({ length: visibleEnd - visibleStart }, (_, vi) => {
|
|
2603
|
+
const idx = visibleStart + vi;
|
|
2604
|
+
const isSelected = idx === selectedIdx;
|
|
2605
|
+
if (isStaleRow(idx)) {
|
|
2606
|
+
const timeout = localConfig.alerts.staleTimeout;
|
|
2607
|
+
return /* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2608
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isSelected ? colors.primary : colors.text, children: [
|
|
2609
|
+
isSelected ? "> " : " ",
|
|
2610
|
+
" Stale timeout ",
|
|
2611
|
+
"............ "
|
|
2612
|
+
] }),
|
|
2613
|
+
/* @__PURE__ */ jsxs12(Text12, { color: colors.bright, children: [
|
|
2614
|
+
timeout,
|
|
2615
|
+
"s"
|
|
2616
|
+
] }),
|
|
2617
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: " (+/-)" })
|
|
2618
|
+
] }, "stale-timeout");
|
|
2619
|
+
}
|
|
2620
|
+
if (isBuiltinRow(idx)) {
|
|
2621
|
+
const ruleKey = getBuiltinKey(idx);
|
|
2622
|
+
const label2 = RULE_LABELS2[ruleKey];
|
|
2623
|
+
const enabled = localConfig.security.rules[ruleKey];
|
|
2624
|
+
const showHeader = idx === 1 && visibleStart <= 1;
|
|
2625
|
+
return /* @__PURE__ */ jsxs12(React12.Fragment, { children: [
|
|
2626
|
+
showHeader && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text12, { color: colors.accent, bold: true, children: [
|
|
2627
|
+
" ",
|
|
2628
|
+
"BUILT-IN RULES"
|
|
2629
|
+
] }) }),
|
|
2630
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2631
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isSelected ? colors.primary : colors.text, children: [
|
|
2632
|
+
isSelected ? "> " : " ",
|
|
2633
|
+
" ",
|
|
2634
|
+
label2,
|
|
2635
|
+
" ",
|
|
2636
|
+
".".repeat(Math.max(2, 28 - label2.length)),
|
|
2637
|
+
" "
|
|
2638
|
+
] }),
|
|
2639
|
+
/* @__PURE__ */ jsx12(Text12, { color: enabled ? colors.secondary : colors.error, children: enabled ? "ON" : "OFF" })
|
|
2640
|
+
] })
|
|
2641
|
+
] }, `builtin-${ruleKey}`);
|
|
2642
|
+
}
|
|
2643
|
+
if (isCustomRow(idx)) {
|
|
2644
|
+
const ci = getCustomIndex(idx);
|
|
2645
|
+
const rule = customRules[ci];
|
|
2646
|
+
const showHeader = ci === 0;
|
|
2647
|
+
return /* @__PURE__ */ jsxs12(React12.Fragment, { children: [
|
|
2648
|
+
showHeader && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text12, { color: colors.accent, bold: true, children: [
|
|
2649
|
+
" ",
|
|
2650
|
+
"CUSTOM RULES"
|
|
2651
|
+
] }) }),
|
|
2652
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2653
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isSelected ? colors.primary : colors.text, children: [
|
|
2654
|
+
isSelected ? "> " : " ",
|
|
2655
|
+
" ",
|
|
2656
|
+
rule.name,
|
|
2657
|
+
" "
|
|
2658
|
+
] }),
|
|
2659
|
+
/* @__PURE__ */ jsxs12(Text12, { color: colors.muted, children: [
|
|
2660
|
+
"/",
|
|
2661
|
+
rule.pattern,
|
|
2662
|
+
"/ "
|
|
2663
|
+
] }),
|
|
2664
|
+
/* @__PURE__ */ jsx12(Text12, { color: rule.enabled ? colors.secondary : colors.error, children: rule.enabled ? "ON" : "OFF" })
|
|
2665
|
+
] })
|
|
2666
|
+
] }, `custom-${ci}`);
|
|
2667
|
+
}
|
|
2668
|
+
return null;
|
|
2669
|
+
}),
|
|
2670
|
+
toast && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx12(Text12, { color: colors.warning, children: toast }) })
|
|
2671
|
+
]
|
|
2672
|
+
}
|
|
2673
|
+
) });
|
|
2674
|
+
});
|
|
2675
|
+
|
|
2676
|
+
// src/ui/components/ThemePickerModal.tsx
|
|
2677
|
+
import React13, { useState as useState8, useEffect as useEffect5 } from "react";
|
|
2678
|
+
import { Box as Box13, Text as Text13, useInput as useInput7 } from "ink";
|
|
2679
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2680
|
+
var ThemePickerModal = React13.memo(({ onSelect, onSkip, onDismiss }) => {
|
|
2681
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
1985
2682
|
const themes = BUILTIN_THEMES;
|
|
1986
|
-
|
|
2683
|
+
useEffect5(() => {
|
|
1987
2684
|
applyTheme(themes[selectedIndex]);
|
|
1988
2685
|
}, [selectedIndex]);
|
|
1989
|
-
|
|
2686
|
+
useInput7((input, key) => {
|
|
1990
2687
|
if (key.upArrow) setSelectedIndex((i) => Math.max(0, i - 1));
|
|
1991
2688
|
if (key.downArrow) setSelectedIndex((i) => Math.min(themes.length - 1, i + 1));
|
|
1992
2689
|
if (key.return) onSelect(themes[selectedIndex].name);
|
|
@@ -1995,33 +2692,33 @@ var ThemePickerModal = React12.memo(({ onSelect, onSkip, onDismiss }) => {
|
|
|
1995
2692
|
});
|
|
1996
2693
|
const renderSwatch = (theme) => {
|
|
1997
2694
|
const c = theme.colors;
|
|
1998
|
-
return /* @__PURE__ */
|
|
1999
|
-
/* @__PURE__ */
|
|
2000
|
-
/* @__PURE__ */
|
|
2001
|
-
/* @__PURE__ */
|
|
2002
|
-
/* @__PURE__ */
|
|
2003
|
-
/* @__PURE__ */
|
|
2695
|
+
return /* @__PURE__ */ jsxs13(Text13, { children: [
|
|
2696
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.primary, children: "\u2588" }),
|
|
2697
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.secondary, children: "\u2588" }),
|
|
2698
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.accent, children: "\u2588" }),
|
|
2699
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.warning, children: "\u2588" }),
|
|
2700
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.error, children: "\u2588" })
|
|
2004
2701
|
] });
|
|
2005
2702
|
};
|
|
2006
|
-
return /* @__PURE__ */
|
|
2007
|
-
/* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2009
|
-
themes.map((theme, i) => /* @__PURE__ */
|
|
2010
|
-
/* @__PURE__ */
|
|
2703
|
+
return /* @__PURE__ */ jsx13(Box13, { flexDirection: "column", paddingX: 4, paddingY: 1, children: /* @__PURE__ */ jsxs13(Box13, { borderStyle: "round", borderColor: colors.primary, flexDirection: "column", paddingX: 3, paddingY: 1, children: [
|
|
2704
|
+
/* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.header, bold: true, children: "Choose a theme" }) }),
|
|
2705
|
+
/* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.text, children: "Select a theme to get started. You can change this later in settings (s)." }) }),
|
|
2706
|
+
themes.map((theme, i) => /* @__PURE__ */ jsxs13(Box13, { children: [
|
|
2707
|
+
/* @__PURE__ */ jsx13(Text13, { color: i === selectedIndex ? colors.primary : colors.muted, children: i === selectedIndex ? "> " : " " }),
|
|
2011
2708
|
renderSwatch(theme),
|
|
2012
|
-
/* @__PURE__ */
|
|
2709
|
+
/* @__PURE__ */ jsxs13(Text13, { color: i === selectedIndex ? colors.bright : colors.text, children: [
|
|
2013
2710
|
" ",
|
|
2014
2711
|
theme.name
|
|
2015
2712
|
] })
|
|
2016
2713
|
] }, theme.name)),
|
|
2017
|
-
/* @__PURE__ */
|
|
2714
|
+
/* @__PURE__ */ jsx13(Box13, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx13(Text13, { color: colors.muted, children: "Enter = select | n = not now | d = don't ask again" }) })
|
|
2018
2715
|
] }) });
|
|
2019
2716
|
});
|
|
2020
2717
|
|
|
2021
2718
|
// src/ui/components/GuidedTour.tsx
|
|
2022
|
-
import
|
|
2023
|
-
import { Box as
|
|
2024
|
-
import { jsx as
|
|
2719
|
+
import React14, { useState as useState9 } from "react";
|
|
2720
|
+
import { Box as Box14, Text as Text14, useInput as useInput8 } from "ink";
|
|
2721
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2025
2722
|
var STEPS = [
|
|
2026
2723
|
{
|
|
2027
2724
|
title: "Session list",
|
|
@@ -2052,11 +2749,11 @@ var STEPS = [
|
|
|
2052
2749
|
body: "Press s to open settings. Customise keybindings, manage themes, and configure updates."
|
|
2053
2750
|
}
|
|
2054
2751
|
];
|
|
2055
|
-
var GuidedTour =
|
|
2056
|
-
const [stepIndex, setStepIndex] =
|
|
2752
|
+
var GuidedTour = React14.memo(({ onComplete, onSkip }) => {
|
|
2753
|
+
const [stepIndex, setStepIndex] = useState9(0);
|
|
2057
2754
|
const step = STEPS[stepIndex];
|
|
2058
2755
|
const isLast = stepIndex === STEPS.length - 1;
|
|
2059
|
-
|
|
2756
|
+
useInput8((input, key) => {
|
|
2060
2757
|
if (key.return || key.rightArrow) {
|
|
2061
2758
|
if (isLast) onComplete();
|
|
2062
2759
|
else setStepIndex((i) => i + 1);
|
|
@@ -2064,17 +2761,17 @@ var GuidedTour = React13.memo(({ onComplete, onSkip }) => {
|
|
|
2064
2761
|
if (key.leftArrow && stepIndex > 0) setStepIndex((i) => i - 1);
|
|
2065
2762
|
if (input === "q" || key.escape) onSkip();
|
|
2066
2763
|
});
|
|
2067
|
-
return /* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
2764
|
+
return /* @__PURE__ */ jsx14(Box14, { flexDirection: "column", paddingX: 4, paddingY: 1, children: /* @__PURE__ */ jsxs14(Box14, { borderStyle: "round", borderColor: colors.primary, flexDirection: "column", paddingX: 3, paddingY: 1, children: [
|
|
2765
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsxs14(Text14, { color: colors.header, bold: true, children: [
|
|
2069
2766
|
"Quick tour (",
|
|
2070
2767
|
stepIndex + 1,
|
|
2071
2768
|
"/",
|
|
2072
2769
|
STEPS.length,
|
|
2073
2770
|
")"
|
|
2074
2771
|
] }) }),
|
|
2075
|
-
/* @__PURE__ */
|
|
2076
|
-
/* @__PURE__ */
|
|
2077
|
-
/* @__PURE__ */
|
|
2772
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.bright, bold: true, children: step.title }) }),
|
|
2773
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: step.body }) }),
|
|
2774
|
+
/* @__PURE__ */ jsxs14(Text14, { color: colors.muted, children: [
|
|
2078
2775
|
isLast ? "Enter = finish" : "Enter/\u2192 = next",
|
|
2079
2776
|
" | ",
|
|
2080
2777
|
stepIndex > 0 ? "\u2190 = back | " : "",
|
|
@@ -2084,19 +2781,19 @@ var GuidedTour = React13.memo(({ onComplete, onSkip }) => {
|
|
|
2084
2781
|
});
|
|
2085
2782
|
|
|
2086
2783
|
// src/ui/components/ConfirmModal.tsx
|
|
2087
|
-
import
|
|
2088
|
-
import { Box as
|
|
2089
|
-
import { jsx as
|
|
2090
|
-
var ConfirmModal =
|
|
2091
|
-
|
|
2784
|
+
import React15 from "react";
|
|
2785
|
+
import { Box as Box15, Text as Text15, useInput as useInput9 } from "ink";
|
|
2786
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2787
|
+
var ConfirmModal = React15.memo(({ title, message, onConfirm, onCancel }) => {
|
|
2788
|
+
useInput9((input, key) => {
|
|
2092
2789
|
if (input === "y" || input === "Y") {
|
|
2093
2790
|
onConfirm();
|
|
2094
2791
|
} else if (input === "n" || input === "N" || key.escape) {
|
|
2095
2792
|
onCancel();
|
|
2096
2793
|
}
|
|
2097
2794
|
});
|
|
2098
|
-
return /* @__PURE__ */
|
|
2099
|
-
|
|
2795
|
+
return /* @__PURE__ */ jsxs15(
|
|
2796
|
+
Box15,
|
|
2100
2797
|
{
|
|
2101
2798
|
borderStyle: "round",
|
|
2102
2799
|
borderColor: colors.warning,
|
|
@@ -2105,27 +2802,27 @@ var ConfirmModal = React14.memo(({ title, message, onConfirm, onCancel }) => {
|
|
|
2105
2802
|
paddingY: 1,
|
|
2106
2803
|
alignSelf: "center",
|
|
2107
2804
|
children: [
|
|
2108
|
-
/* @__PURE__ */
|
|
2109
|
-
/* @__PURE__ */
|
|
2110
|
-
/* @__PURE__ */
|
|
2805
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.warning, bold: true, children: title }),
|
|
2806
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, children: message }),
|
|
2807
|
+
/* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.muted, children: "[y] confirm [n/esc] cancel" }) })
|
|
2111
2808
|
]
|
|
2112
2809
|
}
|
|
2113
2810
|
);
|
|
2114
2811
|
});
|
|
2115
2812
|
|
|
2116
2813
|
// src/ui/components/UpdateModal.tsx
|
|
2117
|
-
import
|
|
2118
|
-
import { Box as
|
|
2119
|
-
import { Fragment as Fragment2, jsx as
|
|
2814
|
+
import React16, { useState as useState10, useCallback as useCallback2 } from "react";
|
|
2815
|
+
import { Box as Box16, Text as Text16, useInput as useInput10 } from "ink";
|
|
2816
|
+
import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2120
2817
|
var options = [
|
|
2121
2818
|
{ key: "now", label: "Update now" },
|
|
2122
2819
|
{ key: "later", label: "Not now" },
|
|
2123
2820
|
{ key: "never", label: "Don't ask again" }
|
|
2124
2821
|
];
|
|
2125
|
-
var UpdateModal =
|
|
2126
|
-
const [selected, setSelected] =
|
|
2127
|
-
const [status, setStatus] =
|
|
2128
|
-
const [errorMsg, setErrorMsg] =
|
|
2822
|
+
var UpdateModal = React16.memo(({ current, latest, onNotNow, onDontAskAgain }) => {
|
|
2823
|
+
const [selected, setSelected] = useState10(0);
|
|
2824
|
+
const [status, setStatus] = useState10("idle");
|
|
2825
|
+
const [errorMsg, setErrorMsg] = useState10("");
|
|
2129
2826
|
const doUpdate = useCallback2(() => {
|
|
2130
2827
|
setStatus("updating");
|
|
2131
2828
|
installUpdate().then(() => {
|
|
@@ -2136,7 +2833,7 @@ var UpdateModal = React15.memo(({ current, latest, onNotNow, onDontAskAgain }) =
|
|
|
2136
2833
|
setStatus("error");
|
|
2137
2834
|
});
|
|
2138
2835
|
}, []);
|
|
2139
|
-
|
|
2836
|
+
useInput10((input, key) => {
|
|
2140
2837
|
if (status === "updating" || status === "restarting") return;
|
|
2141
2838
|
if (status === "error") {
|
|
2142
2839
|
if (key.escape || key.return) {
|
|
@@ -2168,8 +2865,8 @@ var UpdateModal = React15.memo(({ current, latest, onNotNow, onDontAskAgain }) =
|
|
|
2168
2865
|
}
|
|
2169
2866
|
}
|
|
2170
2867
|
});
|
|
2171
|
-
return /* @__PURE__ */
|
|
2172
|
-
|
|
2868
|
+
return /* @__PURE__ */ jsxs16(
|
|
2869
|
+
Box16,
|
|
2173
2870
|
{
|
|
2174
2871
|
borderStyle: "round",
|
|
2175
2872
|
borderColor: colors.primary,
|
|
@@ -2178,8 +2875,8 @@ var UpdateModal = React15.memo(({ current, latest, onNotNow, onDontAskAgain }) =
|
|
|
2178
2875
|
paddingY: 1,
|
|
2179
2876
|
alignSelf: "center",
|
|
2180
2877
|
children: [
|
|
2181
|
-
/* @__PURE__ */
|
|
2182
|
-
/* @__PURE__ */
|
|
2878
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.primary, bold: true, children: "Update available" }),
|
|
2879
|
+
/* @__PURE__ */ jsxs16(Text16, { color: colors.text, children: [
|
|
2183
2880
|
"v",
|
|
2184
2881
|
current,
|
|
2185
2882
|
" ",
|
|
@@ -2187,10 +2884,10 @@ var UpdateModal = React15.memo(({ current, latest, onNotNow, onDontAskAgain }) =
|
|
|
2187
2884
|
" v",
|
|
2188
2885
|
latest
|
|
2189
2886
|
] }),
|
|
2190
|
-
/* @__PURE__ */
|
|
2191
|
-
/* @__PURE__ */
|
|
2192
|
-
/* @__PURE__ */
|
|
2193
|
-
] }) : options.map((opt, i) => /* @__PURE__ */
|
|
2887
|
+
/* @__PURE__ */ jsx16(Box16, { marginTop: 1, flexDirection: "column", children: status === "updating" ? /* @__PURE__ */ jsx16(Text16, { color: colors.warning, children: "updating..." }) : status === "restarting" ? /* @__PURE__ */ jsx16(Text16, { color: colors.secondary, children: "restarting..." }) : status === "error" ? /* @__PURE__ */ jsxs16(Fragment2, { children: [
|
|
2888
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.error, children: errorMsg }),
|
|
2889
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.muted, children: "press enter to continue" })
|
|
2890
|
+
] }) : options.map((opt, i) => /* @__PURE__ */ jsxs16(Text16, { color: i === selected ? colors.primary : colors.muted, children: [
|
|
2194
2891
|
i === selected ? "> " : " ",
|
|
2195
2892
|
opt.label
|
|
2196
2893
|
] }, opt.key)) })
|
|
@@ -2200,10 +2897,10 @@ var UpdateModal = React15.memo(({ current, latest, onNotNow, onDontAskAgain }) =
|
|
|
2200
2897
|
});
|
|
2201
2898
|
|
|
2202
2899
|
// src/ui/components/SplitPanel.tsx
|
|
2203
|
-
import
|
|
2204
|
-
import { Box as
|
|
2205
|
-
import { jsx as
|
|
2206
|
-
var SplitPanel =
|
|
2900
|
+
import React17 from "react";
|
|
2901
|
+
import { Box as Box17 } from "ink";
|
|
2902
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2903
|
+
var SplitPanel = React17.memo(
|
|
2207
2904
|
({
|
|
2208
2905
|
activePanel,
|
|
2209
2906
|
leftSession,
|
|
@@ -2218,35 +2915,35 @@ var SplitPanel = React16.memo(
|
|
|
2218
2915
|
rightShowDetail,
|
|
2219
2916
|
height
|
|
2220
2917
|
}) => {
|
|
2221
|
-
const left = leftShowDetail && leftSession ? /* @__PURE__ */
|
|
2918
|
+
const left = leftShowDetail && leftSession ? /* @__PURE__ */ jsx17(SessionDetail, { session: leftSession, focused: activePanel === "left", height }) : /* @__PURE__ */ jsx17(
|
|
2222
2919
|
ActivityFeed,
|
|
2223
2920
|
{
|
|
2224
2921
|
events: leftEvents,
|
|
2225
2922
|
sessionSlug: leftSession?.slug ?? null,
|
|
2226
2923
|
sessionId: leftSession?.sessionId,
|
|
2227
|
-
|
|
2924
|
+
status: leftSession ? leftSession.status : void 0,
|
|
2228
2925
|
focused: activePanel === "left",
|
|
2229
2926
|
height,
|
|
2230
2927
|
scrollOffset: leftScroll,
|
|
2231
2928
|
filter: leftFilter || void 0
|
|
2232
2929
|
}
|
|
2233
2930
|
);
|
|
2234
|
-
const right = rightShowDetail && rightSession ? /* @__PURE__ */
|
|
2931
|
+
const right = rightShowDetail && rightSession ? /* @__PURE__ */ jsx17(SessionDetail, { session: rightSession, focused: activePanel === "right", height }) : /* @__PURE__ */ jsx17(
|
|
2235
2932
|
ActivityFeed,
|
|
2236
2933
|
{
|
|
2237
2934
|
events: rightEvents,
|
|
2238
2935
|
sessionSlug: rightSession?.slug ?? null,
|
|
2239
2936
|
sessionId: rightSession?.sessionId,
|
|
2240
|
-
|
|
2937
|
+
status: rightSession ? rightSession.status : void 0,
|
|
2241
2938
|
focused: activePanel === "right",
|
|
2242
2939
|
height,
|
|
2243
2940
|
scrollOffset: rightScroll,
|
|
2244
2941
|
filter: rightFilter || void 0
|
|
2245
2942
|
}
|
|
2246
2943
|
);
|
|
2247
|
-
return /* @__PURE__ */
|
|
2248
|
-
/* @__PURE__ */
|
|
2249
|
-
|
|
2944
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "row", flexGrow: 1, children: [
|
|
2945
|
+
/* @__PURE__ */ jsx17(
|
|
2946
|
+
Box17,
|
|
2250
2947
|
{
|
|
2251
2948
|
flexGrow: 1,
|
|
2252
2949
|
borderStyle: "single",
|
|
@@ -2264,10 +2961,10 @@ var SplitPanel = React16.memo(
|
|
|
2264
2961
|
);
|
|
2265
2962
|
|
|
2266
2963
|
// src/ui/hooks/useSessions.ts
|
|
2267
|
-
import { useState as
|
|
2964
|
+
import { useState as useState11, useEffect as useEffect6, useCallback as useCallback3, useRef as useRef5, useMemo as useMemo2 } from "react";
|
|
2268
2965
|
|
|
2269
2966
|
// src/discovery/sessionsAsync.ts
|
|
2270
|
-
import { readdir, stat as stat2 } from "fs/promises";
|
|
2967
|
+
import { readdir, stat as stat2, open as open2 } from "fs/promises";
|
|
2271
2968
|
import { join as join2, basename } from "path";
|
|
2272
2969
|
|
|
2273
2970
|
// src/discovery/cache.ts
|
|
@@ -2306,44 +3003,9 @@ var pruneFileMetaCache = (validPaths) => {
|
|
|
2306
3003
|
};
|
|
2307
3004
|
|
|
2308
3005
|
// src/discovery/asyncHelpers.ts
|
|
2309
|
-
import {
|
|
2310
|
-
import {
|
|
2311
|
-
var normalisePath = (p) => p.replace(
|
|
2312
|
-
var getClaudeProcessesAsync = async () => {
|
|
2313
|
-
const stdout = await new Promise((resolve) => {
|
|
2314
|
-
execFile2("ps", ["aux"], { encoding: "utf-8", timeout: 5e3, maxBuffer: 4 * 1024 * 1024 }, (err, out) => {
|
|
2315
|
-
resolve(err || !out ? "" : out);
|
|
2316
|
-
});
|
|
2317
|
-
});
|
|
2318
|
-
if (!stdout) return [];
|
|
2319
|
-
const procs = [];
|
|
2320
|
-
for (const line of stdout.split("\n")) {
|
|
2321
|
-
if (!line.includes("/claude") || line.includes("grep") || line.includes("agenttop")) continue;
|
|
2322
|
-
const parts = line.trim().split(/\s+/);
|
|
2323
|
-
const pid = parseInt(parts[1], 10);
|
|
2324
|
-
if (isNaN(pid)) continue;
|
|
2325
|
-
const command = parts.slice(10).join(" ");
|
|
2326
|
-
if (command.startsWith("sudo")) continue;
|
|
2327
|
-
procs.push({
|
|
2328
|
-
pid,
|
|
2329
|
-
cpu: parseFloat(parts[2]) || 0,
|
|
2330
|
-
mem: parseFloat(parts[3]) || 0,
|
|
2331
|
-
memKB: parseInt(parts[5], 10) || 0,
|
|
2332
|
-
startTime: parts[8] || "",
|
|
2333
|
-
command,
|
|
2334
|
-
cwd: ""
|
|
2335
|
-
});
|
|
2336
|
-
}
|
|
2337
|
-
await Promise.all(
|
|
2338
|
-
procs.map(async (p) => {
|
|
2339
|
-
try {
|
|
2340
|
-
p.cwd = await readlink(`/proc/${p.pid}/cwd`);
|
|
2341
|
-
} catch {
|
|
2342
|
-
}
|
|
2343
|
-
})
|
|
2344
|
-
);
|
|
2345
|
-
return procs;
|
|
2346
|
-
};
|
|
3006
|
+
import { open, stat } from "fs/promises";
|
|
3007
|
+
import { normalize } from "path";
|
|
3008
|
+
var normalisePath = (p) => normalize(p).replace(/[\\/]+$/, "");
|
|
2347
3009
|
var readFirstLinesAsync = async (filePath, bytes) => {
|
|
2348
3010
|
let fh;
|
|
2349
3011
|
try {
|
|
@@ -2461,7 +3123,47 @@ var findModelAndUsageAsync = async (filePath) => {
|
|
|
2461
3123
|
};
|
|
2462
3124
|
|
|
2463
3125
|
// src/discovery/sessionsAsync.ts
|
|
2464
|
-
var
|
|
3126
|
+
var readTailBytesAsync = async (filePath, bytes) => {
|
|
3127
|
+
let fh;
|
|
3128
|
+
try {
|
|
3129
|
+
fh = await open2(filePath, "r");
|
|
3130
|
+
const fstat = await stat2(filePath);
|
|
3131
|
+
const start = Math.max(0, fstat.size - bytes);
|
|
3132
|
+
const readSize = Math.min(bytes, fstat.size);
|
|
3133
|
+
const buf = Buffer.alloc(readSize);
|
|
3134
|
+
await fh.read(buf, 0, readSize, start);
|
|
3135
|
+
return buf.toString("utf-8");
|
|
3136
|
+
} catch {
|
|
3137
|
+
return "";
|
|
3138
|
+
} finally {
|
|
3139
|
+
await fh?.close();
|
|
3140
|
+
}
|
|
3141
|
+
};
|
|
3142
|
+
var detectStatusAsync = async (filePath, hasPid, lastActivity, staleTimeout) => {
|
|
3143
|
+
if (!hasPid) return "inactive";
|
|
3144
|
+
const tail = await readTailBytesAsync(filePath, 4096);
|
|
3145
|
+
const lines = tail.split("\n").filter(Boolean);
|
|
3146
|
+
if (lines.length > 0) {
|
|
3147
|
+
try {
|
|
3148
|
+
const lastEvent = JSON.parse(lines[lines.length - 1]);
|
|
3149
|
+
if (lastEvent.type === "assistant") {
|
|
3150
|
+
const content = lastEvent.message?.content;
|
|
3151
|
+
if (Array.isArray(content)) {
|
|
3152
|
+
const hasAskUser = content.some(
|
|
3153
|
+
(b) => b.type === "tool_use" && b.name === "AskUserQuestion"
|
|
3154
|
+
);
|
|
3155
|
+
if (hasAskUser) return "waiting";
|
|
3156
|
+
const hasToolUse = content.some((b) => b.type === "tool_use");
|
|
3157
|
+
if (!hasToolUse) return "waiting";
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
} catch {
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
if (Date.now() - lastActivity > staleTimeout * 1e3) return "stale";
|
|
3164
|
+
return "active";
|
|
3165
|
+
};
|
|
3166
|
+
var discoverFromProjectsAsync = async (allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder) => {
|
|
2465
3167
|
const projectsDirs = getProjectsDirs(allUsers);
|
|
2466
3168
|
for (const projectsDir of projectsDirs) {
|
|
2467
3169
|
let projectNames;
|
|
@@ -2516,14 +3218,16 @@ var discoverFromProjectsAsync = async (allUsers, processes, sessionMap, seenFile
|
|
|
2516
3218
|
outputFiles: [filePath],
|
|
2517
3219
|
startTime: fstat.birthtimeMs || fstat.ctimeMs,
|
|
2518
3220
|
lastActivity: fstat.mtimeMs,
|
|
2519
|
-
usage: meta.usage
|
|
3221
|
+
usage: meta.usage,
|
|
3222
|
+
status: await detectStatusAsync(filePath, matchingProcess !== void 0, fstat.mtimeMs, staleTimeout),
|
|
3223
|
+
pinned: pinnedOrder.includes(meta.sessionId)
|
|
2520
3224
|
};
|
|
2521
3225
|
sessionMap.set(meta.sessionId, session);
|
|
2522
3226
|
}
|
|
2523
3227
|
}
|
|
2524
3228
|
}
|
|
2525
3229
|
};
|
|
2526
|
-
var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) => {
|
|
3230
|
+
var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder) => {
|
|
2527
3231
|
const taskDirs = getTaskDirs(allUsers);
|
|
2528
3232
|
for (const taskDir of taskDirs) {
|
|
2529
3233
|
let projectDirs;
|
|
@@ -2613,6 +3317,13 @@ var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) =>
|
|
|
2613
3317
|
if (sessionMap.has(sessionId || projectName)) continue;
|
|
2614
3318
|
const normCwd = normalisePath(cwd);
|
|
2615
3319
|
const matchingProcess = processes.find((p) => p.cwd && normalisePath(p.cwd) === normCwd);
|
|
3320
|
+
let latestFile = outputFiles[0];
|
|
3321
|
+
for (const f of outputFiles) {
|
|
3322
|
+
try {
|
|
3323
|
+
if ((await stat2(f)).mtimeMs > (await stat2(latestFile)).mtimeMs) latestFile = f;
|
|
3324
|
+
} catch {
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
2616
3327
|
const session = {
|
|
2617
3328
|
sessionId,
|
|
2618
3329
|
slug: slug || sessionId.slice(0, 12),
|
|
@@ -2630,7 +3341,9 @@ var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) =>
|
|
|
2630
3341
|
outputFiles,
|
|
2631
3342
|
startTime: startTime === Infinity ? Date.now() : startTime,
|
|
2632
3343
|
lastActivity,
|
|
2633
|
-
usage: totalUsage
|
|
3344
|
+
usage: totalUsage,
|
|
3345
|
+
status: await detectStatusAsync(latestFile, matchingProcess !== void 0, lastActivity, staleTimeout),
|
|
3346
|
+
pinned: pinnedOrder.includes(sessionId)
|
|
2634
3347
|
};
|
|
2635
3348
|
sessionMap.set(sessionId || projectName, session);
|
|
2636
3349
|
}
|
|
@@ -2638,16 +3351,26 @@ var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) =>
|
|
|
2638
3351
|
}
|
|
2639
3352
|
};
|
|
2640
3353
|
var discoverSessionsAsync = async (allUsers) => {
|
|
3354
|
+
const config = loadConfig();
|
|
3355
|
+
const staleTimeout = config.alerts.staleTimeout ?? 60;
|
|
3356
|
+
const pinnedOrder = config.pinnedSessions ?? [];
|
|
2641
3357
|
const processes = await getClaudeProcessesAsync();
|
|
2642
3358
|
const sessionMap = /* @__PURE__ */ new Map();
|
|
2643
3359
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
2644
|
-
await discoverFromProjectsAsync(allUsers, processes, sessionMap, seenFiles);
|
|
2645
|
-
await discoverFromTmpAsync(allUsers, processes, sessionMap, seenFiles);
|
|
3360
|
+
await discoverFromProjectsAsync(allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder);
|
|
3361
|
+
await discoverFromTmpAsync(allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder);
|
|
2646
3362
|
pruneFileMetaCache(seenFiles);
|
|
2647
3363
|
return Array.from(sessionMap.values()).sort((a, b) => {
|
|
2648
|
-
const
|
|
2649
|
-
const
|
|
2650
|
-
|
|
3364
|
+
const aPin = pinnedOrder.indexOf(a.sessionId);
|
|
3365
|
+
const bPin = pinnedOrder.indexOf(b.sessionId);
|
|
3366
|
+
const aIsPinned = aPin !== -1;
|
|
3367
|
+
const bIsPinned = bPin !== -1;
|
|
3368
|
+
if (aIsPinned && !bIsPinned) return -1;
|
|
3369
|
+
if (!aIsPinned && bIsPinned) return 1;
|
|
3370
|
+
if (aIsPinned && bIsPinned) return aPin - bPin;
|
|
3371
|
+
const aPri = STATUS_PRIORITY[a.status];
|
|
3372
|
+
const bPri = STATUS_PRIORITY[b.status];
|
|
3373
|
+
if (aPri !== bPri) return aPri - bPri;
|
|
2651
3374
|
return b.lastActivity - a.lastActivity;
|
|
2652
3375
|
});
|
|
2653
3376
|
};
|
|
@@ -2692,7 +3415,9 @@ var buildGroups = (sessions2, expandedKeys) => {
|
|
|
2692
3415
|
totalInputTokens: totalIn,
|
|
2693
3416
|
totalOutputTokens: totalOut,
|
|
2694
3417
|
latestModel: list[0].model,
|
|
2695
|
-
|
|
3418
|
+
status: list.reduce((best, s) => {
|
|
3419
|
+
return (STATUS_PRIORITY[s.status] ?? 3) < (STATUS_PRIORITY[best] ?? 3) ? s.status : best;
|
|
3420
|
+
}, "inactive"),
|
|
2696
3421
|
latestActivity: list[0].lastActivity,
|
|
2697
3422
|
earliestStart: Math.min(...list.map((s) => s.startTime))
|
|
2698
3423
|
});
|
|
@@ -2749,17 +3474,17 @@ var enrichAndFilter = (found, usageOverrides, filter, archivedIds, viewingArchiv
|
|
|
2749
3474
|
return enriched;
|
|
2750
3475
|
};
|
|
2751
3476
|
var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
2752
|
-
const [sessions2, setSessions] =
|
|
2753
|
-
const [selectedIndex, setSelectedIndex] =
|
|
2754
|
-
const [expandedKeys, setExpandedKeys] =
|
|
2755
|
-
const usageOverrides =
|
|
3477
|
+
const [sessions2, setSessions] = useState11([]);
|
|
3478
|
+
const [selectedIndex, setSelectedIndex] = useState11(0);
|
|
3479
|
+
const [expandedKeys, setExpandedKeys] = useState11(/* @__PURE__ */ new Set());
|
|
3480
|
+
const usageOverrides = useRef5(/* @__PURE__ */ new Map());
|
|
2756
3481
|
const refresh = useCallback3(() => {
|
|
2757
3482
|
const found = getCachedSessions();
|
|
2758
3483
|
const filtered = enrichAndFilter(found, usageOverrides.current, filter, archivedIds, viewingArchive);
|
|
2759
3484
|
setSessions(filtered);
|
|
2760
3485
|
triggerRefresh(allUsers);
|
|
2761
3486
|
}, [allUsers, filter, archivedIds, viewingArchive]);
|
|
2762
|
-
|
|
3487
|
+
useEffect6(() => {
|
|
2763
3488
|
const unsubscribe = subscribe(() => {
|
|
2764
3489
|
const found = getCachedSessions();
|
|
2765
3490
|
const filtered = enrichAndFilter(found, usageOverrides.current, filter, archivedIds, viewingArchive);
|
|
@@ -2767,7 +3492,7 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2767
3492
|
});
|
|
2768
3493
|
return unsubscribe;
|
|
2769
3494
|
}, [filter, archivedIds, viewingArchive]);
|
|
2770
|
-
|
|
3495
|
+
useEffect6(() => {
|
|
2771
3496
|
refresh();
|
|
2772
3497
|
const pollMs = sessions2.length > 0 ? ACTIVE_POLL_MS : IDLE_POLL_MS;
|
|
2773
3498
|
const interval = setInterval(() => triggerRefresh(allUsers), pollMs);
|
|
@@ -2775,7 +3500,7 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2775
3500
|
}, [refresh, sessions2.length > 0]);
|
|
2776
3501
|
const groups = useMemo2(() => buildGroups(sessions2, expandedKeys), [sessions2, expandedKeys]);
|
|
2777
3502
|
const visibleItems = useMemo2(() => buildVisibleItems(groups), [groups]);
|
|
2778
|
-
const itemCountRef =
|
|
3503
|
+
const itemCountRef = useRef5(visibleItems.length);
|
|
2779
3504
|
itemCountRef.current = visibleItems.length;
|
|
2780
3505
|
const selectedItem = visibleItems[selectedIndex] ?? null;
|
|
2781
3506
|
const selectedSession = selectedItem?.type === "ungrouped" ? selectedItem.session : selectedItem?.type === "session" ? selectedItem.session : null;
|
|
@@ -2827,18 +3552,42 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2827
3552
|
};
|
|
2828
3553
|
|
|
2829
3554
|
// src/ui/hooks/useActivityStream.ts
|
|
2830
|
-
import { useState as
|
|
3555
|
+
import { useState as useState12, useEffect as useEffect7, useRef as useRef6, useMemo as useMemo3, useCallback as useCallback4 } from "react";
|
|
2831
3556
|
var MAX_EVENTS = 200;
|
|
3557
|
+
var DEBOUNCE_MS = 80;
|
|
2832
3558
|
var useActivityStream = (session, allUsers) => {
|
|
2833
|
-
const [calls, setCalls] =
|
|
2834
|
-
const [results, setResults] =
|
|
2835
|
-
const watcherRef =
|
|
3559
|
+
const [calls, setCalls] = useState12([]);
|
|
3560
|
+
const [results, setResults] = useState12([]);
|
|
3561
|
+
const watcherRef = useRef6(null);
|
|
3562
|
+
const pendingCallsRef = useRef6([]);
|
|
3563
|
+
const pendingResultsRef = useRef6([]);
|
|
3564
|
+
const flushTimerRef = useRef6(null);
|
|
2836
3565
|
const sessions2 = session === null ? [] : Array.isArray(session) ? session : [session];
|
|
2837
3566
|
const sessionKey = sessions2.map((s) => s.sessionId).sort().join(",");
|
|
2838
3567
|
const sessionIdSet = new Set(sessions2.map((s) => s.sessionId));
|
|
2839
|
-
|
|
3568
|
+
const flush = useCallback4(() => {
|
|
3569
|
+
flushTimerRef.current = null;
|
|
3570
|
+
const pc = pendingCallsRef.current;
|
|
3571
|
+
const pr = pendingResultsRef.current;
|
|
3572
|
+
if (pc.length > 0) {
|
|
3573
|
+
const batch = pc.splice(0);
|
|
3574
|
+
setCalls((prev) => [...prev, ...batch].slice(-MAX_EVENTS));
|
|
3575
|
+
}
|
|
3576
|
+
if (pr.length > 0) {
|
|
3577
|
+
const batch = pr.splice(0);
|
|
3578
|
+
setResults((prev) => [...prev, ...batch].slice(-MAX_EVENTS * 2));
|
|
3579
|
+
}
|
|
3580
|
+
}, []);
|
|
3581
|
+
const scheduleFlush = useCallback4(() => {
|
|
3582
|
+
if (!flushTimerRef.current) {
|
|
3583
|
+
flushTimerRef.current = setTimeout(flush, DEBOUNCE_MS);
|
|
3584
|
+
}
|
|
3585
|
+
}, [flush]);
|
|
3586
|
+
useEffect7(() => {
|
|
2840
3587
|
setCalls([]);
|
|
2841
3588
|
setResults([]);
|
|
3589
|
+
pendingCallsRef.current = [];
|
|
3590
|
+
pendingResultsRef.current = [];
|
|
2842
3591
|
if (sessions2.length === 0) return;
|
|
2843
3592
|
let cancelled = false;
|
|
2844
3593
|
const loadExisting = async () => {
|
|
@@ -2865,18 +3614,21 @@ var useActivityStream = (session, allUsers) => {
|
|
|
2865
3614
|
const callHandler = (newCalls) => {
|
|
2866
3615
|
const matched = newCalls.filter((c) => sessionIdSet.has(c.sessionId));
|
|
2867
3616
|
if (matched.length === 0) return;
|
|
2868
|
-
|
|
3617
|
+
pendingCallsRef.current.push(...matched);
|
|
3618
|
+
scheduleFlush();
|
|
2869
3619
|
};
|
|
2870
3620
|
const resultHandler = (newResults) => {
|
|
2871
3621
|
const matched = newResults.filter((r) => sessionIdSet.has(r.sessionId));
|
|
2872
3622
|
if (matched.length === 0) return;
|
|
2873
|
-
|
|
3623
|
+
pendingResultsRef.current.push(...matched);
|
|
3624
|
+
scheduleFlush();
|
|
2874
3625
|
};
|
|
2875
3626
|
const watcher = new Watcher(callHandler, allUsers, void 0, void 0, resultHandler);
|
|
2876
3627
|
watcherRef.current = watcher;
|
|
2877
3628
|
watcher.start();
|
|
2878
3629
|
return () => {
|
|
2879
3630
|
cancelled = true;
|
|
3631
|
+
if (flushTimerRef.current) clearTimeout(flushTimerRef.current);
|
|
2880
3632
|
watcher.stop();
|
|
2881
3633
|
watcherRef.current = null;
|
|
2882
3634
|
};
|
|
@@ -2905,10 +3657,10 @@ var applyFilter = (events, filter) => {
|
|
|
2905
3657
|
var useFilteredEvents = (rawEvents, filter) => useMemo4(() => applyFilter(rawEvents, filter), [rawEvents, filter]);
|
|
2906
3658
|
|
|
2907
3659
|
// src/ui/hooks/useAlerts.ts
|
|
2908
|
-
import { useState as
|
|
3660
|
+
import { useState as useState13, useEffect as useEffect8, useRef as useRef7 } from "react";
|
|
2909
3661
|
|
|
2910
3662
|
// src/notifications.ts
|
|
2911
|
-
import {
|
|
3663
|
+
import { execFile as execFile2 } from "child_process";
|
|
2912
3664
|
import { platform } from "os";
|
|
2913
3665
|
var SEVERITY_ORDER = {
|
|
2914
3666
|
info: 0,
|
|
@@ -2931,11 +3683,23 @@ var notify = (alert, config) => {
|
|
|
2931
3683
|
const body = `${alert.sessionSlug}: ${alert.message.slice(0, 100)}`;
|
|
2932
3684
|
const os = platform();
|
|
2933
3685
|
if (os === "linux") {
|
|
2934
|
-
|
|
3686
|
+
execFile2("notify-send", [title, body], { timeout: 3e3 });
|
|
2935
3687
|
} else if (os === "darwin") {
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
3688
|
+
execFile2(
|
|
3689
|
+
"osascript",
|
|
3690
|
+
["-e", `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}`],
|
|
3691
|
+
{ timeout: 3e3 }
|
|
3692
|
+
);
|
|
3693
|
+
} else if (os === "win32") {
|
|
3694
|
+
execFile2(
|
|
3695
|
+
"powershell",
|
|
3696
|
+
[
|
|
3697
|
+
"-NoProfile",
|
|
3698
|
+
"-Command",
|
|
3699
|
+
`Add-Type -AssemblyName System.Windows.Forms; $n = New-Object System.Windows.Forms.NotifyIcon; $n.Icon = [System.Drawing.SystemIcons]::Information; $n.Visible = $true; $n.ShowBalloonTip(5000, ${JSON.stringify(title)}, ${JSON.stringify(body)}, 'Warning'); Start-Sleep -Seconds 6; $n.Dispose()`
|
|
3700
|
+
],
|
|
3701
|
+
{ timeout: 1e4 }
|
|
3702
|
+
);
|
|
2939
3703
|
}
|
|
2940
3704
|
}
|
|
2941
3705
|
};
|
|
@@ -2973,11 +3737,11 @@ var AlertLogger = class {
|
|
|
2973
3737
|
// src/ui/hooks/useAlerts.ts
|
|
2974
3738
|
var MAX_ALERTS = 100;
|
|
2975
3739
|
var useAlerts = (enabled, alertLevel, allUsers, config) => {
|
|
2976
|
-
const [alerts, setAlerts] =
|
|
2977
|
-
const engineRef =
|
|
2978
|
-
const watcherRef =
|
|
2979
|
-
const loggerRef =
|
|
2980
|
-
|
|
3740
|
+
const [alerts, setAlerts] = useState13([]);
|
|
3741
|
+
const engineRef = useRef7(new SecurityEngine(alertLevel));
|
|
3742
|
+
const watcherRef = useRef7(null);
|
|
3743
|
+
const loggerRef = useRef7(null);
|
|
3744
|
+
useEffect8(() => {
|
|
2981
3745
|
if (!enabled) return;
|
|
2982
3746
|
engineRef.current = new SecurityEngine(alertLevel);
|
|
2983
3747
|
if (config?.alerts.enabled) {
|
|
@@ -3007,33 +3771,33 @@ var useAlerts = (enabled, alertLevel, allUsers, config) => {
|
|
|
3007
3771
|
watcherRef.current = null;
|
|
3008
3772
|
loggerRef.current = null;
|
|
3009
3773
|
};
|
|
3010
|
-
}, [enabled, alertLevel, allUsers]);
|
|
3774
|
+
}, [enabled, alertLevel, allUsers, config]);
|
|
3011
3775
|
const clearAlerts = () => setAlerts([]);
|
|
3012
3776
|
return { alerts, clearAlerts };
|
|
3013
3777
|
};
|
|
3014
3778
|
|
|
3015
3779
|
// src/ui/hooks/useTextInput.ts
|
|
3016
|
-
import { useState as
|
|
3780
|
+
import { useState as useState14, useCallback as useCallback5 } from "react";
|
|
3017
3781
|
var useTextInput = (onConfirm, onCancel) => {
|
|
3018
|
-
const [value, setValue] =
|
|
3019
|
-
const [isActive, setIsActive] =
|
|
3020
|
-
const start =
|
|
3782
|
+
const [value, setValue] = useState14("");
|
|
3783
|
+
const [isActive, setIsActive] = useState14(false);
|
|
3784
|
+
const start = useCallback5((initial = "") => {
|
|
3021
3785
|
setValue(initial);
|
|
3022
3786
|
setIsActive(true);
|
|
3023
3787
|
}, []);
|
|
3024
|
-
const cancel =
|
|
3788
|
+
const cancel = useCallback5(() => {
|
|
3025
3789
|
setValue("");
|
|
3026
3790
|
setIsActive(false);
|
|
3027
3791
|
onCancel?.();
|
|
3028
3792
|
}, [onCancel]);
|
|
3029
|
-
const confirm =
|
|
3793
|
+
const confirm = useCallback5(() => {
|
|
3030
3794
|
const result = value;
|
|
3031
3795
|
setIsActive(false);
|
|
3032
3796
|
setValue("");
|
|
3033
3797
|
onConfirm?.(result);
|
|
3034
3798
|
return result;
|
|
3035
3799
|
}, [value, onConfirm]);
|
|
3036
|
-
const handleInput =
|
|
3800
|
+
const handleInput = useCallback5(
|
|
3037
3801
|
(input, key) => {
|
|
3038
3802
|
if (!isActive) return false;
|
|
3039
3803
|
if (key.escape) {
|
|
@@ -3066,16 +3830,17 @@ var useTextInput = (onConfirm, onCancel) => {
|
|
|
3066
3830
|
};
|
|
3067
3831
|
|
|
3068
3832
|
// src/ui/hooks/useKeyHandler.ts
|
|
3069
|
-
import { useInput as
|
|
3833
|
+
import { useInput as useInput11 } from "ink";
|
|
3070
3834
|
var matchKey = (binding, input, key) => {
|
|
3071
3835
|
if (binding === "tab") return Boolean(key.tab);
|
|
3072
3836
|
if (binding === "shift+tab") return Boolean(key.shift && key.tab);
|
|
3073
3837
|
if (binding === "enter") return Boolean(key.return);
|
|
3838
|
+
if (binding.startsWith("ctrl+")) return Boolean(key.ctrl) && input === binding.slice(5);
|
|
3074
3839
|
return input === binding;
|
|
3075
3840
|
};
|
|
3076
3841
|
var useKeyHandler = (deps) => {
|
|
3077
3842
|
const d = deps;
|
|
3078
|
-
|
|
3843
|
+
useInput11((input, key) => {
|
|
3079
3844
|
if (d.showSetup || d.showSettings || d.confirmAction || d.showUpdateModal) return;
|
|
3080
3845
|
if (d.inputMode === "nickname") {
|
|
3081
3846
|
d.nicknameInput.handleInput(input, key);
|
|
@@ -3246,10 +4011,26 @@ var useKeyHandler = (deps) => {
|
|
|
3246
4011
|
d.setShowSettings(true);
|
|
3247
4012
|
return;
|
|
3248
4013
|
}
|
|
4014
|
+
if (matchKey(d.kb.alertRules, input, key)) {
|
|
4015
|
+
d.setShowAlertRules(true);
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
3249
4018
|
if (matchKey(d.kb.viewArchive, input, key)) {
|
|
3250
4019
|
d.setViewingArchive((v) => !v);
|
|
3251
4020
|
return;
|
|
3252
4021
|
}
|
|
4022
|
+
if (matchKey(d.kb.pin, input, key) && d.selectedSession) {
|
|
4023
|
+
d.onTogglePin(d.selectedSession.sessionId);
|
|
4024
|
+
return;
|
|
4025
|
+
}
|
|
4026
|
+
if (matchKey(d.kb.pinMoveUp, input, key) && d.selectedSession?.pinned) {
|
|
4027
|
+
d.onMovePinned(d.selectedSession.sessionId, "up");
|
|
4028
|
+
return;
|
|
4029
|
+
}
|
|
4030
|
+
if (matchKey(d.kb.pinMoveDown, input, key) && d.selectedSession?.pinned) {
|
|
4031
|
+
d.onMovePinned(d.selectedSession.sessionId, "down");
|
|
4032
|
+
return;
|
|
4033
|
+
}
|
|
3253
4034
|
if (matchKey(d.kb.archive, input, key) && d.selectedSession) {
|
|
3254
4035
|
if (d.viewingArchive) d.onUnarchive(d.selectedSession.sessionId);
|
|
3255
4036
|
else d.onArchive(d.selectedSession.sessionId);
|
|
@@ -3308,10 +4089,10 @@ var useKeyHandler = (deps) => {
|
|
|
3308
4089
|
};
|
|
3309
4090
|
|
|
3310
4091
|
// src/ui/hooks/useUpdateChecker.ts
|
|
3311
|
-
import { useState as
|
|
4092
|
+
import { useState as useState15, useEffect as useEffect9 } from "react";
|
|
3312
4093
|
var useUpdateChecker = (disabled, checkOnLaunch, checkInterval) => {
|
|
3313
|
-
const [updateInfo, setUpdateInfo] =
|
|
3314
|
-
|
|
4094
|
+
const [updateInfo, setUpdateInfo] = useState15(null);
|
|
4095
|
+
useEffect9(() => {
|
|
3315
4096
|
if (disabled || !checkOnLaunch) return;
|
|
3316
4097
|
let cancelled = false;
|
|
3317
4098
|
const check = () => {
|
|
@@ -3326,12 +4107,12 @@ var useUpdateChecker = (disabled, checkOnLaunch, checkInterval) => {
|
|
|
3326
4107
|
cancelled = true;
|
|
3327
4108
|
clearInterval(iv);
|
|
3328
4109
|
};
|
|
3329
|
-
}, []);
|
|
4110
|
+
}, [disabled, checkOnLaunch, checkInterval]);
|
|
3330
4111
|
return updateInfo;
|
|
3331
4112
|
};
|
|
3332
4113
|
|
|
3333
4114
|
// src/ui/hooks/useSetupFlow.ts
|
|
3334
|
-
import { useState as
|
|
4115
|
+
import { useState as useState16, useCallback as useCallback6 } from "react";
|
|
3335
4116
|
|
|
3336
4117
|
// src/hooks/installer.ts
|
|
3337
4118
|
import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync as mkdirSync2, chmodSync } from "fs";
|
|
@@ -3451,25 +4232,25 @@ var installMcpConfig = () => {
|
|
|
3451
4232
|
|
|
3452
4233
|
// src/ui/hooks/useSetupFlow.ts
|
|
3453
4234
|
var useSetupFlow = (initialConfig, firstRun) => {
|
|
3454
|
-
const [liveConfig, setLiveConfig] =
|
|
3455
|
-
const [showSetup, setShowSetup] =
|
|
3456
|
-
const [showThemePicker, setShowThemePicker] =
|
|
3457
|
-
const [showTour, setShowTour] =
|
|
3458
|
-
const [showSettings, setShowSettings] =
|
|
3459
|
-
const [showThemeMenu, setShowThemeMenu] =
|
|
3460
|
-
const handleSettingsClose =
|
|
4235
|
+
const [liveConfig, setLiveConfig] = useState16(initialConfig);
|
|
4236
|
+
const [showSetup, setShowSetup] = useState16(firstRun);
|
|
4237
|
+
const [showThemePicker, setShowThemePicker] = useState16(false);
|
|
4238
|
+
const [showTour, setShowTour] = useState16(false);
|
|
4239
|
+
const [showSettings, setShowSettings] = useState16(false);
|
|
4240
|
+
const [showThemeMenu, setShowThemeMenu] = useState16(false);
|
|
4241
|
+
const handleSettingsClose = useCallback6((c) => {
|
|
3461
4242
|
setLiveConfig(c);
|
|
3462
4243
|
saveConfig(c);
|
|
3463
4244
|
setShowSettings(false);
|
|
3464
4245
|
}, []);
|
|
3465
|
-
const handleThemeMenuClose =
|
|
4246
|
+
const handleThemeMenuClose = useCallback6((c) => {
|
|
3466
4247
|
setLiveConfig(c);
|
|
3467
4248
|
saveConfig(c);
|
|
3468
4249
|
setShowThemeMenu(false);
|
|
3469
4250
|
setShowSettings(true);
|
|
3470
4251
|
}, []);
|
|
3471
|
-
const handleOpenThemeMenu =
|
|
3472
|
-
const handleSetupComplete =
|
|
4252
|
+
const handleOpenThemeMenu = useCallback6(() => setShowThemeMenu(true), []);
|
|
4253
|
+
const handleSetupComplete = useCallback6(
|
|
3473
4254
|
(results) => {
|
|
3474
4255
|
const nc = { ...liveConfig };
|
|
3475
4256
|
const [hc, mc] = results;
|
|
@@ -3494,7 +4275,7 @@ var useSetupFlow = (initialConfig, firstRun) => {
|
|
|
3494
4275
|
},
|
|
3495
4276
|
[liveConfig]
|
|
3496
4277
|
);
|
|
3497
|
-
const handleThemePickerSelect =
|
|
4278
|
+
const handleThemePickerSelect = useCallback6(
|
|
3498
4279
|
(themeName) => {
|
|
3499
4280
|
const nc = { ...liveConfig, theme: themeName, prompts: { ...liveConfig.prompts, theme: "done" } };
|
|
3500
4281
|
setLiveConfig(nc);
|
|
@@ -3504,24 +4285,24 @@ var useSetupFlow = (initialConfig, firstRun) => {
|
|
|
3504
4285
|
},
|
|
3505
4286
|
[liveConfig]
|
|
3506
4287
|
);
|
|
3507
|
-
const handleThemePickerSkip =
|
|
4288
|
+
const handleThemePickerSkip = useCallback6(() => {
|
|
3508
4289
|
setShowThemePicker(false);
|
|
3509
4290
|
if (liveConfig.prompts.tour === "pending") setShowTour(true);
|
|
3510
4291
|
}, [liveConfig]);
|
|
3511
|
-
const handleThemePickerDismiss =
|
|
4292
|
+
const handleThemePickerDismiss = useCallback6(() => {
|
|
3512
4293
|
const nc = { ...liveConfig, prompts: { ...liveConfig.prompts, theme: "dismissed" } };
|
|
3513
4294
|
setLiveConfig(nc);
|
|
3514
4295
|
saveConfig(nc);
|
|
3515
4296
|
setShowThemePicker(false);
|
|
3516
4297
|
if (nc.prompts.tour === "pending") setShowTour(true);
|
|
3517
4298
|
}, [liveConfig]);
|
|
3518
|
-
const handleTourComplete =
|
|
4299
|
+
const handleTourComplete = useCallback6(() => {
|
|
3519
4300
|
const nc = { ...liveConfig, prompts: { ...liveConfig.prompts, tour: "done" } };
|
|
3520
4301
|
setLiveConfig(nc);
|
|
3521
4302
|
saveConfig(nc);
|
|
3522
4303
|
setShowTour(false);
|
|
3523
4304
|
}, [liveConfig]);
|
|
3524
|
-
const handleTourSkip =
|
|
4305
|
+
const handleTourSkip = useCallback6(() => {
|
|
3525
4306
|
setShowTour(false);
|
|
3526
4307
|
}, []);
|
|
3527
4308
|
return {
|
|
@@ -3547,18 +4328,18 @@ var useSetupFlow = (initialConfig, firstRun) => {
|
|
|
3547
4328
|
};
|
|
3548
4329
|
|
|
3549
4330
|
// src/ui/hooks/useSplitPanel.ts
|
|
3550
|
-
import { useState as
|
|
4331
|
+
import { useState as useState17, useCallback as useCallback7 } from "react";
|
|
3551
4332
|
var useSplitPanel = () => {
|
|
3552
|
-
const [splitMode, setSplitMode] =
|
|
3553
|
-
const [leftSession, setLeftSession] =
|
|
3554
|
-
const [rightSession, setRightSession] =
|
|
3555
|
-
const [leftScroll, setLeftScroll] =
|
|
3556
|
-
const [rightScroll, setRightScroll] =
|
|
3557
|
-
const [leftFilter, setLeftFilter] =
|
|
3558
|
-
const [rightFilter, setRightFilter] =
|
|
3559
|
-
const [leftShowDetail, setLeftShowDetail] =
|
|
3560
|
-
const [rightShowDetail, setRightShowDetail] =
|
|
3561
|
-
const clearSplitState =
|
|
4333
|
+
const [splitMode, setSplitMode] = useState17(false);
|
|
4334
|
+
const [leftSession, setLeftSession] = useState17(null);
|
|
4335
|
+
const [rightSession, setRightSession] = useState17(null);
|
|
4336
|
+
const [leftScroll, setLeftScroll] = useState17(0);
|
|
4337
|
+
const [rightScroll, setRightScroll] = useState17(0);
|
|
4338
|
+
const [leftFilter, setLeftFilter] = useState17("");
|
|
4339
|
+
const [rightFilter, setRightFilter] = useState17("");
|
|
4340
|
+
const [leftShowDetail, setLeftShowDetail] = useState17(false);
|
|
4341
|
+
const [rightShowDetail, setRightShowDetail] = useState17(false);
|
|
4342
|
+
const clearSplitState = useCallback7(() => {
|
|
3562
4343
|
setSplitMode(false);
|
|
3563
4344
|
setLeftSession(null);
|
|
3564
4345
|
setRightSession(null);
|
|
@@ -3569,7 +4350,7 @@ var useSplitPanel = () => {
|
|
|
3569
4350
|
setLeftShowDetail(false);
|
|
3570
4351
|
setRightShowDetail(false);
|
|
3571
4352
|
}, []);
|
|
3572
|
-
const resetPanel =
|
|
4353
|
+
const resetPanel = useCallback7((side) => {
|
|
3573
4354
|
if (side === "left") {
|
|
3574
4355
|
setLeftSession(null);
|
|
3575
4356
|
setLeftScroll(0);
|
|
@@ -3582,7 +4363,7 @@ var useSplitPanel = () => {
|
|
|
3582
4363
|
setRightShowDetail(false);
|
|
3583
4364
|
}
|
|
3584
4365
|
}, []);
|
|
3585
|
-
const switchPanel =
|
|
4366
|
+
const switchPanel = useCallback7(
|
|
3586
4367
|
(dir, setActivePanel) => {
|
|
3587
4368
|
if (splitMode) {
|
|
3588
4369
|
const order = ["sessions", "left", "right"];
|
|
@@ -3623,32 +4404,33 @@ var useSplitPanel = () => {
|
|
|
3623
4404
|
};
|
|
3624
4405
|
|
|
3625
4406
|
// src/ui/App.tsx
|
|
3626
|
-
import { jsx as
|
|
4407
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
3627
4408
|
var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
3628
4409
|
const { exit } = useApp();
|
|
3629
|
-
const { stdout } =
|
|
4410
|
+
const { stdout } = useStdout4();
|
|
3630
4411
|
const termHeight = stdout?.rows ?? 40;
|
|
3631
4412
|
const setup = useSetupFlow(initialConfig, firstRun);
|
|
3632
4413
|
const split = useSplitPanel();
|
|
3633
4414
|
const kb = setup.liveConfig.keybindings;
|
|
3634
|
-
const [activePanel, setActivePanel] =
|
|
3635
|
-
const [activityScroll, setActivityScroll] =
|
|
3636
|
-
const [inputMode, setInputMode] =
|
|
3637
|
-
const [filter, setFilter] =
|
|
3638
|
-
const [activityFilter, setActivityFilter] =
|
|
3639
|
-
const [updateStatus, setUpdateStatus] =
|
|
3640
|
-
const [showDetail, setShowDetail] =
|
|
3641
|
-
const [viewingArchive, setViewingArchive] =
|
|
3642
|
-
const [confirmAction, setConfirmAction] =
|
|
4415
|
+
const [activePanel, setActivePanel] = useState18("sessions");
|
|
4416
|
+
const [activityScroll, setActivityScroll] = useState18(0);
|
|
4417
|
+
const [inputMode, setInputMode] = useState18("normal");
|
|
4418
|
+
const [filter, setFilter] = useState18("");
|
|
4419
|
+
const [activityFilter, setActivityFilter] = useState18("");
|
|
4420
|
+
const [updateStatus, setUpdateStatus] = useState18("");
|
|
4421
|
+
const [showDetail, setShowDetail] = useState18(false);
|
|
4422
|
+
const [viewingArchive, setViewingArchive] = useState18(false);
|
|
4423
|
+
const [confirmAction, setConfirmAction] = useState18(
|
|
3643
4424
|
null
|
|
3644
4425
|
);
|
|
3645
|
-
const [archivedIds, setArchivedIds] =
|
|
3646
|
-
const [sidebarWidth, setSidebarWidth] =
|
|
3647
|
-
const [selectedEventIndex, setSelectedEventIndex] =
|
|
3648
|
-
const [showEventDetail, setShowEventDetail] =
|
|
3649
|
-
const [showUpdateModal, setShowUpdateModal] =
|
|
3650
|
-
const
|
|
3651
|
-
const
|
|
4426
|
+
const [archivedIds, setArchivedIds] = useState18(() => new Set(Object.keys(getArchived())));
|
|
4427
|
+
const [sidebarWidth, setSidebarWidth] = useState18(() => initialConfig.sidebarWidth ?? 30);
|
|
4428
|
+
const [selectedEventIndex, setSelectedEventIndex] = useState18(0);
|
|
4429
|
+
const [showEventDetail, setShowEventDetail] = useState18(false);
|
|
4430
|
+
const [showUpdateModal, setShowUpdateModal] = useState18(false);
|
|
4431
|
+
const [showAlertRules, setShowAlertRules] = useState18(false);
|
|
4432
|
+
const refreshArchived = useCallback8(() => setArchivedIds(new Set(Object.keys(getArchived()))), []);
|
|
4433
|
+
const persistSidebarWidth = useCallback8((v) => {
|
|
3652
4434
|
setSidebarWidth((prev) => {
|
|
3653
4435
|
const next = typeof v === "function" ? v(prev) : v;
|
|
3654
4436
|
if (next !== prev) {
|
|
@@ -3664,10 +4446,10 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3664
4446
|
setup.liveConfig.updates.checkOnLaunch,
|
|
3665
4447
|
setup.liveConfig.updates.checkInterval
|
|
3666
4448
|
);
|
|
3667
|
-
|
|
4449
|
+
useEffect10(() => {
|
|
3668
4450
|
applyTheme(resolveTheme(setup.liveConfig.theme, setup.liveConfig.customThemes));
|
|
3669
4451
|
}, [setup.liveConfig.theme, setup.liveConfig.customThemes]);
|
|
3670
|
-
|
|
4452
|
+
useEffect10(() => {
|
|
3671
4453
|
if (updateInfo?.available && setup.liveConfig.prompts.autoUpdate === "pending") {
|
|
3672
4454
|
setShowUpdateModal(true);
|
|
3673
4455
|
}
|
|
@@ -3717,16 +4499,16 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3717
4499
|
setInputMode("normal");
|
|
3718
4500
|
}
|
|
3719
4501
|
);
|
|
3720
|
-
|
|
4502
|
+
useEffect10(() => {
|
|
3721
4503
|
purgeExpiredArchives();
|
|
3722
4504
|
refreshArchived();
|
|
3723
4505
|
}, []);
|
|
3724
|
-
|
|
4506
|
+
useEffect10(() => {
|
|
3725
4507
|
setActivityScroll(0);
|
|
3726
4508
|
setSelectedEventIndex(0);
|
|
3727
4509
|
setShowEventDetail(false);
|
|
3728
4510
|
}, [selectedSession?.sessionId, selectedGroup?.key]);
|
|
3729
|
-
|
|
4511
|
+
useEffect10(() => {
|
|
3730
4512
|
const totalEvents = events.length;
|
|
3731
4513
|
const vRows = termHeight - 3 - (options2.noSecurity ? 0 : 6) - 1 - (inputMode !== "normal" ? 1 : 0) - 2;
|
|
3732
4514
|
if (vRows <= 0 || totalEvents === 0) return;
|
|
@@ -3738,7 +4520,7 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3738
4520
|
setActivityScroll(totalEvents - vRows - (selectedEventIndex - vRows + 1));
|
|
3739
4521
|
}
|
|
3740
4522
|
}, [selectedEventIndex, events.length]);
|
|
3741
|
-
|
|
4523
|
+
useEffect10(() => {
|
|
3742
4524
|
if (events.length > 0 && selectedEventIndex >= events.length) {
|
|
3743
4525
|
setSelectedEventIndex(events.length - 1);
|
|
3744
4526
|
}
|
|
@@ -3746,27 +4528,46 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3746
4528
|
const alertHeight = options2.noSecurity ? 0 : 6;
|
|
3747
4529
|
const mainHeight = termHeight - 3 - alertHeight - 1 - (inputMode !== "normal" ? 1 : 0);
|
|
3748
4530
|
const viewportRows = mainHeight - 2;
|
|
3749
|
-
const switchPanel =
|
|
4531
|
+
const switchPanel = useCallback8(
|
|
3750
4532
|
(dir) => split.switchPanel(dir, setActivePanel),
|
|
3751
4533
|
[split.switchPanel]
|
|
3752
4534
|
);
|
|
3753
|
-
const clearSplitState =
|
|
4535
|
+
const clearSplitState = useCallback8(() => {
|
|
3754
4536
|
split.clearSplitState();
|
|
3755
4537
|
setActivePanel("sessions");
|
|
3756
4538
|
}, [split.clearSplitState]);
|
|
3757
|
-
const getActiveFilter =
|
|
4539
|
+
const getActiveFilter = useCallback8(() => {
|
|
3758
4540
|
if (activePanel === "sessions") return filter;
|
|
3759
4541
|
if (activePanel === "left") return split.leftFilter;
|
|
3760
4542
|
if (activePanel === "right") return split.rightFilter;
|
|
3761
4543
|
return activityFilter;
|
|
3762
4544
|
}, [activePanel, filter, split.leftFilter, split.rightFilter, activityFilter]);
|
|
4545
|
+
const handleTogglePin = useCallback8(
|
|
4546
|
+
(sessionId) => {
|
|
4547
|
+
const cfg = loadConfig();
|
|
4548
|
+
if (cfg.pinnedSessions.includes(sessionId)) {
|
|
4549
|
+
unpinSession(sessionId);
|
|
4550
|
+
} else {
|
|
4551
|
+
pinSession(sessionId);
|
|
4552
|
+
}
|
|
4553
|
+
refresh();
|
|
4554
|
+
},
|
|
4555
|
+
[refresh]
|
|
4556
|
+
);
|
|
4557
|
+
const handleMovePinned = useCallback8(
|
|
4558
|
+
(sessionId, dir) => {
|
|
4559
|
+
movePinned(sessionId, dir);
|
|
4560
|
+
refresh();
|
|
4561
|
+
},
|
|
4562
|
+
[refresh]
|
|
4563
|
+
);
|
|
3763
4564
|
useKeyHandler({
|
|
3764
4565
|
kb,
|
|
3765
4566
|
activePanel,
|
|
3766
4567
|
splitMode: split.splitMode,
|
|
3767
4568
|
inputMode,
|
|
3768
4569
|
showSetup: setup.showSetup,
|
|
3769
|
-
showSettings: setup.showSettings || setup.showThemeMenu || setup.showThemePicker || setup.showTour,
|
|
4570
|
+
showSettings: setup.showSettings || setup.showThemeMenu || setup.showThemePicker || setup.showTour || showAlertRules,
|
|
3770
4571
|
showDetail,
|
|
3771
4572
|
showEventDetail,
|
|
3772
4573
|
leftShowDetail: split.leftShowDetail,
|
|
@@ -3810,6 +4611,8 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3810
4611
|
setLeftShowDetail: split.setLeftShowDetail,
|
|
3811
4612
|
setRightShowDetail: split.setRightShowDetail,
|
|
3812
4613
|
setShowSettings: setup.setShowSettings,
|
|
4614
|
+
showAlertRules,
|
|
4615
|
+
setShowAlertRules,
|
|
3813
4616
|
setViewingArchive,
|
|
3814
4617
|
setSplitMode: split.setSplitMode,
|
|
3815
4618
|
setLeftSession: split.setLeftSession,
|
|
@@ -3824,14 +4627,12 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3824
4627
|
setSidebarWidth: persistSidebarWidth,
|
|
3825
4628
|
nicknameInput,
|
|
3826
4629
|
filterInput,
|
|
3827
|
-
onNickname: (id) => {
|
|
3828
|
-
clearNickname(id);
|
|
3829
|
-
refresh();
|
|
3830
|
-
},
|
|
3831
4630
|
onClearNickname: (id) => {
|
|
3832
4631
|
clearNickname(id);
|
|
3833
4632
|
refresh();
|
|
3834
4633
|
},
|
|
4634
|
+
onTogglePin: handleTogglePin,
|
|
4635
|
+
onMovePinned: handleMovePinned,
|
|
3835
4636
|
onArchive: (id) => {
|
|
3836
4637
|
archiveSession(id);
|
|
3837
4638
|
refreshArchived();
|
|
@@ -3883,10 +4684,10 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3883
4684
|
setup.setShowSetup(false);
|
|
3884
4685
|
return null;
|
|
3885
4686
|
}
|
|
3886
|
-
return /* @__PURE__ */
|
|
4687
|
+
return /* @__PURE__ */ jsx18(SetupModal, { steps, onComplete: setup.handleSetupComplete });
|
|
3887
4688
|
}
|
|
3888
4689
|
if (setup.showThemePicker)
|
|
3889
|
-
return /* @__PURE__ */
|
|
4690
|
+
return /* @__PURE__ */ jsx18(
|
|
3890
4691
|
ThemePickerModal,
|
|
3891
4692
|
{
|
|
3892
4693
|
onSelect: setup.handleThemePickerSelect,
|
|
@@ -3894,10 +4695,22 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3894
4695
|
onDismiss: setup.handleThemePickerDismiss
|
|
3895
4696
|
}
|
|
3896
4697
|
);
|
|
3897
|
-
if (setup.showTour) return /* @__PURE__ */
|
|
3898
|
-
if (setup.showThemeMenu) return /* @__PURE__ */
|
|
4698
|
+
if (setup.showTour) return /* @__PURE__ */ jsx18(GuidedTour, { onComplete: setup.handleTourComplete, onSkip: setup.handleTourSkip });
|
|
4699
|
+
if (setup.showThemeMenu) return /* @__PURE__ */ jsx18(ThemeMenu, { config: setup.liveConfig, onClose: setup.handleThemeMenuClose });
|
|
4700
|
+
if (showAlertRules)
|
|
4701
|
+
return /* @__PURE__ */ jsx18(
|
|
4702
|
+
AlertRulesMenu,
|
|
4703
|
+
{
|
|
4704
|
+
config: setup.liveConfig,
|
|
4705
|
+
onClose: () => setShowAlertRules(false),
|
|
4706
|
+
onSave: (newConfig) => {
|
|
4707
|
+
saveConfig(newConfig);
|
|
4708
|
+
setup.setLiveConfig(newConfig);
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4711
|
+
);
|
|
3899
4712
|
if (setup.showSettings)
|
|
3900
|
-
return /* @__PURE__ */
|
|
4713
|
+
return /* @__PURE__ */ jsx18(
|
|
3901
4714
|
SettingsMenu,
|
|
3902
4715
|
{
|
|
3903
4716
|
config: setup.liveConfig,
|
|
@@ -3906,7 +4719,7 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3906
4719
|
}
|
|
3907
4720
|
);
|
|
3908
4721
|
if (showUpdateModal && updateInfo?.available) {
|
|
3909
|
-
return /* @__PURE__ */
|
|
4722
|
+
return /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", height: termHeight, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx18(
|
|
3910
4723
|
UpdateModal,
|
|
3911
4724
|
{
|
|
3912
4725
|
current: updateInfo.current,
|
|
@@ -3923,7 +4736,7 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3923
4736
|
) });
|
|
3924
4737
|
}
|
|
3925
4738
|
if (confirmAction) {
|
|
3926
|
-
return /* @__PURE__ */
|
|
4739
|
+
return /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", height: termHeight, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx18(
|
|
3927
4740
|
ConfirmModal,
|
|
3928
4741
|
{
|
|
3929
4742
|
title: confirmAction.title,
|
|
@@ -3936,7 +4749,7 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3936
4749
|
const activitySlug = selectedGroup ? selectedGroup.key : selectedSession?.slug ?? null;
|
|
3937
4750
|
const isMerged = selectedGroup !== null;
|
|
3938
4751
|
const selectedEvent = events[selectedEventIndex];
|
|
3939
|
-
const rightPanel = split.splitMode ? /* @__PURE__ */
|
|
4752
|
+
const rightPanel = split.splitMode ? /* @__PURE__ */ jsx18(
|
|
3940
4753
|
SplitPanel,
|
|
3941
4754
|
{
|
|
3942
4755
|
activePanel,
|
|
@@ -3952,13 +4765,13 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3952
4765
|
rightShowDetail: split.rightShowDetail,
|
|
3953
4766
|
height: mainHeight
|
|
3954
4767
|
}
|
|
3955
|
-
) : showEventDetail && selectedEvent ? /* @__PURE__ */
|
|
4768
|
+
) : showEventDetail && selectedEvent ? /* @__PURE__ */ jsx18(ToolCallDetail, { event: selectedEvent, focused: activePanel === "activity", height: mainHeight }) : showDetail && selectedSession ? /* @__PURE__ */ jsx18(SessionDetail, { session: selectedSession, focused: activePanel === "activity", height: mainHeight }) : /* @__PURE__ */ jsx18(
|
|
3956
4769
|
ActivityFeed,
|
|
3957
4770
|
{
|
|
3958
4771
|
events,
|
|
3959
4772
|
sessionSlug: activitySlug,
|
|
3960
4773
|
sessionId: selectedSession?.sessionId,
|
|
3961
|
-
|
|
4774
|
+
status: selectedGroup ? selectedGroup.status : selectedSession ? selectedSession.status : void 0,
|
|
3962
4775
|
focused: activePanel === "activity",
|
|
3963
4776
|
height: mainHeight,
|
|
3964
4777
|
scrollOffset: activityScroll,
|
|
@@ -3968,10 +4781,10 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3968
4781
|
selectedEventIndex
|
|
3969
4782
|
}
|
|
3970
4783
|
);
|
|
3971
|
-
return /* @__PURE__ */
|
|
3972
|
-
/* @__PURE__ */
|
|
3973
|
-
/* @__PURE__ */
|
|
3974
|
-
/* @__PURE__ */
|
|
4784
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", height: termHeight, children: [
|
|
4785
|
+
/* @__PURE__ */ jsx18(StatusBar, { sessionCount: sessions2.length, alertCount: alerts.length, version, updateInfo }),
|
|
4786
|
+
/* @__PURE__ */ jsxs18(Box18, { flexGrow: 1, height: mainHeight, children: [
|
|
4787
|
+
/* @__PURE__ */ jsx18(
|
|
3975
4788
|
SessionList,
|
|
3976
4789
|
{
|
|
3977
4790
|
visibleItems,
|
|
@@ -3984,21 +4797,21 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
3984
4797
|
sidebarWidth
|
|
3985
4798
|
}
|
|
3986
4799
|
),
|
|
3987
|
-
/* @__PURE__ */
|
|
4800
|
+
/* @__PURE__ */ jsx18(Box18, { flexGrow: 1, flexShrink: 1, minWidth: 0, overflow: "hidden", children: rightPanel })
|
|
3988
4801
|
] }),
|
|
3989
|
-
!options2.noSecurity && /* @__PURE__ */
|
|
3990
|
-
inputMode === "nickname" && /* @__PURE__ */
|
|
3991
|
-
/* @__PURE__ */
|
|
3992
|
-
/* @__PURE__ */
|
|
3993
|
-
/* @__PURE__ */
|
|
4802
|
+
!options2.noSecurity && /* @__PURE__ */ jsx18(AlertBar, { alerts }),
|
|
4803
|
+
inputMode === "nickname" && /* @__PURE__ */ jsxs18(Box18, { paddingX: 1, children: [
|
|
4804
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.primary, children: "nickname: " }),
|
|
4805
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.bright, children: nicknameInput.value }),
|
|
4806
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.muted, children: "_" })
|
|
3994
4807
|
] }),
|
|
3995
|
-
inputMode === "filter" && /* @__PURE__ */
|
|
3996
|
-
/* @__PURE__ */
|
|
3997
|
-
/* @__PURE__ */
|
|
3998
|
-
/* @__PURE__ */
|
|
3999
|
-
/* @__PURE__ */
|
|
4808
|
+
inputMode === "filter" && /* @__PURE__ */ jsxs18(Box18, { paddingX: 1, children: [
|
|
4809
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.muted, children: activePanel === "sessions" ? "sessions" : activePanel === "left" ? "left" : activePanel === "right" ? "right" : "activity" }),
|
|
4810
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.primary, children: "/" }),
|
|
4811
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.bright, children: filterInput.value }),
|
|
4812
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.muted, children: "_" })
|
|
4000
4813
|
] }),
|
|
4001
|
-
inputMode === "normal" && /* @__PURE__ */
|
|
4814
|
+
inputMode === "normal" && /* @__PURE__ */ jsx18(
|
|
4002
4815
|
FooterBar,
|
|
4003
4816
|
{
|
|
4004
4817
|
keybindings: kb,
|
|
@@ -4014,11 +4827,6 @@ var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
|
4014
4827
|
var write = (msg) => {
|
|
4015
4828
|
process.stdout.write(msg + "\n");
|
|
4016
4829
|
};
|
|
4017
|
-
var formatTokens3 = (n) => {
|
|
4018
|
-
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
4019
|
-
if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
|
|
4020
|
-
return String(n);
|
|
4021
|
-
};
|
|
4022
4830
|
var runStreamMode = (options2, isJson) => {
|
|
4023
4831
|
const engine = options2.noSecurity ? null : new SecurityEngine(options2.alertLevel);
|
|
4024
4832
|
const sessions2 = discoverSessions(options2.allUsers);
|
|
@@ -4027,7 +4835,7 @@ var runStreamMode = (options2, isJson) => {
|
|
|
4027
4835
|
} else {
|
|
4028
4836
|
for (const s of sessions2) {
|
|
4029
4837
|
write(
|
|
4030
|
-
`SESSION ${s.slug} | ${s.model} | ${s.cwd} | CPU ${s.cpu}% | ${s.memMB}MB | ${
|
|
4838
|
+
`SESSION ${s.slug} | ${s.status} | ${s.model} | ${s.cwd} | CPU ${s.cpu}% | ${s.memMB}MB | ${formatTokens(s.usage.inputTokens)} in / ${formatTokens(s.usage.outputTokens)} out`
|
|
4031
4839
|
);
|
|
4032
4840
|
}
|
|
4033
4841
|
}
|
|
@@ -4060,7 +4868,7 @@ var runStreamMode = (options2, isJson) => {
|
|
|
4060
4868
|
write(JSON.stringify({ type: "usage", data: { sessionId, usage } }));
|
|
4061
4869
|
} else {
|
|
4062
4870
|
write(
|
|
4063
|
-
`USAGE ${sessionId.slice(0, 12)} +${
|
|
4871
|
+
`USAGE ${sessionId.slice(0, 12)} +${formatTokens(usage.inputTokens)} in / +${formatTokens(usage.outputTokens)} out`
|
|
4064
4872
|
);
|
|
4065
4873
|
}
|
|
4066
4874
|
};
|
|
@@ -4244,7 +5052,7 @@ var main = () => {
|
|
|
4244
5052
|
if (options2.noUpdates) config.updates.checkOnLaunch = false;
|
|
4245
5053
|
if (options2.noSecurity) config.security.enabled = false;
|
|
4246
5054
|
if (firstRun) saveConfig(config);
|
|
4247
|
-
render(
|
|
5055
|
+
render(React19.createElement(App, { options: options2, config, version: VERSION, firstRun }));
|
|
4248
5056
|
};
|
|
4249
5057
|
main();
|
|
4250
5058
|
//# sourceMappingURL=index.js.map
|