claude-code-kanban 4.24.0 → 4.25.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
@@ -22,6 +22,7 @@
22
22
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github.min.css" id="hljs-theme-light" disabled>
23
23
  <script defer src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"></script>
24
24
  <script defer src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
25
+ <script>window.__STORAGE_NS__ = null;</script>
25
26
  <script defer src="/app.js"></script>
26
27
  </head>
27
28
  <body>
@@ -355,7 +356,7 @@
355
356
  </svg>
356
357
  </button>
357
358
  </div>
358
- <div class="modal-body modal-zoomable">
359
+ <div class="modal-body">
359
360
  <dl class="shortcuts" id="help-shortcuts"></dl>
360
361
  </div>
361
362
  </div>
@@ -611,8 +612,11 @@
611
612
  <div id="session-picker-modal" class="modal-overlay top-aligned" onclick="closeSessionPicker()">
612
613
  <div class="modal session-picker" onclick="event.stopPropagation()">
613
614
  <input type="text" id="session-picker-input" class="form-input sp-input" placeholder="Jump to session..." autocomplete="off" spellcheck="false">
614
- <div id="session-picker-list" class="sp-list"></div>
615
- <div class="sp-hint"><kbd>&uarr;</kbd><kbd>&darr;</kbd> move &middot; <kbd>Enter</kbd> open &middot; <kbd>Esc</kbd> close</div>
615
+ <div class="sp-body">
616
+ <div id="session-picker-list" class="sp-list"></div>
617
+ <div id="session-picker-peek" class="sp-peek"></div>
618
+ </div>
619
+ <div class="sp-hint"><kbd>&uarr;</kbd><kbd>&darr;</kbd> move &middot; <kbd>Enter</kbd> open &middot; <kbd>Ctrl</kbd><kbd>Space</kbd> peek &middot; <kbd>Esc</kbd> close</div>
616
620
  </div>
617
621
  </div>
618
622
 
package/public/style.css CHANGED
@@ -2264,7 +2264,8 @@ body::before {
2264
2264
  flex-direction: column;
2265
2265
  }
2266
2266
  #team-modal .modal-body,
2267
- #agent-modal .modal-body {
2267
+ #agent-modal .modal-body,
2268
+ .modal-help .modal-body {
2268
2269
  flex: 1 1 auto;
2269
2270
  overflow-y: auto;
2270
2271
  min-height: 0;
@@ -2349,7 +2350,6 @@ body::before {
2349
2350
  padding: 10px 14px;
2350
2351
  background: var(--bg-elevated);
2351
2352
  border: 1px solid var(--border);
2352
- border-left: 3px solid var(--warning);
2353
2353
  border-radius: 8px;
2354
2354
  }
2355
2355
  .info-goal-head {
@@ -4519,8 +4519,21 @@ body.light .msg-assistant .msg-text {
4519
4519
  max-width: 440px;
4520
4520
  }
4521
4521
 
4522
+ /* Reference card, not reading material: it stays out of the modal zoom, uses the app's
4523
+ small type, and scrolls its body (rule shared with #team-modal) instead of growing past
4524
+ the viewport cap. */
4522
4525
  .modal-help {
4523
- max-width: 960px;
4526
+ max-width: 900px;
4527
+ padding: 16px 20px 20px;
4528
+ display: flex;
4529
+ flex-direction: column;
4530
+ font-size: 13px;
4531
+ }
4532
+ .modal-help .modal-header {
4533
+ margin-bottom: 8px;
4534
+ }
4535
+ .modal-help .modal-title {
4536
+ font-size: 14px;
4524
4537
  }
4525
4538
 
4526
4539
  /* One shared grid for both halves (key | label | spacer | key | label): each key
@@ -4844,13 +4857,59 @@ select.form-input option:checked {
4844
4857
  font-size: 13px;
4845
4858
  }
4846
4859
 
4860
+ .modal.session-picker.peeking {
4861
+ max-width: 1240px;
4862
+ }
4863
+
4864
+ .sp-body {
4865
+ display: flex;
4866
+ gap: 10px;
4867
+ min-height: 0;
4868
+ }
4869
+
4870
+ .sp-body > * {
4871
+ min-width: 0;
4872
+ }
4873
+
4847
4874
  .sp-list {
4875
+ flex: 1;
4848
4876
  overflow-y: auto;
4849
4877
  display: flex;
4850
4878
  flex-direction: column;
4851
4879
  gap: 2px;
4852
4880
  }
4853
4881
 
4882
+ .sp-peek {
4883
+ flex: 0 0 42%;
4884
+ overflow-y: auto;
4885
+ border-left: 1px solid var(--border);
4886
+ padding-left: 10px;
4887
+ }
4888
+
4889
+ .modal.session-picker:not(.peeking) .sp-peek {
4890
+ display: none;
4891
+ }
4892
+
4893
+ .sp-peek-title {
4894
+ display: flex;
4895
+ align-items: center;
4896
+ justify-content: space-between;
4897
+ gap: 8px;
4898
+ margin-bottom: 6px;
4899
+ font-family: var(--mono);
4900
+ font-size: 11px;
4901
+ color: var(--text-muted);
4902
+ white-space: nowrap;
4903
+ overflow: hidden;
4904
+ text-overflow: ellipsis;
4905
+ }
4906
+
4907
+ /* Row clicks open the live panel's detail modal by index, which means nothing
4908
+ for a peeked session. The renderer's readOnly mode already drops the buttons. */
4909
+ .sp-peek-items {
4910
+ pointer-events: none;
4911
+ }
4912
+
4854
4913
  .sp-row {
4855
4914
  display: flex;
4856
4915
  align-items: center;
package/server.js CHANGED
@@ -34,6 +34,7 @@ const {
34
34
  } = require('./lib/parsers');
35
35
  const { inlineHtmlAssets } = require('./lib/inline-assets');
36
36
  const { buildDecision, decisionFileName, isDecisionFile, waitSecondsFrom, isLapsed } = require('./lib/approvals');
37
+ const { getClaudeDir, getArgValue, storageNamespace } = require('./lib/claude-dir');
37
38
 
38
39
  if (process.argv.includes("--install") || process.argv.includes("--uninstall")) {
39
40
  const { runInstall, runUninstall } = require("./install");
@@ -56,30 +57,8 @@ app.use(net.hostGuard);
56
57
  app.use(net.frameGuard);
57
58
  app.use(net.originGuard);
58
59
 
59
- // Parse --dir flag for custom Claude directory
60
- function getClaudeDir() {
61
- const dirIndex = process.argv.findIndex(arg => arg.startsWith('--dir'));
62
- if (dirIndex !== -1) {
63
- const arg = process.argv[dirIndex];
64
- if (arg.includes('=')) {
65
- const dir = arg.split('=')[1];
66
- return dir.startsWith('~') ? dir.replace('~', os.homedir()) : dir;
67
- } else if (process.argv[dirIndex + 1]) {
68
- const dir = process.argv[dirIndex + 1];
69
- return dir.startsWith('~') ? dir.replace('~', os.homedir()) : dir;
70
- }
71
- }
72
- return process.env.CLAUDE_CONFIG_DIR || process.env.CLAUDE_DIR || path.join(os.homedir(), '.claude');
73
- }
74
-
75
60
  function getArgUrl(argName, envName) {
76
- const idx = process.argv.findIndex(arg => arg.startsWith(`--${argName}`));
77
- if (idx !== -1) {
78
- const arg = process.argv[idx];
79
- if (arg.includes('=')) return arg.split('=').slice(1).join('=');
80
- if (process.argv[idx + 1]) return process.argv[idx + 1];
81
- }
82
- return process.env[envName] || null;
61
+ return getArgValue(argName) || process.env[envName] || null;
83
62
  }
84
63
 
85
64
  const MARKETPLACE_URL = getArgUrl('marketplace-url', 'MARKETPLACE_URL');
@@ -516,6 +495,18 @@ app.get('/hub-config', (_req, res) => {
516
495
  res.json({ enabled: !!process.env.CLAUDE_HUB, url: process.env.HUB_URL || null });
517
496
  });
518
497
 
498
+ // app.js reads localStorage synchronously at startup, before any fetch could deliver the
499
+ // namespace, so it is injected into the page instead of served from /hub-config.
500
+ const STORAGE_NS = storageNamespace(CLAUDE_DIR);
501
+ const NS_DECL = 'window.__STORAGE_NS__ = null;';
502
+ const RAW_INDEX = readFileSync(path.join(__dirname, 'public', 'index.html'), 'utf8');
503
+ if (!RAW_INDEX.includes(NS_DECL)) throw new Error(`public/index.html is missing "${NS_DECL}"`);
504
+ const INDEX_HTML = RAW_INDEX.replace(NS_DECL, `window.__STORAGE_NS__ = ${JSON.stringify(STORAGE_NS)};`);
505
+ app.get(['/', '/index.html'], (_req, res) => {
506
+ res.setHeader('Cache-Control', 'no-cache');
507
+ res.type('html').send(INDEX_HTML);
508
+ });
509
+
519
510
  // Serve static files
520
511
  app.get('/sw.js', (_req, res) => {
521
512
  res.setHeader('Cache-Control', 'no-cache');