claude-code-kanban 7.0.1 → 7.0.3

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/lib/parsers.js CHANGED
@@ -646,28 +646,47 @@ function countTranscriptsBornBefore(dir, birthtimeMs) {
646
646
  return n;
647
647
  }
648
648
 
649
+ // Cache: jsonlPath -> { ino, size, mtimeMs }, the transcript as it last grew.
650
+ // Claude Code, `claude --resume` and backup tools set a transcript's mtime without writing
651
+ // to it (#50), so only a file that grew, shrank or was replaced counts as activity.
652
+ const logActivityCache = new Map();
653
+
654
+ function transcriptActivityMs(jsonlPath, stat) {
655
+ const prev = logActivityCache.get(jsonlPath);
656
+ if (prev && prev.ino === stat.ino && prev.size === stat.size) return prev.mtimeMs;
657
+ logActivityCache.delete(jsonlPath);
658
+ logActivityCache.set(jsonlPath, { ino: stat.ino, size: stat.size, mtimeMs: stat.mtimeMs });
659
+ if (logActivityCache.size > SESSION_INFO_CACHE_MAX) logActivityCache.delete(logActivityCache.keys().next().value);
660
+ sessionCacheDirty = true;
661
+ return stat.mtimeMs;
662
+ }
663
+
649
664
  const sessionCachesDirty = () => sessionCacheDirty;
650
665
 
651
666
  // Snapshot of the per-transcript caches for lib/session-cache.js. Entries of deleted
652
667
  // transcripts are left out, so the snapshot never holds more than the live set.
653
668
  function exportSessionCaches() {
654
669
  sessionCacheDirty = false;
655
- const livePaths = new Set([...sessionInfoCache.keys(), ...customTitleCache.keys()].filter((p) => fs.existsSync(p)));
670
+ const livePaths = new Set([...sessionInfoCache.keys(), ...customTitleCache.keys(), ...logActivityCache.keys()]);
671
+ for (const p of livePaths) if (!fs.existsSync(p)) livePaths.delete(p);
656
672
  const live = (map) => [...map].filter(([p]) => livePaths.has(p));
657
- return { info: live(sessionInfoCache), titles: live(customTitleCache) };
673
+ return { info: live(sessionInfoCache), titles: live(customTitleCache), activity: live(logActivityCache) };
658
674
  }
659
675
 
660
676
  function importSessionCaches(snapshot) {
661
- const valid = (e) => e && typeof e === 'object' && typeof e.ino === 'number' && typeof e.scannedUpTo === 'number' && typeof e.mtimeMs === 'number';
662
- const load = (map, entries) => {
677
+ const num = (v) => typeof v === 'number';
678
+ const scanned = (e) => num(e.ino) && num(e.scannedUpTo) && num(e.mtimeMs);
679
+ const grown = (e) => num(e.ino) && num(e.size) && num(e.mtimeMs);
680
+ const load = (map, entries, valid) => {
663
681
  if (!Array.isArray(entries)) return;
664
682
  for (const pair of entries) {
665
- if (!Array.isArray(pair) || typeof pair[0] !== 'string' || !valid(pair[1])) continue;
683
+ if (!Array.isArray(pair) || typeof pair[0] !== 'string' || !pair[1] || typeof pair[1] !== 'object' || !valid(pair[1])) continue;
666
684
  map.set(pair[0], pair[1]);
667
685
  }
668
686
  };
669
- load(sessionInfoCache, snapshot?.info?.slice(-SESSION_INFO_CACHE_MAX));
670
- load(customTitleCache, snapshot?.titles?.slice(-SESSION_INFO_CACHE_MAX));
687
+ load(sessionInfoCache, snapshot?.info?.slice(-SESSION_INFO_CACHE_MAX), scanned);
688
+ load(customTitleCache, snapshot?.titles?.slice(-SESSION_INFO_CACHE_MAX), scanned);
689
+ load(logActivityCache, snapshot?.activity?.slice(-SESSION_INFO_CACHE_MAX), grown);
671
690
  }
672
691
 
673
692
  // Background-task completion records arrive as a user message whose content is a
@@ -1972,6 +1991,7 @@ module.exports = {
1972
1991
  exportSessionCaches,
1973
1992
  importSessionCaches,
1974
1993
  sessionCachesDirty,
1994
+ transcriptActivityMs,
1975
1995
  countTranscriptsBornBefore,
1976
1996
  readRecentMessages,
1977
1997
  readMessagesPage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-kanban",
3
- "version": "7.0.1",
3
+ "version": "7.0.3",
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
@@ -11932,7 +11932,7 @@ const PANE_FRAME_LIMIT = 3;
11932
11932
  const PANE_URL_SANDBOX = 'allow-scripts allow-same-origin allow-forms allow-popups allow-downloads';
11933
11933
  const PANE_ICONS = {
11934
11934
  board:
11935
- '<svg class="kind" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="5" height="16" rx="1"/><rect x="10" y="4" width="5" height="10" rx="1"/><rect x="17" y="4" width="4" height="13" rx="1"/></svg>',
11935
+ '<svg class="kind" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 5v14"/><path d="M12 5v8"/><path d="M18 5v11"/></svg>',
11936
11936
  url: '<svg class="kind" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15 15 0 0 1 0 20M12 2a15 15 0 0 0 0 20"/></svg>',
11937
11937
  file: '<svg class="kind" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>',
11938
11938
  warning:
package/server.js CHANGED
@@ -24,6 +24,7 @@ const {
24
24
  readRecentMessages: _readRecentMessagesUncached,
25
25
  readMessagesPage: _readMessagesPageUncached,
26
26
  readSessionInfoFromJsonl,
27
+ transcriptActivityMs,
27
28
  modelDisplayName,
28
29
  buildSessionDigest,
29
30
  readCompactSummaries,
@@ -362,7 +363,7 @@ function getSessionLogStat(meta) {
362
363
  if (!meta.jsonlPath) return { mtime: null, hasMessages: false };
363
364
  try {
364
365
  const st = statSync(meta.jsonlPath);
365
- return { mtime: st.mtimeMs, hasMessages: st.size > 1000 };
366
+ return { mtime: transcriptActivityMs(meta.jsonlPath, st), hasMessages: st.size > 1000 };
366
367
  } catch { return { mtime: null, hasMessages: false }; }
367
368
  }
368
369