claude-code-kanban 7.5.0 → 7.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/hub-app.json +5 -0
  2. package/lib/panes.js +16 -2
  3. package/lib/parsers.js +27 -2
  4. package/lib/retention.js +29 -6
  5. package/lib/session-events.js +154 -42
  6. package/lib/show.js +385 -0
  7. package/lib/terminal-client.js +14 -1
  8. package/lib/terminal-host.js +2 -1
  9. package/lib/terminal.js +27 -7
  10. package/package.json +1 -1
  11. package/plugin/plugins/claude-code-kanban/.claude-plugin/plugin.json +1 -1
  12. package/plugin/plugins/claude-code-kanban/hooks/doorbell.ts +66 -10
  13. package/plugin/plugins/claude-code-kanban/hooks/index.ts +2 -0
  14. package/plugin/plugins/claude-code-kanban/hooks/show.ts +120 -0
  15. package/plugin/plugins/claude-code-kanban/skills/dispatch/SKILL.md +2 -0
  16. package/plugin/plugins/claude-code-kanban/skills/kanban/SKILL.md +2 -0
  17. package/plugin/plugins/claude-code-kanban/skills/show/SKILL.md +45 -0
  18. package/plugin/plugins/claude-code-kanban/skills/show/references/NOTICE.md +27 -0
  19. package/plugin/plugins/claude-code-kanban/skills/show/references/chart.md +58 -0
  20. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/architecture.md +18 -0
  21. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/er.md +10 -0
  22. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/flow.md +13 -0
  23. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/layers.md +10 -0
  24. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/sequence.md +19 -0
  25. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/state.md +12 -0
  26. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/swimlane.md +10 -0
  27. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/timeline.md +9 -0
  28. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/tree.md +10 -0
  29. package/plugin/plugins/claude-code-kanban/skills/show/references/diagram.md +87 -0
  30. package/plugin/plugins/claude-code-kanban/skills/show/references/explain.md +98 -0
  31. package/plugin/plugins/claude-code-kanban/skills/show/references/mockup.md +30 -0
  32. package/plugin/plugins/claude-code-kanban/tests/doorbell.test.ts +69 -10
  33. package/plugin/plugins/claude-code-kanban/tests/show.test.ts +137 -0
  34. package/public/app.js +1133 -108
  35. package/public/index.html +7 -6
  36. package/public/style.css +770 -9
  37. package/public/terminal-frame.js +0 -2
  38. package/public/tree-highlight.js +137 -15
  39. package/server.js +71 -24
  40. package/lib/dispatch.js +0 -32
package/public/style.css CHANGED
@@ -862,7 +862,8 @@ body.booting .session-skeleton {
862
862
  display: flex;
863
863
  }
864
864
 
865
- .session-skeleton span {
865
+ .session-skeleton span,
866
+ .msg-log-loading-row span {
866
867
  height: 9px;
867
868
  width: 70%;
868
869
  border-radius: 4px;
@@ -937,6 +938,7 @@ body.booting .boot-splash {
937
938
 
938
939
  @media (prefers-reduced-motion: reduce) {
939
940
  .session-skeleton span,
941
+ .msg-log-loading-row span,
940
942
  .clawd-jump {
941
943
  animation: none;
942
944
  }
@@ -1049,7 +1051,9 @@ body.booting .boot-splash {
1049
1051
  }
1050
1052
 
1051
1053
  .session-item.unread::before,
1052
- .session-item.permission-pending::before {
1054
+ .session-item.permission-pending::before,
1055
+ .sp-row.unread::before,
1056
+ .sp-row.permission-pending::before {
1053
1057
  content: '';
1054
1058
  position: absolute;
1055
1059
  inset: -1px;
@@ -1058,13 +1062,15 @@ body.booting .boot-splash {
1058
1062
  pointer-events: none;
1059
1063
  }
1060
1064
 
1061
- .session-item.permission-pending::before {
1065
+ .session-item.permission-pending::before,
1066
+ .sp-row.permission-pending::before {
1062
1067
  border-left-color: var(--warning);
1063
1068
  animation: agent-badge-pulse 1.6s ease-in-out infinite;
1064
1069
  }
1065
1070
 
1066
1071
  @media (prefers-reduced-motion: reduce) {
1067
- .session-item.permission-pending::before {
1072
+ .session-item.permission-pending::before,
1073
+ .sp-row.permission-pending::before {
1068
1074
  animation: none;
1069
1075
  }
1070
1076
  }
@@ -2451,7 +2457,8 @@ body.booting .boot-splash {
2451
2457
  .detail-desc pre code {
2452
2458
  background: color-mix(in srgb, var(--text-muted) 8%, transparent);
2453
2459
  border: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
2454
- padding: 12px;
2460
+ --code-pad-x: 12px;
2461
+ padding: 12px var(--code-pad-x);
2455
2462
  border-radius: 6px;
2456
2463
  display: block;
2457
2464
  overflow-x: auto;
@@ -2465,6 +2472,163 @@ code.language-tree .hljs-title {
2465
2472
  font-weight: 600;
2466
2473
  }
2467
2474
 
2475
+ code.ct {
2476
+ --ct-line: color-mix(in srgb, var(--text-muted) 85%, transparent);
2477
+ }
2478
+
2479
+ /* One grid column: every row stretches to the widest one, so the bands line up when the block scrolls.
2480
+ The rows hold the side padding, so a band and the focus bar run to the block's edges. A container
2481
+ sets --code-pad-x to its code blocks' side padding. */
2482
+ pre code.hljs.ct {
2483
+ display: grid;
2484
+ padding-inline: 0;
2485
+ }
2486
+
2487
+ code.ct .ct-name {
2488
+ color: var(--text-primary);
2489
+ font-weight: 600;
2490
+ }
2491
+
2492
+ code.ct .ct-lib:not(.ct-focus) .ct-name {
2493
+ font-weight: 400;
2494
+ }
2495
+
2496
+ code.ct .ct-row {
2497
+ min-width: max-content;
2498
+ padding-inline: var(--code-pad-x, 10px);
2499
+ }
2500
+
2501
+ code.ct .ct-row:empty::before {
2502
+ content: ' ';
2503
+ }
2504
+
2505
+ code.ct .ct-nl,
2506
+ code.ct .ct-hidden {
2507
+ display: none;
2508
+ }
2509
+
2510
+ code.ct .ct-g {
2511
+ display: inline-block;
2512
+ position: relative;
2513
+ height: 1lh;
2514
+ vertical-align: top;
2515
+ }
2516
+
2517
+ code.ct .ct-g::before,
2518
+ code.ct .ct-g::after {
2519
+ content: '';
2520
+ position: absolute;
2521
+ }
2522
+
2523
+ code.ct .ct-v::before,
2524
+ code.ct .ct-t::before,
2525
+ code.ct .ct-l::before {
2526
+ left: 50%;
2527
+ top: 0;
2528
+ bottom: 0;
2529
+ border-left: 1px solid var(--ct-line);
2530
+ }
2531
+
2532
+ code.ct .ct-l::before {
2533
+ bottom: 50%;
2534
+ }
2535
+
2536
+ code.ct .ct-t::after,
2537
+ code.ct .ct-l::after,
2538
+ code.ct .ct-h::after {
2539
+ left: 50%;
2540
+ right: 0;
2541
+ top: 50%;
2542
+ border-top: 1px solid var(--ct-line);
2543
+ }
2544
+
2545
+ code.ct .ct-h::after {
2546
+ left: 0;
2547
+ right: 2px;
2548
+ }
2549
+
2550
+ code.ct .ct-note,
2551
+ code.ct .ct-star {
2552
+ color: var(--text-muted);
2553
+ }
2554
+
2555
+ code.ct .ct-fold {
2556
+ color: var(--text-muted);
2557
+ font-style: italic;
2558
+ }
2559
+
2560
+ code.ct .ct-loc {
2561
+ color: var(--accent-text);
2562
+ text-decoration: underline dotted;
2563
+ text-underline-offset: 3px;
2564
+ }
2565
+
2566
+ code.ct .ct-focus {
2567
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
2568
+ box-shadow: inset 2px 0 0 var(--accent);
2569
+ }
2570
+
2571
+ code.ct .ct-add {
2572
+ --ct-change: var(--success);
2573
+ }
2574
+
2575
+ code.ct .ct-del {
2576
+ --ct-change: var(--danger);
2577
+ }
2578
+
2579
+ code.ct :is(.ct-add, .ct-del) {
2580
+ background: color-mix(in srgb, var(--ct-change) 10%, transparent);
2581
+ }
2582
+
2583
+ code.ct .ct-m {
2584
+ color: var(--ct-change);
2585
+ font-weight: 600;
2586
+ }
2587
+
2588
+ code.ct .ct-has {
2589
+ cursor: pointer;
2590
+ }
2591
+
2592
+ code.ct .ct-has:hover,
2593
+ code.ct .ct-has:focus-visible {
2594
+ background: color-mix(in srgb, var(--text-muted) 12%, transparent);
2595
+ outline: none;
2596
+ }
2597
+
2598
+ code.ct .ct-has .ct-tilde {
2599
+ display: inline-block;
2600
+ color: transparent;
2601
+ position: relative;
2602
+ }
2603
+
2604
+ code.ct .ct-has .ct-tilde::after {
2605
+ content: '▸';
2606
+ position: absolute;
2607
+ inset: 0;
2608
+ color: var(--text-muted);
2609
+ font-style: normal;
2610
+ text-align: center;
2611
+ transition: transform 0.12s;
2612
+ }
2613
+
2614
+ code.ct .ct-has[aria-expanded='true'] .ct-tilde::after {
2615
+ transform: rotate(90deg);
2616
+ }
2617
+
2618
+ /* Out of flow, so the notes stay in their column: it sits in the gap after the name. */
2619
+ code.ct .ct-has[aria-expanded='false'] .ct-name {
2620
+ position: relative;
2621
+ }
2622
+
2623
+ code.ct .ct-has[aria-expanded='false'] .ct-name::after {
2624
+ content: '…';
2625
+ position: absolute;
2626
+ left: 100%;
2627
+ padding-left: 0.3ch;
2628
+ color: var(--text-muted);
2629
+ font-weight: 400;
2630
+ }
2631
+
2468
2632
  .detail-desc code {
2469
2633
  background: color-mix(in srgb, var(--text-muted) 12%, transparent);
2470
2634
  border: 1px solid color-mix(in srgb, var(--border) 45%, transparent);
@@ -3223,13 +3387,27 @@ code.language-tree .hljs-title {
3223
3387
  }
3224
3388
 
3225
3389
  .terminal-bar {
3390
+ position: absolute;
3391
+ z-index: 3;
3392
+ top: 16px;
3393
+ right: 20px;
3226
3394
  display: flex;
3227
3395
  align-items: center;
3228
- justify-content: space-between;
3229
3396
  gap: 8px;
3230
3397
  font-family: var(--font-mono);
3231
3398
  font-size: 12px;
3232
3399
  color: var(--text-muted);
3400
+ pointer-events: none;
3401
+ }
3402
+
3403
+ .terminal-bar > * {
3404
+ pointer-events: auto;
3405
+ }
3406
+
3407
+ .terminal-status:not(:empty) {
3408
+ padding: 2px 8px;
3409
+ border-radius: 4px;
3410
+ background: var(--bg-surface);
3233
3411
  }
3234
3412
 
3235
3413
  .terminal-host {
@@ -3492,6 +3670,520 @@ code.language-tree .hljs-title {
3492
3670
 
3493
3671
  /* #endregion */
3494
3672
 
3673
+ /* #region SHOW */
3674
+ .terminal-host {
3675
+ position: relative;
3676
+ }
3677
+
3678
+ .show-card {
3679
+ --show-inset: 8px;
3680
+ /* Six terminal rows (prompt, its rules, status line) at xterm's cell height of about 1.2 × font size. */
3681
+ --show-prompt-inset: calc(var(--show-inset) + 7.2 * var(--show-term-font, 13px));
3682
+ position: absolute;
3683
+ z-index: 2;
3684
+ top: var(--show-inset);
3685
+ right: var(--show-inset);
3686
+ display: none;
3687
+ flex-direction: column;
3688
+ box-sizing: border-box;
3689
+ min-width: 280px;
3690
+ max-width: var(--show-fit-w, 640px);
3691
+ width: max-content;
3692
+ max-height: var(--show-fit-h, 60%);
3693
+ background: var(--bg-surface);
3694
+ border: 1px solid var(--border);
3695
+ border-radius: 8px;
3696
+ box-shadow: 0 4px 14px -6px rgba(0, 0, 0, 0.3);
3697
+ color: var(--text-secondary);
3698
+ font-family: var(--font-mono);
3699
+ overflow: hidden;
3700
+ }
3701
+
3702
+ body.light .show-card {
3703
+ box-shadow: 0 4px 14px -8px rgba(0, 0, 0, 0.12);
3704
+ }
3705
+
3706
+ .show-card.open {
3707
+ display: flex;
3708
+ }
3709
+
3710
+ .terminal-pane:has(.terminal-prompt.visible) .show-card {
3711
+ display: none;
3712
+ }
3713
+
3714
+ .show-card.html {
3715
+ width: var(--show-fit-w);
3716
+ }
3717
+
3718
+ .show-card.sized {
3719
+ width: var(--show-w);
3720
+ height: var(--show-h);
3721
+ max-width: none;
3722
+ max-height: none;
3723
+ }
3724
+
3725
+ .show-card.expanded {
3726
+ left: var(--show-inset);
3727
+ bottom: var(--show-prompt-inset);
3728
+ width: auto;
3729
+ height: auto;
3730
+ max-width: none;
3731
+ max-height: none;
3732
+ }
3733
+
3734
+ .show-card.collapsed {
3735
+ left: auto;
3736
+ bottom: auto;
3737
+ width: max-content;
3738
+ height: auto;
3739
+ max-height: none;
3740
+ }
3741
+
3742
+ .show-card.collapsed .show-body,
3743
+ .show-card.collapsed .show-review,
3744
+ .show-card.collapsed .show-grip,
3745
+ .show-card.expanded .show-grip {
3746
+ display: none;
3747
+ }
3748
+
3749
+ .show-card.collapsed .show-head {
3750
+ border-bottom-color: transparent;
3751
+ }
3752
+
3753
+ /* The ticks wrap to the header's width instead of setting the card's. */
3754
+ .show-card.collapsed .show-ticks {
3755
+ contain: inline-size;
3756
+ padding-bottom: 5px;
3757
+ }
3758
+
3759
+ .show-card.flash {
3760
+ animation: show-in 0.16s ease-out;
3761
+ }
3762
+
3763
+ @keyframes show-in {
3764
+ from {
3765
+ opacity: 0;
3766
+ transform: translateY(-4px);
3767
+ }
3768
+ to {
3769
+ opacity: 1;
3770
+ transform: none;
3771
+ }
3772
+ }
3773
+
3774
+ .show-head {
3775
+ flex: none;
3776
+ display: flex;
3777
+ align-items: center;
3778
+ gap: 2px;
3779
+ height: 30px;
3780
+ padding: 0 4px 0 10px;
3781
+ border-bottom: 1px solid var(--border);
3782
+ font-size: 11.5px;
3783
+ color: var(--text-muted);
3784
+ white-space: nowrap;
3785
+ user-select: none;
3786
+ }
3787
+
3788
+ .show-nav {
3789
+ display: flex;
3790
+ align-items: center;
3791
+ gap: 2px;
3792
+ min-width: 0;
3793
+ flex: 1;
3794
+ }
3795
+
3796
+ .show-title {
3797
+ min-width: 0;
3798
+ overflow: hidden;
3799
+ text-overflow: ellipsis;
3800
+ color: var(--text-primary);
3801
+ font-weight: 500;
3802
+ }
3803
+
3804
+ .show-sep {
3805
+ opacity: 0.7;
3806
+ padding: 0 1px;
3807
+ }
3808
+
3809
+ .show-key {
3810
+ flex: none;
3811
+ color: var(--text-tertiary);
3812
+ }
3813
+
3814
+ .show-pager {
3815
+ flex: none;
3816
+ display: flex;
3817
+ align-items: center;
3818
+ margin-left: 8px;
3819
+ padding-right: 6px;
3820
+ border-right: 1px solid var(--border);
3821
+ }
3822
+
3823
+ .show-pos {
3824
+ font-variant-numeric: tabular-nums;
3825
+ }
3826
+
3827
+ .show-card.focused,
3828
+ body.light .show-card.focused {
3829
+ border-color: var(--accent);
3830
+ box-shadow:
3831
+ 0 0 0 1px var(--accent),
3832
+ 0 0 10px var(--accent-glow);
3833
+ }
3834
+
3835
+ .show-actions {
3836
+ flex: none;
3837
+ display: flex;
3838
+ align-items: center;
3839
+ gap: 1px;
3840
+ margin-left: 6px;
3841
+ }
3842
+
3843
+ .show-btn {
3844
+ flex: none;
3845
+ width: 22px;
3846
+ height: 22px;
3847
+ display: inline-flex;
3848
+ align-items: center;
3849
+ justify-content: center;
3850
+ padding: 0;
3851
+ border: 0;
3852
+ border-radius: 4px;
3853
+ background: none;
3854
+ color: var(--text-tertiary);
3855
+ cursor: pointer;
3856
+ }
3857
+
3858
+ .show-btn:hover:not(:disabled) {
3859
+ background: var(--bg-hover);
3860
+ color: var(--text-primary);
3861
+ }
3862
+
3863
+ .show-btn:disabled {
3864
+ opacity: 0.35;
3865
+ cursor: default;
3866
+ }
3867
+
3868
+ .show-btn svg {
3869
+ width: 14px;
3870
+ height: 14px;
3871
+ }
3872
+
3873
+ .show-btn.remove:hover:not(:disabled) {
3874
+ color: var(--danger);
3875
+ background: var(--danger-dim);
3876
+ }
3877
+
3878
+ .show-ticks {
3879
+ flex: none;
3880
+ display: flex;
3881
+ flex-wrap: wrap;
3882
+ justify-content: flex-end;
3883
+ gap: 3px;
3884
+ padding: 5px 10px 0;
3885
+ }
3886
+
3887
+ .show-tick {
3888
+ width: 14px;
3889
+ height: 3px;
3890
+ padding: 0;
3891
+ border: 0;
3892
+ border-radius: 2px;
3893
+ background: var(--border);
3894
+ cursor: pointer;
3895
+ }
3896
+
3897
+ .show-tick:hover {
3898
+ background: var(--text-muted);
3899
+ }
3900
+
3901
+ .show-tick.on {
3902
+ background: var(--text-tertiary);
3903
+ }
3904
+
3905
+ .show-tick.dot {
3906
+ background: var(--accent);
3907
+ }
3908
+
3909
+ .show-body {
3910
+ container-type: inline-size;
3911
+ flex: 1;
3912
+ min-height: 0;
3913
+ overflow: auto;
3914
+ overscroll-behavior: contain;
3915
+ }
3916
+
3917
+ .show-body:focus {
3918
+ outline: none;
3919
+ }
3920
+
3921
+ .show-card.html:not(.collapsed) .show-body {
3922
+ display: flex;
3923
+ overflow: hidden;
3924
+ }
3925
+
3926
+ .show-frame {
3927
+ display: block;
3928
+ width: 100%;
3929
+ flex: 1;
3930
+ border: 0;
3931
+ background: transparent;
3932
+ }
3933
+
3934
+ .show-card .show-review {
3935
+ flex: none;
3936
+ max-height: 40%;
3937
+ padding: 8px 10px 6px;
3938
+ border-left: 0;
3939
+ border-top: 1px solid var(--border);
3940
+ font-size: 11.5px;
3941
+ }
3942
+
3943
+ .show-md {
3944
+ padding: 0.8em 1.1em 1em;
3945
+ /* The same scale as an HTML card's frame (the zoom in showBridge). */
3946
+ font-size: clamp(12.5px, calc(9.7px + 0.58cqi), 17.5px);
3947
+ line-height: 1.6;
3948
+ color: var(--text-secondary);
3949
+ overflow-wrap: anywhere;
3950
+ }
3951
+
3952
+ .show-md > :first-child {
3953
+ margin-top: 0;
3954
+ }
3955
+
3956
+ .show-md > :last-child {
3957
+ margin-bottom: 0;
3958
+ }
3959
+
3960
+ .show-md p {
3961
+ margin: 0.5em 0;
3962
+ }
3963
+
3964
+ .show-md h1,
3965
+ .show-md h2,
3966
+ .show-md h3,
3967
+ .show-md h4 {
3968
+ margin: 1em 0 0.4em;
3969
+ color: var(--text-primary);
3970
+ font-size: 1em;
3971
+ font-weight: 600;
3972
+ }
3973
+
3974
+ .show-md h1 {
3975
+ font-size: 1.12em;
3976
+ }
3977
+
3978
+ .show-md ul,
3979
+ .show-md ol {
3980
+ margin: 0.4em 0;
3981
+ padding-left: 1.6em;
3982
+ }
3983
+
3984
+ .show-md li {
3985
+ margin: 0.15em 0;
3986
+ }
3987
+
3988
+ .show-md li:has(> input[type='checkbox']) {
3989
+ list-style: none;
3990
+ margin-left: -1.3em;
3991
+ }
3992
+
3993
+ .show-md input[type='checkbox'] {
3994
+ accent-color: var(--accent);
3995
+ margin-right: 6px;
3996
+ vertical-align: -1px;
3997
+ }
3998
+
3999
+ .show-md a {
4000
+ color: var(--accent);
4001
+ }
4002
+
4003
+ .show-md blockquote {
4004
+ margin: 0.6em 0;
4005
+ padding-left: 10px;
4006
+ border-left: 2px solid var(--border);
4007
+ color: var(--text-tertiary);
4008
+ }
4009
+
4010
+ .show-md table {
4011
+ display: block;
4012
+ margin: 0.6em 0;
4013
+ overflow-x: auto;
4014
+ border-collapse: collapse;
4015
+ font-size: 0.96em;
4016
+ }
4017
+
4018
+ .show-md th,
4019
+ .show-md td {
4020
+ border: 1px solid var(--border);
4021
+ padding: 4px 9px;
4022
+ text-align: left;
4023
+ }
4024
+
4025
+ .show-md th {
4026
+ background: var(--bg-hover);
4027
+ font-weight: 600;
4028
+ color: var(--text-primary);
4029
+ }
4030
+
4031
+ .show-md :not(pre) > code {
4032
+ background: color-mix(in srgb, var(--accent) 10%, transparent);
4033
+ border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
4034
+ color: var(--accent-text);
4035
+ padding: 0 4px;
4036
+ border-radius: 4px;
4037
+ font-size: 0.92em;
4038
+ }
4039
+
4040
+ .show-md pre {
4041
+ margin: 0.6em 0;
4042
+ font-size: 0.92em;
4043
+ line-height: 1.5;
4044
+ overflow-wrap: normal;
4045
+ }
4046
+
4047
+ .show-md pre code {
4048
+ display: block;
4049
+ overflow-x: auto;
4050
+ --code-pad-x: 10px;
4051
+ padding: 8px var(--code-pad-x);
4052
+ border-radius: 6px;
4053
+ background: color-mix(in srgb, var(--text-muted) 8%, transparent);
4054
+ border: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
4055
+ }
4056
+
4057
+ .show-md pre.preview-source {
4058
+ margin: 0;
4059
+ padding: 0;
4060
+ border: 0;
4061
+ background: none;
4062
+ }
4063
+
4064
+ .show-md pre.preview-source code {
4065
+ padding: 0;
4066
+ border: 0;
4067
+ background: none;
4068
+ }
4069
+
4070
+ .show-md code.language-diff .hljs-addition,
4071
+ .show-md code.language-diff .hljs-deletion {
4072
+ display: inline-block;
4073
+ min-width: 100%;
4074
+ margin: 0 -10px;
4075
+ padding: 0 10px;
4076
+ box-sizing: content-box;
4077
+ }
4078
+
4079
+ .show-md code.language-diff .hljs-addition {
4080
+ color: var(--success);
4081
+ background: color-mix(in srgb, var(--success) 10%, transparent);
4082
+ }
4083
+
4084
+ .show-md code.language-diff .hljs-deletion {
4085
+ color: var(--danger);
4086
+ background: color-mix(in srgb, var(--danger) 10%, transparent);
4087
+ }
4088
+
4089
+ .show-md pre.mermaid {
4090
+ min-height: 40px;
4091
+ margin: 0.6em 0;
4092
+ overflow-x: auto;
4093
+ text-align: center;
4094
+ background: transparent;
4095
+ color: transparent;
4096
+ }
4097
+
4098
+ .show-md pre.mermaid[data-processed] {
4099
+ color: inherit;
4100
+ }
4101
+
4102
+ .show-md pre.mermaid svg {
4103
+ max-width: 100%;
4104
+ height: auto;
4105
+ }
4106
+
4107
+ .show-md img {
4108
+ display: block;
4109
+ max-width: 100%;
4110
+ height: auto;
4111
+ }
4112
+
4113
+ .show-gone {
4114
+ color: var(--text-muted);
4115
+ }
4116
+
4117
+ .show-grip {
4118
+ position: absolute;
4119
+ left: 0;
4120
+ bottom: 0;
4121
+ width: 14px;
4122
+ height: 14px;
4123
+ cursor: nesw-resize;
4124
+ color: var(--text-muted);
4125
+ opacity: 0;
4126
+ transition: opacity 0.15s ease;
4127
+ touch-action: none;
4128
+ }
4129
+
4130
+ .show-card:hover .show-grip,
4131
+ .show-card.sized .show-grip {
4132
+ opacity: 0.8;
4133
+ }
4134
+
4135
+ .show-grip:hover {
4136
+ opacity: 1;
4137
+ color: var(--text-primary);
4138
+ }
4139
+
4140
+ .show-grip svg {
4141
+ position: absolute;
4142
+ left: 2px;
4143
+ bottom: 2px;
4144
+ width: 9px;
4145
+ height: 9px;
4146
+ }
4147
+
4148
+ body.show-resizing {
4149
+ user-select: none;
4150
+ }
4151
+
4152
+ body.show-resizing iframe {
4153
+ pointer-events: none;
4154
+ }
4155
+
4156
+ .show-reopen {
4157
+ display: inline-flex;
4158
+ align-items: center;
4159
+ gap: 5px;
4160
+ height: 22px;
4161
+ padding: 0 8px;
4162
+ border: 1px solid var(--border);
4163
+ border-radius: 11px;
4164
+ background: var(--bg-surface);
4165
+ color: var(--text-tertiary);
4166
+ font: inherit;
4167
+ font-size: 11px;
4168
+ cursor: pointer;
4169
+ }
4170
+
4171
+ .show-reopen[hidden] {
4172
+ display: none;
4173
+ }
4174
+
4175
+ .show-reopen:hover {
4176
+ color: var(--text-primary);
4177
+ background: var(--bg-hover);
4178
+ }
4179
+
4180
+ .show-reopen svg {
4181
+ width: 12px;
4182
+ height: 12px;
4183
+ }
4184
+
4185
+ /* #endregion */
4186
+
3495
4187
  /* #region PANES */
3496
4188
  .pane-strip {
3497
4189
  display: none;
@@ -4730,10 +5422,12 @@ code.language-tree .hljs-title {
4730
5422
  display: block;
4731
5423
  overflow-x: auto;
4732
5424
  }
4733
- /* The bodies around these tables set `word-break: break-word`, which lets a cell break
5425
+ /* The bodies around these tables set `word-break: break-word` or `overflow-wrap: anywhere`, which let a cell break
4734
5426
  between any two letters, so the table layout shrinks short columns to one letter. */
4735
5427
  .rendered-md th,
4736
5428
  .rendered-md td,
5429
+ .show-md th,
5430
+ .show-md td,
4737
5431
  .waiting-question-text th,
4738
5432
  .waiting-question-text td,
4739
5433
  .waiting-option-desc th,
@@ -5367,6 +6061,32 @@ code.language-tree .hljs-title {
5367
6061
  color: var(--text-muted);
5368
6062
  border-bottom: 1px solid var(--border);
5369
6063
  }
6064
+ .msg-log-loading {
6065
+ display: flex;
6066
+ flex-direction: column;
6067
+ gap: 14px;
6068
+ padding: 16px 14px;
6069
+ animation: boot-fade 0.2s ease-out var(--log-loading-delay, 0ms) both;
6070
+ }
6071
+ .msg-log-loading-row {
6072
+ display: flex;
6073
+ flex-direction: column;
6074
+ gap: 7px;
6075
+ }
6076
+ .msg-log-loading-row span {
6077
+ width: 75%;
6078
+ }
6079
+ .msg-log-loading-row span + span {
6080
+ width: 45%;
6081
+ }
6082
+ .msg-log-loading-row:nth-child(even) span:first-child {
6083
+ width: 60%;
6084
+ }
6085
+ .msg-log-loading-label {
6086
+ color: var(--text-muted);
6087
+ font-size: 12px;
6088
+ text-align: center;
6089
+ }
5370
6090
 
5371
6091
  /* #endregion */
5372
6092
 
@@ -6493,6 +7213,7 @@ body.light .msg-assistant .msg-text {
6493
7213
  max-height: 90vh;
6494
7214
  display: flex;
6495
7215
  flex-direction: column;
7216
+ outline: none;
6496
7217
  }
6497
7218
 
6498
7219
  .modal.preview-modal-dialog.fullscreen {
@@ -6636,8 +7357,10 @@ body.light .msg-assistant .msg-text {
6636
7357
  /* Source is read line by line, so it keeps its own line breaks and scrolls sideways
6637
7358
  instead of inheriting the body's `word-break: break-word`. */
6638
7359
  .preview-source {
7360
+ --src-pad-y: 10px;
7361
+ position: relative;
6639
7362
  margin: 0;
6640
- padding: 10px 12px;
7363
+ padding: var(--src-pad-y) 12px;
6641
7364
  background: var(--bg-elevated);
6642
7365
  border: 1px solid var(--border);
6643
7366
  border-radius: 6px;
@@ -6650,12 +7373,49 @@ body.light .msg-assistant .msg-text {
6650
7373
  tab-size: 4;
6651
7374
  }
6652
7375
 
6653
- .preview-source code {
7376
+ .preview-source:has(.src-gutter) {
7377
+ display: grid;
7378
+ grid-template-columns: auto 1fr;
7379
+ padding-left: 0;
7380
+ }
7381
+
7382
+ /* Sticky, so the numbers stay put while the code scrolls sideways. */
7383
+ .preview-source .src-gutter {
7384
+ position: sticky;
7385
+ left: 0;
7386
+ z-index: 1;
7387
+ margin-right: 12px;
7388
+ padding: 0 10px 0 12px;
7389
+ text-align: right;
7390
+ color: var(--text-muted);
7391
+ background: inherit;
7392
+ border-right: 1px solid var(--border);
7393
+ user-select: none;
7394
+ }
7395
+
7396
+ /* `.hljs` in the selector outranks the theme's `pre code.hljs` padding and scroll, which would
7397
+ shift the text off the gutter and the line band. */
7398
+ .preview-source code.hljs {
7399
+ position: relative;
6654
7400
  background: none;
6655
7401
  padding: 0;
7402
+ overflow: visible;
6656
7403
  font: inherit;
6657
7404
  }
6658
7405
 
7406
+ /* Lines never wrap (white-space: pre), so line N starts N - 1 line heights below the padding. */
7407
+ .preview-source .src-line {
7408
+ position: absolute;
7409
+ left: 0;
7410
+ right: 0;
7411
+ top: calc(var(--src-pad-y) + var(--line) * 1lh);
7412
+ height: 1lh;
7413
+ background: color-mix(in srgb, var(--accent) 16%, transparent);
7414
+ box-shadow: inset 2px 0 0 var(--accent);
7415
+ z-index: 2;
7416
+ pointer-events: none;
7417
+ }
7418
+
6659
7419
  .preview-html-frame {
6660
7420
  width: 100%;
6661
7421
  height: 100%;
@@ -7362,6 +8122,7 @@ select.form-input option:checked {
7362
8122
  }
7363
8123
 
7364
8124
  .sp-row {
8125
+ position: relative;
7365
8126
  display: flex;
7366
8127
  align-items: center;
7367
8128
  gap: 8px;