claude-code-kanban 4.23.2 → 4.25.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 +4 -1
- package/cli.js +1 -1
- package/install.js +14 -9
- package/lib/claude-dir.js +53 -0
- package/lib/open-editor.js +4 -1
- package/lib/parsers.js +54 -4
- package/package.json +1 -1
- package/plugin/plugins/claude-code-kanban/.claude-plugin/plugin.json +1 -1
- package/plugin/plugins/claude-code-kanban/scripts/agent-spy.sh +2 -2
- package/plugin/plugins/claude-code-kanban/scripts/approval-gate.sh +6 -6
- package/plugin/plugins/claude-code-kanban/scripts/context-status.sh +2 -2
- package/plugin/plugins/claude-code-kanban/scripts/postman.js +2 -1
- package/public/app.js +589 -186
- package/public/index.html +15 -132
- package/public/style.css +312 -6
- package/server.js +14 -23
package/public/index.html
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github.min.css" id="hljs-theme-light" disabled>
|
|
23
23
|
<script defer src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"></script>
|
|
24
24
|
<script defer src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
|
25
|
+
<script>window.__STORAGE_NS__ = null;</script>
|
|
25
26
|
<script defer src="/app.js"></script>
|
|
26
27
|
</head>
|
|
27
28
|
<body>
|
|
@@ -346,7 +347,7 @@
|
|
|
346
347
|
|
|
347
348
|
<!-- Help Modal -->
|
|
348
349
|
<div id="help-modal" class="modal-overlay" onclick="closeHelpModal()">
|
|
349
|
-
<div class="modal" onclick="event.stopPropagation()">
|
|
350
|
+
<div class="modal modal-help" onclick="event.stopPropagation()">
|
|
350
351
|
<div class="modal-header">
|
|
351
352
|
<h3 class="modal-title">Keyboard Shortcuts</h3>
|
|
352
353
|
<button class="modal-close" aria-label="Close dialog" onclick="closeHelpModal()">
|
|
@@ -355,137 +356,8 @@
|
|
|
355
356
|
</svg>
|
|
356
357
|
</button>
|
|
357
358
|
</div>
|
|
358
|
-
<div class="modal-body
|
|
359
|
-
<
|
|
360
|
-
<div style="display: grid; gap: 16px; align-content: start;">
|
|
361
|
-
<div>
|
|
362
|
-
<h4 style="margin: 0 0 8px 0; color: var(--text-primary); font-size: 14px; font-weight: 600;">Global</h4>
|
|
363
|
-
<table style="width: 100%; font-size: 13px;">
|
|
364
|
-
<tr>
|
|
365
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">?</kbd></td>
|
|
366
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Show keyboard shortcuts</td>
|
|
367
|
-
</tr>
|
|
368
|
-
<tr>
|
|
369
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Esc</kbd></td>
|
|
370
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Close panels or cancel</td>
|
|
371
|
-
</tr>
|
|
372
|
-
<tr>
|
|
373
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Tab</kbd></td>
|
|
374
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle sidebar / board focus</td>
|
|
375
|
-
</tr>
|
|
376
|
-
<tr>
|
|
377
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">[</kbd></td>
|
|
378
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle sidebar collapse</td>
|
|
379
|
-
</tr>
|
|
380
|
-
<tr>
|
|
381
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">R</kbd></td>
|
|
382
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Reload page</td>
|
|
383
|
-
</tr>
|
|
384
|
-
</table>
|
|
385
|
-
</div>
|
|
386
|
-
<div>
|
|
387
|
-
<h4 style="margin: 0 0 8px 0; color: var(--text-primary); font-size: 14px; font-weight: 600;">Navigation</h4>
|
|
388
|
-
<table style="width: 100%; font-size: 13px;">
|
|
389
|
-
<tr>
|
|
390
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">J</kbd> / <kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">↓</kbd></td>
|
|
391
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Next task in column</td>
|
|
392
|
-
</tr>
|
|
393
|
-
<tr>
|
|
394
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">K</kbd> / <kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">↑</kbd></td>
|
|
395
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Previous task in column</td>
|
|
396
|
-
</tr>
|
|
397
|
-
<tr>
|
|
398
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">H</kbd> / <kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">←</kbd></td>
|
|
399
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Move to left column</td>
|
|
400
|
-
</tr>
|
|
401
|
-
<tr>
|
|
402
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">L</kbd> / <kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">→</kbd></td>
|
|
403
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Move to right column</td>
|
|
404
|
-
</tr>
|
|
405
|
-
<tr>
|
|
406
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Enter</kbd></td>
|
|
407
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle task detail panel</td>
|
|
408
|
-
</tr>
|
|
409
|
-
</table>
|
|
410
|
-
</div>
|
|
411
|
-
</div>
|
|
412
|
-
<div style="align-content: start;">
|
|
413
|
-
<h4 style="margin: 0 0 8px 0; color: var(--text-primary); font-size: 14px; font-weight: 600;">Actions</h4>
|
|
414
|
-
<table style="width: 100%; font-size: 13px;">
|
|
415
|
-
<tr>
|
|
416
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">P</kbd></td>
|
|
417
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Open session plan</td>
|
|
418
|
-
</tr>
|
|
419
|
-
<tr>
|
|
420
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">I</kbd></td>
|
|
421
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Open session info</td>
|
|
422
|
-
</tr>
|
|
423
|
-
<tr>
|
|
424
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Ctrl+D</kbd></td>
|
|
425
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Dismiss selected session</td>
|
|
426
|
-
</tr>
|
|
427
|
-
<tr>
|
|
428
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">D</kbd></td>
|
|
429
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Delete selected task</td>
|
|
430
|
-
</tr>
|
|
431
|
-
<tr>
|
|
432
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">N</kbd></td>
|
|
433
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle scratchpad</td>
|
|
434
|
-
</tr>
|
|
435
|
-
<tr>
|
|
436
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">.</kbd></td>
|
|
437
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Pin/unpin selected session</td>
|
|
438
|
-
</tr>
|
|
439
|
-
<tr>
|
|
440
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">></kbd></td>
|
|
441
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle sticky on selected session</td>
|
|
442
|
-
</tr>
|
|
443
|
-
<tr>
|
|
444
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">T</kbd></td>
|
|
445
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle theme</td>
|
|
446
|
-
</tr>
|
|
447
|
-
<tr>
|
|
448
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">M</kbd></td>
|
|
449
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Jump to marketplace</td>
|
|
450
|
-
</tr>
|
|
451
|
-
<tr>
|
|
452
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">$</kbd></td>
|
|
453
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Jump to cost</td>
|
|
454
|
-
</tr>
|
|
455
|
-
<tr>
|
|
456
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Shift+L</kbd></td>
|
|
457
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Toggle session log</td>
|
|
458
|
-
</tr>
|
|
459
|
-
<tr>
|
|
460
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Shift+M</kbd></td>
|
|
461
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Open last message detail</td>
|
|
462
|
-
</tr>
|
|
463
|
-
<tr>
|
|
464
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Ctrl++</kbd> / <kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Ctrl+-</kbd></td>
|
|
465
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Modal text size</td>
|
|
466
|
-
</tr>
|
|
467
|
-
<tr>
|
|
468
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Ctrl+0</kbd></td>
|
|
469
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Reset text size</td>
|
|
470
|
-
</tr>
|
|
471
|
-
<tr>
|
|
472
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Shift+S</kbd></td>
|
|
473
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Storage manager</td>
|
|
474
|
-
</tr>
|
|
475
|
-
<tr>
|
|
476
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">Shift+C</kbd></td>
|
|
477
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Copy session id</td>
|
|
478
|
-
</tr>
|
|
479
|
-
<tr>
|
|
480
|
-
<td style="padding: 4px 0; color: var(--text-secondary);"><kbd style="background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-family: monospace;">J/K</kbd></td>
|
|
481
|
-
<td style="padding: 4px 0; color: var(--text-primary);">Navigate messages in detail modal</td>
|
|
482
|
-
</tr>
|
|
483
|
-
</table>
|
|
484
|
-
</div>
|
|
485
|
-
</div>
|
|
486
|
-
</div>
|
|
487
|
-
<div class="modal-footer">
|
|
488
|
-
<button class="btn btn-primary" onclick="closeHelpModal()">Got it</button>
|
|
359
|
+
<div class="modal-body">
|
|
360
|
+
<dl class="shortcuts" id="help-shortcuts"></dl>
|
|
489
361
|
</div>
|
|
490
362
|
</div>
|
|
491
363
|
</div>
|
|
@@ -737,6 +609,17 @@
|
|
|
737
609
|
</div>
|
|
738
610
|
</div>
|
|
739
611
|
|
|
612
|
+
<div id="session-picker-modal" class="modal-overlay top-aligned" onclick="closeSessionPicker()">
|
|
613
|
+
<div class="modal session-picker" onclick="event.stopPropagation()">
|
|
614
|
+
<input type="text" id="session-picker-input" class="form-input sp-input" placeholder="Jump to session..." autocomplete="off" spellcheck="false">
|
|
615
|
+
<div class="sp-body">
|
|
616
|
+
<div id="session-picker-list" class="sp-list"></div>
|
|
617
|
+
<div id="session-picker-peek" class="sp-peek"></div>
|
|
618
|
+
</div>
|
|
619
|
+
<div class="sp-hint"><kbd>↑</kbd><kbd>↓</kbd> move · <kbd>Enter</kbd> open · <kbd>Ctrl</kbd><kbd>Space</kbd> peek · <kbd>Esc</kbd> close</div>
|
|
620
|
+
</div>
|
|
621
|
+
</div>
|
|
622
|
+
|
|
740
623
|
<div id="toast" class="toast"></div>
|
|
741
624
|
</body>
|
|
742
625
|
</html>
|
package/public/style.css
CHANGED
|
@@ -2264,7 +2264,8 @@ body::before {
|
|
|
2264
2264
|
flex-direction: column;
|
|
2265
2265
|
}
|
|
2266
2266
|
#team-modal .modal-body,
|
|
2267
|
-
#agent-modal .modal-body
|
|
2267
|
+
#agent-modal .modal-body,
|
|
2268
|
+
.modal-help .modal-body {
|
|
2268
2269
|
flex: 1 1 auto;
|
|
2269
2270
|
overflow-y: auto;
|
|
2270
2271
|
min-height: 0;
|
|
@@ -2349,7 +2350,6 @@ body::before {
|
|
|
2349
2350
|
padding: 10px 14px;
|
|
2350
2351
|
background: var(--bg-elevated);
|
|
2351
2352
|
border: 1px solid var(--border);
|
|
2352
|
-
border-left: 3px solid var(--warning);
|
|
2353
2353
|
border-radius: 8px;
|
|
2354
2354
|
}
|
|
2355
2355
|
.info-goal-head {
|
|
@@ -4264,6 +4264,13 @@ body.light .msg-assistant .msg-text {
|
|
|
4264
4264
|
display: flex;
|
|
4265
4265
|
}
|
|
4266
4266
|
|
|
4267
|
+
/* For pickers: the dialog sits above the vertical centre so its list grows
|
|
4268
|
+
downward instead of shifting rows under the cursor as it filters. */
|
|
4269
|
+
.modal-overlay.top-aligned {
|
|
4270
|
+
align-items: flex-start;
|
|
4271
|
+
padding-top: 12vh;
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4267
4274
|
.plan-modal-overlay {
|
|
4268
4275
|
z-index: 10001;
|
|
4269
4276
|
background: rgba(0, 0, 0, 0.6);
|
|
@@ -4512,6 +4519,119 @@ body.light .msg-assistant .msg-text {
|
|
|
4512
4519
|
max-width: 440px;
|
|
4513
4520
|
}
|
|
4514
4521
|
|
|
4522
|
+
/* Reference card, not reading material: it stays out of the modal zoom, uses the app's
|
|
4523
|
+
small type, and scrolls its body (rule shared with #team-modal) instead of growing past
|
|
4524
|
+
the viewport cap. */
|
|
4525
|
+
.modal-help {
|
|
4526
|
+
max-width: 900px;
|
|
4527
|
+
padding: 16px 20px 20px;
|
|
4528
|
+
display: flex;
|
|
4529
|
+
flex-direction: column;
|
|
4530
|
+
font-size: 13px;
|
|
4531
|
+
}
|
|
4532
|
+
.modal-help .modal-header {
|
|
4533
|
+
margin-bottom: 8px;
|
|
4534
|
+
}
|
|
4535
|
+
.modal-help .modal-title {
|
|
4536
|
+
font-size: 14px;
|
|
4537
|
+
}
|
|
4538
|
+
|
|
4539
|
+
/* One shared grid for both halves (key | label | spacer | key | label): each key
|
|
4540
|
+
gutter is sized by its column's widest combo, and left/right rows share row
|
|
4541
|
+
tracks, so paired groups line up — a shorter group just leaves empty rows.
|
|
4542
|
+
Cells opt into a half via sc-l / sc-r; the markup is generated from
|
|
4543
|
+
SHORTCUT_PAIRS in app.js. */
|
|
4544
|
+
.shortcuts {
|
|
4545
|
+
margin: 0;
|
|
4546
|
+
display: grid;
|
|
4547
|
+
grid-template-columns: max-content 1fr 28px max-content 1fr;
|
|
4548
|
+
column-gap: 14px;
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4551
|
+
.shortcuts dt.sc-l {
|
|
4552
|
+
grid-column: 1;
|
|
4553
|
+
}
|
|
4554
|
+
.shortcuts dd.sc-l {
|
|
4555
|
+
grid-column: 2;
|
|
4556
|
+
}
|
|
4557
|
+
.shortcuts dt.sc-r {
|
|
4558
|
+
grid-column: 4;
|
|
4559
|
+
}
|
|
4560
|
+
.shortcuts dd.sc-r {
|
|
4561
|
+
grid-column: 5;
|
|
4562
|
+
}
|
|
4563
|
+
.shortcuts .sc-group.sc-l {
|
|
4564
|
+
grid-column: 1 / 3;
|
|
4565
|
+
}
|
|
4566
|
+
.shortcuts .sc-group.sc-r {
|
|
4567
|
+
grid-column: 4 / 6;
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
.shortcuts dt {
|
|
4571
|
+
margin: 0;
|
|
4572
|
+
display: flex;
|
|
4573
|
+
align-items: center;
|
|
4574
|
+
align-self: center;
|
|
4575
|
+
gap: 4px;
|
|
4576
|
+
padding: 3px 0;
|
|
4577
|
+
}
|
|
4578
|
+
|
|
4579
|
+
.shortcuts dd {
|
|
4580
|
+
margin: 0;
|
|
4581
|
+
font-size: 13px;
|
|
4582
|
+
color: var(--text-secondary);
|
|
4583
|
+
align-self: center;
|
|
4584
|
+
padding: 3px 0;
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4587
|
+
/* Section headings carry the column: full-width rule + primary ink, so the eye
|
|
4588
|
+
finds the group before it reads any single row. */
|
|
4589
|
+
.shortcuts .sc-group {
|
|
4590
|
+
padding: 18px 0 6px;
|
|
4591
|
+
margin-bottom: 6px;
|
|
4592
|
+
font-size: 11px;
|
|
4593
|
+
font-weight: 700;
|
|
4594
|
+
letter-spacing: 0.16em;
|
|
4595
|
+
text-transform: uppercase;
|
|
4596
|
+
color: var(--text-primary);
|
|
4597
|
+
border-bottom: 1px solid var(--border);
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4600
|
+
.shortcuts .sc-group.sc-first {
|
|
4601
|
+
padding-top: 2px;
|
|
4602
|
+
}
|
|
4603
|
+
|
|
4604
|
+
/* keycap chips: elevated fill + thicker bottom border reads as a key */
|
|
4605
|
+
.sp-hint kbd,
|
|
4606
|
+
.shortcuts kbd {
|
|
4607
|
+
display: inline-flex;
|
|
4608
|
+
align-items: center;
|
|
4609
|
+
justify-content: center;
|
|
4610
|
+
min-width: 22px;
|
|
4611
|
+
height: 22px;
|
|
4612
|
+
padding: 0 6px;
|
|
4613
|
+
box-sizing: border-box;
|
|
4614
|
+
font-family: var(--font-mono, monospace);
|
|
4615
|
+
font-size: 11px;
|
|
4616
|
+
color: var(--text-primary);
|
|
4617
|
+
background: var(--bg-hover);
|
|
4618
|
+
border: 1px solid var(--border);
|
|
4619
|
+
border-bottom-width: 2px;
|
|
4620
|
+
border-radius: 5px;
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
.shortcuts .sc-plus,
|
|
4624
|
+
.shortcuts .sc-or {
|
|
4625
|
+
color: var(--text-muted);
|
|
4626
|
+
font-size: 11px;
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
/* Hub jumps are no-ops outside Claude Code Hub, so the standalone board hides
|
|
4630
|
+
that whole column rather than listing keys that do nothing. */
|
|
4631
|
+
.shortcuts.sc-standalone .sc-hub {
|
|
4632
|
+
display: none;
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4515
4635
|
@keyframes live-border-pulse {
|
|
4516
4636
|
0%,
|
|
4517
4637
|
100% {
|
|
@@ -4721,6 +4841,176 @@ select.form-input option:checked {
|
|
|
4721
4841
|
|
|
4722
4842
|
/* #endregion */
|
|
4723
4843
|
|
|
4844
|
+
/* #region SESSION_PICKER */
|
|
4845
|
+
.modal.session-picker {
|
|
4846
|
+
max-height: 70vh;
|
|
4847
|
+
padding: 12px;
|
|
4848
|
+
display: flex;
|
|
4849
|
+
flex-direction: column;
|
|
4850
|
+
gap: 8px;
|
|
4851
|
+
overflow: hidden;
|
|
4852
|
+
}
|
|
4853
|
+
|
|
4854
|
+
.sp-input {
|
|
4855
|
+
padding: 9px 12px;
|
|
4856
|
+
background: var(--bg-deep);
|
|
4857
|
+
font-size: 13px;
|
|
4858
|
+
}
|
|
4859
|
+
|
|
4860
|
+
.modal.session-picker.peeking {
|
|
4861
|
+
max-width: 1240px;
|
|
4862
|
+
}
|
|
4863
|
+
|
|
4864
|
+
.sp-body {
|
|
4865
|
+
display: flex;
|
|
4866
|
+
gap: 10px;
|
|
4867
|
+
min-height: 0;
|
|
4868
|
+
}
|
|
4869
|
+
|
|
4870
|
+
.sp-body > * {
|
|
4871
|
+
min-width: 0;
|
|
4872
|
+
}
|
|
4873
|
+
|
|
4874
|
+
.sp-list {
|
|
4875
|
+
flex: 1;
|
|
4876
|
+
overflow-y: auto;
|
|
4877
|
+
display: flex;
|
|
4878
|
+
flex-direction: column;
|
|
4879
|
+
gap: 2px;
|
|
4880
|
+
}
|
|
4881
|
+
|
|
4882
|
+
.sp-peek {
|
|
4883
|
+
flex: 0 0 42%;
|
|
4884
|
+
overflow-y: auto;
|
|
4885
|
+
border-left: 1px solid var(--border);
|
|
4886
|
+
padding-left: 10px;
|
|
4887
|
+
}
|
|
4888
|
+
|
|
4889
|
+
.modal.session-picker:not(.peeking) .sp-peek {
|
|
4890
|
+
display: none;
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4893
|
+
.sp-peek-title {
|
|
4894
|
+
display: flex;
|
|
4895
|
+
align-items: center;
|
|
4896
|
+
justify-content: space-between;
|
|
4897
|
+
gap: 8px;
|
|
4898
|
+
margin-bottom: 6px;
|
|
4899
|
+
font-family: var(--mono);
|
|
4900
|
+
font-size: 11px;
|
|
4901
|
+
color: var(--text-muted);
|
|
4902
|
+
white-space: nowrap;
|
|
4903
|
+
overflow: hidden;
|
|
4904
|
+
text-overflow: ellipsis;
|
|
4905
|
+
}
|
|
4906
|
+
|
|
4907
|
+
/* Row clicks open the live panel's detail modal by index, which means nothing
|
|
4908
|
+
for a peeked session. The renderer's readOnly mode already drops the buttons. */
|
|
4909
|
+
.sp-peek-items {
|
|
4910
|
+
pointer-events: none;
|
|
4911
|
+
}
|
|
4912
|
+
|
|
4913
|
+
.sp-row {
|
|
4914
|
+
display: flex;
|
|
4915
|
+
align-items: center;
|
|
4916
|
+
gap: 8px;
|
|
4917
|
+
width: 100%;
|
|
4918
|
+
padding: 6px 8px;
|
|
4919
|
+
background: none;
|
|
4920
|
+
border: 1px solid transparent;
|
|
4921
|
+
border-radius: 5px;
|
|
4922
|
+
color: var(--text-secondary);
|
|
4923
|
+
font-family: var(--mono);
|
|
4924
|
+
font-size: 12px;
|
|
4925
|
+
text-align: left;
|
|
4926
|
+
cursor: pointer;
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4929
|
+
.sp-row:hover {
|
|
4930
|
+
background: var(--bg-hover);
|
|
4931
|
+
}
|
|
4932
|
+
|
|
4933
|
+
.sp-row.selected {
|
|
4934
|
+
background: var(--bg-elevated);
|
|
4935
|
+
border-color: var(--accent);
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
.sp-row .activity-dot.live {
|
|
4939
|
+
background: var(--success);
|
|
4940
|
+
}
|
|
4941
|
+
|
|
4942
|
+
.sp-row .activity-dot.active {
|
|
4943
|
+
background: var(--accent);
|
|
4944
|
+
}
|
|
4945
|
+
|
|
4946
|
+
.sp-row .activity-dot.waiting {
|
|
4947
|
+
background: var(--warning);
|
|
4948
|
+
}
|
|
4949
|
+
|
|
4950
|
+
.sp-name,
|
|
4951
|
+
.sp-project,
|
|
4952
|
+
.sp-branch {
|
|
4953
|
+
overflow: hidden;
|
|
4954
|
+
text-overflow: ellipsis;
|
|
4955
|
+
white-space: nowrap;
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
.sp-name {
|
|
4959
|
+
flex: none;
|
|
4960
|
+
max-width: 40%;
|
|
4961
|
+
color: var(--text-primary);
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4964
|
+
.sp-row.current .sp-name {
|
|
4965
|
+
color: var(--accent-text);
|
|
4966
|
+
}
|
|
4967
|
+
|
|
4968
|
+
.sp-project {
|
|
4969
|
+
flex: 1;
|
|
4970
|
+
min-width: 0;
|
|
4971
|
+
color: var(--text-muted);
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4974
|
+
.sp-branch {
|
|
4975
|
+
flex: none;
|
|
4976
|
+
max-width: 25%;
|
|
4977
|
+
padding: 1px 5px;
|
|
4978
|
+
border-radius: 3px;
|
|
4979
|
+
background: var(--bg-hover);
|
|
4980
|
+
color: var(--text-tertiary);
|
|
4981
|
+
font-size: 11px;
|
|
4982
|
+
}
|
|
4983
|
+
|
|
4984
|
+
.sp-count,
|
|
4985
|
+
.sp-time {
|
|
4986
|
+
flex: none;
|
|
4987
|
+
color: var(--text-muted);
|
|
4988
|
+
font-size: 11px;
|
|
4989
|
+
white-space: nowrap;
|
|
4990
|
+
}
|
|
4991
|
+
|
|
4992
|
+
.sp-time {
|
|
4993
|
+
min-width: 62px;
|
|
4994
|
+
text-align: right;
|
|
4995
|
+
}
|
|
4996
|
+
|
|
4997
|
+
.sp-empty {
|
|
4998
|
+
padding: 20px 8px;
|
|
4999
|
+
color: var(--text-muted);
|
|
5000
|
+
font-size: 12px;
|
|
5001
|
+
text-align: center;
|
|
5002
|
+
}
|
|
5003
|
+
|
|
5004
|
+
.sp-hint {
|
|
5005
|
+
display: flex;
|
|
5006
|
+
align-items: center;
|
|
5007
|
+
gap: 5px;
|
|
5008
|
+
color: var(--text-muted);
|
|
5009
|
+
font-size: 11px;
|
|
5010
|
+
}
|
|
5011
|
+
|
|
5012
|
+
/* #endregion */
|
|
5013
|
+
|
|
4724
5014
|
/* #region TOOL_STATS */
|
|
4725
5015
|
.modal.tool-stats-modal {
|
|
4726
5016
|
width: 90%;
|
|
@@ -5314,21 +5604,24 @@ pre.mermaid svg {
|
|
|
5314
5604
|
}
|
|
5315
5605
|
|
|
5316
5606
|
.project-group-header.kb-selected,
|
|
5317
|
-
.pinned-sub-header.kb-selected
|
|
5607
|
+
.pinned-sub-header.kb-selected,
|
|
5608
|
+
.sg-section-toggle.kb-selected {
|
|
5318
5609
|
color: var(--text-primary);
|
|
5319
5610
|
background: var(--bg-hover);
|
|
5320
5611
|
border-radius: 4px;
|
|
5321
5612
|
}
|
|
5322
5613
|
|
|
5323
5614
|
.project-group-header .group-chevron,
|
|
5324
|
-
.session-group-header .group-chevron
|
|
5615
|
+
.session-group-header .group-chevron,
|
|
5616
|
+
.sg-section-toggle .group-chevron {
|
|
5325
5617
|
transition: transform 0.15s ease;
|
|
5326
5618
|
flex-shrink: 0;
|
|
5327
5619
|
display: block;
|
|
5328
5620
|
}
|
|
5329
5621
|
|
|
5330
5622
|
.project-group-header.collapsed .group-chevron,
|
|
5331
|
-
.session-group-header.collapsed .group-chevron
|
|
5623
|
+
.session-group-header.collapsed .group-chevron,
|
|
5624
|
+
.sg-section-toggle.collapsed .group-chevron {
|
|
5332
5625
|
transform: rotate(-90deg);
|
|
5333
5626
|
}
|
|
5334
5627
|
|
|
@@ -5522,6 +5815,18 @@ pre.mermaid svg {
|
|
|
5522
5815
|
margin-top: 0;
|
|
5523
5816
|
}
|
|
5524
5817
|
|
|
5818
|
+
.sg-section-toggle {
|
|
5819
|
+
display: flex;
|
|
5820
|
+
align-items: center;
|
|
5821
|
+
gap: 4px;
|
|
5822
|
+
padding-bottom: 4px;
|
|
5823
|
+
cursor: pointer;
|
|
5824
|
+
}
|
|
5825
|
+
|
|
5826
|
+
.sg-section-toggle:hover {
|
|
5827
|
+
color: var(--text-primary);
|
|
5828
|
+
}
|
|
5829
|
+
|
|
5525
5830
|
.session-group-header {
|
|
5526
5831
|
display: flex;
|
|
5527
5832
|
align-items: center;
|
|
@@ -5584,7 +5889,8 @@ pre.mermaid svg {
|
|
|
5584
5889
|
margin-left: 6px;
|
|
5585
5890
|
}
|
|
5586
5891
|
|
|
5587
|
-
.session-group-sessions.collapsed
|
|
5892
|
+
.session-group-sessions.collapsed,
|
|
5893
|
+
.sg-section-body.collapsed {
|
|
5588
5894
|
display: none;
|
|
5589
5895
|
}
|
|
5590
5896
|
|
package/server.js
CHANGED
|
@@ -34,6 +34,7 @@ const {
|
|
|
34
34
|
} = require('./lib/parsers');
|
|
35
35
|
const { inlineHtmlAssets } = require('./lib/inline-assets');
|
|
36
36
|
const { buildDecision, decisionFileName, isDecisionFile, waitSecondsFrom, isLapsed } = require('./lib/approvals');
|
|
37
|
+
const { getClaudeDir, getArgValue, storageNamespace } = require('./lib/claude-dir');
|
|
37
38
|
|
|
38
39
|
if (process.argv.includes("--install") || process.argv.includes("--uninstall")) {
|
|
39
40
|
const { runInstall, runUninstall } = require("./install");
|
|
@@ -56,30 +57,8 @@ app.use(net.hostGuard);
|
|
|
56
57
|
app.use(net.frameGuard);
|
|
57
58
|
app.use(net.originGuard);
|
|
58
59
|
|
|
59
|
-
// Parse --dir flag for custom Claude directory
|
|
60
|
-
function getClaudeDir() {
|
|
61
|
-
const dirIndex = process.argv.findIndex(arg => arg.startsWith('--dir'));
|
|
62
|
-
if (dirIndex !== -1) {
|
|
63
|
-
const arg = process.argv[dirIndex];
|
|
64
|
-
if (arg.includes('=')) {
|
|
65
|
-
const dir = arg.split('=')[1];
|
|
66
|
-
return dir.startsWith('~') ? dir.replace('~', os.homedir()) : dir;
|
|
67
|
-
} else if (process.argv[dirIndex + 1]) {
|
|
68
|
-
const dir = process.argv[dirIndex + 1];
|
|
69
|
-
return dir.startsWith('~') ? dir.replace('~', os.homedir()) : dir;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return process.env.CLAUDE_CONFIG_DIR || process.env.CLAUDE_DIR || path.join(os.homedir(), '.claude');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
60
|
function getArgUrl(argName, envName) {
|
|
76
|
-
|
|
77
|
-
if (idx !== -1) {
|
|
78
|
-
const arg = process.argv[idx];
|
|
79
|
-
if (arg.includes('=')) return arg.split('=').slice(1).join('=');
|
|
80
|
-
if (process.argv[idx + 1]) return process.argv[idx + 1];
|
|
81
|
-
}
|
|
82
|
-
return process.env[envName] || null;
|
|
61
|
+
return getArgValue(argName) || process.env[envName] || null;
|
|
83
62
|
}
|
|
84
63
|
|
|
85
64
|
const MARKETPLACE_URL = getArgUrl('marketplace-url', 'MARKETPLACE_URL');
|
|
@@ -516,6 +495,18 @@ app.get('/hub-config', (_req, res) => {
|
|
|
516
495
|
res.json({ enabled: !!process.env.CLAUDE_HUB, url: process.env.HUB_URL || null });
|
|
517
496
|
});
|
|
518
497
|
|
|
498
|
+
// app.js reads localStorage synchronously at startup, before any fetch could deliver the
|
|
499
|
+
// namespace, so it is injected into the page instead of served from /hub-config.
|
|
500
|
+
const STORAGE_NS = storageNamespace(CLAUDE_DIR);
|
|
501
|
+
const NS_DECL = 'window.__STORAGE_NS__ = null;';
|
|
502
|
+
const RAW_INDEX = readFileSync(path.join(__dirname, 'public', 'index.html'), 'utf8');
|
|
503
|
+
if (!RAW_INDEX.includes(NS_DECL)) throw new Error(`public/index.html is missing "${NS_DECL}"`);
|
|
504
|
+
const INDEX_HTML = RAW_INDEX.replace(NS_DECL, `window.__STORAGE_NS__ = ${JSON.stringify(STORAGE_NS)};`);
|
|
505
|
+
app.get(['/', '/index.html'], (_req, res) => {
|
|
506
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
507
|
+
res.type('html').send(INDEX_HTML);
|
|
508
|
+
});
|
|
509
|
+
|
|
519
510
|
// Serve static files
|
|
520
511
|
app.get('/sw.js', (_req, res) => {
|
|
521
512
|
res.setHeader('Cache-Control', 'no-cache');
|