mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-19 15:32:05 +08:00
fix(claude-sync): skip subagent transcripts to prevent main session corruption (#854)
The session indexer scans ~/.claude/projects recursively via findFilesRecursivelyCreatedAfter, which descends into per-session subagents/ directories. Claude writes subagent transcripts at: ~/.claude/projects/<encoded-cwd>/<session-id>/subagents/agent-<id>.jsonl These files repeat the parent session's sessionId. When indexed as standalone sessions they upsert over the parent row and overwrite its jsonl_path with the subagent path, corrupting the main session record (the sidebar then points at, and renders, the subagent transcript). Add a single isSubagentTranscript() guard (path segment named "subagents") and apply it in both the recursive scan and the single-file watcher path. Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
This commit is contained in:
@@ -25,6 +25,21 @@ export class ClaudeSessionSynchronizer implements IProviderSessionSynchronizer {
|
||||
private readonly provider = 'claude' as const;
|
||||
private readonly claudeHome = path.join(os.homedir(), '.claude');
|
||||
|
||||
/**
|
||||
* Returns true when a JSONL file is a subagent transcript rather than a
|
||||
* top-level session.
|
||||
*
|
||||
* Claude stores subagent transcripts under a `subagents/` directory, e.g.
|
||||
* `~/.claude/projects/<encoded-cwd>/<session-id>/subagents/agent-<id>.jsonl`.
|
||||
* Those files repeat the parent session's `sessionId`, so indexing them as
|
||||
* standalone sessions overwrites the parent row's `jsonl_path` and corrupts
|
||||
* the main session record. The recursive scan in `synchronize()` reaches
|
||||
* them, so both entry points must skip them.
|
||||
*/
|
||||
private isSubagentTranscript(filePath: string): boolean {
|
||||
return path.normalize(filePath).split(path.sep).includes('subagents');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans ~/.claude/projects and upserts discovered sessions into DB.
|
||||
*/
|
||||
@@ -38,6 +53,10 @@ export class ClaudeSessionSynchronizer implements IProviderSessionSynchronizer {
|
||||
|
||||
let processed = 0;
|
||||
for (const filePath of files) {
|
||||
if (this.isSubagentTranscript(filePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const parsed = await this.processSessionFile(filePath, nameMap);
|
||||
if (!parsed) {
|
||||
continue;
|
||||
@@ -66,6 +85,9 @@ export class ClaudeSessionSynchronizer implements IProviderSessionSynchronizer {
|
||||
if (!filePath.endsWith('.jsonl')) {
|
||||
return null;
|
||||
}
|
||||
if (this.isSubagentTranscript(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nameMap = await buildLookupMap(path.join(this.claudeHome, 'history.jsonl'), 'sessionId', 'display');
|
||||
const parsed = await this.processSessionFile(filePath, nameMap);
|
||||
|
||||
Reference in New Issue
Block a user