claude-code-kanban 7.9.0 → 7.10.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 CHANGED
@@ -5,7 +5,7 @@
5
5
  "icon": "columns",
6
6
  "run": { "entry": "server.js", "defaultPort": 3541 },
7
7
  "publishes": ["session.changed"],
8
- "keys": { "keeps": ["ctrl+alt+n", "ctrl+alt+r", "ctrl+alt+s", "ctrl+shift+k", "ctrl+shift+p", "ctrl+shift+z"] },
8
+ "keys": { "keeps": ["ctrl+alt+n", "ctrl+alt+r", "ctrl+alt+s", "ctrl+shift+d", "ctrl+shift+k", "ctrl+shift+p", "ctrl+shift+z"] },
9
9
  "plugin": {
10
10
  "marketplace": "plugin",
11
11
  "name": "claude-code-kanban",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-kanban",
3
- "version": "7.9.0",
3
+ "version": "7.10.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
@@ -2565,20 +2565,28 @@ function unmountMsgReview() {
2565
2565
 
2566
2566
  // Only the main session's replies: the agent has them in context, so a quote is enough.
2567
2567
  function mountReplyReview(m, body, modal) {
2568
- if (m.type !== 'assistant' || agentLogMode || !m.timestamp) return unmountMsgReview();
2568
+ const opts = !agentLogMode && replyReviewOpts(m, body, currentSessionId);
2569
+ if (!opts) return unmountMsgReview();
2569
2570
  mountReview({
2570
- contentEl: body,
2571
+ ...opts,
2571
2572
  panelEl: document.getElementById('msg-review-panel'),
2572
2573
  hostEl: modal,
2574
+ onComment: () => setMsgDetailFollow(false),
2575
+ onSent: closeMsgDetailModal,
2576
+ });
2577
+ }
2578
+
2579
+ function replyReviewOpts(m, contentEl, sid) {
2580
+ if (m.type !== 'assistant' || !m.timestamp) return null;
2581
+ return {
2582
+ contentEl,
2573
2583
  source: {
2574
2584
  kind: 'reply',
2575
2585
  id: m.timestamp,
2576
2586
  label: replyReviewLabel(m.timestamp),
2577
- locate: replyLocateHint(m.timestamp),
2587
+ locate: replyLocateHint(m.timestamp, sid),
2578
2588
  },
2579
- onComment: () => setMsgDetailFollow(false),
2580
- onSent: closeMsgDetailModal,
2581
- });
2589
+ };
2582
2590
  }
2583
2591
 
2584
2592
  function replyReviewLabel(timestamp) {
@@ -2590,8 +2598,8 @@ function replyReviewLabel(timestamp) {
2590
2598
  return `your reply${day} at ${d.toLocaleTimeString()}`;
2591
2599
  }
2592
2600
 
2593
- function replyLocateHint(timestamp) {
2594
- const transcript = sessions.find((s) => s.id === currentSessionId)?.jsonlPath;
2601
+ function replyLocateHint(timestamp, sid) {
2602
+ const transcript = sessions.find((s) => s.id === sid)?.jsonlPath;
2595
2603
  if (!transcript) return undefined;
2596
2604
  return `If that reply is not in your context, it is in ${transcript}, the assistant entry with timestamp ${timestamp}.`;
2597
2605
  }
@@ -7610,6 +7618,17 @@ async function dismissSession(sid) {
7610
7618
  if (await confirmDismissBlockers(sid)) dismissSessionFromList(sid);
7611
7619
  }
7612
7620
 
7621
+ function contextSessionId() {
7622
+ if (terminalPaneFocused()) return termState.sessionId || currentSessionId;
7623
+ if (focusZone !== 'sidebar') return selectedSessionId || currentSessionId;
7624
+ return sessionsList.querySelector('.kb-selected')?.dataset.sessionId || currentSessionId;
7625
+ }
7626
+
7627
+ function dismissContextSession() {
7628
+ const sid = contextSessionId();
7629
+ if (sid) dismissSession(sid);
7630
+ }
7631
+
7613
7632
  const MODAL_ESC_PRIORITY = [
7614
7633
  'preview-modal',
7615
7634
  'msg-detail-modal',
@@ -7968,9 +7987,7 @@ document.addEventListener('keydown', (e) => {
7968
7987
  }
7969
7988
 
7970
7989
  // Shared actions — work in both sidebar and board
7971
- const cursorEl = focusZone === 'sidebar' ? sessionsList.querySelector('.kb-selected') : null;
7972
- const contextSid =
7973
- focusZone === 'sidebar' ? cursorEl?.dataset.sessionId || currentSessionId : selectedSessionId || currentSessionId;
7990
+ const contextSid = contextSessionId();
7974
7991
  if (matchKey(e, 'KeyP')) {
7975
7992
  e.preventDefault();
7976
7993
  if (contextSid) openPlanForSession(contextSid);
@@ -7983,7 +8000,7 @@ document.addEventListener('keydown', (e) => {
7983
8000
  }
7984
8001
  if (matchKey(e, 'KeyN')) {
7985
8002
  e.preventDefault();
7986
- const cursorKey = _scratchpadKeyOf(cursorEl);
8003
+ const cursorKey = _scratchpadKeyOf(focusZone === 'sidebar' ? sessionsList.querySelector('.kb-selected') : null);
7987
8004
  if (cursorKey) showScratchpad(cursorKey);
7988
8005
  else toggleScratchpad();
7989
8006
  return;
@@ -8007,8 +8024,7 @@ document.addEventListener('keydown', (e) => {
8007
8024
  }
8008
8025
  if (ClaudeHub.comboOf(e) === 'ctrl+d') {
8009
8026
  e.preventDefault();
8010
- if (!contextSid) return;
8011
- dismissSession(contextSid);
8027
+ dismissContextSession();
8012
8028
  return;
8013
8029
  }
8014
8030
  if (e.code === 'KeyC' && e.shiftKey && !e.altKey && !e.metaKey) {
@@ -13671,7 +13687,9 @@ async function loadMessagePaneView(sid, pane, view) {
13671
13687
  return;
13672
13688
  }
13673
13689
  const meta = [msgDetailTitle(m), ...msgDetailMeta(m)].join(' · ');
13674
- appendPaneDoc(view).innerHTML = `<div class="pane-msg-meta">${escapeHtml(meta)}</div>${msgDetailContent(m)}`;
13690
+ const body = appendPaneDoc(view);
13691
+ body.innerHTML = `<div class="pane-msg-meta">${escapeHtml(meta)}</div>${msgDetailContent(m)}`;
13692
+ attachPaneReview(view, sid, replyReviewOpts(m, body, sid));
13675
13693
  }
13676
13694
 
13677
13695
  function onPaneFileChanged(filePath) {
@@ -14738,6 +14756,7 @@ function terminalShortcut(e, probe = false) {
14738
14756
  // Ctrl+Shift+Z is redo in a text field, so only the terminal's own textarea gives it up.
14739
14757
  if (ctrlShift && e.code === 'KeyZ') return inPageField(e) ? null : toggleZenMode;
14740
14758
  if (ctrlShift && e.code === 'KeyK') return kanbotAvailable() ? () => toggleKanbot() : null;
14759
+ if (ctrlShift && e.code === 'KeyD') return dismissContextSession;
14741
14760
  if (ctrlAlt && (e.code === 'KeyN' || e.code === 'KeyR') && terminalAvailable()) {
14742
14761
  return () => openNewSession(null, e.code === 'KeyR');
14743
14762
  }