claude-code-kanban 7.2.0 → 7.4.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/hub-app.json +1 -0
- package/lib/terminal.js +72 -33
- package/package.json +1 -1
- package/public/app.js +321 -126
- package/public/index.html +11 -7
- package/public/style.css +70 -13
- package/public/terminal-frame.js +6 -4
- package/public/vendor/claude-hub-sdk.js +40 -6
package/public/index.html
CHANGED
|
@@ -138,6 +138,7 @@
|
|
|
138
138
|
class="pf-input"
|
|
139
139
|
placeholder="Any project"
|
|
140
140
|
autocomplete="off"
|
|
141
|
+
data-bwignore data-1p-ignore data-lpignore="true"
|
|
141
142
|
spellcheck="false"
|
|
142
143
|
role="combobox"
|
|
143
144
|
aria-expanded="true"
|
|
@@ -169,6 +170,8 @@
|
|
|
169
170
|
type="text"
|
|
170
171
|
class="search-input"
|
|
171
172
|
placeholder="Search tasks, sessions, projects..."
|
|
173
|
+
autocomplete="off"
|
|
174
|
+
data-bwignore data-1p-ignore data-lpignore="true"
|
|
172
175
|
oninput="handleSearch(this.value)"
|
|
173
176
|
/>
|
|
174
177
|
<button id="search-clear-btn" class="search-clear" onclick="clearSearch()" title="Clear search" aria-label="Clear search">
|
|
@@ -503,7 +506,7 @@
|
|
|
503
506
|
</div>
|
|
504
507
|
<div class="help-bar">
|
|
505
508
|
<div class="help-tabs" id="help-tabs" role="tablist" aria-label="Shortcut groups"></div>
|
|
506
|
-
<input type="search" id="help-filter" class="form-input help-filter" placeholder="Filter shortcuts" aria-label="Filter shortcuts" autocomplete="off" spellcheck="false">
|
|
509
|
+
<input type="search" id="help-filter" class="form-input help-filter" placeholder="Filter shortcuts" aria-label="Filter shortcuts" autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false">
|
|
507
510
|
</div>
|
|
508
511
|
<div class="modal-body">
|
|
509
512
|
<dl class="shortcuts" id="help-shortcuts"></dl>
|
|
@@ -802,7 +805,7 @@
|
|
|
802
805
|
<label class="ns-label" for="ns-folder">Folder</label>
|
|
803
806
|
<div class="ns-field ns-folder-field">
|
|
804
807
|
<div class="ns-inline">
|
|
805
|
-
<input type="text" id="ns-folder" class="form-input" placeholder="Type to find a project" autocomplete="off" spellcheck="false" role="combobox" aria-expanded="false" aria-controls="ns-folder-list">
|
|
808
|
+
<input type="text" id="ns-folder" class="form-input" placeholder="Type to find a project" autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false" role="combobox" aria-expanded="false" aria-controls="ns-folder-list">
|
|
806
809
|
<button type="button" id="ns-browse" class="btn btn-secondary ns-browse" onclick="browseNewSessionFolder()">Browse…</button>
|
|
807
810
|
</div>
|
|
808
811
|
<div id="ns-folder-list" class="ns-dropdown" role="listbox" hidden></div>
|
|
@@ -811,7 +814,7 @@
|
|
|
811
814
|
<div class="ns-row ns-extra">
|
|
812
815
|
<label class="ns-label" for="ns-name">Name</label>
|
|
813
816
|
<div class="ns-field">
|
|
814
|
-
<input type="text" id="ns-name" class="form-input" placeholder="Optional" maxlength="80" autocomplete="off" spellcheck="false">
|
|
817
|
+
<input type="text" id="ns-name" class="form-input" placeholder="Optional" maxlength="80" autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false">
|
|
815
818
|
</div>
|
|
816
819
|
</div>
|
|
817
820
|
<div class="ns-row ns-extra">
|
|
@@ -828,7 +831,7 @@
|
|
|
828
831
|
<div class="ns-field">
|
|
829
832
|
<div class="ns-inline">
|
|
830
833
|
<label class="ns-check"><input type="checkbox" id="ns-wt"> New worktree</label>
|
|
831
|
-
<input type="text" id="ns-wt-name" class="form-input" placeholder="Name (optional)" maxlength="64" autocomplete="off" spellcheck="false" disabled aria-label="Worktree name">
|
|
834
|
+
<input type="text" id="ns-wt-name" class="form-input" placeholder="Name (optional)" maxlength="64" autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false" disabled aria-label="Worktree name">
|
|
832
835
|
</div>
|
|
833
836
|
<div id="ns-wt-hint" class="ns-hint" hidden></div>
|
|
834
837
|
</div>
|
|
@@ -849,6 +852,7 @@
|
|
|
849
852
|
</div>
|
|
850
853
|
<div class="modal-footer ns-footer">
|
|
851
854
|
<label class="ns-check ns-stay" title="Start in the background and keep the current view"><input type="checkbox" id="ns-stay"> Stay here</label>
|
|
855
|
+
<label class="ns-check ns-edit" title="Open a shell in the folder with the claude command typed in. Press Enter to run it."><input type="checkbox" id="ns-edit"> Edit before run</label>
|
|
852
856
|
<button type="button" class="btn btn-secondary" onclick="closeNewSession()">Cancel</button>
|
|
853
857
|
<button type="button" id="ns-start" class="btn btn-primary" onclick="startNewSession()" disabled>Start</button>
|
|
854
858
|
</div>
|
|
@@ -863,7 +867,7 @@
|
|
|
863
867
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
|
|
864
868
|
</button>
|
|
865
869
|
</div>
|
|
866
|
-
<input id="pane-pop-input" class="form-input" placeholder="Search linked docs, or paste a URL or a file path" autocomplete="off" spellcheck="false">
|
|
870
|
+
<input id="pane-pop-input" class="form-input" placeholder="Search linked docs, or paste a URL or a file path" autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false">
|
|
867
871
|
<div id="pane-pop-detect" class="pane-pop-detect"></div>
|
|
868
872
|
<div class="pane-pop-label">Linked docs</div>
|
|
869
873
|
<div id="pane-pop-docs" class="pane-pop-docs"></div>
|
|
@@ -873,7 +877,7 @@
|
|
|
873
877
|
|
|
874
878
|
<div id="session-picker-modal" class="modal-overlay top-aligned" onclick="closeSessionPicker()">
|
|
875
879
|
<div class="modal session-picker" onclick="event.stopPropagation()">
|
|
876
|
-
<input type="text" id="session-picker-input" class="form-input sp-input" placeholder="Jump to session..." autocomplete="off" spellcheck="false">
|
|
880
|
+
<input type="text" id="session-picker-input" class="form-input sp-input" placeholder="Jump to session..." autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false">
|
|
877
881
|
<div class="sp-body">
|
|
878
882
|
<div id="session-picker-list" class="sp-list"></div>
|
|
879
883
|
<div id="session-picker-peek" class="sp-peek"></div>
|
|
@@ -884,7 +888,7 @@
|
|
|
884
888
|
|
|
885
889
|
<div id="project-picker-modal" class="modal-overlay top-aligned" onclick="closeProjectPicker()">
|
|
886
890
|
<div class="modal session-picker" onclick="event.stopPropagation()">
|
|
887
|
-
<input type="text" id="project-picker-input" class="form-input sp-input" placeholder="Filter by project..." autocomplete="off" spellcheck="false">
|
|
891
|
+
<input type="text" id="project-picker-input" class="form-input sp-input" placeholder="Filter by project..." autocomplete="off" data-bwignore data-1p-ignore data-lpignore="true" spellcheck="false">
|
|
888
892
|
<div class="pp-chips">
|
|
889
893
|
<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>
|
|
890
894
|
</div>
|
package/public/style.css
CHANGED
|
@@ -3909,6 +3909,49 @@ code.language-tree .hljs-title {
|
|
|
3909
3909
|
background: #fff;
|
|
3910
3910
|
}
|
|
3911
3911
|
|
|
3912
|
+
.pane-url-bar {
|
|
3913
|
+
position: absolute;
|
|
3914
|
+
right: 12px;
|
|
3915
|
+
bottom: 12px;
|
|
3916
|
+
display: flex;
|
|
3917
|
+
align-items: center;
|
|
3918
|
+
gap: 2px;
|
|
3919
|
+
padding: 3px;
|
|
3920
|
+
border: 1px solid var(--border);
|
|
3921
|
+
border-radius: 8px;
|
|
3922
|
+
background: var(--bg-elevated);
|
|
3923
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
|
|
3924
|
+
font-family: var(--font-mono);
|
|
3925
|
+
font-size: 12px;
|
|
3926
|
+
opacity: 0;
|
|
3927
|
+
pointer-events: none;
|
|
3928
|
+
transition: opacity 0.15s;
|
|
3929
|
+
}
|
|
3930
|
+
|
|
3931
|
+
.pane-view:hover > .pane-url-bar,
|
|
3932
|
+
.pane-view.frame-focus > .pane-url-bar {
|
|
3933
|
+
opacity: 1;
|
|
3934
|
+
pointer-events: auto;
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
.pane-url-bar .icon-btn {
|
|
3938
|
+
width: auto;
|
|
3939
|
+
min-width: 26px;
|
|
3940
|
+
height: 24px;
|
|
3941
|
+
padding: 0 6px;
|
|
3942
|
+
border-color: transparent;
|
|
3943
|
+
font: inherit;
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3946
|
+
.pane-url-bar .pane-keys {
|
|
3947
|
+
display: none;
|
|
3948
|
+
color: var(--accent);
|
|
3949
|
+
}
|
|
3950
|
+
|
|
3951
|
+
.pane-view.frame-focus .pane-keys {
|
|
3952
|
+
display: flex;
|
|
3953
|
+
}
|
|
3954
|
+
|
|
3912
3955
|
.pane-doc {
|
|
3913
3956
|
flex: 1;
|
|
3914
3957
|
min-height: 0;
|
|
@@ -7100,7 +7143,8 @@ select.form-input option:checked {
|
|
|
7100
7143
|
|
|
7101
7144
|
/* #region SESSION_PICKER */
|
|
7102
7145
|
.modal.session-picker {
|
|
7103
|
-
max-
|
|
7146
|
+
max-width: 920px;
|
|
7147
|
+
max-height: 74vh;
|
|
7104
7148
|
padding: 12px;
|
|
7105
7149
|
display: flex;
|
|
7106
7150
|
flex-direction: column;
|
|
@@ -7109,9 +7153,9 @@ select.form-input option:checked {
|
|
|
7109
7153
|
}
|
|
7110
7154
|
|
|
7111
7155
|
.sp-input {
|
|
7112
|
-
padding:
|
|
7156
|
+
padding: 10px 12px;
|
|
7113
7157
|
background: var(--bg-deep);
|
|
7114
|
-
font-size:
|
|
7158
|
+
font-size: 14px;
|
|
7115
7159
|
}
|
|
7116
7160
|
|
|
7117
7161
|
.modal.session-picker.peeking {
|
|
@@ -7154,7 +7198,7 @@ select.form-input option:checked {
|
|
|
7154
7198
|
gap: 8px;
|
|
7155
7199
|
margin-bottom: 6px;
|
|
7156
7200
|
font-family: var(--mono);
|
|
7157
|
-
font-size:
|
|
7201
|
+
font-size: 11.5px;
|
|
7158
7202
|
color: var(--text-muted);
|
|
7159
7203
|
white-space: nowrap;
|
|
7160
7204
|
overflow: hidden;
|
|
@@ -7172,13 +7216,13 @@ select.form-input option:checked {
|
|
|
7172
7216
|
align-items: center;
|
|
7173
7217
|
gap: 8px;
|
|
7174
7218
|
width: 100%;
|
|
7175
|
-
padding:
|
|
7219
|
+
padding: 7px 8px;
|
|
7176
7220
|
background: none;
|
|
7177
7221
|
border: 1px solid transparent;
|
|
7178
7222
|
border-radius: 5px;
|
|
7179
7223
|
color: var(--text-secondary);
|
|
7180
7224
|
font-family: var(--mono);
|
|
7181
|
-
font-size:
|
|
7225
|
+
font-size: 13px;
|
|
7182
7226
|
text-align: left;
|
|
7183
7227
|
cursor: pointer;
|
|
7184
7228
|
}
|
|
@@ -7287,14 +7331,14 @@ select.form-input option:checked {
|
|
|
7287
7331
|
border-radius: 3px;
|
|
7288
7332
|
background: var(--bg-hover);
|
|
7289
7333
|
color: var(--text-tertiary);
|
|
7290
|
-
font-size:
|
|
7334
|
+
font-size: 11.5px;
|
|
7291
7335
|
}
|
|
7292
7336
|
|
|
7293
7337
|
.sp-count,
|
|
7294
7338
|
.sp-time {
|
|
7295
7339
|
flex: none;
|
|
7296
7340
|
color: var(--text-muted);
|
|
7297
|
-
font-size:
|
|
7341
|
+
font-size: 11.5px;
|
|
7298
7342
|
white-space: nowrap;
|
|
7299
7343
|
}
|
|
7300
7344
|
|
|
@@ -7333,7 +7377,7 @@ select.form-input option:checked {
|
|
|
7333
7377
|
|
|
7334
7378
|
/* #region NEW_SESSION */
|
|
7335
7379
|
.modal.new-session-modal {
|
|
7336
|
-
width:
|
|
7380
|
+
width: 640px;
|
|
7337
7381
|
max-width: calc(100vw - 32px);
|
|
7338
7382
|
overflow: visible;
|
|
7339
7383
|
}
|
|
@@ -7462,7 +7506,8 @@ select.form-input option:checked {
|
|
|
7462
7506
|
accent-color: var(--accent);
|
|
7463
7507
|
}
|
|
7464
7508
|
|
|
7465
|
-
.ns-inline .form-input:disabled
|
|
7509
|
+
.ns-inline .form-input:disabled,
|
|
7510
|
+
.ns-check:has(input:disabled) {
|
|
7466
7511
|
opacity: 0.5;
|
|
7467
7512
|
cursor: not-allowed;
|
|
7468
7513
|
}
|
|
@@ -7545,15 +7590,27 @@ select.form-input option:checked {
|
|
|
7545
7590
|
border-top: 1px solid var(--border);
|
|
7546
7591
|
}
|
|
7547
7592
|
|
|
7548
|
-
.ns-stay
|
|
7549
|
-
|
|
7593
|
+
.ns-stay,
|
|
7594
|
+
.ns-edit {
|
|
7550
7595
|
color: var(--text-tertiary);
|
|
7551
7596
|
}
|
|
7552
7597
|
|
|
7553
|
-
.
|
|
7598
|
+
.ns-edit {
|
|
7599
|
+
margin-right: auto;
|
|
7600
|
+
}
|
|
7601
|
+
|
|
7602
|
+
.new-session-modal.ns-resume .ns-stay,
|
|
7603
|
+
.new-session-modal.ns-resume .ns-edit {
|
|
7554
7604
|
visibility: hidden;
|
|
7555
7605
|
}
|
|
7556
7606
|
|
|
7607
|
+
.ns-footer .btn-primary {
|
|
7608
|
+
min-width: 0;
|
|
7609
|
+
overflow: hidden;
|
|
7610
|
+
text-overflow: ellipsis;
|
|
7611
|
+
white-space: nowrap;
|
|
7612
|
+
}
|
|
7613
|
+
|
|
7557
7614
|
.ns-footer .btn-primary:disabled {
|
|
7558
7615
|
opacity: 0.5;
|
|
7559
7616
|
cursor: not-allowed;
|
package/public/terminal-frame.js
CHANGED
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
const modsOf = (e) =>
|
|
12
12
|
[e.ctrlKey && 'ctrl', e.altKey && 'alt', e.shiftKey && 'shift', e.metaKey && 'meta'].filter(Boolean).join('+');
|
|
13
13
|
|
|
14
|
-
// A claim names a key by its physical code, or by its character when the layout moves it.
|
|
14
|
+
// A claim names a key by its physical code, or by its character when the layout moves it. A press
|
|
15
|
+
// that AltGr turns into a character (Polish AltGr+S is 'ś') is matched by its character only.
|
|
15
16
|
function keySigs(e) {
|
|
16
17
|
const mods = modsOf(e);
|
|
17
|
-
return [
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
return [
|
|
19
|
+
e.code && !e.getModifierState?.('AltGraph') && `${mods}|c:${e.code}`,
|
|
20
|
+
typeof e.key === 'string' && `${mods}|k:${e.key.toLowerCase()}`,
|
|
21
|
+
].filter(Boolean);
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
const claimSig = (c) => keySigs(c)[0];
|
|
@@ -1,18 +1,51 @@
|
|
|
1
|
-
// claude-hub-sdk 1.
|
|
2
|
-
// Claude Code Hub SDK
|
|
3
|
-
//
|
|
4
|
-
|
|
1
|
+
// claude-hub-sdk 1.4.0 (sha256 7d559a8888ce). Copied by npm run sdk:sync in claude-code-hub. Do not edit.
|
|
2
|
+
// Claude Code Hub SDK: the one rule that names a key press, shared by the hub page, client.js and
|
|
3
|
+
// stub.js. The hub serves it to its page as /sdk/keys.js; mount() and sdk:sync put it in front of
|
|
4
|
+
// client.js and stub.js, so an app still loads one file.
|
|
5
|
+
// var, not const: the hub page and an app page each load it as a classic script, and a second
|
|
6
|
+
// const declaration in the same page would throw.
|
|
7
|
+
var ClaudeHubKeys = (() => {
|
|
5
8
|
'use strict';
|
|
6
9
|
|
|
7
|
-
//
|
|
10
|
+
// Modifiers in ctrl, alt, shift, meta order, joined by '+' to the key. macOS composes
|
|
11
|
+
// Option+<key> into a character (Option+1 is '¡', Option+P is 'π') and holding Control does not
|
|
12
|
+
// undo it, so e.key alone cannot name these presses there. e.code is the physical key, which is
|
|
13
|
+
// wrong for non-US layouts, hence only as a fallback. No fallback under AltGraph: Chromium sets it
|
|
14
|
+
// when AltGr types a character, and that press is text. Takes a real KeyboardEvent or a forwarded
|
|
15
|
+
// {key, code} payload; a payload without code degrades to key. A payload needs no AltGraph: the
|
|
16
|
+
// SDK forwards only a press whose key already names a bound combo.
|
|
17
|
+
// Self-contained on purpose: cck puts its source text into a sandboxed frame.
|
|
8
18
|
function comboOf(e) {
|
|
9
19
|
const lower = typeof e.key === 'string' ? e.key.toLowerCase() : '';
|
|
10
|
-
const m = /^(?:Key|Digit)([A-Z1-9])$/.exec(e.code || '');
|
|
20
|
+
const m = !e.getModifierState?.('AltGraph') && /^(?:Key|Digit)([A-Z1-9])$/.exec(e.code || '');
|
|
11
21
|
const key = /^[a-z1-9]$/.test(lower) ? lower : m ? m[1].toLowerCase() : e.key;
|
|
12
22
|
const mods = [e.ctrlKey && 'ctrl', e.altKey && 'alt', e.shiftKey && 'shift', e.metaKey && 'meta'];
|
|
13
23
|
return [...mods, key].filter(Boolean).join('+');
|
|
14
24
|
}
|
|
15
25
|
|
|
26
|
+
// The keys of a combo as a help row shows them: ['Ctrl', 'Alt', 'P'], or ['⌃', '⌥', 'P'] on macOS.
|
|
27
|
+
// The {n} of a numbered combo reads 1…9.
|
|
28
|
+
function keyParts(combo, mac) {
|
|
29
|
+
const mods = mac
|
|
30
|
+
? { ctrl: '⌃', alt: '⌥', shift: '⇧', meta: '⌘' }
|
|
31
|
+
: { ctrl: 'Ctrl', alt: 'Alt', shift: 'Shift', meta: 'Win' };
|
|
32
|
+
const named = { '{n}': '1…9', ArrowLeft: '←', ArrowRight: '→', ArrowUp: '↑', ArrowDown: '↓' };
|
|
33
|
+
return combo.split('+').map((k) => mods[k] ?? named[k] ?? (k.length === 1 ? k.toUpperCase() : k));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { comboOf, keyParts };
|
|
37
|
+
})();
|
|
38
|
+
|
|
39
|
+
if (typeof module === 'object' && module.exports) module.exports = ClaudeHubKeys;
|
|
40
|
+
|
|
41
|
+
// Claude Code Hub SDK stub: what an app serves when no hub runs it. Under a hub, the hub hands the
|
|
42
|
+
// app its real SDK (client.js) in place of this file. The API must match client.js; a test checks it.
|
|
43
|
+
((root) => {
|
|
44
|
+
'use strict';
|
|
45
|
+
|
|
46
|
+
// keys.js comes first in the synced file. Required as a module, stub.js loads it itself.
|
|
47
|
+
const { comboOf } = typeof ClaudeHubKeys === 'object' ? ClaudeHubKeys : require('./keys');
|
|
48
|
+
|
|
16
49
|
function createClaudeHub(win) {
|
|
17
50
|
let hub = null;
|
|
18
51
|
const off = () => {};
|
|
@@ -43,6 +76,7 @@
|
|
|
43
76
|
can: (action) => !!standaloneFn(action),
|
|
44
77
|
forwards: () => false,
|
|
45
78
|
forwardCombos: () => [],
|
|
79
|
+
keyLabel: () => null,
|
|
46
80
|
closeGuard() {},
|
|
47
81
|
openExternal(url) {
|
|
48
82
|
win.open(url, '_blank', 'noopener');
|