claude-code-kanban 7.0.1 → 7.0.2

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.2",
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/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