claude-code-kanban 4.31.0 → 5.0.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/public/index.html CHANGED
@@ -32,6 +32,7 @@
32
32
  <script defer src="/app.js"></script>
33
33
  </head>
34
34
  <body class="booting">
35
+ <script src="/vendor/claude-hub-sdk.js"></script>
35
36
  <div id="offline-overlay" class="offline-overlay">
36
37
  <div class="offline-card">
37
38
  <div class="clawd-sleep" aria-hidden="true">
@@ -74,7 +75,7 @@
74
75
 
75
76
  <!-- Tasks -->
76
77
  <div class="sidebar-section flex-1">
77
- <div class="section-header" onclick="toggleSection('sessions-filters', 'sessions-chevron')" style="cursor: pointer;">
78
+ <div class="section-header">
78
79
  <span class="section-header-label">Sessions</span>
79
80
  <span id="filter-summary" class="filter-summary" title=""></span>
80
81
  <span class="section-header-actions">
@@ -116,9 +117,16 @@
116
117
  <path d="M3.51 15a9 9 0 1 0 2.13-9.36L3 8"/>
117
118
  </svg>
118
119
  </button>
119
- <svg id="sessions-chevron" class="collapse-chevron" viewBox="0 0 24 24">
120
- <path d="M6 9l6 6 6-6"/>
121
- </svg>
120
+ <button
121
+ class="icon-btn section-btn"
122
+ onclick="toggleSection('sessions-filters', 'sessions-chevron')"
123
+ title="Show or hide search and filters"
124
+ aria-label="Show or hide search and filters"
125
+ >
126
+ <svg id="sessions-chevron" class="collapse-chevron" viewBox="0 0 24 24">
127
+ <path d="M6 9l6 6 6-6"/>
128
+ </svg>
129
+ </button>
122
130
  </span>
123
131
  <div id="filter-menu" class="filter-menu" onclick="event.stopPropagation()">
124
132
  <div class="pf-field">
@@ -325,6 +333,7 @@
325
333
  <div id="terminal-boot" class="terminal-boot" aria-hidden="true">
326
334
  <svg class="clawd clawd-jump" viewBox="1 0 16 10" shape-rendering="crispEdges"><use href="#clawd-shape"/></svg>
327
335
  <p id="terminal-boot-verb"></p>
336
+ <p class="terminal-boot-slow">Slow to connect. Press <kbd>R</kbd> to reconnect.</p>
328
337
  </div>
329
338
  <div id="terminal-host" class="terminal-host"></div>
330
339
  </div>
@@ -450,12 +459,17 @@
450
459
  <div class="modal modal-help" onclick="event.stopPropagation()">
451
460
  <div class="modal-header">
452
461
  <h3 class="modal-title">Keyboard Shortcuts</h3>
462
+ <a class="help-docs" id="help-docs" href="https://nikiforovall.blog/claude-code-kanban/" target="_blank" rel="noopener">Docs ↗</a>
453
463
  <button class="modal-close" aria-label="Close dialog" onclick="closeHelpModal()">
454
464
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
455
465
  <path d="M18 6L6 18M6 6l12 12"/>
456
466
  </svg>
457
467
  </button>
458
468
  </div>
469
+ <div class="help-bar">
470
+ <div class="help-tabs" id="help-tabs" role="tablist" aria-label="Shortcut groups"></div>
471
+ <input type="search" id="help-filter" class="form-input help-filter" placeholder="Filter shortcuts" aria-label="Filter shortcuts" autocomplete="off" spellcheck="false">
472
+ </div>
459
473
  <div class="modal-body">
460
474
  <dl class="shortcuts" id="help-shortcuts"></dl>
461
475
  </div>
@@ -801,6 +815,19 @@
801
815
  </div>
802
816
  </div>
803
817
 
818
+ <div id="project-picker-modal" class="modal-overlay top-aligned" onclick="closeProjectPicker()">
819
+ <div class="modal session-picker" onclick="event.stopPropagation()">
820
+ <input type="text" id="project-picker-input" class="form-input sp-input" placeholder="Filter by project..." autocomplete="off" spellcheck="false">
821
+ <div class="pp-chips">
822
+ <button type="button" class="pf-recent" id="pp-recent-chip" aria-pressed="false" title="List only projects active in the last 24h" onclick="ppToggleRecentOnly()">Recent</button>
823
+ </div>
824
+ <div class="sp-body">
825
+ <div id="project-picker-list" class="sp-list"></div>
826
+ </div>
827
+ <div class="sp-hint"><kbd>&uarr;</kbd><kbd>&darr;</kbd> move &middot; <kbd>Enter</kbd> filter &middot; <kbd>Alt</kbd><kbd>R</kbd> recent &middot; <kbd>Alt</kbd><kbd>C</kbd> reset filter &middot; <kbd>Esc</kbd> close</div>
828
+ </div>
829
+ </div>
830
+
804
831
  <div id="toast" class="toast"></div>
805
832
  </body>
806
833
  </html>
package/public/style.css CHANGED
@@ -232,6 +232,25 @@ body::before {
232
232
  animation: pulse 2.5s ease-in-out infinite;
233
233
  }
234
234
 
235
+ .activity-icon {
236
+ display: inline-flex;
237
+ margin: 0 -2px;
238
+ color: var(--chip-color, var(--accent));
239
+ }
240
+ .activity-icon svg {
241
+ width: 11px;
242
+ height: 11px;
243
+ }
244
+ .activity-chip.activity-zero .activity-icon {
245
+ color: var(--text-muted);
246
+ }
247
+ .activity-chip.activity-warn {
248
+ --chip-color: var(--warning);
249
+ background: var(--warning-dim);
250
+ border-color: color-mix(in srgb, var(--chip-color) 60%, var(--border));
251
+ color: var(--chip-color);
252
+ }
253
+
235
254
  .sidebar.collapsed .activity-chips {
236
255
  display: none;
237
256
  }
@@ -942,6 +961,22 @@ body.booting .boot-splash {
942
961
  background: var(--success);
943
962
  }
944
963
 
964
+ .session-item.warm.idle .session-time {
965
+ color: var(--text-tertiary);
966
+ }
967
+
968
+ .session-item.warm.idle .session-time::before {
969
+ background: var(--text-tertiary);
970
+ }
971
+
972
+ .session-item.warm.permission-pending .session-time {
973
+ color: var(--warning);
974
+ }
975
+
976
+ .session-item.warm.permission-pending .session-time::before {
977
+ background: var(--warning);
978
+ }
979
+
945
980
  .session-item.stale .session-time {
946
981
  color: var(--text-muted);
947
982
  }
@@ -962,6 +997,27 @@ body.booting .boot-splash {
962
997
  padding-right: 22px;
963
998
  }
964
999
 
1000
+ .session-item.unread::before,
1001
+ .session-item.permission-pending::before {
1002
+ content: '';
1003
+ position: absolute;
1004
+ inset: -1px;
1005
+ border-left: 3px solid var(--accent);
1006
+ border-radius: inherit;
1007
+ pointer-events: none;
1008
+ }
1009
+
1010
+ .session-item.permission-pending::before {
1011
+ border-left-color: var(--warning);
1012
+ animation: agent-badge-pulse 1.6s ease-in-out infinite;
1013
+ }
1014
+
1015
+ @media (prefers-reduced-motion: reduce) {
1016
+ .session-item.permission-pending::before {
1017
+ animation: none;
1018
+ }
1019
+ }
1020
+
965
1021
  .session-indicators .pulse,
966
1022
  .wf-live-name .pulse,
967
1023
  .session-waiting .pulse {
@@ -3132,6 +3188,14 @@ body.booting .boot-splash {
3132
3188
  animation: boot-fade 0.3s ease-out 0.2s both;
3133
3189
  }
3134
3190
 
3191
+ .terminal-boot-slow {
3192
+ display: none;
3193
+ }
3194
+
3195
+ .terminal-boot.slow .terminal-boot-slow {
3196
+ display: block;
3197
+ }
3198
+
3135
3199
  /* Opacity, not visibility: a hidden textarea drops focus, and the terminal must keep it. */
3136
3200
  .terminal-pane:has(.terminal-boot.visible) .xterm {
3137
3201
  opacity: 0;
@@ -5587,6 +5651,7 @@ body.light .msg-assistant .msg-text {
5587
5651
  the viewport cap. */
5588
5652
  .modal-help {
5589
5653
  max-width: 900px;
5654
+ height: min(700px, 90vh);
5590
5655
  padding: 16px 20px 20px;
5591
5656
  display: flex;
5592
5657
  flex-direction: column;
@@ -5599,11 +5664,30 @@ body.light .msg-assistant .msg-text {
5599
5664
  font-size: 14px;
5600
5665
  }
5601
5666
 
5667
+ .help-docs {
5668
+ margin: 0 12px 0 auto;
5669
+ padding: 4px 10px;
5670
+ border: 1px solid var(--border);
5671
+ border-radius: 6px;
5672
+ color: var(--text-secondary);
5673
+ font-size: 12px;
5674
+ text-decoration: none;
5675
+ white-space: nowrap;
5676
+ transition:
5677
+ color 0.15s ease,
5678
+ border-color 0.15s ease;
5679
+ }
5680
+
5681
+ .help-docs:hover {
5682
+ color: var(--accent);
5683
+ border-color: var(--accent);
5684
+ }
5685
+
5602
5686
  /* One shared grid for both halves (key | label | spacer | key | label): each key
5603
5687
  gutter is sized by its column's widest combo, and left/right rows share row
5604
5688
  tracks, so paired groups line up — a shorter group just leaves empty rows.
5605
5689
  Cells opt into a half via sc-l / sc-r; the markup is generated from
5606
- SHORTCUT_PAIRS in app.js. */
5690
+ SHORTCUT_TABS in app.js. */
5607
5691
  .shortcuts {
5608
5692
  margin: 0;
5609
5693
  display: grid;
@@ -5666,7 +5750,8 @@ body.light .msg-assistant .msg-text {
5666
5750
 
5667
5751
  /* keycap chips: elevated fill + thicker bottom border reads as a key */
5668
5752
  .sp-hint kbd,
5669
- .shortcuts kbd {
5753
+ .shortcuts kbd,
5754
+ .terminal-boot-slow kbd {
5670
5755
  display: inline-flex;
5671
5756
  align-items: center;
5672
5757
  justify-content: center;
@@ -5689,10 +5774,31 @@ body.light .msg-assistant .msg-text {
5689
5774
  font-size: 11px;
5690
5775
  }
5691
5776
 
5692
- /* Hub jumps are no-ops outside Claude Code Hub, so the standalone board hides
5693
- that whole column rather than listing keys that do nothing. */
5694
- .shortcuts.sc-standalone .sc-hub {
5695
- display: none;
5777
+ .shortcuts .sc-empty {
5778
+ grid-column: 1 / -1;
5779
+ padding: 24px 0;
5780
+ color: var(--text-muted);
5781
+ text-align: center;
5782
+ }
5783
+
5784
+ .help-bar {
5785
+ display: flex;
5786
+ align-items: flex-end;
5787
+ gap: 12px;
5788
+ margin-bottom: 12px;
5789
+ border-bottom: 1px solid var(--border);
5790
+ flex-shrink: 0;
5791
+ }
5792
+
5793
+ .help-tabs {
5794
+ display: flex;
5795
+ }
5796
+
5797
+ .help-bar .help-filter {
5798
+ margin: 0 0 6px auto;
5799
+ width: 220px;
5800
+ padding: 4px 10px;
5801
+ font-size: 12px;
5696
5802
  }
5697
5803
 
5698
5804
  @keyframes live-border-pulse {
@@ -6024,6 +6130,21 @@ select.form-input option:checked {
6024
6130
  color: var(--text-primary);
6025
6131
  }
6026
6132
 
6133
+ .sp-pin {
6134
+ flex: none;
6135
+ line-height: 0;
6136
+ }
6137
+
6138
+ .sp-pin.pinned svg {
6139
+ fill: var(--accent);
6140
+ stroke: var(--accent);
6141
+ }
6142
+
6143
+ .sp-pin.sticky svg {
6144
+ fill: var(--warning);
6145
+ stroke: var(--warning);
6146
+ }
6147
+
6027
6148
  .sp-row:not(.outside) + .sp-row.outside {
6028
6149
  margin-top: 8px;
6029
6150
  }
@@ -6076,6 +6197,17 @@ select.form-input option:checked {
6076
6197
  font-size: 11px;
6077
6198
  }
6078
6199
 
6200
+ .pp-chips {
6201
+ display: flex;
6202
+ gap: 6px;
6203
+ }
6204
+
6205
+ .sp-row.recent .sp-name::before {
6206
+ content: '•';
6207
+ margin-right: 5px;
6208
+ color: var(--accent-text);
6209
+ }
6210
+
6079
6211
  /* #endregion */
6080
6212
 
6081
6213
  /* #region NEW_SESSION */
@@ -6556,7 +6688,8 @@ select.form-input option:checked {
6556
6688
  flex-shrink: 0;
6557
6689
  }
6558
6690
 
6559
- .storage-tab {
6691
+ .storage-tab,
6692
+ .help-tab {
6560
6693
  background: none;
6561
6694
  border: none;
6562
6695
  color: var(--text-secondary);
@@ -6570,11 +6703,13 @@ select.form-input option:checked {
6570
6703
  border-color 0.15s;
6571
6704
  }
6572
6705
 
6573
- .storage-tab:hover {
6706
+ .storage-tab:hover,
6707
+ .help-tab:hover {
6574
6708
  color: var(--text-primary);
6575
6709
  }
6576
6710
 
6577
- .storage-tab.active {
6711
+ .storage-tab.active,
6712
+ .help-tab.active {
6578
6713
  color: var(--accent);
6579
6714
  border-bottom-color: var(--accent);
6580
6715
  }
@@ -7258,6 +7393,11 @@ pre.mermaid svg {
7258
7393
  background: var(--accent-dim);
7259
7394
  }
7260
7395
 
7396
+ /* An empty section shows only while a drag needs its ungroup drop zone. */
7397
+ .sessions-list:not(.sg-dragging-active) .sg-section-empty {
7398
+ display: none;
7399
+ }
7400
+
7261
7401
  .sessions-list.sg-dragging-active .sg-ungroup-zone {
7262
7402
  border: 1px dashed var(--accent);
7263
7403
  border-radius: 4px;
@@ -0,0 +1,50 @@
1
+ // claude-hub-sdk 1.1.0 (sha256 0fed14faa670). Copied by npm run sdk:sync in claude-code-hub. Do not edit.
2
+ // Claude Code Hub SDK stub: what an app serves when no hub runs it. Under a hub, the hub hands the
3
+ // app its real SDK (client.js) in place of this file. The API must match client.js; a test checks it.
4
+ ((root) => {
5
+ 'use strict';
6
+
7
+ function createClaudeHub(win) {
8
+ let hub = null;
9
+ const off = () => {};
10
+
11
+ function connect({ standalone = {} } = {}) {
12
+ if (hub) return hub;
13
+ const standaloneFn = (action) => {
14
+ const fn = (typeof standalone === 'function' ? standalone() : standalone)[action];
15
+ return typeof fn === 'function' ? fn : null;
16
+ };
17
+ hub = {
18
+ status: 'standalone',
19
+ themes: [],
20
+ inHub: false,
21
+ onStatus: () => off,
22
+ onActive: () => off,
23
+ onThemes: () => off,
24
+ subscribe: () => off,
25
+ bindTheme: () => off,
26
+ handle() {},
27
+ publish() {},
28
+ invoke(action, params = {}) {
29
+ const target = standaloneFn(action)?.(params);
30
+ if (!target) return Promise.resolve({ ok: false, reason: 'unhandled' });
31
+ win.open(target, '_blank', 'noopener');
32
+ return Promise.resolve({ ok: true, handledBy: 'standalone' });
33
+ },
34
+ can: (action) => !!standaloneFn(action),
35
+ forwards: () => false,
36
+ closeGuard() {},
37
+ openExternal(url) {
38
+ win.open(url, '_blank', 'noopener');
39
+ },
40
+ terminalToken: () => Promise.resolve(null),
41
+ };
42
+ return hub;
43
+ }
44
+
45
+ return { connect };
46
+ }
47
+
48
+ if (typeof module === 'object' && module.exports) module.exports = { createClaudeHub };
49
+ else root.ClaudeHub = createClaudeHub(root);
50
+ })(typeof window !== 'undefined' ? window : globalThis);