From 5f103cb967066eaff68824c42e39a0cbaaf0c1a0 Mon Sep 17 00:00:00 2001 From: kamioj <74751128+kamioj@users.noreply.github.com> Date: Mon, 4 May 2026 14:49:09 +0800 Subject: [PATCH] fix(claude-sync): skip subagent JSONL files to prevent main session corruption Subagent transcripts under `~/.claude/projects/...//subagents/` share their parent's sessionId. Indexing them as standalone sessions overwrites the parent's row in the sessions DB, which breaks session resume and history listing. Skip them in both the bulk `synchronize()` scan and the watcher-driven `synchronizeFile()` entry point. Path check covers Windows backslash and POSIX slash so the same guard works regardless of how findFilesRecursively emits the path. --- .../claude-session-synchronizer.provider.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts b/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts index 7d089a2d3c..b295cd31a3 100644 --- a/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +++ b/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts @@ -37,6 +37,14 @@ export class ClaudeSessionSynchronizer implements IProviderSessionSynchronizer { let processed = 0; for (const filePath of files) { + // PATCH (kamioj): subagent .jsonl 文件共享父 session 的 sessionId, + // 会被当成主 session 写入 DB → 污染主会话记录。直接跳过。 + if ( + filePath.includes(`${path.sep}subagents${path.sep}`) || + filePath.replace(/\\/g, '/').includes('/subagents/') + ) { + continue; + } const parsed = await this.processSessionFile(filePath, nameMap); if (!parsed) { continue; @@ -65,6 +73,13 @@ export class ClaudeSessionSynchronizer implements IProviderSessionSynchronizer { if (!filePath.endsWith('.jsonl')) { return null; } + // PATCH (kamioj): 同 synchronize(),单文件路径走 watcher 进来时也要排除 subagents/ + if ( + filePath.includes(`${path.sep}subagents${path.sep}`) || + filePath.replace(/\\/g, '/').includes('/subagents/') + ) { + return null; + } const nameMap = await buildLookupMap(path.join(this.claudeHome, 'history.jsonl'), 'sessionId', 'display'); const parsed = await this.processSessionFile(filePath, nameMap);