claude-code-kanban 3.1.1 → 3.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-kanban",
3
- "version": "3.1.1",
3
+ "version": "3.2.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
  "bin": {
package/public/app.js CHANGED
@@ -25,7 +25,7 @@ let agentPollInterval = null;
25
25
  let selectedTaskId = null;
26
26
  let selectedSessionId = null;
27
27
  let focusZone = 'board'; // 'board' | 'sidebar'
28
- let appConfig = { marketplaceUrl: null, costUrl: null };
28
+ let appConfig = { marketplaceUrl: null, costUrl: null, memoryUrl: null };
29
29
  let selectedSessionIdx = -1;
30
30
  let selectedSessionKbId = null;
31
31
  let sessionJustSelected = false;
@@ -1330,6 +1330,8 @@ function _renderPinToDetail(pin) {
1330
1330
  const SESSION_PIN_SVG = PIN_SVG.replace('width="14" height="14"', 'width="12" height="12"');
1331
1331
  const MARKETPLACE_SVG =
1332
1332
  '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 01-8 0"/></svg>';
1333
+ const MEMORY_SVG =
1334
+ '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>';
1333
1335
 
1334
1336
  //#endregion
1335
1337
 
@@ -1463,17 +1465,19 @@ function updateFullscreenBtnIcon(btnId, isFullscreen) {
1463
1465
  }
1464
1466
 
1465
1467
  let _toastTimer = null;
1468
+ let _manualRefreshing = false;
1466
1469
  //#endregion
1467
1470
 
1468
1471
  //#region TOAST
1469
- function showToast(msg) {
1472
+ function showToast(msg, type) {
1470
1473
  const el = document.getElementById('toast');
1471
1474
  clearTimeout(_toastTimer);
1472
1475
  el.style.transition = 'none';
1473
- el.classList.remove('visible');
1476
+ el.classList.remove('visible', 'toast-success', 'toast-error', 'toast-info');
1474
1477
  void el.offsetHeight;
1475
1478
  el.style.transition = '';
1476
1479
  el.textContent = msg;
1480
+ if (type) el.classList.add(`toast-${type}`);
1477
1481
  el.classList.add('visible');
1478
1482
  _toastTimer = setTimeout(() => el.classList.remove('visible'), 2000);
1479
1483
  }
@@ -2242,6 +2246,7 @@ function renderSessions() {
2242
2246
  ${session.planSourceSessionId ? `<span class="plan-indicator" title="Implements plan — click to reveal plan session" onclick="event.stopPropagation(); revealPlanSession('${escapeHtml(session.planSourceSessionId)}')">📋</span>` : ''}
2243
2247
  ${session.hasWaitingForUser ? '<span class="agent-badge" title="Waiting for user">❓</span>' : ''}
2244
2248
  ${(window.__HUB__?.enabled || appConfig.marketplaceUrl) && session.project ? `<span class="marketplace-btn" data-project-path="${escapeHtml(session.project)}" onclick="event.stopPropagation(); openMarketplace(this.dataset.projectPath)" title="Open in Marketplace">${MARKETPLACE_SVG}</span>` : ''}
2249
+ ${(window.__HUB__?.enabled || appConfig.memoryUrl) && session.project ? `<span class="marketplace-btn" data-project-path="${escapeHtml(session.project)}" onclick="event.stopPropagation(); openMemory(this.dataset.projectPath)" title="Open in Memory">${MEMORY_SVG}</span>` : ''}
2245
2250
  ${isLive ? '<span class="pulse"></span>' : ''}
2246
2251
  </span>
2247
2252
  <div class="progress-bar"><div class="progress-fill" style="width: ${percent}%"></div></div>
@@ -3991,9 +3996,23 @@ document.addEventListener('keydown', (e) => {
3991
3996
  hubNavigate('marketplace', mSession?.project ? `?project=${encodeURIComponent(mSession.project)}` : undefined);
3992
3997
  return;
3993
3998
  }
3999
+ if (e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && e.key === 'm') {
4000
+ e.preventDefault();
4001
+ const mSession = contextSid ? sessions.find((s) => s.id === contextSid) : null;
4002
+ hubNavigate('memory', mSession?.project ? `?project=${encodeURIComponent(mSession.project)}` : undefined);
4003
+ return;
4004
+ }
3994
4005
  if (matchKey(e, 'KeyR')) {
3995
4006
  e.preventDefault();
3996
- location.reload();
4007
+ if (_manualRefreshing) return;
4008
+ _manualRefreshing = true;
4009
+ const refreshes = [fetchSessions()];
4010
+ if (currentSessionId) refreshes.push(fetchTasks(currentSessionId));
4011
+ Promise.all(refreshes)
4012
+ .then(() => showToast('Data refreshed', 'success'))
4013
+ .finally(() => {
4014
+ _manualRefreshing = false;
4015
+ });
3997
4016
  return;
3998
4017
  }
3999
4018
  if (matchKey(e, 'KeyT')) {
@@ -5105,6 +5124,18 @@ function openMarketplace(projectPath) {
5105
5124
  }
5106
5125
  }
5107
5126
 
5127
+ // biome-ignore lint/correctness/noUnusedVariables: used in HTML
5128
+ function openMemory(projectPath) {
5129
+ const params = new URLSearchParams({ project: projectPath });
5130
+ if (window.__HUB__?.enabled) {
5131
+ hubNavigate('memory', `?${params}`);
5132
+ } else if (appConfig.memoryUrl) {
5133
+ const url = new URL(appConfig.memoryUrl);
5134
+ url.search = params.toString();
5135
+ window.open(url.toString(), '_blank');
5136
+ }
5137
+ }
5138
+
5108
5139
  //#endregion
5109
5140
 
5110
5141
  //#region OWNER_FILTER
package/public/style.css CHANGED
@@ -2076,29 +2076,38 @@ body::before {
2076
2076
  }
2077
2077
  .toast {
2078
2078
  position: fixed;
2079
- bottom: 24px;
2080
- left: 24px;
2081
- transform: translateY(20px);
2079
+ bottom: 16px;
2080
+ left: 16px;
2082
2081
  background: var(--bg-elevated);
2083
- color: var(--accent-text);
2084
2082
  border: 1px solid var(--border);
2085
- border-left: 3px solid var(--accent);
2086
- border-radius: 8px;
2087
- padding: 10px 20px;
2088
- font-size: 13px;
2089
- font-weight: 600;
2083
+ border-radius: 6px;
2084
+ padding: 8px 14px;
2085
+ font-size: 11px;
2086
+ color: var(--text-secondary);
2090
2087
  z-index: 10000;
2091
2088
  opacity: 0;
2089
+ transform: translateY(10px);
2092
2090
  transition:
2093
- opacity 0.25s,
2094
- transform 0.25s;
2091
+ opacity 0.2s ease,
2092
+ transform 0.2s ease;
2095
2093
  pointer-events: none;
2096
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
2097
2094
  }
2098
2095
  .toast.visible {
2099
2096
  opacity: 1;
2100
2097
  transform: translateY(0);
2101
2098
  }
2099
+ .toast.toast-success {
2100
+ border-color: var(--success);
2101
+ color: var(--success);
2102
+ }
2103
+ .toast.toast-error {
2104
+ border-color: #f85149;
2105
+ color: #f85149;
2106
+ }
2107
+ .toast.toast-info {
2108
+ border-color: var(--accent);
2109
+ color: var(--accent);
2110
+ }
2102
2111
  .rendered-md h1,
2103
2112
  .rendered-md h2,
2104
2113
  .rendered-md h3,
package/server.js CHANGED
@@ -60,6 +60,7 @@ function getArgUrl(argName, envName) {
60
60
 
61
61
  const MARKETPLACE_URL = getArgUrl('marketplace-url', 'MARKETPLACE_URL');
62
62
  const COST_URL = getArgUrl('cost-url', 'COST_URL');
63
+ const MEMORY_URL = getArgUrl('memory-url', 'MEMORY_URL');
63
64
  const CLAUDE_DIR = getClaudeDir();
64
65
  const TASKS_DIR = path.join(CLAUDE_DIR, 'tasks');
65
66
  const PROJECTS_DIR = path.join(CLAUDE_DIR, 'projects');
@@ -1277,7 +1278,7 @@ app.get('/api/version', (req, res) => {
1277
1278
  });
1278
1279
 
1279
1280
  app.get('/api/config', (req, res) => {
1280
- res.json({ marketplaceUrl: MARKETPLACE_URL, costUrl: COST_URL });
1281
+ res.json({ marketplaceUrl: MARKETPLACE_URL, costUrl: COST_URL, memoryUrl: MEMORY_URL });
1281
1282
  });
1282
1283
 
1283
1284
  // API: Get all tasks across all sessions