-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Body:
Description
When running npx claude-code-templates@latest --chats, the web interface shows "No sessions found" even though
conversation files exist in ~/.claude/projects/.
Important: Regression After Claude Code Upgrade
The user reported that the --chats service was working normally, but stopped showing any conversations after
upgrading Claude Code to version 2.1.61. This suggests a compatibility issue introduced by changes in how Claude Code
or its plugins interact with the ~/.claude/ directory structure.
Root Cause
The issue is in cli-tool/src/analytics/core/ConversationAnalyzer.js in the loadConversations() function.
The recursive file scanner (findJsonlFiles) traverses the entire ~/.claude/ directory, including the plugins/
subdirectory. When it encounters certain special files (e.g., browser profile files like SingletonCookie created by
dev-browser plugin), the fs.stat() call fails with an ENOENT error.
Because there's no error handling around individual file operations, the entire loadConversations function fails
and returns an empty array, even though the actual conversation files are perfectly valid.
Error Log
Error loading conversations: ENOENT: no such file or directory, stat
'/root/.claude/plugins/dev-browser/skills/dev-browser/profiles/browser-data/SingletonCookie'
📂 Loaded 0 conversations
Reproduction
- Install a Claude Code plugin that creates files in
~/.claude/plugins/(e.g., dev-browser plugin) - Run
npx claude-code-templates@latest --chats - Open http://localhost:9876/ in browser
- Observe "No sessions found" even though conversations exist
Solution
Add error handling around individual file/directory operations:
const findJsonlFiles = async (dir) => {
const files = [];
let items;
try {
items = await fs.readdir(dir);
} catch (e) {
return files;
}
for (const item of items) {
// Skip plugins directory and hidden directories
if (item === 'plugins' || item.startsWith('.')) {
continue;
}
const itemPath = path.join(dir, item);
let stats;
try {
stats = await fs.stat(itemPath);
} catch (e) {
continue; // Skip files that can't be stat'd
}
if (stats.isDirectory()) {
try {
const subFiles = await findJsonlFiles(itemPath);
files.push(...subFiles);
} catch (e) {
continue;
}
} else if (item.endsWith('.jsonl')) {
files.push(itemPath);
}
}
return files;
};
Environment
- Claude Code version: 2.1.61
- Claude Code Templates version: v1.28.13
- OS: Linux (WSL2)
---