agenttop 0.10.6 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -20
- package/dist/{chunk-24HX2MSZ.js → chunk-LPXME2WB.js} +572 -54
- package/dist/chunk-LPXME2WB.js.map +1 -0
- package/dist/index.js +1260 -365
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-24HX2MSZ.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-LPXME2WB.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 useCallback7 } 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 {
|
|
@@ -397,6 +657,14 @@ var installUpdate = () => {
|
|
|
397
657
|
});
|
|
398
658
|
});
|
|
399
659
|
};
|
|
660
|
+
var restartProcess = () => {
|
|
661
|
+
const child = spawn(process.argv[0], process.argv.slice(1), {
|
|
662
|
+
detached: true,
|
|
663
|
+
stdio: "inherit"
|
|
664
|
+
});
|
|
665
|
+
child.unref();
|
|
666
|
+
process.exit(0);
|
|
667
|
+
};
|
|
400
668
|
var compareVersions = (a, b) => {
|
|
401
669
|
const pa = a.split(".").map(Number);
|
|
402
670
|
const pb = b.split(".").map(Number);
|
|
@@ -421,12 +689,15 @@ var colors = {
|
|
|
421
689
|
warning: "#E5C07B",
|
|
422
690
|
error: "#E06C75",
|
|
423
691
|
critical: "#FF0000",
|
|
692
|
+
success: "#98C379",
|
|
424
693
|
muted: "#5C6370",
|
|
425
694
|
text: "#ABB2BF",
|
|
426
695
|
bright: "#FFFFFF",
|
|
427
696
|
border: "#3E4451",
|
|
428
697
|
selected: "#2C313A",
|
|
429
|
-
header: "#61AFEF"
|
|
698
|
+
header: "#61AFEF",
|
|
699
|
+
waiting: "#E5C07B",
|
|
700
|
+
stale: "#D19A66"
|
|
430
701
|
};
|
|
431
702
|
var severityColors = {
|
|
432
703
|
info: colors.muted,
|
|
@@ -448,6 +719,7 @@ var toolColors = {
|
|
|
448
719
|
var getToolColor = (toolName) => toolColors[toolName] || colors.text;
|
|
449
720
|
var applyTheme = (theme) => {
|
|
450
721
|
Object.assign(colors, theme.colors);
|
|
722
|
+
colors.success = theme.colors.secondary;
|
|
451
723
|
Object.assign(toolColors, theme.toolColors);
|
|
452
724
|
Object.assign(severityColors, deriveSeverityColors(theme.colors));
|
|
453
725
|
};
|
|
@@ -488,18 +760,32 @@ var StatusBar = React.memo(({ sessionCount, alertCount, version, updateInfo }) =
|
|
|
488
760
|
// src/ui/components/SessionList.tsx
|
|
489
761
|
import React2 from "react";
|
|
490
762
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
491
|
-
|
|
763
|
+
|
|
764
|
+
// src/ui/format.ts
|
|
765
|
+
var formatTokens = (n) => {
|
|
766
|
+
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
767
|
+
if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
|
|
768
|
+
return String(n);
|
|
769
|
+
};
|
|
770
|
+
var formatTime = (ts) => {
|
|
771
|
+
const d = new Date(ts);
|
|
772
|
+
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
773
|
+
};
|
|
492
774
|
var formatModel = (model) => {
|
|
775
|
+
if (model.includes("opus")) return "opus";
|
|
776
|
+
if (model.includes("sonnet")) return "sonnet";
|
|
777
|
+
if (model.includes("haiku")) return "haiku";
|
|
778
|
+
return model.slice(0, 4);
|
|
779
|
+
};
|
|
780
|
+
var formatModelShort = (model) => {
|
|
493
781
|
if (model.includes("opus")) return "opus";
|
|
494
782
|
if (model.includes("sonnet")) return "son";
|
|
495
783
|
if (model.includes("haiku")) return "hai";
|
|
496
784
|
return model.slice(0, 4);
|
|
497
785
|
};
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return String(n);
|
|
502
|
-
};
|
|
786
|
+
|
|
787
|
+
// src/ui/components/SessionList.tsx
|
|
788
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
503
789
|
var truncate = (s, max) => s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
504
790
|
var getDisplayName = (s) => {
|
|
505
791
|
if (s.nickname) return s.nickname;
|
|
@@ -559,11 +845,14 @@ var SessionList = React2.memo(
|
|
|
559
845
|
if (item.type === "group") {
|
|
560
846
|
const g = item.group;
|
|
561
847
|
const arrow = g.expanded ? "\u25BE" : "\u25B8";
|
|
562
|
-
const dotColor2 = g.
|
|
563
|
-
const statusDot2 = g.
|
|
564
|
-
const nameColor2 = isSelected ? colors.bright : g.
|
|
565
|
-
const
|
|
566
|
-
const
|
|
848
|
+
const dotColor2 = g.status === "waiting" ? colors.waiting : g.status === "stale" ? colors.stale : g.status === "active" ? colors.success : colors.muted;
|
|
849
|
+
const statusDot2 = g.status === "inactive" ? "\u25CB" : "\u25CF";
|
|
850
|
+
const nameColor2 = isSelected ? colors.bright : g.status !== "inactive" ? colors.secondary : colors.text;
|
|
851
|
+
const groupPinned = g.sessions.some((s) => s.pinned);
|
|
852
|
+
const pinMarker2 = groupPinned ? "* " : " ";
|
|
853
|
+
const statusTag2 = g.status === "waiting" ? " [waiting]" : g.status === "stale" ? " [stale]" : "";
|
|
854
|
+
const label2 = truncate(`${g.key} (${g.sessions.length})${statusTag2}`, INNER_WIDTH - 4);
|
|
855
|
+
const model2 = formatModelShort(g.latestModel);
|
|
567
856
|
return /* @__PURE__ */ jsxs2(
|
|
568
857
|
Box2,
|
|
569
858
|
{
|
|
@@ -576,6 +865,7 @@ var SessionList = React2.memo(
|
|
|
576
865
|
" ",
|
|
577
866
|
/* @__PURE__ */ jsx2(Text2, { color: dotColor2, children: statusDot2 }),
|
|
578
867
|
" ",
|
|
868
|
+
pinMarker2,
|
|
579
869
|
label2
|
|
580
870
|
] }),
|
|
581
871
|
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? colors.text : colors.muted, wrap: "truncate", children: [
|
|
@@ -594,14 +884,15 @@ var SessionList = React2.memo(
|
|
|
594
884
|
);
|
|
595
885
|
}
|
|
596
886
|
const session = item.type === "session" ? item.session : item.session;
|
|
597
|
-
const
|
|
598
|
-
const statusDot =
|
|
599
|
-
const
|
|
887
|
+
const dotColor = session.status === "waiting" ? colors.waiting : session.status === "stale" ? colors.stale : session.status === "active" ? colors.success : colors.muted;
|
|
888
|
+
const statusDot = session.status === "inactive" ? "\u25CB" : "\u25CF";
|
|
889
|
+
const pinMarker = session.pinned ? "* " : " ";
|
|
890
|
+
const statusTag = session.status === "waiting" ? " [waiting]" : session.status === "stale" ? " [stale]" : "";
|
|
600
891
|
const totalIn = session.usage.inputTokens + session.usage.cacheReadTokens;
|
|
601
|
-
const model =
|
|
892
|
+
const model = formatModelShort(session.model);
|
|
602
893
|
if (item.type === "session") {
|
|
603
|
-
const nameColor2 = isSelected ? colors.bright :
|
|
604
|
-
const displayName2 = truncate(session.nickname || session.slug
|
|
894
|
+
const nameColor2 = isSelected ? colors.bright : session.status !== "inactive" ? colors.secondary : colors.muted;
|
|
895
|
+
const displayName2 = truncate(`${session.nickname || session.slug}${statusTag}`, INNER_WIDTH - 6);
|
|
605
896
|
return /* @__PURE__ */ jsxs2(
|
|
606
897
|
Box2,
|
|
607
898
|
{
|
|
@@ -614,6 +905,7 @@ var SessionList = React2.memo(
|
|
|
614
905
|
" ",
|
|
615
906
|
/* @__PURE__ */ jsx2(Text2, { color: dotColor, children: statusDot }),
|
|
616
907
|
" ",
|
|
908
|
+
pinMarker,
|
|
617
909
|
displayName2
|
|
618
910
|
] }),
|
|
619
911
|
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? colors.text : colors.muted, wrap: "truncate", children: [
|
|
@@ -632,8 +924,8 @@ var SessionList = React2.memo(
|
|
|
632
924
|
);
|
|
633
925
|
}
|
|
634
926
|
const indicator = isSelected ? "\u25B8" : " ";
|
|
635
|
-
const nameColor = isSelected ? colors.bright :
|
|
636
|
-
const displayName = truncate(getDisplayName(session)
|
|
927
|
+
const nameColor = isSelected ? colors.bright : session.status !== "inactive" ? colors.secondary : colors.text;
|
|
928
|
+
const displayName = truncate(`${getDisplayName(session)}${statusTag}`, INNER_WIDTH - 4);
|
|
637
929
|
return /* @__PURE__ */ jsxs2(
|
|
638
930
|
Box2,
|
|
639
931
|
{
|
|
@@ -646,6 +938,7 @@ var SessionList = React2.memo(
|
|
|
646
938
|
" ",
|
|
647
939
|
/* @__PURE__ */ jsx2(Text2, { color: dotColor, children: statusDot }),
|
|
648
940
|
" ",
|
|
941
|
+
pinMarker,
|
|
649
942
|
displayName
|
|
650
943
|
] }),
|
|
651
944
|
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? colors.text : colors.muted, wrap: "truncate", children: [
|
|
@@ -674,10 +967,6 @@ import React3 from "react";
|
|
|
674
967
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
675
968
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
676
969
|
var TAG_COLORS = ["#61AFEF", "#98C379", "#C678DD", "#E5C07B", "#E06C75", "#56B6C2", "#D19A66", "#BE5046"];
|
|
677
|
-
var formatTime = (ts) => {
|
|
678
|
-
const d = new Date(ts);
|
|
679
|
-
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
680
|
-
};
|
|
681
970
|
var summarizeInput = (call) => {
|
|
682
971
|
const input = call.toolInput;
|
|
683
972
|
switch (call.toolName) {
|
|
@@ -705,7 +994,7 @@ var ActivityFeed = React3.memo(
|
|
|
705
994
|
events,
|
|
706
995
|
sessionSlug,
|
|
707
996
|
sessionId,
|
|
708
|
-
|
|
997
|
+
status,
|
|
709
998
|
focused,
|
|
710
999
|
height,
|
|
711
1000
|
scrollOffset,
|
|
@@ -782,7 +1071,7 @@ var ActivityFeed = React3.memo(
|
|
|
782
1071
|
] }) }, `${call.timestamp}-${i}`);
|
|
783
1072
|
}),
|
|
784
1073
|
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 " }) }),
|
|
785
|
-
!merged && sessionId &&
|
|
1074
|
+
!merged && sessionId && status === "inactive" && /* @__PURE__ */ jsxs3(Box3, { paddingX: 1, flexDirection: "column", children: [
|
|
786
1075
|
/* @__PURE__ */ jsx3(Text3, { color: colors.muted, children: " " }),
|
|
787
1076
|
/* @__PURE__ */ jsxs3(Text3, { color: colors.muted, children: [
|
|
788
1077
|
"resume: ",
|
|
@@ -807,10 +1096,6 @@ var ActivityFeed = React3.memo(
|
|
|
807
1096
|
import React4 from "react";
|
|
808
1097
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
809
1098
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
810
|
-
var formatTime2 = (ts) => {
|
|
811
|
-
const d = new Date(ts);
|
|
812
|
-
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
813
|
-
};
|
|
814
1099
|
var severityIcon = {
|
|
815
1100
|
info: "i",
|
|
816
1101
|
warn: "!",
|
|
@@ -832,7 +1117,7 @@ var AlertBar = React4.memo(({ alerts, maxVisible = 4 }) => {
|
|
|
832
1117
|
] }),
|
|
833
1118
|
/* @__PURE__ */ jsxs4(Text4, { color: colors.muted, children: [
|
|
834
1119
|
" ",
|
|
835
|
-
|
|
1120
|
+
formatTime(alert.timestamp),
|
|
836
1121
|
" "
|
|
837
1122
|
] }),
|
|
838
1123
|
/* @__PURE__ */ jsxs4(Text4, { color: colors.warning, children: [
|
|
@@ -848,11 +1133,6 @@ var AlertBar = React4.memo(({ alerts, maxVisible = 4 }) => {
|
|
|
848
1133
|
import React5 from "react";
|
|
849
1134
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
850
1135
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
851
|
-
var formatTokens2 = (n) => {
|
|
852
|
-
if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
|
|
853
|
-
if (n >= 1e3) return (n / 1e3).toFixed(1) + "k";
|
|
854
|
-
return String(n);
|
|
855
|
-
};
|
|
856
1136
|
var formatUptime = (startTime) => {
|
|
857
1137
|
const ms = Date.now() - startTime;
|
|
858
1138
|
const secs = Math.floor(ms / 1e3);
|
|
@@ -862,12 +1142,6 @@ var formatUptime = (startTime) => {
|
|
|
862
1142
|
if (mins > 0) return `${mins}m ${secs % 60}s`;
|
|
863
1143
|
return `${secs}s`;
|
|
864
1144
|
};
|
|
865
|
-
var formatModel2 = (model) => {
|
|
866
|
-
if (model.includes("opus")) return "opus";
|
|
867
|
-
if (model.includes("sonnet")) return "sonnet";
|
|
868
|
-
if (model.includes("haiku")) return "haiku";
|
|
869
|
-
return model.slice(0, 20);
|
|
870
|
-
};
|
|
871
1145
|
var SessionDetail = React5.memo(({ session, focused }) => {
|
|
872
1146
|
const totalInput = session.usage.inputTokens + session.usage.cacheCreationTokens + session.usage.cacheReadTokens;
|
|
873
1147
|
const totalTokens = totalInput + session.usage.outputTokens;
|
|
@@ -895,7 +1169,7 @@ var SessionDetail = React5.memo(({ session, focused }) => {
|
|
|
895
1169
|
] }),
|
|
896
1170
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
897
1171
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: "model: " }),
|
|
898
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1172
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatModel(session.model) })
|
|
899
1173
|
] }),
|
|
900
1174
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
901
1175
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: "cwd: " }),
|
|
@@ -938,19 +1212,19 @@ var SessionDetail = React5.memo(({ session, focused }) => {
|
|
|
938
1212
|
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: colors.header, bold: true, children: "Token usage" }) }),
|
|
939
1213
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
940
1214
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " input: " }),
|
|
941
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1215
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.inputTokens) })
|
|
942
1216
|
] }),
|
|
943
1217
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
944
1218
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " output: " }),
|
|
945
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1219
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.outputTokens) })
|
|
946
1220
|
] }),
|
|
947
1221
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
948
1222
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " cache write: " }),
|
|
949
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1223
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.cacheCreationTokens) })
|
|
950
1224
|
] }),
|
|
951
1225
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
952
1226
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " cache read: " }),
|
|
953
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children:
|
|
1227
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.text, children: formatTokens(session.usage.cacheReadTokens) })
|
|
954
1228
|
] }),
|
|
955
1229
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
956
1230
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " cache hit: " }),
|
|
@@ -961,7 +1235,7 @@ var SessionDetail = React5.memo(({ session, focused }) => {
|
|
|
961
1235
|
] }),
|
|
962
1236
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
963
1237
|
/* @__PURE__ */ jsx5(Text5, { color: colors.muted, children: " total: " }),
|
|
964
|
-
/* @__PURE__ */ jsx5(Text5, { color: colors.bright, bold: true, children:
|
|
1238
|
+
/* @__PURE__ */ jsx5(Text5, { color: colors.bright, bold: true, children: formatTokens(totalTokens) })
|
|
965
1239
|
] })
|
|
966
1240
|
] })
|
|
967
1241
|
]
|
|
@@ -1101,10 +1375,6 @@ var FooterBar = React7.memo(
|
|
|
1101
1375
|
import React8, { useState as useState3 } from "react";
|
|
1102
1376
|
import { Box as Box8, Text as Text8, useInput as useInput2 } from "ink";
|
|
1103
1377
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1104
|
-
var formatTime3 = (ts) => {
|
|
1105
|
-
const d = new Date(ts);
|
|
1106
|
-
return d.toLocaleTimeString("en-GB", { hour12: false });
|
|
1107
|
-
};
|
|
1108
1378
|
var renderBash = (event) => {
|
|
1109
1379
|
const lines = [];
|
|
1110
1380
|
const cmd = String(event.call.toolInput.command || "");
|
|
@@ -1278,7 +1548,7 @@ var ToolCallDetail = React8.memo(({ event, focused, height }) => {
|
|
|
1278
1548
|
/* @__PURE__ */ jsx8(Text8, { color: getToolColor(event.call.toolName), bold: true, children: event.call.toolName }),
|
|
1279
1549
|
/* @__PURE__ */ jsxs8(Text8, { color: colors.muted, children: [
|
|
1280
1550
|
" ",
|
|
1281
|
-
|
|
1551
|
+
formatTime(event.call.timestamp)
|
|
1282
1552
|
] }),
|
|
1283
1553
|
/* @__PURE__ */ jsxs8(Text8, { color: colors.muted, children: [
|
|
1284
1554
|
" ",
|
|
@@ -1962,23 +2232,451 @@ var ThemeMenu = React11.memo(({ config, onClose }) => {
|
|
|
1962
2232
|
/* @__PURE__ */ jsx11(Text11, { color: theme.colors.error, children: "\u2588" })
|
|
1963
2233
|
] }, theme.name);
|
|
1964
2234
|
}),
|
|
1965
|
-
toast && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx11(Text11, { color: colors.warning, children: toast }) })
|
|
2235
|
+
toast && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx11(Text11, { color: colors.warning, children: toast }) }),
|
|
2236
|
+
/* @__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)." }) })
|
|
1966
2237
|
]
|
|
1967
2238
|
}
|
|
1968
2239
|
) });
|
|
1969
2240
|
});
|
|
1970
2241
|
|
|
1971
|
-
// src/ui/components/
|
|
1972
|
-
import React12, { useState as useState7, useEffect as useEffect4 } from "react";
|
|
1973
|
-
import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
|
|
2242
|
+
// src/ui/components/AlertRulesMenu.tsx
|
|
2243
|
+
import React12, { useState as useState7, useRef as useRef3, useEffect as useEffect4 } from "react";
|
|
2244
|
+
import { Box as Box12, Text as Text12, useInput as useInput6, useStdout as useStdout3 } from "ink";
|
|
1974
2245
|
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1975
|
-
var
|
|
1976
|
-
|
|
2246
|
+
var MATCH_OPTIONS = ["input", "output", "toolName", "all"];
|
|
2247
|
+
var SEVERITY_OPTIONS2 = ["info", "warn", "high", "critical"];
|
|
2248
|
+
var RULE_LABELS2 = {
|
|
2249
|
+
network: "Network detection",
|
|
2250
|
+
exfiltration: "Exfiltration detection",
|
|
2251
|
+
sensitiveFiles: "Sensitive files",
|
|
2252
|
+
shellEscape: "Shell escape",
|
|
2253
|
+
injection: "Prompt injection"
|
|
2254
|
+
};
|
|
2255
|
+
var BUILTIN_RULE_KEYS = Object.keys(RULE_LABELS2);
|
|
2256
|
+
var FORM_FIELDS = ["name", "pattern", "match", "severity", "message"];
|
|
2257
|
+
var FORM_LABELS = {
|
|
2258
|
+
name: "Name",
|
|
2259
|
+
pattern: "Pattern (regex)",
|
|
2260
|
+
match: "Match target",
|
|
2261
|
+
severity: "Severity",
|
|
2262
|
+
message: "Message"
|
|
2263
|
+
};
|
|
2264
|
+
var emptyForm = () => ({
|
|
2265
|
+
name: "",
|
|
2266
|
+
pattern: "",
|
|
2267
|
+
match: "all",
|
|
2268
|
+
severity: "warn",
|
|
2269
|
+
message: ""
|
|
2270
|
+
});
|
|
2271
|
+
var formFromRule = (rule) => ({
|
|
2272
|
+
name: rule.name,
|
|
2273
|
+
pattern: rule.pattern,
|
|
2274
|
+
match: rule.match,
|
|
2275
|
+
severity: rule.severity,
|
|
2276
|
+
message: rule.message
|
|
2277
|
+
});
|
|
2278
|
+
var validatePattern = (pattern) => {
|
|
2279
|
+
if (!pattern.trim()) return "Pattern cannot be empty";
|
|
2280
|
+
try {
|
|
2281
|
+
new RegExp(pattern);
|
|
2282
|
+
return null;
|
|
2283
|
+
} catch {
|
|
2284
|
+
return "Invalid regex";
|
|
2285
|
+
}
|
|
2286
|
+
};
|
|
2287
|
+
var AlertRulesMenu = React12.memo(({ config, onClose, onSave }) => {
|
|
2288
|
+
const { stdout } = useStdout3();
|
|
2289
|
+
const termHeight = stdout?.rows ?? 40;
|
|
2290
|
+
const [localConfig, setLocalConfig] = useState7(() => JSON.parse(JSON.stringify(config)));
|
|
2291
|
+
const [selectedIdx, setSelectedIdx] = useState7(0);
|
|
2292
|
+
const [view, setView] = useState7("list");
|
|
2293
|
+
const [toast, setToast] = useState7("");
|
|
2294
|
+
const toastTimer = useRef3(null);
|
|
2295
|
+
const [formData, setFormData] = useState7(emptyForm());
|
|
2296
|
+
const [formField, setFormField] = useState7(0);
|
|
2297
|
+
const [formError, setFormError] = useState7("");
|
|
2298
|
+
const [editingIndex, setEditingIndex] = useState7(null);
|
|
2299
|
+
useEffect4(
|
|
2300
|
+
() => () => {
|
|
2301
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2302
|
+
},
|
|
2303
|
+
[]
|
|
2304
|
+
);
|
|
2305
|
+
const showToast = (msg) => {
|
|
2306
|
+
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2307
|
+
setToast(msg);
|
|
2308
|
+
toastTimer.current = setTimeout(() => setToast(""), 2500);
|
|
2309
|
+
};
|
|
2310
|
+
const customRules = localConfig.alerts.custom || [];
|
|
2311
|
+
const totalItems = 1 + BUILTIN_RULE_KEYS.length + customRules.length;
|
|
2312
|
+
const isStaleRow = (idx) => idx === 0;
|
|
2313
|
+
const isBuiltinRow = (idx) => idx >= 1 && idx <= BUILTIN_RULE_KEYS.length;
|
|
2314
|
+
const isCustomRow = (idx) => idx > BUILTIN_RULE_KEYS.length;
|
|
2315
|
+
const getBuiltinKey = (idx) => BUILTIN_RULE_KEYS[idx - 1];
|
|
2316
|
+
const getCustomIndex = (idx) => idx - BUILTIN_RULE_KEYS.length - 1;
|
|
2317
|
+
useInput6((input, key) => {
|
|
2318
|
+
if (view === "form") {
|
|
2319
|
+
const currentField = FORM_FIELDS[formField];
|
|
2320
|
+
if (key.escape) {
|
|
2321
|
+
setView("list");
|
|
2322
|
+
setFormError("");
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
if (currentField === "match") {
|
|
2326
|
+
if (key.return || input === " ") {
|
|
2327
|
+
const idx = MATCH_OPTIONS.indexOf(formData.match);
|
|
2328
|
+
setFormData((f) => ({ ...f, match: MATCH_OPTIONS[(idx + 1) % MATCH_OPTIONS.length] }));
|
|
2329
|
+
return;
|
|
2330
|
+
}
|
|
2331
|
+
if (key.downArrow) {
|
|
2332
|
+
setFormField((f) => Math.min(f + 1, FORM_FIELDS.length - 1));
|
|
2333
|
+
return;
|
|
2334
|
+
}
|
|
2335
|
+
if (key.upArrow) {
|
|
2336
|
+
setFormField((f) => Math.max(f - 1, 0));
|
|
2337
|
+
return;
|
|
2338
|
+
}
|
|
2339
|
+
if (key.tab) {
|
|
2340
|
+
if (formField < FORM_FIELDS.length - 1) {
|
|
2341
|
+
setFormField((f) => f + 1);
|
|
2342
|
+
}
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
2345
|
+
return;
|
|
2346
|
+
}
|
|
2347
|
+
if (currentField === "severity") {
|
|
2348
|
+
if (key.return || input === " ") {
|
|
2349
|
+
const idx = SEVERITY_OPTIONS2.indexOf(formData.severity);
|
|
2350
|
+
setFormData((f) => ({ ...f, severity: SEVERITY_OPTIONS2[(idx + 1) % SEVERITY_OPTIONS2.length] }));
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
if (key.downArrow) {
|
|
2354
|
+
setFormField((f) => Math.min(f + 1, FORM_FIELDS.length - 1));
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
if (key.upArrow) {
|
|
2358
|
+
setFormField((f) => Math.max(f - 1, 0));
|
|
2359
|
+
return;
|
|
2360
|
+
}
|
|
2361
|
+
if (key.tab) {
|
|
2362
|
+
if (formField < FORM_FIELDS.length - 1) {
|
|
2363
|
+
setFormField((f) => f + 1);
|
|
2364
|
+
}
|
|
2365
|
+
return;
|
|
2366
|
+
}
|
|
2367
|
+
return;
|
|
2368
|
+
}
|
|
2369
|
+
if (key.return) {
|
|
2370
|
+
if (currentField === "pattern") {
|
|
2371
|
+
const err = validatePattern(formData.pattern);
|
|
2372
|
+
if (err) {
|
|
2373
|
+
setFormError(err);
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
setFormError("");
|
|
2377
|
+
}
|
|
2378
|
+
if (formField < FORM_FIELDS.length - 1) {
|
|
2379
|
+
setFormField((f) => f + 1);
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
if (!formData.name.trim()) {
|
|
2383
|
+
setFormError("Name cannot be empty");
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
const patErr = validatePattern(formData.pattern);
|
|
2387
|
+
if (patErr) {
|
|
2388
|
+
setFormError(patErr);
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
const newRule = {
|
|
2392
|
+
name: formData.name.trim(),
|
|
2393
|
+
pattern: formData.pattern,
|
|
2394
|
+
match: formData.match,
|
|
2395
|
+
severity: formData.severity,
|
|
2396
|
+
message: formData.message.trim(),
|
|
2397
|
+
enabled: true
|
|
2398
|
+
};
|
|
2399
|
+
setLocalConfig((c) => {
|
|
2400
|
+
const customs = [...c.alerts.custom || []];
|
|
2401
|
+
if (editingIndex !== null) {
|
|
2402
|
+
newRule.enabled = customs[editingIndex].enabled;
|
|
2403
|
+
customs[editingIndex] = newRule;
|
|
2404
|
+
} else {
|
|
2405
|
+
customs.push(newRule);
|
|
2406
|
+
}
|
|
2407
|
+
const updated = { ...c, alerts: { ...c.alerts, custom: customs } };
|
|
2408
|
+
onSave(updated);
|
|
2409
|
+
return updated;
|
|
2410
|
+
});
|
|
2411
|
+
showToast(editingIndex !== null ? `Updated '${newRule.name}'` : `Added '${newRule.name}'`);
|
|
2412
|
+
setView("list");
|
|
2413
|
+
setFormError("");
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
if (key.backspace || key.delete) {
|
|
2417
|
+
setFormData((f) => ({ ...f, [currentField]: f[currentField].slice(0, -1) }));
|
|
2418
|
+
setFormError("");
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
if (key.upArrow) {
|
|
2422
|
+
setFormField((f) => Math.max(f - 1, 0));
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
if (key.downArrow || key.tab) {
|
|
2426
|
+
if (currentField === "pattern") {
|
|
2427
|
+
const err = validatePattern(formData.pattern);
|
|
2428
|
+
if (err && formData.pattern.trim()) {
|
|
2429
|
+
setFormError(err);
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
setFormField((f) => Math.min(f + 1, FORM_FIELDS.length - 1));
|
|
2434
|
+
return;
|
|
2435
|
+
}
|
|
2436
|
+
if (input && input.length === 1) {
|
|
2437
|
+
setFormData((f) => ({ ...f, [currentField]: f[currentField] + input }));
|
|
2438
|
+
setFormError("");
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
if (key.escape) {
|
|
2444
|
+
onSave(localConfig);
|
|
2445
|
+
onClose();
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
if (key.upArrow) {
|
|
2449
|
+
setSelectedIdx((i) => Math.max(0, i - 1));
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
if (key.downArrow) {
|
|
2453
|
+
setSelectedIdx((i) => Math.min(totalItems - 1, i + 1));
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
if (input === " ") {
|
|
2457
|
+
if (isStaleRow(selectedIdx)) return;
|
|
2458
|
+
if (isBuiltinRow(selectedIdx)) {
|
|
2459
|
+
const ruleKey = getBuiltinKey(selectedIdx);
|
|
2460
|
+
setLocalConfig((c) => {
|
|
2461
|
+
const updated = {
|
|
2462
|
+
...c,
|
|
2463
|
+
security: { ...c.security, rules: { ...c.security.rules, [ruleKey]: !c.security.rules[ruleKey] } }
|
|
2464
|
+
};
|
|
2465
|
+
onSave(updated);
|
|
2466
|
+
return updated;
|
|
2467
|
+
});
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
if (isCustomRow(selectedIdx)) {
|
|
2471
|
+
const ci = getCustomIndex(selectedIdx);
|
|
2472
|
+
setLocalConfig((c) => {
|
|
2473
|
+
const customs = [...c.alerts.custom || []];
|
|
2474
|
+
customs[ci] = { ...customs[ci], enabled: !customs[ci].enabled };
|
|
2475
|
+
const updated = { ...c, alerts: { ...c.alerts, custom: customs } };
|
|
2476
|
+
onSave(updated);
|
|
2477
|
+
return updated;
|
|
2478
|
+
});
|
|
2479
|
+
return;
|
|
2480
|
+
}
|
|
2481
|
+
return;
|
|
2482
|
+
}
|
|
2483
|
+
if (isStaleRow(selectedIdx)) {
|
|
2484
|
+
if (input === "+" || input === "=") {
|
|
2485
|
+
setLocalConfig((c) => {
|
|
2486
|
+
const updated = { ...c, alerts: { ...c.alerts, staleTimeout: c.alerts.staleTimeout + 15 } };
|
|
2487
|
+
onSave(updated);
|
|
2488
|
+
return updated;
|
|
2489
|
+
});
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
if (input === "-" || input === "_") {
|
|
2493
|
+
setLocalConfig((c) => {
|
|
2494
|
+
const newTimeout = Math.max(15, c.alerts.staleTimeout - 15);
|
|
2495
|
+
const updated = { ...c, alerts: { ...c.alerts, staleTimeout: newTimeout } };
|
|
2496
|
+
onSave(updated);
|
|
2497
|
+
return updated;
|
|
2498
|
+
});
|
|
2499
|
+
return;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
if (input === "n") {
|
|
2503
|
+
setFormData(emptyForm());
|
|
2504
|
+
setFormField(0);
|
|
2505
|
+
setEditingIndex(null);
|
|
2506
|
+
setFormError("");
|
|
2507
|
+
setView("form");
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
if (input === "e" && isCustomRow(selectedIdx)) {
|
|
2511
|
+
const ci = getCustomIndex(selectedIdx);
|
|
2512
|
+
const rule = customRules[ci];
|
|
2513
|
+
setFormData(formFromRule(rule));
|
|
2514
|
+
setFormField(0);
|
|
2515
|
+
setEditingIndex(ci);
|
|
2516
|
+
setFormError("");
|
|
2517
|
+
setView("form");
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
if (input === "d" && isCustomRow(selectedIdx)) {
|
|
2521
|
+
const ci = getCustomIndex(selectedIdx);
|
|
2522
|
+
const name = customRules[ci].name;
|
|
2523
|
+
setLocalConfig((c) => {
|
|
2524
|
+
const customs = [...c.alerts.custom || []];
|
|
2525
|
+
customs.splice(ci, 1);
|
|
2526
|
+
const updated = { ...c, alerts: { ...c.alerts, custom: customs } };
|
|
2527
|
+
onSave(updated);
|
|
2528
|
+
return updated;
|
|
2529
|
+
});
|
|
2530
|
+
setSelectedIdx((i) => Math.min(i, totalItems - 2));
|
|
2531
|
+
showToast(`Deleted '${name}'`);
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2534
|
+
});
|
|
2535
|
+
if (view === "form") {
|
|
2536
|
+
const currentField = FORM_FIELDS[formField];
|
|
2537
|
+
return /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsxs12(
|
|
2538
|
+
Box12,
|
|
2539
|
+
{
|
|
2540
|
+
borderStyle: "round",
|
|
2541
|
+
borderColor: colors.primary,
|
|
2542
|
+
flexDirection: "column",
|
|
2543
|
+
paddingX: 2,
|
|
2544
|
+
paddingY: 1,
|
|
2545
|
+
height: termHeight,
|
|
2546
|
+
children: [
|
|
2547
|
+
/* @__PURE__ */ jsxs12(Box12, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
2548
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.header, bold: true, children: editingIndex !== null ? "EDIT RULE" : "NEW RULE" }),
|
|
2549
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: "enter:next/save esc:cancel" })
|
|
2550
|
+
] }),
|
|
2551
|
+
FORM_FIELDS.map((field, fi) => {
|
|
2552
|
+
const isCurrent = fi === formField;
|
|
2553
|
+
const value = formData[field];
|
|
2554
|
+
const isTextInput = field === "name" || field === "pattern" || field === "message";
|
|
2555
|
+
const displayValue = isTextInput ? isCurrent ? `${value}_` : value || "(empty)" : field === "match" ? `${value} (space to cycle)` : `${value} (space to cycle)`;
|
|
2556
|
+
return /* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2557
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isCurrent ? colors.primary : colors.text, children: [
|
|
2558
|
+
isCurrent ? "> " : " ",
|
|
2559
|
+
FORM_LABELS[field],
|
|
2560
|
+
":",
|
|
2561
|
+
" "
|
|
2562
|
+
] }),
|
|
2563
|
+
/* @__PURE__ */ jsx12(Text12, { color: isCurrent ? colors.bright : colors.muted, children: displayValue })
|
|
2564
|
+
] }, field);
|
|
2565
|
+
}),
|
|
2566
|
+
formError && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx12(Text12, { color: colors.error, children: formError }) }),
|
|
2567
|
+
/* @__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" }) })
|
|
2568
|
+
]
|
|
2569
|
+
}
|
|
2570
|
+
) });
|
|
2571
|
+
}
|
|
2572
|
+
const contentHeight = termHeight - 6;
|
|
2573
|
+
const halfView = Math.floor(contentHeight / 2);
|
|
2574
|
+
const scrollStart = Math.max(0, Math.min(selectedIdx - halfView, totalItems - contentHeight));
|
|
2575
|
+
const visibleStart = Math.max(0, scrollStart);
|
|
2576
|
+
const visibleEnd = Math.min(totalItems, visibleStart + contentHeight);
|
|
2577
|
+
return /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", height: termHeight, children: /* @__PURE__ */ jsxs12(
|
|
2578
|
+
Box12,
|
|
2579
|
+
{
|
|
2580
|
+
borderStyle: "round",
|
|
2581
|
+
borderColor: colors.primary,
|
|
2582
|
+
flexDirection: "column",
|
|
2583
|
+
paddingX: 2,
|
|
2584
|
+
paddingY: 1,
|
|
2585
|
+
height: termHeight,
|
|
2586
|
+
children: [
|
|
2587
|
+
/* @__PURE__ */ jsxs12(Box12, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
2588
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.header, bold: true, children: "ALERT RULES" }),
|
|
2589
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: "space:toggle n:new e:edit d:delete esc:close" })
|
|
2590
|
+
] }),
|
|
2591
|
+
visibleStart === 0 && /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text12, { color: colors.accent, bold: true, children: [
|
|
2592
|
+
" ",
|
|
2593
|
+
"STALE SESSION"
|
|
2594
|
+
] }) }) }),
|
|
2595
|
+
Array.from({ length: visibleEnd - visibleStart }, (_, vi) => {
|
|
2596
|
+
const idx = visibleStart + vi;
|
|
2597
|
+
const isSelected = idx === selectedIdx;
|
|
2598
|
+
if (isStaleRow(idx)) {
|
|
2599
|
+
const timeout = localConfig.alerts.staleTimeout;
|
|
2600
|
+
return /* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2601
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isSelected ? colors.primary : colors.text, children: [
|
|
2602
|
+
isSelected ? "> " : " ",
|
|
2603
|
+
" Stale timeout ",
|
|
2604
|
+
"............ "
|
|
2605
|
+
] }),
|
|
2606
|
+
/* @__PURE__ */ jsxs12(Text12, { color: colors.bright, children: [
|
|
2607
|
+
timeout,
|
|
2608
|
+
"s"
|
|
2609
|
+
] }),
|
|
2610
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.muted, children: " (+/-)" })
|
|
2611
|
+
] }, "stale-timeout");
|
|
2612
|
+
}
|
|
2613
|
+
if (isBuiltinRow(idx)) {
|
|
2614
|
+
const ruleKey = getBuiltinKey(idx);
|
|
2615
|
+
const label2 = RULE_LABELS2[ruleKey];
|
|
2616
|
+
const enabled = localConfig.security.rules[ruleKey];
|
|
2617
|
+
const showHeader = idx === 1 && visibleStart <= 1;
|
|
2618
|
+
return /* @__PURE__ */ jsxs12(React12.Fragment, { children: [
|
|
2619
|
+
showHeader && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text12, { color: colors.accent, bold: true, children: [
|
|
2620
|
+
" ",
|
|
2621
|
+
"BUILT-IN RULES"
|
|
2622
|
+
] }) }),
|
|
2623
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2624
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isSelected ? colors.primary : colors.text, children: [
|
|
2625
|
+
isSelected ? "> " : " ",
|
|
2626
|
+
" ",
|
|
2627
|
+
label2,
|
|
2628
|
+
" ",
|
|
2629
|
+
".".repeat(Math.max(2, 28 - label2.length)),
|
|
2630
|
+
" "
|
|
2631
|
+
] }),
|
|
2632
|
+
/* @__PURE__ */ jsx12(Text12, { color: enabled ? colors.secondary : colors.error, children: enabled ? "ON" : "OFF" })
|
|
2633
|
+
] })
|
|
2634
|
+
] }, `builtin-${ruleKey}`);
|
|
2635
|
+
}
|
|
2636
|
+
if (isCustomRow(idx)) {
|
|
2637
|
+
const ci = getCustomIndex(idx);
|
|
2638
|
+
const rule = customRules[ci];
|
|
2639
|
+
const showHeader = ci === 0;
|
|
2640
|
+
return /* @__PURE__ */ jsxs12(React12.Fragment, { children: [
|
|
2641
|
+
showHeader && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text12, { color: colors.accent, bold: true, children: [
|
|
2642
|
+
" ",
|
|
2643
|
+
"CUSTOM RULES"
|
|
2644
|
+
] }) }),
|
|
2645
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
2646
|
+
/* @__PURE__ */ jsxs12(Text12, { color: isSelected ? colors.primary : colors.text, children: [
|
|
2647
|
+
isSelected ? "> " : " ",
|
|
2648
|
+
" ",
|
|
2649
|
+
rule.name,
|
|
2650
|
+
" "
|
|
2651
|
+
] }),
|
|
2652
|
+
/* @__PURE__ */ jsxs12(Text12, { color: colors.muted, children: [
|
|
2653
|
+
"/",
|
|
2654
|
+
rule.pattern,
|
|
2655
|
+
"/ "
|
|
2656
|
+
] }),
|
|
2657
|
+
/* @__PURE__ */ jsx12(Text12, { color: rule.enabled ? colors.secondary : colors.error, children: rule.enabled ? "ON" : "OFF" })
|
|
2658
|
+
] })
|
|
2659
|
+
] }, `custom-${ci}`);
|
|
2660
|
+
}
|
|
2661
|
+
return null;
|
|
2662
|
+
}),
|
|
2663
|
+
toast && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, paddingX: 2, children: /* @__PURE__ */ jsx12(Text12, { color: colors.warning, children: toast }) })
|
|
2664
|
+
]
|
|
2665
|
+
}
|
|
2666
|
+
) });
|
|
2667
|
+
});
|
|
2668
|
+
|
|
2669
|
+
// src/ui/components/ThemePickerModal.tsx
|
|
2670
|
+
import React13, { useState as useState8, useEffect as useEffect5 } from "react";
|
|
2671
|
+
import { Box as Box13, Text as Text13, useInput as useInput7 } from "ink";
|
|
2672
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2673
|
+
var ThemePickerModal = React13.memo(({ onSelect, onSkip, onDismiss }) => {
|
|
2674
|
+
const [selectedIndex, setSelectedIndex] = useState8(0);
|
|
1977
2675
|
const themes = BUILTIN_THEMES;
|
|
1978
|
-
|
|
2676
|
+
useEffect5(() => {
|
|
1979
2677
|
applyTheme(themes[selectedIndex]);
|
|
1980
2678
|
}, [selectedIndex]);
|
|
1981
|
-
|
|
2679
|
+
useInput7((input, key) => {
|
|
1982
2680
|
if (key.upArrow) setSelectedIndex((i) => Math.max(0, i - 1));
|
|
1983
2681
|
if (key.downArrow) setSelectedIndex((i) => Math.min(themes.length - 1, i + 1));
|
|
1984
2682
|
if (key.return) onSelect(themes[selectedIndex].name);
|
|
@@ -1987,33 +2685,33 @@ var ThemePickerModal = React12.memo(({ onSelect, onSkip, onDismiss }) => {
|
|
|
1987
2685
|
});
|
|
1988
2686
|
const renderSwatch = (theme) => {
|
|
1989
2687
|
const c = theme.colors;
|
|
1990
|
-
return /* @__PURE__ */
|
|
1991
|
-
/* @__PURE__ */
|
|
1992
|
-
/* @__PURE__ */
|
|
1993
|
-
/* @__PURE__ */
|
|
1994
|
-
/* @__PURE__ */
|
|
1995
|
-
/* @__PURE__ */
|
|
2688
|
+
return /* @__PURE__ */ jsxs13(Text13, { children: [
|
|
2689
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.primary, children: "\u2588" }),
|
|
2690
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.secondary, children: "\u2588" }),
|
|
2691
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.accent, children: "\u2588" }),
|
|
2692
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.warning, children: "\u2588" }),
|
|
2693
|
+
/* @__PURE__ */ jsx13(Text13, { color: c.error, children: "\u2588" })
|
|
1996
2694
|
] });
|
|
1997
2695
|
};
|
|
1998
|
-
return /* @__PURE__ */
|
|
1999
|
-
/* @__PURE__ */
|
|
2000
|
-
/* @__PURE__ */
|
|
2001
|
-
themes.map((theme, i) => /* @__PURE__ */
|
|
2002
|
-
/* @__PURE__ */
|
|
2696
|
+
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: [
|
|
2697
|
+
/* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.header, bold: true, children: "Choose a theme" }) }),
|
|
2698
|
+
/* @__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)." }) }),
|
|
2699
|
+
themes.map((theme, i) => /* @__PURE__ */ jsxs13(Box13, { children: [
|
|
2700
|
+
/* @__PURE__ */ jsx13(Text13, { color: i === selectedIndex ? colors.primary : colors.muted, children: i === selectedIndex ? "> " : " " }),
|
|
2003
2701
|
renderSwatch(theme),
|
|
2004
|
-
/* @__PURE__ */
|
|
2702
|
+
/* @__PURE__ */ jsxs13(Text13, { color: i === selectedIndex ? colors.bright : colors.text, children: [
|
|
2005
2703
|
" ",
|
|
2006
2704
|
theme.name
|
|
2007
2705
|
] })
|
|
2008
2706
|
] }, theme.name)),
|
|
2009
|
-
/* @__PURE__ */
|
|
2707
|
+
/* @__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" }) })
|
|
2010
2708
|
] }) });
|
|
2011
2709
|
});
|
|
2012
2710
|
|
|
2013
2711
|
// src/ui/components/GuidedTour.tsx
|
|
2014
|
-
import
|
|
2015
|
-
import { Box as
|
|
2016
|
-
import { jsx as
|
|
2712
|
+
import React14, { useState as useState9 } from "react";
|
|
2713
|
+
import { Box as Box14, Text as Text14, useInput as useInput8 } from "ink";
|
|
2714
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2017
2715
|
var STEPS = [
|
|
2018
2716
|
{
|
|
2019
2717
|
title: "Session list",
|
|
@@ -2044,11 +2742,11 @@ var STEPS = [
|
|
|
2044
2742
|
body: "Press s to open settings. Customise keybindings, manage themes, and configure updates."
|
|
2045
2743
|
}
|
|
2046
2744
|
];
|
|
2047
|
-
var GuidedTour =
|
|
2048
|
-
const [stepIndex, setStepIndex] =
|
|
2745
|
+
var GuidedTour = React14.memo(({ onComplete, onSkip }) => {
|
|
2746
|
+
const [stepIndex, setStepIndex] = useState9(0);
|
|
2049
2747
|
const step = STEPS[stepIndex];
|
|
2050
2748
|
const isLast = stepIndex === STEPS.length - 1;
|
|
2051
|
-
|
|
2749
|
+
useInput8((input, key) => {
|
|
2052
2750
|
if (key.return || key.rightArrow) {
|
|
2053
2751
|
if (isLast) onComplete();
|
|
2054
2752
|
else setStepIndex((i) => i + 1);
|
|
@@ -2056,17 +2754,17 @@ var GuidedTour = React13.memo(({ onComplete, onSkip }) => {
|
|
|
2056
2754
|
if (key.leftArrow && stepIndex > 0) setStepIndex((i) => i - 1);
|
|
2057
2755
|
if (input === "q" || key.escape) onSkip();
|
|
2058
2756
|
});
|
|
2059
|
-
return /* @__PURE__ */
|
|
2060
|
-
/* @__PURE__ */
|
|
2757
|
+
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: [
|
|
2758
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsxs14(Text14, { color: colors.header, bold: true, children: [
|
|
2061
2759
|
"Quick tour (",
|
|
2062
2760
|
stepIndex + 1,
|
|
2063
2761
|
"/",
|
|
2064
2762
|
STEPS.length,
|
|
2065
2763
|
")"
|
|
2066
2764
|
] }) }),
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
2069
|
-
/* @__PURE__ */
|
|
2765
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.bright, bold: true, children: step.title }) }),
|
|
2766
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: step.body }) }),
|
|
2767
|
+
/* @__PURE__ */ jsxs14(Text14, { color: colors.muted, children: [
|
|
2070
2768
|
isLast ? "Enter = finish" : "Enter/\u2192 = next",
|
|
2071
2769
|
" | ",
|
|
2072
2770
|
stepIndex > 0 ? "\u2190 = back | " : "",
|
|
@@ -2076,19 +2774,19 @@ var GuidedTour = React13.memo(({ onComplete, onSkip }) => {
|
|
|
2076
2774
|
});
|
|
2077
2775
|
|
|
2078
2776
|
// src/ui/components/ConfirmModal.tsx
|
|
2079
|
-
import
|
|
2080
|
-
import { Box as
|
|
2081
|
-
import { jsx as
|
|
2082
|
-
var ConfirmModal =
|
|
2083
|
-
|
|
2777
|
+
import React15 from "react";
|
|
2778
|
+
import { Box as Box15, Text as Text15, useInput as useInput9 } from "ink";
|
|
2779
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2780
|
+
var ConfirmModal = React15.memo(({ title, message, onConfirm, onCancel }) => {
|
|
2781
|
+
useInput9((input, key) => {
|
|
2084
2782
|
if (input === "y" || input === "Y") {
|
|
2085
2783
|
onConfirm();
|
|
2086
2784
|
} else if (input === "n" || input === "N" || key.escape) {
|
|
2087
2785
|
onCancel();
|
|
2088
2786
|
}
|
|
2089
2787
|
});
|
|
2090
|
-
return /* @__PURE__ */
|
|
2091
|
-
|
|
2788
|
+
return /* @__PURE__ */ jsxs15(
|
|
2789
|
+
Box15,
|
|
2092
2790
|
{
|
|
2093
2791
|
borderStyle: "round",
|
|
2094
2792
|
borderColor: colors.warning,
|
|
@@ -2097,19 +2795,105 @@ var ConfirmModal = React14.memo(({ title, message, onConfirm, onCancel }) => {
|
|
|
2097
2795
|
paddingY: 1,
|
|
2098
2796
|
alignSelf: "center",
|
|
2099
2797
|
children: [
|
|
2100
|
-
/* @__PURE__ */
|
|
2101
|
-
/* @__PURE__ */
|
|
2102
|
-
/* @__PURE__ */
|
|
2798
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.warning, bold: true, children: title }),
|
|
2799
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, children: message }),
|
|
2800
|
+
/* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.muted, children: "[y] confirm [n/esc] cancel" }) })
|
|
2801
|
+
]
|
|
2802
|
+
}
|
|
2803
|
+
);
|
|
2804
|
+
});
|
|
2805
|
+
|
|
2806
|
+
// src/ui/components/UpdateModal.tsx
|
|
2807
|
+
import React16, { useState as useState10, useCallback as useCallback2 } from "react";
|
|
2808
|
+
import { Box as Box16, Text as Text16, useInput as useInput10 } from "ink";
|
|
2809
|
+
import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2810
|
+
var options = [
|
|
2811
|
+
{ key: "now", label: "Update now" },
|
|
2812
|
+
{ key: "later", label: "Not now" },
|
|
2813
|
+
{ key: "never", label: "Don't ask again" }
|
|
2814
|
+
];
|
|
2815
|
+
var UpdateModal = React16.memo(({ current, latest, onNotNow, onDontAskAgain }) => {
|
|
2816
|
+
const [selected, setSelected] = useState10(0);
|
|
2817
|
+
const [status, setStatus] = useState10("idle");
|
|
2818
|
+
const [errorMsg, setErrorMsg] = useState10("");
|
|
2819
|
+
const doUpdate = useCallback2(() => {
|
|
2820
|
+
setStatus("updating");
|
|
2821
|
+
installUpdate().then(() => {
|
|
2822
|
+
setStatus("restarting");
|
|
2823
|
+
setTimeout(() => restartProcess(), 500);
|
|
2824
|
+
}).catch((err) => {
|
|
2825
|
+
setErrorMsg(err.message || "update failed");
|
|
2826
|
+
setStatus("error");
|
|
2827
|
+
});
|
|
2828
|
+
}, []);
|
|
2829
|
+
useInput10((input, key) => {
|
|
2830
|
+
if (status === "updating" || status === "restarting") return;
|
|
2831
|
+
if (status === "error") {
|
|
2832
|
+
if (key.escape || key.return) {
|
|
2833
|
+
setStatus("idle");
|
|
2834
|
+
setErrorMsg("");
|
|
2835
|
+
}
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
if (key.upArrow || input === "k") {
|
|
2839
|
+
setSelected((s) => s > 0 ? s - 1 : options.length - 1);
|
|
2840
|
+
return;
|
|
2841
|
+
}
|
|
2842
|
+
if (key.downArrow || input === "j") {
|
|
2843
|
+
setSelected((s) => s < options.length - 1 ? s + 1 : 0);
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
if (key.escape) {
|
|
2847
|
+
onNotNow();
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
if (key.return) {
|
|
2851
|
+
const choice = options[selected].key;
|
|
2852
|
+
if (choice === "now") {
|
|
2853
|
+
doUpdate();
|
|
2854
|
+
} else if (choice === "later") {
|
|
2855
|
+
onNotNow();
|
|
2856
|
+
} else {
|
|
2857
|
+
onDontAskAgain();
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
});
|
|
2861
|
+
return /* @__PURE__ */ jsxs16(
|
|
2862
|
+
Box16,
|
|
2863
|
+
{
|
|
2864
|
+
borderStyle: "round",
|
|
2865
|
+
borderColor: colors.primary,
|
|
2866
|
+
flexDirection: "column",
|
|
2867
|
+
paddingX: 2,
|
|
2868
|
+
paddingY: 1,
|
|
2869
|
+
alignSelf: "center",
|
|
2870
|
+
children: [
|
|
2871
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.primary, bold: true, children: "Update available" }),
|
|
2872
|
+
/* @__PURE__ */ jsxs16(Text16, { color: colors.text, children: [
|
|
2873
|
+
"v",
|
|
2874
|
+
current,
|
|
2875
|
+
" ",
|
|
2876
|
+
"->",
|
|
2877
|
+
" v",
|
|
2878
|
+
latest
|
|
2879
|
+
] }),
|
|
2880
|
+
/* @__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: [
|
|
2881
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.error, children: errorMsg }),
|
|
2882
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.muted, children: "press enter to continue" })
|
|
2883
|
+
] }) : options.map((opt, i) => /* @__PURE__ */ jsxs16(Text16, { color: i === selected ? colors.primary : colors.muted, children: [
|
|
2884
|
+
i === selected ? "> " : " ",
|
|
2885
|
+
opt.label
|
|
2886
|
+
] }, opt.key)) })
|
|
2103
2887
|
]
|
|
2104
2888
|
}
|
|
2105
2889
|
);
|
|
2106
2890
|
});
|
|
2107
2891
|
|
|
2108
2892
|
// src/ui/components/SplitPanel.tsx
|
|
2109
|
-
import
|
|
2110
|
-
import { Box as
|
|
2111
|
-
import { jsx as
|
|
2112
|
-
var SplitPanel =
|
|
2893
|
+
import React17 from "react";
|
|
2894
|
+
import { Box as Box17 } from "ink";
|
|
2895
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2896
|
+
var SplitPanel = React17.memo(
|
|
2113
2897
|
({
|
|
2114
2898
|
activePanel,
|
|
2115
2899
|
leftSession,
|
|
@@ -2124,35 +2908,35 @@ var SplitPanel = React15.memo(
|
|
|
2124
2908
|
rightShowDetail,
|
|
2125
2909
|
height
|
|
2126
2910
|
}) => {
|
|
2127
|
-
const left = leftShowDetail && leftSession ? /* @__PURE__ */
|
|
2911
|
+
const left = leftShowDetail && leftSession ? /* @__PURE__ */ jsx17(SessionDetail, { session: leftSession, focused: activePanel === "left", height }) : /* @__PURE__ */ jsx17(
|
|
2128
2912
|
ActivityFeed,
|
|
2129
2913
|
{
|
|
2130
2914
|
events: leftEvents,
|
|
2131
2915
|
sessionSlug: leftSession?.slug ?? null,
|
|
2132
2916
|
sessionId: leftSession?.sessionId,
|
|
2133
|
-
|
|
2917
|
+
status: leftSession ? leftSession.status : void 0,
|
|
2134
2918
|
focused: activePanel === "left",
|
|
2135
2919
|
height,
|
|
2136
2920
|
scrollOffset: leftScroll,
|
|
2137
2921
|
filter: leftFilter || void 0
|
|
2138
2922
|
}
|
|
2139
2923
|
);
|
|
2140
|
-
const right = rightShowDetail && rightSession ? /* @__PURE__ */
|
|
2924
|
+
const right = rightShowDetail && rightSession ? /* @__PURE__ */ jsx17(SessionDetail, { session: rightSession, focused: activePanel === "right", height }) : /* @__PURE__ */ jsx17(
|
|
2141
2925
|
ActivityFeed,
|
|
2142
2926
|
{
|
|
2143
2927
|
events: rightEvents,
|
|
2144
2928
|
sessionSlug: rightSession?.slug ?? null,
|
|
2145
2929
|
sessionId: rightSession?.sessionId,
|
|
2146
|
-
|
|
2930
|
+
status: rightSession ? rightSession.status : void 0,
|
|
2147
2931
|
focused: activePanel === "right",
|
|
2148
2932
|
height,
|
|
2149
2933
|
scrollOffset: rightScroll,
|
|
2150
2934
|
filter: rightFilter || void 0
|
|
2151
2935
|
}
|
|
2152
2936
|
);
|
|
2153
|
-
return /* @__PURE__ */
|
|
2154
|
-
/* @__PURE__ */
|
|
2155
|
-
|
|
2937
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "row", flexGrow: 1, children: [
|
|
2938
|
+
/* @__PURE__ */ jsx17(
|
|
2939
|
+
Box17,
|
|
2156
2940
|
{
|
|
2157
2941
|
flexGrow: 1,
|
|
2158
2942
|
borderStyle: "single",
|
|
@@ -2170,10 +2954,10 @@ var SplitPanel = React15.memo(
|
|
|
2170
2954
|
);
|
|
2171
2955
|
|
|
2172
2956
|
// src/ui/hooks/useSessions.ts
|
|
2173
|
-
import { useState as
|
|
2957
|
+
import { useState as useState11, useEffect as useEffect6, useCallback as useCallback3, useRef as useRef4, useMemo as useMemo2 } from "react";
|
|
2174
2958
|
|
|
2175
2959
|
// src/discovery/sessionsAsync.ts
|
|
2176
|
-
import { readdir, stat as stat2 } from "fs/promises";
|
|
2960
|
+
import { readdir, stat as stat2, open as open2 } from "fs/promises";
|
|
2177
2961
|
import { join as join2, basename } from "path";
|
|
2178
2962
|
|
|
2179
2963
|
// src/discovery/cache.ts
|
|
@@ -2212,44 +2996,9 @@ var pruneFileMetaCache = (validPaths) => {
|
|
|
2212
2996
|
};
|
|
2213
2997
|
|
|
2214
2998
|
// src/discovery/asyncHelpers.ts
|
|
2215
|
-
import {
|
|
2216
|
-
import {
|
|
2217
|
-
var normalisePath = (p) => p.replace(
|
|
2218
|
-
var getClaudeProcessesAsync = async () => {
|
|
2219
|
-
const stdout = await new Promise((resolve) => {
|
|
2220
|
-
execFile2("ps", ["aux"], { encoding: "utf-8", timeout: 5e3, maxBuffer: 4 * 1024 * 1024 }, (err, out) => {
|
|
2221
|
-
resolve(err || !out ? "" : out);
|
|
2222
|
-
});
|
|
2223
|
-
});
|
|
2224
|
-
if (!stdout) return [];
|
|
2225
|
-
const procs = [];
|
|
2226
|
-
for (const line of stdout.split("\n")) {
|
|
2227
|
-
if (!line.includes("/claude") || line.includes("grep") || line.includes("agenttop")) continue;
|
|
2228
|
-
const parts = line.trim().split(/\s+/);
|
|
2229
|
-
const pid = parseInt(parts[1], 10);
|
|
2230
|
-
if (isNaN(pid)) continue;
|
|
2231
|
-
const command = parts.slice(10).join(" ");
|
|
2232
|
-
if (command.startsWith("sudo")) continue;
|
|
2233
|
-
procs.push({
|
|
2234
|
-
pid,
|
|
2235
|
-
cpu: parseFloat(parts[2]) || 0,
|
|
2236
|
-
mem: parseFloat(parts[3]) || 0,
|
|
2237
|
-
memKB: parseInt(parts[5], 10) || 0,
|
|
2238
|
-
startTime: parts[8] || "",
|
|
2239
|
-
command,
|
|
2240
|
-
cwd: ""
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
await Promise.all(
|
|
2244
|
-
procs.map(async (p) => {
|
|
2245
|
-
try {
|
|
2246
|
-
p.cwd = await readlink(`/proc/${p.pid}/cwd`);
|
|
2247
|
-
} catch {
|
|
2248
|
-
}
|
|
2249
|
-
})
|
|
2250
|
-
);
|
|
2251
|
-
return procs;
|
|
2252
|
-
};
|
|
2999
|
+
import { open, stat } from "fs/promises";
|
|
3000
|
+
import { normalize } from "path";
|
|
3001
|
+
var normalisePath = (p) => normalize(p).replace(/[\\/]+$/, "");
|
|
2253
3002
|
var readFirstLinesAsync = async (filePath, bytes) => {
|
|
2254
3003
|
let fh;
|
|
2255
3004
|
try {
|
|
@@ -2367,7 +3116,47 @@ var findModelAndUsageAsync = async (filePath) => {
|
|
|
2367
3116
|
};
|
|
2368
3117
|
|
|
2369
3118
|
// src/discovery/sessionsAsync.ts
|
|
2370
|
-
var
|
|
3119
|
+
var readTailBytesAsync = async (filePath, bytes) => {
|
|
3120
|
+
let fh;
|
|
3121
|
+
try {
|
|
3122
|
+
fh = await open2(filePath, "r");
|
|
3123
|
+
const fstat = await stat2(filePath);
|
|
3124
|
+
const start = Math.max(0, fstat.size - bytes);
|
|
3125
|
+
const readSize = Math.min(bytes, fstat.size);
|
|
3126
|
+
const buf = Buffer.alloc(readSize);
|
|
3127
|
+
await fh.read(buf, 0, readSize, start);
|
|
3128
|
+
return buf.toString("utf-8");
|
|
3129
|
+
} catch {
|
|
3130
|
+
return "";
|
|
3131
|
+
} finally {
|
|
3132
|
+
await fh?.close();
|
|
3133
|
+
}
|
|
3134
|
+
};
|
|
3135
|
+
var detectStatusAsync = async (filePath, hasPid, lastActivity, staleTimeout) => {
|
|
3136
|
+
if (!hasPid) return "inactive";
|
|
3137
|
+
const tail = await readTailBytesAsync(filePath, 4096);
|
|
3138
|
+
const lines = tail.split("\n").filter(Boolean);
|
|
3139
|
+
if (lines.length > 0) {
|
|
3140
|
+
try {
|
|
3141
|
+
const lastEvent = JSON.parse(lines[lines.length - 1]);
|
|
3142
|
+
if (lastEvent.type === "assistant") {
|
|
3143
|
+
const content = lastEvent.message?.content;
|
|
3144
|
+
if (Array.isArray(content)) {
|
|
3145
|
+
const hasAskUser = content.some(
|
|
3146
|
+
(b) => b.type === "tool_use" && b.name === "AskUserQuestion"
|
|
3147
|
+
);
|
|
3148
|
+
if (hasAskUser) return "waiting";
|
|
3149
|
+
const hasToolUse = content.some((b) => b.type === "tool_use");
|
|
3150
|
+
if (!hasToolUse) return "waiting";
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
} catch {
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
if (Date.now() - lastActivity > staleTimeout * 1e3) return "stale";
|
|
3157
|
+
return "active";
|
|
3158
|
+
};
|
|
3159
|
+
var discoverFromProjectsAsync = async (allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder) => {
|
|
2371
3160
|
const projectsDirs = getProjectsDirs(allUsers);
|
|
2372
3161
|
for (const projectsDir of projectsDirs) {
|
|
2373
3162
|
let projectNames;
|
|
@@ -2422,14 +3211,16 @@ var discoverFromProjectsAsync = async (allUsers, processes, sessionMap, seenFile
|
|
|
2422
3211
|
outputFiles: [filePath],
|
|
2423
3212
|
startTime: fstat.birthtimeMs || fstat.ctimeMs,
|
|
2424
3213
|
lastActivity: fstat.mtimeMs,
|
|
2425
|
-
usage: meta.usage
|
|
3214
|
+
usage: meta.usage,
|
|
3215
|
+
status: await detectStatusAsync(filePath, matchingProcess !== void 0, fstat.mtimeMs, staleTimeout),
|
|
3216
|
+
pinned: pinnedOrder.includes(meta.sessionId)
|
|
2426
3217
|
};
|
|
2427
3218
|
sessionMap.set(meta.sessionId, session);
|
|
2428
3219
|
}
|
|
2429
3220
|
}
|
|
2430
3221
|
}
|
|
2431
3222
|
};
|
|
2432
|
-
var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) => {
|
|
3223
|
+
var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder) => {
|
|
2433
3224
|
const taskDirs = getTaskDirs(allUsers);
|
|
2434
3225
|
for (const taskDir of taskDirs) {
|
|
2435
3226
|
let projectDirs;
|
|
@@ -2519,6 +3310,13 @@ var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) =>
|
|
|
2519
3310
|
if (sessionMap.has(sessionId || projectName)) continue;
|
|
2520
3311
|
const normCwd = normalisePath(cwd);
|
|
2521
3312
|
const matchingProcess = processes.find((p) => p.cwd && normalisePath(p.cwd) === normCwd);
|
|
3313
|
+
let latestFile = outputFiles[0];
|
|
3314
|
+
for (const f of outputFiles) {
|
|
3315
|
+
try {
|
|
3316
|
+
if ((await stat2(f)).mtimeMs > (await stat2(latestFile)).mtimeMs) latestFile = f;
|
|
3317
|
+
} catch {
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
2522
3320
|
const session = {
|
|
2523
3321
|
sessionId,
|
|
2524
3322
|
slug: slug || sessionId.slice(0, 12),
|
|
@@ -2536,7 +3334,9 @@ var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) =>
|
|
|
2536
3334
|
outputFiles,
|
|
2537
3335
|
startTime: startTime === Infinity ? Date.now() : startTime,
|
|
2538
3336
|
lastActivity,
|
|
2539
|
-
usage: totalUsage
|
|
3337
|
+
usage: totalUsage,
|
|
3338
|
+
status: await detectStatusAsync(latestFile, matchingProcess !== void 0, lastActivity, staleTimeout),
|
|
3339
|
+
pinned: pinnedOrder.includes(sessionId)
|
|
2540
3340
|
};
|
|
2541
3341
|
sessionMap.set(sessionId || projectName, session);
|
|
2542
3342
|
}
|
|
@@ -2544,16 +3344,26 @@ var discoverFromTmpAsync = async (allUsers, processes, sessionMap, seenFiles) =>
|
|
|
2544
3344
|
}
|
|
2545
3345
|
};
|
|
2546
3346
|
var discoverSessionsAsync = async (allUsers) => {
|
|
3347
|
+
const config = loadConfig();
|
|
3348
|
+
const staleTimeout = config.alerts.staleTimeout ?? 60;
|
|
3349
|
+
const pinnedOrder = config.pinnedSessions ?? [];
|
|
2547
3350
|
const processes = await getClaudeProcessesAsync();
|
|
2548
3351
|
const sessionMap = /* @__PURE__ */ new Map();
|
|
2549
3352
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
2550
|
-
await discoverFromProjectsAsync(allUsers, processes, sessionMap, seenFiles);
|
|
2551
|
-
await discoverFromTmpAsync(allUsers, processes, sessionMap, seenFiles);
|
|
3353
|
+
await discoverFromProjectsAsync(allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder);
|
|
3354
|
+
await discoverFromTmpAsync(allUsers, processes, sessionMap, seenFiles, staleTimeout, pinnedOrder);
|
|
2552
3355
|
pruneFileMetaCache(seenFiles);
|
|
2553
3356
|
return Array.from(sessionMap.values()).sort((a, b) => {
|
|
2554
|
-
const
|
|
2555
|
-
const
|
|
2556
|
-
|
|
3357
|
+
const aPin = pinnedOrder.indexOf(a.sessionId);
|
|
3358
|
+
const bPin = pinnedOrder.indexOf(b.sessionId);
|
|
3359
|
+
const aIsPinned = aPin !== -1;
|
|
3360
|
+
const bIsPinned = bPin !== -1;
|
|
3361
|
+
if (aIsPinned && !bIsPinned) return -1;
|
|
3362
|
+
if (!aIsPinned && bIsPinned) return 1;
|
|
3363
|
+
if (aIsPinned && bIsPinned) return aPin - bPin;
|
|
3364
|
+
const aPri = STATUS_PRIORITY[a.status];
|
|
3365
|
+
const bPri = STATUS_PRIORITY[b.status];
|
|
3366
|
+
if (aPri !== bPri) return aPri - bPri;
|
|
2557
3367
|
return b.lastActivity - a.lastActivity;
|
|
2558
3368
|
});
|
|
2559
3369
|
};
|
|
@@ -2598,7 +3408,9 @@ var buildGroups = (sessions2, expandedKeys) => {
|
|
|
2598
3408
|
totalInputTokens: totalIn,
|
|
2599
3409
|
totalOutputTokens: totalOut,
|
|
2600
3410
|
latestModel: list[0].model,
|
|
2601
|
-
|
|
3411
|
+
status: list.reduce((best, s) => {
|
|
3412
|
+
return (STATUS_PRIORITY[s.status] ?? 3) < (STATUS_PRIORITY[best] ?? 3) ? s.status : best;
|
|
3413
|
+
}, "inactive"),
|
|
2602
3414
|
latestActivity: list[0].lastActivity,
|
|
2603
3415
|
earliestStart: Math.min(...list.map((s) => s.startTime))
|
|
2604
3416
|
});
|
|
@@ -2655,17 +3467,17 @@ var enrichAndFilter = (found, usageOverrides, filter, archivedIds, viewingArchiv
|
|
|
2655
3467
|
return enriched;
|
|
2656
3468
|
};
|
|
2657
3469
|
var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
2658
|
-
const [sessions2, setSessions] =
|
|
2659
|
-
const [selectedIndex, setSelectedIndex] =
|
|
2660
|
-
const [expandedKeys, setExpandedKeys] =
|
|
2661
|
-
const usageOverrides =
|
|
2662
|
-
const refresh =
|
|
3470
|
+
const [sessions2, setSessions] = useState11([]);
|
|
3471
|
+
const [selectedIndex, setSelectedIndex] = useState11(0);
|
|
3472
|
+
const [expandedKeys, setExpandedKeys] = useState11(/* @__PURE__ */ new Set());
|
|
3473
|
+
const usageOverrides = useRef4(/* @__PURE__ */ new Map());
|
|
3474
|
+
const refresh = useCallback3(() => {
|
|
2663
3475
|
const found = getCachedSessions();
|
|
2664
3476
|
const filtered = enrichAndFilter(found, usageOverrides.current, filter, archivedIds, viewingArchive);
|
|
2665
3477
|
setSessions(filtered);
|
|
2666
3478
|
triggerRefresh(allUsers);
|
|
2667
3479
|
}, [allUsers, filter, archivedIds, viewingArchive]);
|
|
2668
|
-
|
|
3480
|
+
useEffect6(() => {
|
|
2669
3481
|
const unsubscribe = subscribe(() => {
|
|
2670
3482
|
const found = getCachedSessions();
|
|
2671
3483
|
const filtered = enrichAndFilter(found, usageOverrides.current, filter, archivedIds, viewingArchive);
|
|
@@ -2673,7 +3485,7 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2673
3485
|
});
|
|
2674
3486
|
return unsubscribe;
|
|
2675
3487
|
}, [filter, archivedIds, viewingArchive]);
|
|
2676
|
-
|
|
3488
|
+
useEffect6(() => {
|
|
2677
3489
|
refresh();
|
|
2678
3490
|
const pollMs = sessions2.length > 0 ? ACTIVE_POLL_MS : IDLE_POLL_MS;
|
|
2679
3491
|
const interval = setInterval(() => triggerRefresh(allUsers), pollMs);
|
|
@@ -2681,21 +3493,21 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2681
3493
|
}, [refresh, sessions2.length > 0]);
|
|
2682
3494
|
const groups = useMemo2(() => buildGroups(sessions2, expandedKeys), [sessions2, expandedKeys]);
|
|
2683
3495
|
const visibleItems = useMemo2(() => buildVisibleItems(groups), [groups]);
|
|
2684
|
-
const itemCountRef =
|
|
3496
|
+
const itemCountRef = useRef4(visibleItems.length);
|
|
2685
3497
|
itemCountRef.current = visibleItems.length;
|
|
2686
3498
|
const selectedItem = visibleItems[selectedIndex] ?? null;
|
|
2687
3499
|
const selectedSession = selectedItem?.type === "ungrouped" ? selectedItem.session : selectedItem?.type === "session" ? selectedItem.session : null;
|
|
2688
3500
|
const selectedGroup = selectedItem?.type === "group" ? selectedItem.group : null;
|
|
2689
|
-
const selectNext =
|
|
3501
|
+
const selectNext = useCallback3(() => {
|
|
2690
3502
|
setSelectedIndex((i) => Math.min(i + 1, Math.max(0, itemCountRef.current - 1)));
|
|
2691
3503
|
}, []);
|
|
2692
|
-
const selectPrev =
|
|
3504
|
+
const selectPrev = useCallback3(() => {
|
|
2693
3505
|
setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
2694
3506
|
}, []);
|
|
2695
|
-
const selectIndex =
|
|
3507
|
+
const selectIndex = useCallback3((i) => {
|
|
2696
3508
|
setSelectedIndex(i);
|
|
2697
3509
|
}, []);
|
|
2698
|
-
const toggleExpand =
|
|
3510
|
+
const toggleExpand = useCallback3((groupKey) => {
|
|
2699
3511
|
setExpandedKeys((prev) => {
|
|
2700
3512
|
const next = new Set(prev);
|
|
2701
3513
|
if (next.has(groupKey)) next.delete(groupKey);
|
|
@@ -2703,7 +3515,7 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2703
3515
|
return next;
|
|
2704
3516
|
});
|
|
2705
3517
|
}, []);
|
|
2706
|
-
const addUsage =
|
|
3518
|
+
const addUsage = useCallback3((sessionId, usage) => {
|
|
2707
3519
|
const existing = usageOverrides.current.get(sessionId);
|
|
2708
3520
|
if (existing) {
|
|
2709
3521
|
usageOverrides.current.set(sessionId, {
|
|
@@ -2733,16 +3545,16 @@ var useSessions = (allUsers, filter, archivedIds, viewingArchive) => {
|
|
|
2733
3545
|
};
|
|
2734
3546
|
|
|
2735
3547
|
// src/ui/hooks/useActivityStream.ts
|
|
2736
|
-
import { useState as
|
|
3548
|
+
import { useState as useState12, useEffect as useEffect7, useRef as useRef5, useMemo as useMemo3 } from "react";
|
|
2737
3549
|
var MAX_EVENTS = 200;
|
|
2738
3550
|
var useActivityStream = (session, allUsers) => {
|
|
2739
|
-
const [calls, setCalls] =
|
|
2740
|
-
const [results, setResults] =
|
|
2741
|
-
const watcherRef =
|
|
3551
|
+
const [calls, setCalls] = useState12([]);
|
|
3552
|
+
const [results, setResults] = useState12([]);
|
|
3553
|
+
const watcherRef = useRef5(null);
|
|
2742
3554
|
const sessions2 = session === null ? [] : Array.isArray(session) ? session : [session];
|
|
2743
3555
|
const sessionKey = sessions2.map((s) => s.sessionId).sort().join(",");
|
|
2744
3556
|
const sessionIdSet = new Set(sessions2.map((s) => s.sessionId));
|
|
2745
|
-
|
|
3557
|
+
useEffect7(() => {
|
|
2746
3558
|
setCalls([]);
|
|
2747
3559
|
setResults([]);
|
|
2748
3560
|
if (sessions2.length === 0) return;
|
|
@@ -2776,7 +3588,7 @@ var useActivityStream = (session, allUsers) => {
|
|
|
2776
3588
|
const resultHandler = (newResults) => {
|
|
2777
3589
|
const matched = newResults.filter((r) => sessionIdSet.has(r.sessionId));
|
|
2778
3590
|
if (matched.length === 0) return;
|
|
2779
|
-
setResults((prev) => [...prev, ...matched]);
|
|
3591
|
+
setResults((prev) => [...prev, ...matched].slice(-MAX_EVENTS * 2));
|
|
2780
3592
|
};
|
|
2781
3593
|
const watcher = new Watcher(callHandler, allUsers, void 0, void 0, resultHandler);
|
|
2782
3594
|
watcherRef.current = watcher;
|
|
@@ -2811,10 +3623,10 @@ var applyFilter = (events, filter) => {
|
|
|
2811
3623
|
var useFilteredEvents = (rawEvents, filter) => useMemo4(() => applyFilter(rawEvents, filter), [rawEvents, filter]);
|
|
2812
3624
|
|
|
2813
3625
|
// src/ui/hooks/useAlerts.ts
|
|
2814
|
-
import { useState as
|
|
3626
|
+
import { useState as useState13, useEffect as useEffect8, useRef as useRef6 } from "react";
|
|
2815
3627
|
|
|
2816
3628
|
// src/notifications.ts
|
|
2817
|
-
import {
|
|
3629
|
+
import { execFile as execFile2 } from "child_process";
|
|
2818
3630
|
import { platform } from "os";
|
|
2819
3631
|
var SEVERITY_ORDER = {
|
|
2820
3632
|
info: 0,
|
|
@@ -2837,11 +3649,23 @@ var notify = (alert, config) => {
|
|
|
2837
3649
|
const body = `${alert.sessionSlug}: ${alert.message.slice(0, 100)}`;
|
|
2838
3650
|
const os = platform();
|
|
2839
3651
|
if (os === "linux") {
|
|
2840
|
-
|
|
3652
|
+
execFile2("notify-send", [title, body], { timeout: 3e3 });
|
|
2841
3653
|
} else if (os === "darwin") {
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
3654
|
+
execFile2(
|
|
3655
|
+
"osascript",
|
|
3656
|
+
["-e", `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)}`],
|
|
3657
|
+
{ timeout: 3e3 }
|
|
3658
|
+
);
|
|
3659
|
+
} else if (os === "win32") {
|
|
3660
|
+
execFile2(
|
|
3661
|
+
"powershell",
|
|
3662
|
+
[
|
|
3663
|
+
"-NoProfile",
|
|
3664
|
+
"-Command",
|
|
3665
|
+
`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()`
|
|
3666
|
+
],
|
|
3667
|
+
{ timeout: 1e4 }
|
|
3668
|
+
);
|
|
2845
3669
|
}
|
|
2846
3670
|
}
|
|
2847
3671
|
};
|
|
@@ -2879,11 +3703,11 @@ var AlertLogger = class {
|
|
|
2879
3703
|
// src/ui/hooks/useAlerts.ts
|
|
2880
3704
|
var MAX_ALERTS = 100;
|
|
2881
3705
|
var useAlerts = (enabled, alertLevel, allUsers, config) => {
|
|
2882
|
-
const [alerts, setAlerts] =
|
|
2883
|
-
const engineRef =
|
|
2884
|
-
const watcherRef =
|
|
2885
|
-
const loggerRef =
|
|
2886
|
-
|
|
3706
|
+
const [alerts, setAlerts] = useState13([]);
|
|
3707
|
+
const engineRef = useRef6(new SecurityEngine(alertLevel));
|
|
3708
|
+
const watcherRef = useRef6(null);
|
|
3709
|
+
const loggerRef = useRef6(null);
|
|
3710
|
+
useEffect8(() => {
|
|
2887
3711
|
if (!enabled) return;
|
|
2888
3712
|
engineRef.current = new SecurityEngine(alertLevel);
|
|
2889
3713
|
if (config?.alerts.enabled) {
|
|
@@ -2913,33 +3737,33 @@ var useAlerts = (enabled, alertLevel, allUsers, config) => {
|
|
|
2913
3737
|
watcherRef.current = null;
|
|
2914
3738
|
loggerRef.current = null;
|
|
2915
3739
|
};
|
|
2916
|
-
}, [enabled, alertLevel, allUsers]);
|
|
3740
|
+
}, [enabled, alertLevel, allUsers, config]);
|
|
2917
3741
|
const clearAlerts = () => setAlerts([]);
|
|
2918
3742
|
return { alerts, clearAlerts };
|
|
2919
3743
|
};
|
|
2920
3744
|
|
|
2921
3745
|
// src/ui/hooks/useTextInput.ts
|
|
2922
|
-
import { useState as
|
|
3746
|
+
import { useState as useState14, useCallback as useCallback4 } from "react";
|
|
2923
3747
|
var useTextInput = (onConfirm, onCancel) => {
|
|
2924
|
-
const [value, setValue] =
|
|
2925
|
-
const [isActive, setIsActive] =
|
|
2926
|
-
const start =
|
|
3748
|
+
const [value, setValue] = useState14("");
|
|
3749
|
+
const [isActive, setIsActive] = useState14(false);
|
|
3750
|
+
const start = useCallback4((initial = "") => {
|
|
2927
3751
|
setValue(initial);
|
|
2928
3752
|
setIsActive(true);
|
|
2929
3753
|
}, []);
|
|
2930
|
-
const cancel =
|
|
3754
|
+
const cancel = useCallback4(() => {
|
|
2931
3755
|
setValue("");
|
|
2932
3756
|
setIsActive(false);
|
|
2933
3757
|
onCancel?.();
|
|
2934
3758
|
}, [onCancel]);
|
|
2935
|
-
const confirm =
|
|
3759
|
+
const confirm = useCallback4(() => {
|
|
2936
3760
|
const result = value;
|
|
2937
3761
|
setIsActive(false);
|
|
2938
3762
|
setValue("");
|
|
2939
3763
|
onConfirm?.(result);
|
|
2940
3764
|
return result;
|
|
2941
3765
|
}, [value, onConfirm]);
|
|
2942
|
-
const handleInput =
|
|
3766
|
+
const handleInput = useCallback4(
|
|
2943
3767
|
(input, key) => {
|
|
2944
3768
|
if (!isActive) return false;
|
|
2945
3769
|
if (key.escape) {
|
|
@@ -2972,17 +3796,18 @@ var useTextInput = (onConfirm, onCancel) => {
|
|
|
2972
3796
|
};
|
|
2973
3797
|
|
|
2974
3798
|
// src/ui/hooks/useKeyHandler.ts
|
|
2975
|
-
import { useInput as
|
|
3799
|
+
import { useInput as useInput11 } from "ink";
|
|
2976
3800
|
var matchKey = (binding, input, key) => {
|
|
2977
3801
|
if (binding === "tab") return Boolean(key.tab);
|
|
2978
3802
|
if (binding === "shift+tab") return Boolean(key.shift && key.tab);
|
|
2979
3803
|
if (binding === "enter") return Boolean(key.return);
|
|
3804
|
+
if (binding.startsWith("ctrl+")) return Boolean(key.ctrl) && input === binding.slice(5);
|
|
2980
3805
|
return input === binding;
|
|
2981
3806
|
};
|
|
2982
3807
|
var useKeyHandler = (deps) => {
|
|
2983
3808
|
const d = deps;
|
|
2984
|
-
|
|
2985
|
-
if (d.showSetup || d.showSettings || d.confirmAction) return;
|
|
3809
|
+
useInput11((input, key) => {
|
|
3810
|
+
if (d.showSetup || d.showSettings || d.confirmAction || d.showUpdateModal) return;
|
|
2986
3811
|
if (d.inputMode === "nickname") {
|
|
2987
3812
|
d.nicknameInput.handleInput(input, key);
|
|
2988
3813
|
return;
|
|
@@ -3152,10 +3977,26 @@ var useKeyHandler = (deps) => {
|
|
|
3152
3977
|
d.setShowSettings(true);
|
|
3153
3978
|
return;
|
|
3154
3979
|
}
|
|
3980
|
+
if (matchKey(d.kb.alertRules, input, key)) {
|
|
3981
|
+
d.setShowAlertRules(true);
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3155
3984
|
if (matchKey(d.kb.viewArchive, input, key)) {
|
|
3156
3985
|
d.setViewingArchive((v) => !v);
|
|
3157
3986
|
return;
|
|
3158
3987
|
}
|
|
3988
|
+
if (matchKey(d.kb.pin, input, key) && d.selectedSession) {
|
|
3989
|
+
d.onTogglePin(d.selectedSession.sessionId);
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3992
|
+
if (matchKey(d.kb.pinMoveUp, input, key) && d.selectedSession?.pinned) {
|
|
3993
|
+
d.onMovePinned(d.selectedSession.sessionId, "up");
|
|
3994
|
+
return;
|
|
3995
|
+
}
|
|
3996
|
+
if (matchKey(d.kb.pinMoveDown, input, key) && d.selectedSession?.pinned) {
|
|
3997
|
+
d.onMovePinned(d.selectedSession.sessionId, "down");
|
|
3998
|
+
return;
|
|
3999
|
+
}
|
|
3159
4000
|
if (matchKey(d.kb.archive, input, key) && d.selectedSession) {
|
|
3160
4001
|
if (d.viewingArchive) d.onUnarchive(d.selectedSession.sessionId);
|
|
3161
4002
|
else d.onArchive(d.selectedSession.sessionId);
|
|
@@ -3214,10 +4055,10 @@ var useKeyHandler = (deps) => {
|
|
|
3214
4055
|
};
|
|
3215
4056
|
|
|
3216
4057
|
// src/ui/hooks/useUpdateChecker.ts
|
|
3217
|
-
import { useState as
|
|
4058
|
+
import { useState as useState15, useEffect as useEffect9 } from "react";
|
|
3218
4059
|
var useUpdateChecker = (disabled, checkOnLaunch, checkInterval) => {
|
|
3219
|
-
const [updateInfo, setUpdateInfo] =
|
|
3220
|
-
|
|
4060
|
+
const [updateInfo, setUpdateInfo] = useState15(null);
|
|
4061
|
+
useEffect9(() => {
|
|
3221
4062
|
if (disabled || !checkOnLaunch) return;
|
|
3222
4063
|
let cancelled = false;
|
|
3223
4064
|
const check = () => {
|
|
@@ -3232,12 +4073,12 @@ var useUpdateChecker = (disabled, checkOnLaunch, checkInterval) => {
|
|
|
3232
4073
|
cancelled = true;
|
|
3233
4074
|
clearInterval(iv);
|
|
3234
4075
|
};
|
|
3235
|
-
}, []);
|
|
4076
|
+
}, [disabled, checkOnLaunch, checkInterval]);
|
|
3236
4077
|
return updateInfo;
|
|
3237
4078
|
};
|
|
3238
4079
|
|
|
3239
4080
|
// src/ui/hooks/useSetupFlow.ts
|
|
3240
|
-
import { useState as
|
|
4081
|
+
import { useState as useState16, useCallback as useCallback5 } from "react";
|
|
3241
4082
|
|
|
3242
4083
|
// src/hooks/installer.ts
|
|
3243
4084
|
import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync as mkdirSync2, chmodSync } from "fs";
|
|
@@ -3357,25 +4198,25 @@ var installMcpConfig = () => {
|
|
|
3357
4198
|
|
|
3358
4199
|
// src/ui/hooks/useSetupFlow.ts
|
|
3359
4200
|
var useSetupFlow = (initialConfig, firstRun) => {
|
|
3360
|
-
const [liveConfig, setLiveConfig] =
|
|
3361
|
-
const [showSetup, setShowSetup] =
|
|
3362
|
-
const [showThemePicker, setShowThemePicker] =
|
|
3363
|
-
const [showTour, setShowTour] =
|
|
3364
|
-
const [showSettings, setShowSettings] =
|
|
3365
|
-
const [showThemeMenu, setShowThemeMenu] =
|
|
3366
|
-
const handleSettingsClose =
|
|
4201
|
+
const [liveConfig, setLiveConfig] = useState16(initialConfig);
|
|
4202
|
+
const [showSetup, setShowSetup] = useState16(firstRun);
|
|
4203
|
+
const [showThemePicker, setShowThemePicker] = useState16(false);
|
|
4204
|
+
const [showTour, setShowTour] = useState16(false);
|
|
4205
|
+
const [showSettings, setShowSettings] = useState16(false);
|
|
4206
|
+
const [showThemeMenu, setShowThemeMenu] = useState16(false);
|
|
4207
|
+
const handleSettingsClose = useCallback5((c) => {
|
|
3367
4208
|
setLiveConfig(c);
|
|
3368
4209
|
saveConfig(c);
|
|
3369
4210
|
setShowSettings(false);
|
|
3370
4211
|
}, []);
|
|
3371
|
-
const handleThemeMenuClose =
|
|
4212
|
+
const handleThemeMenuClose = useCallback5((c) => {
|
|
3372
4213
|
setLiveConfig(c);
|
|
3373
4214
|
saveConfig(c);
|
|
3374
4215
|
setShowThemeMenu(false);
|
|
3375
4216
|
setShowSettings(true);
|
|
3376
4217
|
}, []);
|
|
3377
|
-
const handleOpenThemeMenu =
|
|
3378
|
-
const handleSetupComplete =
|
|
4218
|
+
const handleOpenThemeMenu = useCallback5(() => setShowThemeMenu(true), []);
|
|
4219
|
+
const handleSetupComplete = useCallback5(
|
|
3379
4220
|
(results) => {
|
|
3380
4221
|
const nc = { ...liveConfig };
|
|
3381
4222
|
const [hc, mc] = results;
|
|
@@ -3400,7 +4241,7 @@ var useSetupFlow = (initialConfig, firstRun) => {
|
|
|
3400
4241
|
},
|
|
3401
4242
|
[liveConfig]
|
|
3402
4243
|
);
|
|
3403
|
-
const handleThemePickerSelect =
|
|
4244
|
+
const handleThemePickerSelect = useCallback5(
|
|
3404
4245
|
(themeName) => {
|
|
3405
4246
|
const nc = { ...liveConfig, theme: themeName, prompts: { ...liveConfig.prompts, theme: "done" } };
|
|
3406
4247
|
setLiveConfig(nc);
|
|
@@ -3410,24 +4251,24 @@ var useSetupFlow = (initialConfig, firstRun) => {
|
|
|
3410
4251
|
},
|
|
3411
4252
|
[liveConfig]
|
|
3412
4253
|
);
|
|
3413
|
-
const handleThemePickerSkip =
|
|
4254
|
+
const handleThemePickerSkip = useCallback5(() => {
|
|
3414
4255
|
setShowThemePicker(false);
|
|
3415
4256
|
if (liveConfig.prompts.tour === "pending") setShowTour(true);
|
|
3416
4257
|
}, [liveConfig]);
|
|
3417
|
-
const handleThemePickerDismiss =
|
|
4258
|
+
const handleThemePickerDismiss = useCallback5(() => {
|
|
3418
4259
|
const nc = { ...liveConfig, prompts: { ...liveConfig.prompts, theme: "dismissed" } };
|
|
3419
4260
|
setLiveConfig(nc);
|
|
3420
4261
|
saveConfig(nc);
|
|
3421
4262
|
setShowThemePicker(false);
|
|
3422
4263
|
if (nc.prompts.tour === "pending") setShowTour(true);
|
|
3423
4264
|
}, [liveConfig]);
|
|
3424
|
-
const handleTourComplete =
|
|
4265
|
+
const handleTourComplete = useCallback5(() => {
|
|
3425
4266
|
const nc = { ...liveConfig, prompts: { ...liveConfig.prompts, tour: "done" } };
|
|
3426
4267
|
setLiveConfig(nc);
|
|
3427
4268
|
saveConfig(nc);
|
|
3428
4269
|
setShowTour(false);
|
|
3429
4270
|
}, [liveConfig]);
|
|
3430
|
-
const handleTourSkip =
|
|
4271
|
+
const handleTourSkip = useCallback5(() => {
|
|
3431
4272
|
setShowTour(false);
|
|
3432
4273
|
}, []);
|
|
3433
4274
|
return {
|
|
@@ -3453,18 +4294,18 @@ var useSetupFlow = (initialConfig, firstRun) => {
|
|
|
3453
4294
|
};
|
|
3454
4295
|
|
|
3455
4296
|
// src/ui/hooks/useSplitPanel.ts
|
|
3456
|
-
import { useState as
|
|
4297
|
+
import { useState as useState17, useCallback as useCallback6 } from "react";
|
|
3457
4298
|
var useSplitPanel = () => {
|
|
3458
|
-
const [splitMode, setSplitMode] =
|
|
3459
|
-
const [leftSession, setLeftSession] =
|
|
3460
|
-
const [rightSession, setRightSession] =
|
|
3461
|
-
const [leftScroll, setLeftScroll] =
|
|
3462
|
-
const [rightScroll, setRightScroll] =
|
|
3463
|
-
const [leftFilter, setLeftFilter] =
|
|
3464
|
-
const [rightFilter, setRightFilter] =
|
|
3465
|
-
const [leftShowDetail, setLeftShowDetail] =
|
|
3466
|
-
const [rightShowDetail, setRightShowDetail] =
|
|
3467
|
-
const clearSplitState =
|
|
4299
|
+
const [splitMode, setSplitMode] = useState17(false);
|
|
4300
|
+
const [leftSession, setLeftSession] = useState17(null);
|
|
4301
|
+
const [rightSession, setRightSession] = useState17(null);
|
|
4302
|
+
const [leftScroll, setLeftScroll] = useState17(0);
|
|
4303
|
+
const [rightScroll, setRightScroll] = useState17(0);
|
|
4304
|
+
const [leftFilter, setLeftFilter] = useState17("");
|
|
4305
|
+
const [rightFilter, setRightFilter] = useState17("");
|
|
4306
|
+
const [leftShowDetail, setLeftShowDetail] = useState17(false);
|
|
4307
|
+
const [rightShowDetail, setRightShowDetail] = useState17(false);
|
|
4308
|
+
const clearSplitState = useCallback6(() => {
|
|
3468
4309
|
setSplitMode(false);
|
|
3469
4310
|
setLeftSession(null);
|
|
3470
4311
|
setRightSession(null);
|
|
@@ -3475,7 +4316,7 @@ var useSplitPanel = () => {
|
|
|
3475
4316
|
setLeftShowDetail(false);
|
|
3476
4317
|
setRightShowDetail(false);
|
|
3477
4318
|
}, []);
|
|
3478
|
-
const resetPanel =
|
|
4319
|
+
const resetPanel = useCallback6((side) => {
|
|
3479
4320
|
if (side === "left") {
|
|
3480
4321
|
setLeftSession(null);
|
|
3481
4322
|
setLeftScroll(0);
|
|
@@ -3488,7 +4329,7 @@ var useSplitPanel = () => {
|
|
|
3488
4329
|
setRightShowDetail(false);
|
|
3489
4330
|
}
|
|
3490
4331
|
}, []);
|
|
3491
|
-
const switchPanel =
|
|
4332
|
+
const switchPanel = useCallback6(
|
|
3492
4333
|
(dir, setActivePanel) => {
|
|
3493
4334
|
if (splitMode) {
|
|
3494
4335
|
const order = ["sessions", "left", "right"];
|
|
@@ -3529,31 +4370,33 @@ var useSplitPanel = () => {
|
|
|
3529
4370
|
};
|
|
3530
4371
|
|
|
3531
4372
|
// src/ui/App.tsx
|
|
3532
|
-
import { jsx as
|
|
3533
|
-
var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
4373
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4374
|
+
var App = ({ options: options2, config: initialConfig, version, firstRun }) => {
|
|
3534
4375
|
const { exit } = useApp();
|
|
3535
|
-
const { stdout } =
|
|
4376
|
+
const { stdout } = useStdout4();
|
|
3536
4377
|
const termHeight = stdout?.rows ?? 40;
|
|
3537
4378
|
const setup = useSetupFlow(initialConfig, firstRun);
|
|
3538
4379
|
const split = useSplitPanel();
|
|
3539
4380
|
const kb = setup.liveConfig.keybindings;
|
|
3540
|
-
const [activePanel, setActivePanel] =
|
|
3541
|
-
const [activityScroll, setActivityScroll] =
|
|
3542
|
-
const [inputMode, setInputMode] =
|
|
3543
|
-
const [filter, setFilter] =
|
|
3544
|
-
const [activityFilter, setActivityFilter] =
|
|
3545
|
-
const [updateStatus, setUpdateStatus] =
|
|
3546
|
-
const [showDetail, setShowDetail] =
|
|
3547
|
-
const [viewingArchive, setViewingArchive] =
|
|
3548
|
-
const [confirmAction, setConfirmAction] =
|
|
4381
|
+
const [activePanel, setActivePanel] = useState18("sessions");
|
|
4382
|
+
const [activityScroll, setActivityScroll] = useState18(0);
|
|
4383
|
+
const [inputMode, setInputMode] = useState18("normal");
|
|
4384
|
+
const [filter, setFilter] = useState18("");
|
|
4385
|
+
const [activityFilter, setActivityFilter] = useState18("");
|
|
4386
|
+
const [updateStatus, setUpdateStatus] = useState18("");
|
|
4387
|
+
const [showDetail, setShowDetail] = useState18(false);
|
|
4388
|
+
const [viewingArchive, setViewingArchive] = useState18(false);
|
|
4389
|
+
const [confirmAction, setConfirmAction] = useState18(
|
|
3549
4390
|
null
|
|
3550
4391
|
);
|
|
3551
|
-
const [archivedIds, setArchivedIds] =
|
|
3552
|
-
const [sidebarWidth, setSidebarWidth] =
|
|
3553
|
-
const [selectedEventIndex, setSelectedEventIndex] =
|
|
3554
|
-
const [showEventDetail, setShowEventDetail] =
|
|
3555
|
-
const
|
|
3556
|
-
const
|
|
4392
|
+
const [archivedIds, setArchivedIds] = useState18(() => new Set(Object.keys(getArchived())));
|
|
4393
|
+
const [sidebarWidth, setSidebarWidth] = useState18(() => initialConfig.sidebarWidth ?? 30);
|
|
4394
|
+
const [selectedEventIndex, setSelectedEventIndex] = useState18(0);
|
|
4395
|
+
const [showEventDetail, setShowEventDetail] = useState18(false);
|
|
4396
|
+
const [showUpdateModal, setShowUpdateModal] = useState18(false);
|
|
4397
|
+
const [showAlertRules, setShowAlertRules] = useState18(false);
|
|
4398
|
+
const refreshArchived = useCallback7(() => setArchivedIds(new Set(Object.keys(getArchived()))), []);
|
|
4399
|
+
const persistSidebarWidth = useCallback7((v) => {
|
|
3557
4400
|
setSidebarWidth((prev) => {
|
|
3558
4401
|
const next = typeof v === "function" ? v(prev) : v;
|
|
3559
4402
|
if (next !== prev) {
|
|
@@ -3565,13 +4408,18 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3565
4408
|
});
|
|
3566
4409
|
}, []);
|
|
3567
4410
|
const updateInfo = useUpdateChecker(
|
|
3568
|
-
|
|
4411
|
+
options2.noUpdates,
|
|
3569
4412
|
setup.liveConfig.updates.checkOnLaunch,
|
|
3570
4413
|
setup.liveConfig.updates.checkInterval
|
|
3571
4414
|
);
|
|
3572
|
-
|
|
4415
|
+
useEffect10(() => {
|
|
3573
4416
|
applyTheme(resolveTheme(setup.liveConfig.theme, setup.liveConfig.customThemes));
|
|
3574
4417
|
}, [setup.liveConfig.theme, setup.liveConfig.customThemes]);
|
|
4418
|
+
useEffect10(() => {
|
|
4419
|
+
if (updateInfo?.available && setup.liveConfig.prompts.autoUpdate === "pending") {
|
|
4420
|
+
setShowUpdateModal(true);
|
|
4421
|
+
}
|
|
4422
|
+
}, [updateInfo?.available, setup.liveConfig.prompts.autoUpdate]);
|
|
3575
4423
|
const {
|
|
3576
4424
|
sessions: sessions2,
|
|
3577
4425
|
visibleItems,
|
|
@@ -3582,15 +4430,15 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3582
4430
|
selectPrev,
|
|
3583
4431
|
toggleExpand,
|
|
3584
4432
|
refresh
|
|
3585
|
-
} = useSessions(
|
|
4433
|
+
} = useSessions(options2.allUsers, filter || void 0, archivedIds, viewingArchive);
|
|
3586
4434
|
const activityTarget = split.splitMode ? null : selectedGroup ? selectedGroup.sessions : selectedSession;
|
|
3587
|
-
const rawEvents = useActivityStream(activityTarget,
|
|
3588
|
-
const leftRawEvents = useActivityStream(split.splitMode ? split.leftSession : null,
|
|
3589
|
-
const rightRawEvents = useActivityStream(split.splitMode ? split.rightSession : null,
|
|
4435
|
+
const rawEvents = useActivityStream(activityTarget, options2.allUsers);
|
|
4436
|
+
const leftRawEvents = useActivityStream(split.splitMode ? split.leftSession : null, options2.allUsers);
|
|
4437
|
+
const rightRawEvents = useActivityStream(split.splitMode ? split.rightSession : null, options2.allUsers);
|
|
3590
4438
|
const events = useFilteredEvents(rawEvents, activityFilter);
|
|
3591
4439
|
const leftEvents = useFilteredEvents(leftRawEvents, split.leftFilter);
|
|
3592
4440
|
const rightEvents = useFilteredEvents(rightRawEvents, split.rightFilter);
|
|
3593
|
-
const { alerts } = useAlerts(!
|
|
4441
|
+
const { alerts } = useAlerts(!options2.noSecurity, options2.alertLevel, options2.allUsers, setup.liveConfig);
|
|
3594
4442
|
const nicknameInput = useTextInput(
|
|
3595
4443
|
(value) => {
|
|
3596
4444
|
if (selectedSession && value.trim()) {
|
|
@@ -3617,18 +4465,18 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3617
4465
|
setInputMode("normal");
|
|
3618
4466
|
}
|
|
3619
4467
|
);
|
|
3620
|
-
|
|
4468
|
+
useEffect10(() => {
|
|
3621
4469
|
purgeExpiredArchives();
|
|
3622
4470
|
refreshArchived();
|
|
3623
4471
|
}, []);
|
|
3624
|
-
|
|
4472
|
+
useEffect10(() => {
|
|
3625
4473
|
setActivityScroll(0);
|
|
3626
4474
|
setSelectedEventIndex(0);
|
|
3627
4475
|
setShowEventDetail(false);
|
|
3628
4476
|
}, [selectedSession?.sessionId, selectedGroup?.key]);
|
|
3629
|
-
|
|
4477
|
+
useEffect10(() => {
|
|
3630
4478
|
const totalEvents = events.length;
|
|
3631
|
-
const vRows = termHeight - 3 - (
|
|
4479
|
+
const vRows = termHeight - 3 - (options2.noSecurity ? 0 : 6) - 1 - (inputMode !== "normal" ? 1 : 0) - 2;
|
|
3632
4480
|
if (vRows <= 0 || totalEvents === 0) return;
|
|
3633
4481
|
const start = Math.max(0, totalEvents - vRows - activityScroll);
|
|
3634
4482
|
const end = start + vRows;
|
|
@@ -3638,40 +4486,60 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3638
4486
|
setActivityScroll(totalEvents - vRows - (selectedEventIndex - vRows + 1));
|
|
3639
4487
|
}
|
|
3640
4488
|
}, [selectedEventIndex, events.length]);
|
|
3641
|
-
|
|
4489
|
+
useEffect10(() => {
|
|
3642
4490
|
if (events.length > 0 && selectedEventIndex >= events.length) {
|
|
3643
4491
|
setSelectedEventIndex(events.length - 1);
|
|
3644
4492
|
}
|
|
3645
4493
|
}, [events.length]);
|
|
3646
|
-
const alertHeight =
|
|
4494
|
+
const alertHeight = options2.noSecurity ? 0 : 6;
|
|
3647
4495
|
const mainHeight = termHeight - 3 - alertHeight - 1 - (inputMode !== "normal" ? 1 : 0);
|
|
3648
4496
|
const viewportRows = mainHeight - 2;
|
|
3649
|
-
const switchPanel =
|
|
4497
|
+
const switchPanel = useCallback7(
|
|
3650
4498
|
(dir) => split.switchPanel(dir, setActivePanel),
|
|
3651
4499
|
[split.switchPanel]
|
|
3652
4500
|
);
|
|
3653
|
-
const clearSplitState =
|
|
4501
|
+
const clearSplitState = useCallback7(() => {
|
|
3654
4502
|
split.clearSplitState();
|
|
3655
4503
|
setActivePanel("sessions");
|
|
3656
4504
|
}, [split.clearSplitState]);
|
|
3657
|
-
const getActiveFilter =
|
|
4505
|
+
const getActiveFilter = useCallback7(() => {
|
|
3658
4506
|
if (activePanel === "sessions") return filter;
|
|
3659
4507
|
if (activePanel === "left") return split.leftFilter;
|
|
3660
4508
|
if (activePanel === "right") return split.rightFilter;
|
|
3661
4509
|
return activityFilter;
|
|
3662
4510
|
}, [activePanel, filter, split.leftFilter, split.rightFilter, activityFilter]);
|
|
4511
|
+
const handleTogglePin = useCallback7(
|
|
4512
|
+
(sessionId) => {
|
|
4513
|
+
const cfg = loadConfig();
|
|
4514
|
+
if (cfg.pinnedSessions.includes(sessionId)) {
|
|
4515
|
+
unpinSession(sessionId);
|
|
4516
|
+
} else {
|
|
4517
|
+
pinSession(sessionId);
|
|
4518
|
+
}
|
|
4519
|
+
refresh();
|
|
4520
|
+
},
|
|
4521
|
+
[refresh]
|
|
4522
|
+
);
|
|
4523
|
+
const handleMovePinned = useCallback7(
|
|
4524
|
+
(sessionId, dir) => {
|
|
4525
|
+
movePinned(sessionId, dir);
|
|
4526
|
+
refresh();
|
|
4527
|
+
},
|
|
4528
|
+
[refresh]
|
|
4529
|
+
);
|
|
3663
4530
|
useKeyHandler({
|
|
3664
4531
|
kb,
|
|
3665
4532
|
activePanel,
|
|
3666
4533
|
splitMode: split.splitMode,
|
|
3667
4534
|
inputMode,
|
|
3668
4535
|
showSetup: setup.showSetup,
|
|
3669
|
-
showSettings: setup.showSettings || setup.showThemeMenu || setup.showThemePicker || setup.showTour,
|
|
4536
|
+
showSettings: setup.showSettings || setup.showThemeMenu || setup.showThemePicker || setup.showTour || showAlertRules,
|
|
3670
4537
|
showDetail,
|
|
3671
4538
|
showEventDetail,
|
|
3672
4539
|
leftShowDetail: split.leftShowDetail,
|
|
3673
4540
|
rightShowDetail: split.rightShowDetail,
|
|
3674
4541
|
confirmAction,
|
|
4542
|
+
showUpdateModal,
|
|
3675
4543
|
selectedSession,
|
|
3676
4544
|
selectedGroup,
|
|
3677
4545
|
toggleExpand,
|
|
@@ -3709,6 +4577,8 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3709
4577
|
setLeftShowDetail: split.setLeftShowDetail,
|
|
3710
4578
|
setRightShowDetail: split.setRightShowDetail,
|
|
3711
4579
|
setShowSettings: setup.setShowSettings,
|
|
4580
|
+
showAlertRules,
|
|
4581
|
+
setShowAlertRules,
|
|
3712
4582
|
setViewingArchive,
|
|
3713
4583
|
setSplitMode: split.setSplitMode,
|
|
3714
4584
|
setLeftSession: split.setLeftSession,
|
|
@@ -3723,14 +4593,12 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3723
4593
|
setSidebarWidth: persistSidebarWidth,
|
|
3724
4594
|
nicknameInput,
|
|
3725
4595
|
filterInput,
|
|
3726
|
-
onNickname: (id) => {
|
|
3727
|
-
clearNickname(id);
|
|
3728
|
-
refresh();
|
|
3729
|
-
},
|
|
3730
4596
|
onClearNickname: (id) => {
|
|
3731
4597
|
clearNickname(id);
|
|
3732
4598
|
refresh();
|
|
3733
4599
|
},
|
|
4600
|
+
onTogglePin: handleTogglePin,
|
|
4601
|
+
onMovePinned: handleMovePinned,
|
|
3734
4602
|
onArchive: (id) => {
|
|
3735
4603
|
archiveSession(id);
|
|
3736
4604
|
refreshArchived();
|
|
@@ -3757,7 +4625,10 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3757
4625
|
}),
|
|
3758
4626
|
onUpdate: () => {
|
|
3759
4627
|
setUpdateStatus("updating...");
|
|
3760
|
-
installUpdate().then(() =>
|
|
4628
|
+
installUpdate().then(() => {
|
|
4629
|
+
setUpdateStatus(`updated to v${updateInfo?.latest} \u2014 restarting...`);
|
|
4630
|
+
setTimeout(() => restartProcess(), 500);
|
|
4631
|
+
}).catch(() => setUpdateStatus("update failed"));
|
|
3761
4632
|
}
|
|
3762
4633
|
});
|
|
3763
4634
|
if (setup.showSetup) {
|
|
@@ -3779,10 +4650,10 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3779
4650
|
setup.setShowSetup(false);
|
|
3780
4651
|
return null;
|
|
3781
4652
|
}
|
|
3782
|
-
return /* @__PURE__ */
|
|
4653
|
+
return /* @__PURE__ */ jsx18(SetupModal, { steps, onComplete: setup.handleSetupComplete });
|
|
3783
4654
|
}
|
|
3784
4655
|
if (setup.showThemePicker)
|
|
3785
|
-
return /* @__PURE__ */
|
|
4656
|
+
return /* @__PURE__ */ jsx18(
|
|
3786
4657
|
ThemePickerModal,
|
|
3787
4658
|
{
|
|
3788
4659
|
onSelect: setup.handleThemePickerSelect,
|
|
@@ -3790,10 +4661,22 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3790
4661
|
onDismiss: setup.handleThemePickerDismiss
|
|
3791
4662
|
}
|
|
3792
4663
|
);
|
|
3793
|
-
if (setup.showTour) return /* @__PURE__ */
|
|
3794
|
-
if (setup.showThemeMenu) return /* @__PURE__ */
|
|
4664
|
+
if (setup.showTour) return /* @__PURE__ */ jsx18(GuidedTour, { onComplete: setup.handleTourComplete, onSkip: setup.handleTourSkip });
|
|
4665
|
+
if (setup.showThemeMenu) return /* @__PURE__ */ jsx18(ThemeMenu, { config: setup.liveConfig, onClose: setup.handleThemeMenuClose });
|
|
4666
|
+
if (showAlertRules)
|
|
4667
|
+
return /* @__PURE__ */ jsx18(
|
|
4668
|
+
AlertRulesMenu,
|
|
4669
|
+
{
|
|
4670
|
+
config: setup.liveConfig,
|
|
4671
|
+
onClose: () => setShowAlertRules(false),
|
|
4672
|
+
onSave: (newConfig) => {
|
|
4673
|
+
saveConfig(newConfig);
|
|
4674
|
+
setup.setLiveConfig(newConfig);
|
|
4675
|
+
}
|
|
4676
|
+
}
|
|
4677
|
+
);
|
|
3795
4678
|
if (setup.showSettings)
|
|
3796
|
-
return /* @__PURE__ */
|
|
4679
|
+
return /* @__PURE__ */ jsx18(
|
|
3797
4680
|
SettingsMenu,
|
|
3798
4681
|
{
|
|
3799
4682
|
config: setup.liveConfig,
|
|
@@ -3801,8 +4684,25 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3801
4684
|
onOpenThemeMenu: setup.handleOpenThemeMenu
|
|
3802
4685
|
}
|
|
3803
4686
|
);
|
|
4687
|
+
if (showUpdateModal && updateInfo?.available) {
|
|
4688
|
+
return /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", height: termHeight, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx18(
|
|
4689
|
+
UpdateModal,
|
|
4690
|
+
{
|
|
4691
|
+
current: updateInfo.current,
|
|
4692
|
+
latest: updateInfo.latest,
|
|
4693
|
+
onNotNow: () => setShowUpdateModal(false),
|
|
4694
|
+
onDontAskAgain: () => {
|
|
4695
|
+
const cfg = loadConfig();
|
|
4696
|
+
cfg.prompts.autoUpdate = "dismissed";
|
|
4697
|
+
saveConfig(cfg);
|
|
4698
|
+
setup.setLiveConfig(cfg);
|
|
4699
|
+
setShowUpdateModal(false);
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
) });
|
|
4703
|
+
}
|
|
3804
4704
|
if (confirmAction) {
|
|
3805
|
-
return /* @__PURE__ */
|
|
4705
|
+
return /* @__PURE__ */ jsx18(Box18, { flexDirection: "column", height: termHeight, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx18(
|
|
3806
4706
|
ConfirmModal,
|
|
3807
4707
|
{
|
|
3808
4708
|
title: confirmAction.title,
|
|
@@ -3815,7 +4715,7 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3815
4715
|
const activitySlug = selectedGroup ? selectedGroup.key : selectedSession?.slug ?? null;
|
|
3816
4716
|
const isMerged = selectedGroup !== null;
|
|
3817
4717
|
const selectedEvent = events[selectedEventIndex];
|
|
3818
|
-
const rightPanel = split.splitMode ? /* @__PURE__ */
|
|
4718
|
+
const rightPanel = split.splitMode ? /* @__PURE__ */ jsx18(
|
|
3819
4719
|
SplitPanel,
|
|
3820
4720
|
{
|
|
3821
4721
|
activePanel,
|
|
@@ -3831,13 +4731,13 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3831
4731
|
rightShowDetail: split.rightShowDetail,
|
|
3832
4732
|
height: mainHeight
|
|
3833
4733
|
}
|
|
3834
|
-
) : showEventDetail && selectedEvent ? /* @__PURE__ */
|
|
4734
|
+
) : 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(
|
|
3835
4735
|
ActivityFeed,
|
|
3836
4736
|
{
|
|
3837
4737
|
events,
|
|
3838
4738
|
sessionSlug: activitySlug,
|
|
3839
4739
|
sessionId: selectedSession?.sessionId,
|
|
3840
|
-
|
|
4740
|
+
status: selectedGroup ? selectedGroup.status : selectedSession ? selectedSession.status : void 0,
|
|
3841
4741
|
focused: activePanel === "activity",
|
|
3842
4742
|
height: mainHeight,
|
|
3843
4743
|
scrollOffset: activityScroll,
|
|
@@ -3847,10 +4747,10 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3847
4747
|
selectedEventIndex
|
|
3848
4748
|
}
|
|
3849
4749
|
);
|
|
3850
|
-
return /* @__PURE__ */
|
|
3851
|
-
/* @__PURE__ */
|
|
3852
|
-
/* @__PURE__ */
|
|
3853
|
-
/* @__PURE__ */
|
|
4750
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", height: termHeight, children: [
|
|
4751
|
+
/* @__PURE__ */ jsx18(StatusBar, { sessionCount: sessions2.length, alertCount: alerts.length, version, updateInfo }),
|
|
4752
|
+
/* @__PURE__ */ jsxs18(Box18, { flexGrow: 1, height: mainHeight, children: [
|
|
4753
|
+
/* @__PURE__ */ jsx18(
|
|
3854
4754
|
SessionList,
|
|
3855
4755
|
{
|
|
3856
4756
|
visibleItems,
|
|
@@ -3863,21 +4763,21 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3863
4763
|
sidebarWidth
|
|
3864
4764
|
}
|
|
3865
4765
|
),
|
|
3866
|
-
/* @__PURE__ */
|
|
4766
|
+
/* @__PURE__ */ jsx18(Box18, { flexGrow: 1, flexShrink: 1, minWidth: 0, overflow: "hidden", children: rightPanel })
|
|
3867
4767
|
] }),
|
|
3868
|
-
!
|
|
3869
|
-
inputMode === "nickname" && /* @__PURE__ */
|
|
3870
|
-
/* @__PURE__ */
|
|
3871
|
-
/* @__PURE__ */
|
|
3872
|
-
/* @__PURE__ */
|
|
4768
|
+
!options2.noSecurity && /* @__PURE__ */ jsx18(AlertBar, { alerts }),
|
|
4769
|
+
inputMode === "nickname" && /* @__PURE__ */ jsxs18(Box18, { paddingX: 1, children: [
|
|
4770
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.primary, children: "nickname: " }),
|
|
4771
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.bright, children: nicknameInput.value }),
|
|
4772
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.muted, children: "_" })
|
|
3873
4773
|
] }),
|
|
3874
|
-
inputMode === "filter" && /* @__PURE__ */
|
|
3875
|
-
/* @__PURE__ */
|
|
3876
|
-
/* @__PURE__ */
|
|
3877
|
-
/* @__PURE__ */
|
|
3878
|
-
/* @__PURE__ */
|
|
4774
|
+
inputMode === "filter" && /* @__PURE__ */ jsxs18(Box18, { paddingX: 1, children: [
|
|
4775
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.muted, children: activePanel === "sessions" ? "sessions" : activePanel === "left" ? "left" : activePanel === "right" ? "right" : "activity" }),
|
|
4776
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.primary, children: "/" }),
|
|
4777
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.bright, children: filterInput.value }),
|
|
4778
|
+
/* @__PURE__ */ jsx18(Text17, { color: colors.muted, children: "_" })
|
|
3879
4779
|
] }),
|
|
3880
|
-
inputMode === "normal" && /* @__PURE__ */
|
|
4780
|
+
inputMode === "normal" && /* @__PURE__ */ jsx18(
|
|
3881
4781
|
FooterBar,
|
|
3882
4782
|
{
|
|
3883
4783
|
keybindings: kb,
|
|
@@ -3893,20 +4793,15 @@ var App = ({ options, config: initialConfig, version, firstRun }) => {
|
|
|
3893
4793
|
var write = (msg) => {
|
|
3894
4794
|
process.stdout.write(msg + "\n");
|
|
3895
4795
|
};
|
|
3896
|
-
var
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
return String(n);
|
|
3900
|
-
};
|
|
3901
|
-
var runStreamMode = (options, isJson) => {
|
|
3902
|
-
const engine = options.noSecurity ? null : new SecurityEngine(options.alertLevel);
|
|
3903
|
-
const sessions2 = discoverSessions(options.allUsers);
|
|
4796
|
+
var runStreamMode = (options2, isJson) => {
|
|
4797
|
+
const engine = options2.noSecurity ? null : new SecurityEngine(options2.alertLevel);
|
|
4798
|
+
const sessions2 = discoverSessions(options2.allUsers);
|
|
3904
4799
|
if (isJson) {
|
|
3905
4800
|
write(JSON.stringify({ type: "sessions", data: sessions2 }));
|
|
3906
4801
|
} else {
|
|
3907
4802
|
for (const s of sessions2) {
|
|
3908
4803
|
write(
|
|
3909
|
-
`SESSION ${s.slug} | ${s.model} | ${s.cwd} | CPU ${s.cpu}% | ${s.memMB}MB | ${
|
|
4804
|
+
`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`
|
|
3910
4805
|
);
|
|
3911
4806
|
}
|
|
3912
4807
|
}
|
|
@@ -3939,11 +4834,11 @@ var runStreamMode = (options, isJson) => {
|
|
|
3939
4834
|
write(JSON.stringify({ type: "usage", data: { sessionId, usage } }));
|
|
3940
4835
|
} else {
|
|
3941
4836
|
write(
|
|
3942
|
-
`USAGE ${sessionId.slice(0, 12)} +${
|
|
4837
|
+
`USAGE ${sessionId.slice(0, 12)} +${formatTokens(usage.inputTokens)} in / +${formatTokens(usage.outputTokens)} out`
|
|
3943
4838
|
);
|
|
3944
4839
|
}
|
|
3945
4840
|
};
|
|
3946
|
-
const watcher = new Watcher(handler,
|
|
4841
|
+
const watcher = new Watcher(handler, options2.allUsers, securityHandler, usageHandler);
|
|
3947
4842
|
watcher.start();
|
|
3948
4843
|
process.on("SIGINT", () => {
|
|
3949
4844
|
watcher.stop();
|
|
@@ -4004,7 +4899,7 @@ var write2 = (msg) => {
|
|
|
4004
4899
|
};
|
|
4005
4900
|
var parseArgs = (argv) => {
|
|
4006
4901
|
const args = argv.slice(2);
|
|
4007
|
-
const
|
|
4902
|
+
const options2 = {
|
|
4008
4903
|
allUsers: false,
|
|
4009
4904
|
noSecurity: false,
|
|
4010
4905
|
json: false,
|
|
@@ -4024,106 +4919,106 @@ var parseArgs = (argv) => {
|
|
|
4024
4919
|
for (let i = 0; i < args.length; i++) {
|
|
4025
4920
|
switch (args[i]) {
|
|
4026
4921
|
case "--all-users":
|
|
4027
|
-
|
|
4922
|
+
options2.allUsers = true;
|
|
4028
4923
|
break;
|
|
4029
4924
|
case "--no-security":
|
|
4030
|
-
|
|
4925
|
+
options2.noSecurity = true;
|
|
4031
4926
|
break;
|
|
4032
4927
|
case "--json":
|
|
4033
|
-
|
|
4928
|
+
options2.json = true;
|
|
4034
4929
|
break;
|
|
4035
4930
|
case "--plain":
|
|
4036
|
-
|
|
4931
|
+
options2.plain = true;
|
|
4037
4932
|
break;
|
|
4038
4933
|
case "--alert-level":
|
|
4039
4934
|
i++;
|
|
4040
4935
|
if (["info", "warn", "high", "critical"].includes(args[i])) {
|
|
4041
|
-
|
|
4936
|
+
options2.alertLevel = args[i];
|
|
4042
4937
|
}
|
|
4043
4938
|
break;
|
|
4044
4939
|
case "--no-notify":
|
|
4045
|
-
|
|
4940
|
+
options2.noNotify = true;
|
|
4046
4941
|
break;
|
|
4047
4942
|
case "--no-alert-log":
|
|
4048
|
-
|
|
4943
|
+
options2.noAlertLog = true;
|
|
4049
4944
|
break;
|
|
4050
4945
|
case "--no-updates":
|
|
4051
|
-
|
|
4946
|
+
options2.noUpdates = true;
|
|
4052
4947
|
break;
|
|
4053
4948
|
case "--poll-interval":
|
|
4054
4949
|
i++;
|
|
4055
4950
|
{
|
|
4056
4951
|
const n = parseInt(args[i], 10);
|
|
4057
|
-
if (n > 0)
|
|
4952
|
+
if (n > 0) options2.pollInterval = n;
|
|
4058
4953
|
}
|
|
4059
4954
|
break;
|
|
4060
4955
|
case "--mcp":
|
|
4061
|
-
|
|
4956
|
+
options2.mcp = true;
|
|
4062
4957
|
break;
|
|
4063
4958
|
case "--install-mcp":
|
|
4064
|
-
|
|
4959
|
+
options2.installMcp = true;
|
|
4065
4960
|
break;
|
|
4066
4961
|
case "--install-hooks":
|
|
4067
|
-
|
|
4962
|
+
options2.installHooks = true;
|
|
4068
4963
|
break;
|
|
4069
4964
|
case "--uninstall-hooks":
|
|
4070
|
-
|
|
4965
|
+
options2.uninstallHooks = true;
|
|
4071
4966
|
break;
|
|
4072
4967
|
case "--version":
|
|
4073
|
-
|
|
4968
|
+
options2.version = true;
|
|
4074
4969
|
break;
|
|
4075
4970
|
case "--help":
|
|
4076
|
-
|
|
4971
|
+
options2.help = true;
|
|
4077
4972
|
break;
|
|
4078
4973
|
}
|
|
4079
4974
|
}
|
|
4080
|
-
return
|
|
4975
|
+
return options2;
|
|
4081
4976
|
};
|
|
4082
4977
|
var main = () => {
|
|
4083
|
-
const
|
|
4084
|
-
if (
|
|
4978
|
+
const options2 = parseArgs(process.argv);
|
|
4979
|
+
if (options2.version) {
|
|
4085
4980
|
write2(`agenttop v${VERSION}`);
|
|
4086
4981
|
process.exit(0);
|
|
4087
4982
|
}
|
|
4088
|
-
if (
|
|
4983
|
+
if (options2.help) {
|
|
4089
4984
|
write2(HELP);
|
|
4090
4985
|
process.exit(0);
|
|
4091
4986
|
}
|
|
4092
|
-
if (
|
|
4987
|
+
if (options2.installHooks) {
|
|
4093
4988
|
installHooks();
|
|
4094
4989
|
process.exit(0);
|
|
4095
4990
|
}
|
|
4096
|
-
if (
|
|
4991
|
+
if (options2.uninstallHooks) {
|
|
4097
4992
|
uninstallHooks();
|
|
4098
4993
|
process.exit(0);
|
|
4099
4994
|
}
|
|
4100
|
-
if (
|
|
4995
|
+
if (options2.installMcp) {
|
|
4101
4996
|
installMcpConfig();
|
|
4102
4997
|
process.exit(0);
|
|
4103
4998
|
}
|
|
4104
|
-
if (
|
|
4105
|
-
startMcpServer(
|
|
4999
|
+
if (options2.mcp) {
|
|
5000
|
+
startMcpServer(options2.allUsers, options2.noSecurity).catch((err) => {
|
|
4106
5001
|
process.stderr.write(`mcp server error: ${err}
|
|
4107
5002
|
`);
|
|
4108
5003
|
process.exit(1);
|
|
4109
5004
|
});
|
|
4110
5005
|
return;
|
|
4111
5006
|
}
|
|
4112
|
-
if (
|
|
4113
|
-
runStreamMode(
|
|
5007
|
+
if (options2.json || options2.plain) {
|
|
5008
|
+
runStreamMode(options2, options2.json);
|
|
4114
5009
|
return;
|
|
4115
5010
|
}
|
|
4116
5011
|
const config = loadConfig();
|
|
4117
5012
|
const firstRun = isFirstRun();
|
|
4118
|
-
if (
|
|
5013
|
+
if (options2.noNotify) {
|
|
4119
5014
|
config.notifications.bell = false;
|
|
4120
5015
|
config.notifications.desktop = false;
|
|
4121
5016
|
}
|
|
4122
|
-
if (
|
|
4123
|
-
if (
|
|
4124
|
-
if (
|
|
5017
|
+
if (options2.noAlertLog) config.alerts.enabled = false;
|
|
5018
|
+
if (options2.noUpdates) config.updates.checkOnLaunch = false;
|
|
5019
|
+
if (options2.noSecurity) config.security.enabled = false;
|
|
4125
5020
|
if (firstRun) saveConfig(config);
|
|
4126
|
-
render(
|
|
5021
|
+
render(React19.createElement(App, { options: options2, config, version: VERSION, firstRun }));
|
|
4127
5022
|
};
|
|
4128
5023
|
main();
|
|
4129
5024
|
//# sourceMappingURL=index.js.map
|