claude-code-kanban 4.29.0 → 4.31.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
@@ -26,8 +26,9 @@
26
26
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.12.0/build/styles/github-dark.min.css" integrity="sha384-wH75j6z1lH97ZOpMOInqhgKzFkAInZPPSPlZpYKYTOqsaizPvhQZmAtLcPKXpLyH" crossorigin="anonymous" id="hljs-theme-dark">
27
27
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.12.0/build/styles/github.min.css" integrity="sha384-eFTL69TLRZTkNfYZOLM+G04821K1qZao/4QLJbet1pP4tcF+fdXq/9CdqAbWRl/L" crossorigin="anonymous" id="hljs-theme-light" disabled>
28
28
  <script defer src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.12.0/build/highlight.min.js" integrity="sha384-wjfDDhOPPdjtva8vWBhWeVprSpmxisEu5aYT3q1JyACqXpdKpo3PWZTMVq24MBix" crossorigin="anonymous"></script>
29
- <script defer src="https://cdn.jsdelivr.net/npm/mermaid@12.0.0/dist/mermaid.min.js" integrity="sha384-xzghz1GQ5u9HCpVskeDPqMsdogD1yvuMQbEK53+wi+G70+6J1AG0L2cfi9PHjDWI" crossorigin="anonymous"></script>
30
29
  <script>window.__STORAGE_NS__ = null;</script>
30
+ <script defer src="/project-match.js"></script>
31
+ <script defer src="/link-url.js"></script>
31
32
  <script defer src="/app.js"></script>
32
33
  </head>
33
34
  <body class="booting">
@@ -81,7 +82,7 @@
81
82
  id="zen-mode-btn"
82
83
  class="icon-btn section-btn"
83
84
  onclick="event.stopPropagation(); toggleZenMode()"
84
- title="Zen mode: current session only (Shift+Z)"
85
+ title="Zen mode: current session only (Ctrl+Shift+Z)"
85
86
  aria-label="Zen mode: current session only"
86
87
  aria-pressed="false"
87
88
  >
@@ -120,24 +121,37 @@
120
121
  </svg>
121
122
  </span>
122
123
  <div id="filter-menu" class="filter-menu" onclick="event.stopPropagation()">
123
- <div class="filter-row">
124
- <select id="project-filter" class="filter-dropdown" onchange="filterByProject(this.value)" aria-label="Filter by project">
125
- <option value="">All Projects</option>
126
- </select>
127
- </div>
128
- <div class="filter-row">
129
- <select id="session-filter" class="filter-dropdown" onchange="filterBySessions(this.value)" aria-label="Filter by session status">
130
- <option value="all">All Sessions</option>
131
- <option value="active">Active Only</option>
132
- </select>
124
+ <div class="pf-field">
125
+ <svg class="pf-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
126
+ <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
127
+ </svg>
128
+ <input
129
+ id="project-filter"
130
+ type="text"
131
+ class="pf-input"
132
+ placeholder="Any project"
133
+ autocomplete="off"
134
+ spellcheck="false"
135
+ role="combobox"
136
+ aria-expanded="true"
137
+ aria-controls="project-filter-options"
138
+ aria-autocomplete="list"
139
+ aria-label="Project. Type part of a path, or pick a project."
140
+ oninput="typeProjectFilter(this.value)"
141
+ />
142
+ <button
143
+ id="project-recent-btn"
144
+ type="button"
145
+ class="pf-recent"
146
+ onclick="toggleRecentProjects()"
147
+ aria-pressed="false"
148
+ title="Projects with activity in the last 24 hours"
149
+ >24h</button>
133
150
  </div>
134
- <div class="filter-row">
135
- <select id="session-limit" class="filter-dropdown" onchange="changeSessionLimit(this.value)" aria-label="Number of sessions to show">
136
- <option value="10">Show 10</option>
137
- <option value="20">Show 20</option>
138
- <option value="50">Show 50</option>
139
- <option value="all">Show All</option>
140
- </select>
151
+ <ul id="project-filter-options" class="pf-list" role="listbox" aria-label="Projects"></ul>
152
+ <div class="pf-seg" role="radiogroup" aria-label="Sessions">
153
+ <button type="button" role="radio" data-session-filter="active" onclick="filterBySessions('active')">Active</button>
154
+ <button type="button" role="radio" data-session-filter="all" onclick="filterBySessions('all')">All sessions</button>
141
155
  </div>
142
156
  </div>
143
157
  </div>
@@ -188,11 +202,20 @@
188
202
  </svg>
189
203
  <p id="boot-verb">Clawding…</p>
190
204
  </div>
191
- <div id="no-session" class="empty-state">
192
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
193
- <path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
194
- </svg>
195
- <p>Select a session to view tasks</p>
205
+ <div id="no-session" class="empty-state idle-board">
206
+ <div class="idle-ghost" aria-hidden="true">
207
+ <div><span></span><span></span><span></span></div>
208
+ <div><span></span><span></span></div>
209
+ <div><span></span><span></span><span></span><span></span></div>
210
+ </div>
211
+ <div class="idle-glow" aria-hidden="true"><span></span><span></span></div>
212
+ <div class="idle-content">
213
+ <div class="idle-clawd" aria-hidden="true">
214
+ <svg class="clawd" viewBox="1 0 16 10" shape-rendering="crispEdges"><use href="#clawd-shape"/></svg>
215
+ </div>
216
+ <p class="idle-title">Select a session to view tasks</p>
217
+ <div class="idle-hint sp-hint"><kbd>↑</kbd><kbd>↓</kbd> move <span>·</span> <kbd>Enter</kbd> open <span>·</span> <kbd>?</kbd> shortcuts</div>
218
+ </div>
196
219
  </div>
197
220
 
198
221
  <div id="session-view" class="session-view">
@@ -213,7 +236,7 @@
213
236
  <polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/>
214
237
  </svg>
215
238
  </button>
216
- <button id="message-toggle" class="icon-btn" onclick="toggleMessagePanel()" title="Session log (L)" aria-label="Toggle session log">
239
+ <button id="message-toggle" class="icon-btn" onclick="toggleMessagePanel()" title="Session log (Shift+L)" aria-label="Toggle session log">
217
240
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
218
241
  <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
219
242
  </svg>
@@ -344,6 +367,9 @@
344
367
  <button class="icon-btn" onclick="openLiveLatestMessage()" title="Follow latest message (Shift+M)" aria-label="Follow latest message">
345
368
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
346
369
  </button>
370
+ <button id="message-panel-full-btn" class="icon-btn" onclick="toggleMessagePanelFull()" title="Expand to full width" aria-label="Expand to full width" aria-pressed="false">
371
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
372
+ </button>
347
373
  <button class="detail-close" onclick="toggleMessagePanel()" aria-label="Close message panel">
348
374
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
349
375
  <path d="M6 18L18 6M6 6l12 12"/>
@@ -0,0 +1,15 @@
1
+ // Loaded by the page as a plain script and by lib/linked-docs.js through require, so the
2
+ // sidebar, the API and the CLI accept the same URLs. Only http(s): linked docs render as
3
+ // links, so a `javascript:` or `data:` value sent through the API must not become one.
4
+ function linkUrl(value) {
5
+ if (typeof value !== 'string') return null;
6
+ const v = value.trim();
7
+ if (!/^https?:\/\//i.test(v)) return null;
8
+ try {
9
+ return new URL(v).href;
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+
15
+ if (typeof module === 'object' && module.exports) module.exports = { linkUrl };
@@ -0,0 +1,27 @@
1
+ // Loaded by the page as a plain script and by server.js through require, so the sidebar and
2
+ // the API (and the CLI, which sends `project=`) filter projects by one rule.
3
+ const projectMatch = (() => {
4
+ function normalizeProjectPath(p) {
5
+ return p.toLowerCase().replace(/\\/g, '/').replace(/\/+$/, '');
6
+ }
7
+ function isExactProjectPath(normalized) {
8
+ return /^([a-z]:)?\//.test(normalized);
9
+ }
10
+ function isExactProjectFilter(query) {
11
+ return isExactProjectPath(normalizeProjectPath(query.trim()));
12
+ }
13
+ // An absolute path selects that one project, so the hub's scope does not also pull in
14
+ // `app-2` next to `app`; any other text matches a part of the path.
15
+ function projectMatcher(query) {
16
+ const q = normalizeProjectPath(query.trim());
17
+ const exact = isExactProjectPath(q);
18
+ return (project) => {
19
+ if (!project) return false;
20
+ const p = normalizeProjectPath(project);
21
+ return exact ? p === q : p.includes(q);
22
+ };
23
+ }
24
+ return { normalizeProjectPath, isExactProjectPath, isExactProjectFilter, projectMatcher };
25
+ })();
26
+
27
+ if (typeof module === 'object' && module.exports) module.exports = projectMatch;