claude-code-kanban 7.22.0 → 7.23.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/lib/show.js CHANGED
@@ -173,6 +173,16 @@ function createShowStore(o) {
173
173
  for (const ext of Object.values(EXT)) fs.rmSync(path.join(dir, `${id}.${ext}`), { force: true });
174
174
  }
175
175
 
176
+ // The kind of `file` when it is the post's own claimed file, else null: posting that path as a
177
+ // file post would have removeContent delete it.
178
+ function ownContentKind(dir, id, file) {
179
+ const m = CONTENT_FILE_RE.exec(path.basename(file));
180
+ if (!m || m[1].toLowerCase() !== id.toLowerCase()) return null;
181
+ const real = (p) => { try { return fs.realpathSync.native(p); } catch { return path.resolve(p); } };
182
+ if (real(path.dirname(file)).toLowerCase() !== real(dir).toLowerCase()) return null;
183
+ return Object.keys(EXT).find((k) => EXT[k] === m[2].toLowerCase());
184
+ }
185
+
176
186
  // A session resumed in a new terminal gets a new terminal id, so a terminal with no posts yet
177
187
  // takes the posts of the session it was started with.
178
188
  function sessionOf(terminalId) {
@@ -203,6 +213,11 @@ function createShowStore(o) {
203
213
  let at = key == null ? -1 : posts.findIndex((p) => p.key === key);
204
214
  const old = at >= 0 ? posts[at] : null;
205
215
  const id = old ? old.id : crypto.randomUUID();
216
+ const ownKind = old && file != null ? ownContentKind(dir, id, file) : null;
217
+ if (ownKind) {
218
+ kind = ownKind;
219
+ file = null;
220
+ }
206
221
  const target = file == null ? contentPath(dir, { id, kind }) : null;
207
222
  if (target && old && !old.file) {
208
223
  const from = contentPath(dir, old);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-kanban",
3
- "version": "7.22.0",
3
+ "version": "7.23.0",
4
4
  "description": "A web-based Kanban board for viewing Claude Code tasks with agent teams support",
5
5
  "main": "server.js",
6
6
  "type": "commonjs",
package/public/app.js CHANGED
@@ -16951,6 +16951,11 @@ function focusShowBody() {
16951
16951
 
16952
16952
  const SHOW_KEY_COMMANDS = { 'alt+Enter': 'expand', 'alt+shift+Enter': 'dock', 'alt+w': 'close' };
16953
16953
 
16954
+ // Docked, the card is a dock item, so it shares the dock's expand with the add-ons.
16955
+ const showExpanded = () => (showState.docked ? dockExpanded : showState.expanded);
16956
+
16957
+ const expandTitle = (on, home) => (on ? `Back to the ${home} · Alt+Enter or Esc` : 'Fill the terminal · Alt+Enter');
16958
+
16954
16959
  // The body keeps focus, because a render replaces an HTML card's frame.
16955
16960
  function showCardKey(e) {
16956
16961
  if (matchKey(e, '[', ']')) {
@@ -16960,8 +16965,7 @@ function showCardKey(e) {
16960
16965
  }
16961
16966
  const combo = ClaudeHub.comboOf(e);
16962
16967
  let cmd = SHOW_KEY_COMMANDS[combo];
16963
- if (combo === 'Escape') cmd = showState.expanded && !showState.docked ? 'expand' : 'collapse';
16964
- else if (cmd === 'expand' && showState.docked) cmd = null;
16968
+ if (combo === 'Escape') cmd = showExpanded() ? 'expand' : 'collapse';
16965
16969
  if (cmd) {
16966
16970
  showCommand(cmd);
16967
16971
  if (cmd === 'expand' || cmd === 'dock') focusShowBody();
@@ -17126,16 +17130,11 @@ function showHeaderHtml(p) {
17126
17130
  const i = showState.idx;
17127
17131
  const key = p.key ? `<span class="show-sep">·</span><span class="show-key">${escapeHtml(p.key)}</span>` : '';
17128
17132
  const btn = (...args) => showBtnHtml('show', ...args);
17129
- const { collapsed, expanded, docked } = showState;
17133
+ const { collapsed, docked } = showState;
17134
+ const expanded = showExpanded();
17130
17135
  const dockTitle = docked ? 'Back to the overlay · Alt+Shift+Enter' : 'Dock beside the terminal · Alt+Shift+Enter';
17131
17136
  const dock = btn('dock', 'dock', dockTitle, false, docked);
17132
- const expand = docked
17133
- ? ''
17134
- : btn(
17135
- 'expand',
17136
- expanded ? 'restore' : 'expand',
17137
- expanded ? 'Back to the card · Alt+Enter or Esc' : 'Fill the terminal · Alt+Enter',
17138
- );
17137
+ const expand = btn('expand', expanded ? 'restore' : 'expand', expandTitle(expanded, docked ? 'dock' : 'card'));
17139
17138
  return `<span class="show-nav"><span class="show-title" title="${escapeHtml(p.title)}">${escapeHtml(p.title)}</span>${key}</span>
17140
17139
  <span class="show-pager">${btn('prev', 'prev', 'Previous post', i === 0)}<span class="show-pos">${i + 1}/${n}</span>${btn('next', 'next', 'Next post', i === n - 1)}</span>
17141
17140
  <span class="show-actions">${btn('pane', 'pane', 'Open in a pane of the session')}${dock}${btn('collapse', collapsed ? 'uncollapse' : 'collapse', collapsed ? 'Show the post' : 'Collapse to the header · Esc')}${expand}${btn('remove', 'clear', 'Remove this post · Ctrl+D · Shift+click clears every post')}${btn('close', 'close', 'Close until the next post · Alt+W')}</span>`;
@@ -17176,7 +17175,7 @@ function renderShow({ flash = false } = {}) {
17176
17175
  }
17177
17176
  const p = showState.posts[showState.idx];
17178
17177
  showState.marked.delete(p.id);
17179
- card.classList.toggle('expanded', showState.expanded && !showState.collapsed && !showState.docked);
17178
+ card.classList.toggle('expanded', showExpanded() && !showState.collapsed);
17180
17179
  card.classList.toggle('collapsed', showState.collapsed);
17181
17180
  if (!card.firstChild) {
17182
17181
  card.innerHTML = `<header class="show-head"></header><div class="show-ticks"></div><div class="show-body" tabindex="-1"></div>
@@ -17670,11 +17669,11 @@ function renderDockAddon(pane) {
17670
17669
  panel.classList.toggle('expanded', dockExpanded);
17671
17670
  panel.style.setProperty('--show-term-font', `${currentTerminalFontSize()}px`);
17672
17671
  const expand = panel.querySelector('[data-dock="expand"]');
17673
- const expandTitle = dockExpanded ? 'Back to the dock · Alt+Enter or Esc' : 'Fill the terminal · Alt+Enter';
17674
- if (expand.title !== expandTitle) {
17672
+ const label = expandTitle(dockExpanded, 'dock');
17673
+ if (expand.title !== label) {
17675
17674
  expand.innerHTML = showIcon(dockExpanded ? 'restore' : 'expand');
17676
- expand.title = expandTitle;
17677
- expand.setAttribute('aria-label', expandTitle);
17675
+ expand.title = label;
17676
+ expand.setAttribute('aria-label', label);
17678
17677
  }
17679
17678
  if (!dockFrames.has(pane.id)) {
17680
17679
  const view = createDockView(pane);
@@ -17769,7 +17768,7 @@ async function removeDockItem(item) {
17769
17768
  function setDockExpanded(on) {
17770
17769
  dockExpanded = on;
17771
17770
  store.setItem(DOCK_EXPANDED_KEY, on ? '1' : '');
17772
- renderDockAddon(dockActivePane());
17771
+ renderShow();
17773
17772
  }
17774
17773
 
17775
17774
  // Alt+Enter toggles the full width and Esc goes back; Esc in the dock focuses the terminal.
@@ -17966,8 +17965,9 @@ function showCommand(cmd) {
17966
17965
  showState.docked = !showState.docked;
17967
17966
  showState.collapsed = false;
17968
17967
  } else if (cmd === 'expand') {
17969
- showState.expanded = !showState.expanded;
17970
17968
  showState.collapsed = false;
17969
+ if (showState.docked) return setDockExpanded(!dockExpanded);
17970
+ showState.expanded = !showState.expanded;
17971
17971
  } else if (cmd === 'close') showState.closed = true;
17972
17972
  else if (cmd === 'remove') {
17973
17973
  const id = showState.posts[showState.idx]?.id;
package/public/style.css CHANGED
@@ -69,9 +69,10 @@
69
69
  /* Tokens derived from theme colors live on body, where color themes set those colors;
70
70
  on :root they would resolve to the defaults before a theme applies. */
71
71
  body {
72
- /* Selection reads as a recess against the darker surface here, but light theme's deep tone
73
- sits within a shade of the sidebar, so there it has to rise instead. */
74
- --session-active-bg: var(--bg-deep);
72
+ /* bg-deep and bg-elevated sit within a few shades of the dark sidebar, so dark themes raise
73
+ the open session to the hover tone; light themes use bg-elevated. */
74
+ --session-active-bg: var(--bg-hover);
75
+ --session-active-border: color-mix(in srgb, var(--text-primary) 30%, transparent);
75
76
  --ansi-black: var(--text-muted);
76
77
  --ansi-white: var(--text-secondary);
77
78
  --ansi-bright-black: var(--text-tertiary);
@@ -1059,7 +1060,7 @@ body.booting .boot-splash {
1059
1060
 
1060
1061
  .session-item.active {
1061
1062
  background: var(--session-active-bg);
1062
- border-color: var(--border);
1063
+ border-color: var(--session-active-border);
1063
1064
  }
1064
1065
 
1065
1066
  .session-item.kb-selected,
@@ -4125,14 +4126,16 @@ code.ct .ct-has[aria-expanded='false'] .ct-name::after {
4125
4126
  }
4126
4127
 
4127
4128
  /* Stops above the prompt rows, as the expanded show card does. */
4128
- .dock-addon.expanded {
4129
+ .dock-addon.expanded,
4130
+ .show-card.docked.expanded {
4129
4131
  left: 0;
4130
4132
  bottom: calc(7.2 * var(--show-term-font, 13px));
4131
4133
  width: auto;
4132
4134
  border-bottom: 1px solid var(--border);
4133
4135
  }
4134
4136
 
4135
- .dock-addon.expanded .show-dock-edge {
4137
+ .dock-addon.expanded .show-dock-edge,
4138
+ .show-card.docked.expanded .show-dock-edge {
4136
4139
  display: none;
4137
4140
  }
4138
4141
 
@@ -7994,6 +7997,7 @@ body.light {
7994
7997
  --bg-elevated: #fbfaf9;
7995
7998
  --bg-hover: #d2d0cc;
7996
7999
  --session-active-bg: var(--bg-elevated);
8000
+ --session-active-border: var(--border);
7997
8001
  --border: #cfcbc4;
7998
8002
  --text-primary: #0a0a0a;
7999
8003
  --text-secondary: #2c2c2c;
@@ -10526,6 +10530,7 @@ select.form-input option:checked {
10526
10530
  --bg-elevated: #fbfaf9;
10527
10531
  --bg-hover: #d2d0cc;
10528
10532
  --session-active-bg: var(--bg-elevated);
10533
+ --session-active-border: var(--border);
10529
10534
  --border: #cfcbc4;
10530
10535
  --text-primary: #0a0a0a;
10531
10536
  --text-secondary: #2c2c2c;