claude-code-kanban 3.4.0 → 3.5.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.4.0",
3
+ "version": "3.5.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
@@ -78,11 +78,34 @@ function updateUrl() {
78
78
  const qs = params.toString();
79
79
  const url = qs ? `?${qs}` : window.location.pathname;
80
80
  history.replaceState(null, '', url);
81
+ persistLastView();
82
+ }
83
+
84
+ const LAST_VIEW_KEY = 'lastView';
85
+ function persistLastView() {
86
+ try {
87
+ const data = {
88
+ view: viewMode,
89
+ session: currentSessionId,
90
+ projectPath: viewMode === 'project' ? currentProjectPath : null,
91
+ };
92
+ localStorage.setItem(LAST_VIEW_KEY, JSON.stringify(data));
93
+ } catch (_) {}
94
+ }
95
+ function loadLastView() {
96
+ try {
97
+ return JSON.parse(localStorage.getItem(LAST_VIEW_KEY)) || null;
98
+ } catch (_) {
99
+ return null;
100
+ }
81
101
  }
82
102
 
83
103
  // biome-ignore lint/correctness/noUnusedVariables: used in HTML
84
104
  function resetState() {
85
105
  history.replaceState(null, '', window.location.pathname);
106
+ try {
107
+ localStorage.removeItem(LAST_VIEW_KEY);
108
+ } catch (_) {}
86
109
  sessionFilter = 'active';
87
110
  sessionLimit = '20';
88
111
  filterProject = '__recent__';
@@ -1999,34 +2022,35 @@ function showAgentModal(agentId) {
1999
2022
  const modalNameLabel = agent.agentName ? ` · ${escapeHtml(agent.agentName)}` : '';
2000
2023
  title.innerHTML = `${statusDot} ${escapeHtml(agent.type || 'unknown')}${modalNameLabel}`;
2001
2024
 
2002
- const rows = [
2003
- ['Status', agent.status],
2004
- ['Agent ID', `<code style="font-size:12px;color:var(--text-tertiary)">${escapeHtml(agent.agentId)}</code>`],
2005
- ['Duration', formatDuration(elapsed)],
2006
- ];
2025
+ const shortModel = agent.model ? agent.model.replace(/^claude-/, '').replace(/-\d{8}$/, '') : null;
2026
+ const shortId = agent.agentId ? agent.agentId.slice(0, 8) : '';
2027
+ const chip = (label, value, opts = {}) => {
2028
+ const cls = opts.cls ? ` ${opts.cls}` : '';
2029
+ const style = opts.style ? ` style="${opts.style}"` : '';
2030
+ const title = opts.title ? ` title="${escapeHtml(opts.title)}"` : '';
2031
+ const labelHtml = label ? `<span class="agent-chip-label">${label}</span>` : '';
2032
+ return `<span class="agent-chip${cls}"${style}${title}>${labelHtml}<span class="agent-chip-val">${value}</span></span>`;
2033
+ };
2034
+
2035
+ const chips = [];
2036
+ if (agent.agentId) chips.push(chip('id', escapeHtml(shortId), { cls: 'agent-chip-mono', title: agent.agentId }));
2037
+ chips.push(chip('', escapeHtml(agent.status), { cls: `agent-chip-status agent-chip-${agent.status}` }));
2038
+ chips.push(chip('⏱', formatDuration(elapsed)));
2039
+ if (shortModel) chips.push(chip('model', escapeHtml(shortModel), { cls: 'agent-chip-mono' }));
2007
2040
  if (agent.agentName) {
2008
- const ownerColor = getOwnerColor(agent.agentName);
2009
- rows.push([
2010
- 'Owner',
2011
- `<span class="task-owner-badge" style="background:${ownerColor.bg};color:${ownerColor.color}">${escapeHtml(agent.agentName)}</span>`,
2012
- ]);
2041
+ const c = getOwnerColor(agent.agentName);
2042
+ chips.push(
2043
+ chip('owner', escapeHtml(agent.agentName), {
2044
+ style: `background:${c.bg};color:${c.color};border-color:transparent;`,
2045
+ }),
2046
+ );
2013
2047
  }
2014
- if (agent.model)
2015
- rows.push(['Model', `<code style="font-size:12px;color:var(--text-tertiary)">${escapeHtml(agent.model)}</code>`]);
2016
- if (started) rows.push(['Started', started.toLocaleTimeString()]);
2017
- if (stopped) rows.push(['Stopped', stopped.toLocaleTimeString()]);
2048
+ if (started) chips.push(chip('started', started.toLocaleTimeString()));
2049
+ if (stopped) chips.push(chip('stopped', stopped.toLocaleTimeString()));
2018
2050
 
2019
2051
  const agentMsg = currentMessages.find((m) => m.tool === 'Agent' && m.agentId === agentId);
2020
2052
 
2021
- let html =
2022
- `<table style="width:100%;border-collapse:collapse;">` +
2023
- rows
2024
- .map(
2025
- ([k, v]) =>
2026
- `<tr><td style="padding:6px 12px 6px 0;color:var(--text-tertiary);white-space:nowrap;vertical-align:top;">${k}</td><td style="padding:6px 0;color:var(--text-primary);">${v}</td></tr>`,
2027
- )
2028
- .join('') +
2029
- `</table>`;
2053
+ let html = `<div class="agent-chips">${chips.join('')}</div>`;
2030
2054
 
2031
2055
  const promptText = stripTeammateWrapper(agentMsg?.agentPrompt || agent.prompt || null);
2032
2056
  const responseText = agent.lastMessage ? stripAnsi(agent.lastMessage.trim()) : null;
@@ -5753,8 +5777,21 @@ Promise.all([
5753
5777
  }
5754
5778
  } else if (urlState.session) {
5755
5779
  await fetchTasks(urlState.session);
5756
- } else {
5780
+ } else if (urlState.view === 'all') {
5757
5781
  showAllTasks();
5782
+ } else {
5783
+ const last = loadLastView();
5784
+ if (last?.view === 'project' && last.projectPath && sessions.some((s) => s.project === last.projectPath)) {
5785
+ try {
5786
+ await fetchProjectView(last.projectPath);
5787
+ } catch (_) {
5788
+ showAllTasks();
5789
+ }
5790
+ } else if (last?.view === 'session' && last.session && sessions.some((s) => s.id === last.session)) {
5791
+ await fetchTasks(last.session);
5792
+ } else {
5793
+ showAllTasks();
5794
+ }
5758
5795
  }
5759
5796
  if (urlState.messages && currentSessionId) {
5760
5797
  toggleMessagePanel();
package/public/style.css CHANGED
@@ -1707,6 +1707,61 @@ body::before {
1707
1707
  flex-shrink: 0;
1708
1708
  }
1709
1709
 
1710
+ .agent-chips {
1711
+ display: flex;
1712
+ flex-wrap: wrap;
1713
+ gap: 6px;
1714
+ margin-bottom: 10px;
1715
+ }
1716
+ .agent-chip {
1717
+ display: inline-flex;
1718
+ align-items: center;
1719
+ gap: 4px;
1720
+ padding: 3px 9px;
1721
+ font-size: 11px;
1722
+ font-weight: 500;
1723
+ border-radius: 999px;
1724
+ border: 1px solid var(--border-color, rgba(127, 127, 127, 0.25));
1725
+ background: var(--bg-secondary, rgba(127, 127, 127, 0.08));
1726
+ color: var(--text-secondary);
1727
+ white-space: nowrap;
1728
+ line-height: 1.4;
1729
+ }
1730
+ .agent-chip-label {
1731
+ color: var(--text-tertiary);
1732
+ text-transform: uppercase;
1733
+ font-size: 9.5px;
1734
+ font-weight: 600;
1735
+ letter-spacing: 0.5px;
1736
+ opacity: 0.75;
1737
+ }
1738
+ .agent-chip-val {
1739
+ color: inherit;
1740
+ }
1741
+ .agent-chip-mono .agent-chip-val {
1742
+ font-family: var(--font-mono, monospace);
1743
+ font-size: 10.5px;
1744
+ letter-spacing: 0.2px;
1745
+ }
1746
+ .agent-chip-status {
1747
+ text-transform: capitalize;
1748
+ }
1749
+ .agent-chip-running {
1750
+ background: rgba(34, 197, 94, 0.15);
1751
+ color: rgb(34, 160, 80);
1752
+ border-color: rgba(34, 197, 94, 0.3);
1753
+ }
1754
+ .agent-chip-stopped {
1755
+ background: rgba(127, 127, 127, 0.15);
1756
+ color: var(--text-tertiary);
1757
+ border-color: rgba(127, 127, 127, 0.3);
1758
+ }
1759
+ .agent-chip-error,
1760
+ .agent-chip-failed {
1761
+ background: rgba(239, 68, 68, 0.15);
1762
+ color: rgb(220, 60, 60);
1763
+ border-color: rgba(239, 68, 68, 0.3);
1764
+ }
1710
1765
  .team-modal-desc {
1711
1766
  font-size: 12px;
1712
1767
  color: var(--text-secondary);