Bug: countConcurrentSessions() deletes non-.json files from ~/.claude/sessions/
Description
The countConcurrentSessions() function in the CLI scans ~/.claude/sessions/ and deletes files belonging to "dead processes". However, it incorrectly treats non-.json files (e.g., .tmp files from plugins) as PID files, parses the year from date-prefixed filenames as a PID, and deletes them.
Root Cause
From the bundled cli.js (deminified):
async function countConcurrentSessions() {
const sessionsDir = path.join(getClaudeDir(), "sessions");
const files = await readdir(sessionsDir);
for (const file of files) {
const pid = parseInt(file.replace(/\.json$/, ""), 10);
if (isNaN(pid)) continue;
if (pid === process.pid) { count++; continue; }
if (isProcessRunning(pid)) {
count++;
} else {
// Deletes the file if the "PID" process isn't running
unlink(path.join(sessionsDir, file)).catch(() => {});
}
}
}
The problem: parseInt("2026-03-24-ecosystem-int-session.tmp", 10) returns 2026 (stops at the first -). Since PID 2026 is not running, the file is deleted.
Reproduction
- Install a plugin that writes
.tmpfiles to~/.claude/sessions/(e.g., everything-claude-code which uses this directory for session persistence via/save-session) - Run
/save-session— creates~/.claude/sessions/2026-03-24-<id>-session.tmp(259 lines of session state) - Exit and start a new Claude Code session
- The
.tmpfile is gone — deleted bycountConcurrentSessions()becauseparseInt("2026-...")=2026and PID 2026 is not running
Impact
- Any plugin storing non-
.jsonfiles in~/.claude/sessions/will have its files silently deleted - The everything-claude-code plugin (5k+ GitHub stars) uses this directory for session save/resume functionality, which is completely broken by this bug
- Users lose session state with no error message or warning
Suggested Fix
Only process .json files in the cleanup loop:
for (const file of files) {
if (!file.endsWith('.json')) continue; // Skip non-JSON files
const pid = parseInt(file.replace(/\.json$/, ""), 10);
if (isNaN(pid)) continue;
// ... rest of logic
}
Or alternatively, validate that the entire filename (minus .json) is a valid integer:
const basename = file.replace(/\.json$/, "");
const pid = Number(basename);
if (!Number.isInteger(pid) || String(pid) !== basename) continue;
Environment
- Claude Code version: 2.1.81
- OS: macOS Darwin 25.2.0
- Node: v22.22.0
Workaround
The ECC plugin has submitted a PR to move its session storage to ~/.claude/ecc-sessions/ to avoid this directory entirely: https://github.com/affaan-m/everything-claude-code/pull/899
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗