claude-code-kanban 4.7.1 → 4.9.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/server.js CHANGED
@@ -120,6 +120,16 @@ function readAgentJsonl(filePath) {
120
120
  return merged;
121
121
  }
122
122
 
123
+ // Agent-activity record files in a session dir, excluding the `_`-prefixed sidecars
124
+ // (_waiting.json, _name-*). Returns [] if the dir is missing/unreadable.
125
+ function listAgentFiles(agentDir) {
126
+ try {
127
+ return readdirSync(agentDir).filter((f) => f.endsWith('.jsonl') && !f.startsWith('_'));
128
+ } catch (_) {
129
+ return [];
130
+ }
131
+ }
132
+
123
133
  function persistAgent(dir, agent) {
124
134
  const file = path.join(dir, agent.agentId + '.jsonl');
125
135
  fs.appendFile(file, JSON.stringify({ ...agent, event: 'server-update' }) + '\n', 'utf8').catch(() => {});
@@ -1284,7 +1294,7 @@ app.get('/api/sessions/:sessionId/agents', (req, res) => {
1284
1294
  const isTeam = !!teamConfig;
1285
1295
  const teamMemberNames = isTeam ? new Set(teamConfig.members.map(m => m.name)) : null;
1286
1296
 
1287
- const files = readdirSync(agentDir).filter(f => f.endsWith('.jsonl') && !f.startsWith('_'));
1297
+ const files = listAgentFiles(agentDir);
1288
1298
  const agents = [];
1289
1299
  for (const file of files) {
1290
1300
  try {
@@ -1738,6 +1748,8 @@ app.get('/api/sessions/:sessionId/messages', (req, res) => {
1738
1748
  if (entry) {
1739
1749
  msg.agentId = entry.agentId;
1740
1750
  if (entry.description) msg.agentDescription = entry.description;
1751
+ if (entry.usageText) msg.agentUsage = entry.usageText;
1752
+ if (entry.usage) msg.agentUsageStats = entry.usage;
1741
1753
  if (entry.prompt && !msg.agentPrompt) msg.agentPrompt = entry.prompt;
1742
1754
  try {
1743
1755
  const agentFile = path.join(agentDir, entry.agentId + '.jsonl');
@@ -1752,6 +1764,33 @@ app.get('/api/sessions/:sessionId/messages', (req, res) => {
1752
1764
  } catch (_) {}
1753
1765
  }
1754
1766
  }
1767
+ // Mid-run fallback: the progressMap only carries agentId once the agent completes
1768
+ // (this build writes no agent_progress lines), so a still-running subagent's launch
1769
+ // row has no agentId yet — leaving its ⇗ link / agent modal inert until completion.
1770
+ // Correlate by PROMPT against the live agent-activity files (which know the agentId
1771
+ // from launch): the activity prompt is the launch prompt plus appended harness
1772
+ // boilerplate, so the tool_use prompt is a prefix. Resolving agentId here makes the
1773
+ // row behave identically while running as it does after it finishes.
1774
+ const unresolved = agentMessages.filter(m => !m.agentId && m.agentPrompt);
1775
+ if (unresolved.length && existsSync(agentDir)) {
1776
+ const activity = listAgentFiles(agentDir)
1777
+ .map((f) => { try { return readAgentJsonl(path.join(agentDir, f)); } catch (_) { return null; } })
1778
+ .filter((a) => a && a.agentId && a.prompt);
1779
+ const usedIds = new Set(agentMessages.map(m => m.agentId).filter(Boolean));
1780
+ for (const msg of unresolved) {
1781
+ const key = msg.agentPrompt.slice(0, 200);
1782
+ const match = activity.find(a =>
1783
+ !usedIds.has(a.agentId) &&
1784
+ (!msg.agentType || a.type === msg.agentType) &&
1785
+ a.prompt.startsWith(key)
1786
+ );
1787
+ if (match) {
1788
+ msg.agentId = match.agentId;
1789
+ usedIds.add(match.agentId);
1790
+ if (match.lastMessage) msg.agentLastMessage = match.lastMessage;
1791
+ }
1792
+ }
1793
+ }
1755
1794
  }
1756
1795
  const cachedCompact = compactSummaryCache.get(jsonlPath);
1757
1796
  let compactSummaries;