claude-code-kanban 4.31.1 → 5.1.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/cli.js +16 -5
- package/hub-app.json +25 -0
- package/lib/net-guard.js +6 -1
- package/lib/parsers.js +21 -12
- package/lib/terminal.js +73 -8
- package/package.json +2 -1
- package/plugin/plugins/claude-code-kanban/.claude-plugin/plugin.json +1 -1
- package/plugin/plugins/claude-code-kanban/hooks/hooks.json +12 -0
- package/plugin/plugins/claude-code-kanban/scripts/agent-spy.sh +10 -3
- package/plugin/plugins/claude-code-kanban/scripts/postman.js +13 -2
- package/public/app.js +751 -387
- package/public/index.html +31 -4
- package/public/style.css +202 -15
- package/public/vendor/claude-hub-sdk.js +50 -0
- package/server.js +90 -29
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"
|
|
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
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
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>↑</kbd><kbd>↓</kbd> move · <kbd>Enter</kbd> filter · <kbd>Alt</kbd><kbd>R</kbd> recent · <kbd>Alt</kbd><kbd>C</kbd> reset filter · <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,36 @@ 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
|
+
/* Declared on the element, not :root, so it picks up body.light's --success. */
|
|
973
|
+
.session-item.just-finished,
|
|
974
|
+
.sp-state.just-finished {
|
|
975
|
+
--success-faded: color-mix(in srgb, var(--success) 35%, var(--text-muted));
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.session-item.warm.idle.just-finished .session-time {
|
|
979
|
+
color: var(--success-faded);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.session-item.warm.idle.just-finished .session-time::before {
|
|
983
|
+
background: var(--success-faded);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.session-item.warm.permission-pending .session-time {
|
|
987
|
+
color: var(--warning);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
.session-item.warm.permission-pending .session-time::before {
|
|
991
|
+
background: var(--warning);
|
|
992
|
+
}
|
|
993
|
+
|
|
945
994
|
.session-item.stale .session-time {
|
|
946
995
|
color: var(--text-muted);
|
|
947
996
|
}
|
|
@@ -962,6 +1011,27 @@ body.booting .boot-splash {
|
|
|
962
1011
|
padding-right: 22px;
|
|
963
1012
|
}
|
|
964
1013
|
|
|
1014
|
+
.session-item.unread::before,
|
|
1015
|
+
.session-item.permission-pending::before {
|
|
1016
|
+
content: '';
|
|
1017
|
+
position: absolute;
|
|
1018
|
+
inset: -1px;
|
|
1019
|
+
border-left: 3px solid var(--accent);
|
|
1020
|
+
border-radius: inherit;
|
|
1021
|
+
pointer-events: none;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
.session-item.permission-pending::before {
|
|
1025
|
+
border-left-color: var(--warning);
|
|
1026
|
+
animation: agent-badge-pulse 1.6s ease-in-out infinite;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1030
|
+
.session-item.permission-pending::before {
|
|
1031
|
+
animation: none;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
965
1035
|
.session-indicators .pulse,
|
|
966
1036
|
.wf-live-name .pulse,
|
|
967
1037
|
.session-waiting .pulse {
|
|
@@ -3132,6 +3202,14 @@ body.booting .boot-splash {
|
|
|
3132
3202
|
animation: boot-fade 0.3s ease-out 0.2s both;
|
|
3133
3203
|
}
|
|
3134
3204
|
|
|
3205
|
+
.terminal-boot-slow {
|
|
3206
|
+
display: none;
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
.terminal-boot.slow .terminal-boot-slow {
|
|
3210
|
+
display: block;
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3135
3213
|
/* Opacity, not visibility: a hidden textarea drops focus, and the terminal must keep it. */
|
|
3136
3214
|
.terminal-pane:has(.terminal-boot.visible) .xterm {
|
|
3137
3215
|
opacity: 0;
|
|
@@ -5587,6 +5665,7 @@ body.light .msg-assistant .msg-text {
|
|
|
5587
5665
|
the viewport cap. */
|
|
5588
5666
|
.modal-help {
|
|
5589
5667
|
max-width: 900px;
|
|
5668
|
+
height: min(700px, 90vh);
|
|
5590
5669
|
padding: 16px 20px 20px;
|
|
5591
5670
|
display: flex;
|
|
5592
5671
|
flex-direction: column;
|
|
@@ -5599,11 +5678,30 @@ body.light .msg-assistant .msg-text {
|
|
|
5599
5678
|
font-size: 14px;
|
|
5600
5679
|
}
|
|
5601
5680
|
|
|
5681
|
+
.help-docs {
|
|
5682
|
+
margin: 0 12px 0 auto;
|
|
5683
|
+
padding: 4px 10px;
|
|
5684
|
+
border: 1px solid var(--border);
|
|
5685
|
+
border-radius: 6px;
|
|
5686
|
+
color: var(--text-secondary);
|
|
5687
|
+
font-size: 12px;
|
|
5688
|
+
text-decoration: none;
|
|
5689
|
+
white-space: nowrap;
|
|
5690
|
+
transition:
|
|
5691
|
+
color 0.15s ease,
|
|
5692
|
+
border-color 0.15s ease;
|
|
5693
|
+
}
|
|
5694
|
+
|
|
5695
|
+
.help-docs:hover {
|
|
5696
|
+
color: var(--accent);
|
|
5697
|
+
border-color: var(--accent);
|
|
5698
|
+
}
|
|
5699
|
+
|
|
5602
5700
|
/* One shared grid for both halves (key | label | spacer | key | label): each key
|
|
5603
5701
|
gutter is sized by its column's widest combo, and left/right rows share row
|
|
5604
5702
|
tracks, so paired groups line up — a shorter group just leaves empty rows.
|
|
5605
5703
|
Cells opt into a half via sc-l / sc-r; the markup is generated from
|
|
5606
|
-
|
|
5704
|
+
SHORTCUT_TABS in app.js. */
|
|
5607
5705
|
.shortcuts {
|
|
5608
5706
|
margin: 0;
|
|
5609
5707
|
display: grid;
|
|
@@ -5666,7 +5764,8 @@ body.light .msg-assistant .msg-text {
|
|
|
5666
5764
|
|
|
5667
5765
|
/* keycap chips: elevated fill + thicker bottom border reads as a key */
|
|
5668
5766
|
.sp-hint kbd,
|
|
5669
|
-
.shortcuts kbd
|
|
5767
|
+
.shortcuts kbd,
|
|
5768
|
+
.terminal-boot-slow kbd {
|
|
5670
5769
|
display: inline-flex;
|
|
5671
5770
|
align-items: center;
|
|
5672
5771
|
justify-content: center;
|
|
@@ -5689,10 +5788,31 @@ body.light .msg-assistant .msg-text {
|
|
|
5689
5788
|
font-size: 11px;
|
|
5690
5789
|
}
|
|
5691
5790
|
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5791
|
+
.shortcuts .sc-empty {
|
|
5792
|
+
grid-column: 1 / -1;
|
|
5793
|
+
padding: 24px 0;
|
|
5794
|
+
color: var(--text-muted);
|
|
5795
|
+
text-align: center;
|
|
5796
|
+
}
|
|
5797
|
+
|
|
5798
|
+
.help-bar {
|
|
5799
|
+
display: flex;
|
|
5800
|
+
align-items: flex-end;
|
|
5801
|
+
gap: 12px;
|
|
5802
|
+
margin-bottom: 12px;
|
|
5803
|
+
border-bottom: 1px solid var(--border);
|
|
5804
|
+
flex-shrink: 0;
|
|
5805
|
+
}
|
|
5806
|
+
|
|
5807
|
+
.help-tabs {
|
|
5808
|
+
display: flex;
|
|
5809
|
+
}
|
|
5810
|
+
|
|
5811
|
+
.help-bar .help-filter {
|
|
5812
|
+
margin: 0 0 6px auto;
|
|
5813
|
+
width: 220px;
|
|
5814
|
+
padding: 4px 10px;
|
|
5815
|
+
font-size: 12px;
|
|
5696
5816
|
}
|
|
5697
5817
|
|
|
5698
5818
|
@keyframes live-border-pulse {
|
|
@@ -5998,16 +6118,46 @@ select.form-input option:checked {
|
|
|
5998
6118
|
border-color: var(--accent);
|
|
5999
6119
|
}
|
|
6000
6120
|
|
|
6001
|
-
.sp-
|
|
6002
|
-
|
|
6121
|
+
.sp-state {
|
|
6122
|
+
flex: none;
|
|
6123
|
+
width: 14px;
|
|
6124
|
+
display: flex;
|
|
6125
|
+
align-items: center;
|
|
6126
|
+
justify-content: center;
|
|
6127
|
+
line-height: 0;
|
|
6003
6128
|
}
|
|
6004
6129
|
|
|
6005
|
-
.sp-
|
|
6006
|
-
|
|
6130
|
+
.sp-state.live {
|
|
6131
|
+
color: var(--success);
|
|
6007
6132
|
}
|
|
6008
6133
|
|
|
6009
|
-
.sp-
|
|
6010
|
-
|
|
6134
|
+
.sp-state.active {
|
|
6135
|
+
color: var(--accent);
|
|
6136
|
+
}
|
|
6137
|
+
|
|
6138
|
+
.sp-state.waiting {
|
|
6139
|
+
color: var(--warning);
|
|
6140
|
+
}
|
|
6141
|
+
|
|
6142
|
+
.sp-state.just-finished {
|
|
6143
|
+
color: var(--success-faded);
|
|
6144
|
+
}
|
|
6145
|
+
|
|
6146
|
+
.sp-state.recent {
|
|
6147
|
+
color: var(--text-tertiary);
|
|
6148
|
+
}
|
|
6149
|
+
|
|
6150
|
+
.sp-state.idle {
|
|
6151
|
+
color: var(--text-muted);
|
|
6152
|
+
}
|
|
6153
|
+
|
|
6154
|
+
.sp-state .activity-dot {
|
|
6155
|
+
background: currentColor;
|
|
6156
|
+
}
|
|
6157
|
+
|
|
6158
|
+
.sp-state.idle .activity-dot {
|
|
6159
|
+
background: transparent;
|
|
6160
|
+
border: 1px solid currentColor;
|
|
6011
6161
|
}
|
|
6012
6162
|
|
|
6013
6163
|
.sp-name,
|
|
@@ -6024,6 +6174,24 @@ select.form-input option:checked {
|
|
|
6024
6174
|
color: var(--text-primary);
|
|
6025
6175
|
}
|
|
6026
6176
|
|
|
6177
|
+
.sp-pin {
|
|
6178
|
+
flex: none;
|
|
6179
|
+
width: 14px;
|
|
6180
|
+
display: flex;
|
|
6181
|
+
justify-content: center;
|
|
6182
|
+
line-height: 0;
|
|
6183
|
+
}
|
|
6184
|
+
|
|
6185
|
+
.sp-pin.pinned svg {
|
|
6186
|
+
fill: var(--accent);
|
|
6187
|
+
stroke: var(--accent);
|
|
6188
|
+
}
|
|
6189
|
+
|
|
6190
|
+
.sp-pin.sticky svg {
|
|
6191
|
+
fill: var(--warning);
|
|
6192
|
+
stroke: var(--warning);
|
|
6193
|
+
}
|
|
6194
|
+
|
|
6027
6195
|
.sp-row:not(.outside) + .sp-row.outside {
|
|
6028
6196
|
margin-top: 8px;
|
|
6029
6197
|
}
|
|
@@ -6076,6 +6244,17 @@ select.form-input option:checked {
|
|
|
6076
6244
|
font-size: 11px;
|
|
6077
6245
|
}
|
|
6078
6246
|
|
|
6247
|
+
.pp-chips {
|
|
6248
|
+
display: flex;
|
|
6249
|
+
gap: 6px;
|
|
6250
|
+
}
|
|
6251
|
+
|
|
6252
|
+
.sp-row.recent .sp-name::before {
|
|
6253
|
+
content: '•';
|
|
6254
|
+
margin-right: 5px;
|
|
6255
|
+
color: var(--accent-text);
|
|
6256
|
+
}
|
|
6257
|
+
|
|
6079
6258
|
/* #endregion */
|
|
6080
6259
|
|
|
6081
6260
|
/* #region NEW_SESSION */
|
|
@@ -6556,7 +6735,8 @@ select.form-input option:checked {
|
|
|
6556
6735
|
flex-shrink: 0;
|
|
6557
6736
|
}
|
|
6558
6737
|
|
|
6559
|
-
.storage-tab
|
|
6738
|
+
.storage-tab,
|
|
6739
|
+
.help-tab {
|
|
6560
6740
|
background: none;
|
|
6561
6741
|
border: none;
|
|
6562
6742
|
color: var(--text-secondary);
|
|
@@ -6570,11 +6750,13 @@ select.form-input option:checked {
|
|
|
6570
6750
|
border-color 0.15s;
|
|
6571
6751
|
}
|
|
6572
6752
|
|
|
6573
|
-
.storage-tab:hover
|
|
6753
|
+
.storage-tab:hover,
|
|
6754
|
+
.help-tab:hover {
|
|
6574
6755
|
color: var(--text-primary);
|
|
6575
6756
|
}
|
|
6576
6757
|
|
|
6577
|
-
.storage-tab.active
|
|
6758
|
+
.storage-tab.active,
|
|
6759
|
+
.help-tab.active {
|
|
6578
6760
|
color: var(--accent);
|
|
6579
6761
|
border-bottom-color: var(--accent);
|
|
6580
6762
|
}
|
|
@@ -7258,6 +7440,11 @@ pre.mermaid svg {
|
|
|
7258
7440
|
background: var(--accent-dim);
|
|
7259
7441
|
}
|
|
7260
7442
|
|
|
7443
|
+
/* An empty section shows only while a drag needs its ungroup drop zone. */
|
|
7444
|
+
.sessions-list:not(.sg-dragging-active) .sg-section-empty {
|
|
7445
|
+
display: none;
|
|
7446
|
+
}
|
|
7447
|
+
|
|
7261
7448
|
.sessions-list.sg-dragging-active .sg-ungroup-zone {
|
|
7262
7449
|
border: 1px dashed var(--accent);
|
|
7263
7450
|
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);
|