diff --git a/vscode/src/panel/handlers/issues.ts b/vscode/src/panel/handlers/issues.ts index baa4940..891bdfa 100644 --- a/vscode/src/panel/handlers/issues.ts +++ b/vscode/src/panel/handlers/issues.ts @@ -11,6 +11,7 @@ import { getToken } from '../../auth/secrets' import { buildCcCommand } from '../../cc/ccCommand' import { getDefaultProfilePath, getPrDiffSummaryProfilePath } from '../../cc/profiles' import { getBrainstormPrompt } from '../../cc/prompts' +import { claudeProjectsRoot, installClaudeSession } from '../../cc/sessionBundle' import { projectsDirFor, watchForNewSession } from '../../cc/sessionWatcher' import { spawnClaude } from '../../cc/spawnClaude' import { gitFetch, resolveFeatureBranch } from '../../git/branchSync' @@ -390,45 +391,27 @@ export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber: issueNumber, }) - // Before removing the worktree, copy the impl- and test-session jsonl into - // the workspace-root projects dir so `claude --resume` can still find them - // after the worktree (and its projects dir) are gone. + // 删 worktree 前把实施/测试会话整包(jsonl + 子目录)搬到主仓库 projects 目录, + // 并清掉 worktree 侧副本:新版 claude 遇到重复 sid 会拒绝 resume。 if ((implementSessionId || testSessionId) && worktreePath) { - try { - const worktreeAbs = resolveWorktreePath(worktreePath, workspaceRoot) - const srcProjectsDir = projectsDirFor(worktreeAbs) - const dstProjectsDir = projectsDirFor(workspaceRoot) - const sessionIds = [implementSessionId, testSessionId].filter( - (id): id is string => typeof id === 'string' && id.length > 0, - ) - for (const sessionId of sessionIds) { - const srcJsonl = path.join(srcProjectsDir, `${sessionId}.jsonl`) - const dstJsonl = path.join(dstProjectsDir, `${sessionId}.jsonl`) - if (fs.existsSync(srcJsonl)) { - if (!fs.existsSync(dstProjectsDir)) - fs.mkdirSync(dstProjectsDir, { recursive: true }) - if (!fs.existsSync(dstJsonl)) { - fs.copyFileSync(srcJsonl, dstJsonl) - logger.add({ - level: 'info', - source: 'panel', - message: `已复制 cc session jsonl 到主 workspace projects 目录 (issue #${issueNumber})`, - details: `${srcJsonl} → ${dstJsonl}`, - }) - } - } + const worktreeAbs = resolveWorktreePath(worktreePath, workspaceRoot) + const srcProjectsDir = projectsDirFor(worktreeAbs) + const dstProjectsDir = projectsDirFor(workspaceRoot) + for (const sid of [implementSessionId, testSessionId]) { + if (typeof sid !== 'string' || sid.length === 0) + continue + try { + await installClaudeSession({ sid, srcDir: srcProjectsDir, dstProjectsDir, projectsRoot: claudeProjectsRoot() }) + logger.add({ level: 'info', source: 'panel', message: `cc 会话 ${sid} 已搬到主仓库 projects 目录 (issue #${issueNumber})` }) + } + catch (err) { + logger.add({ + level: 'warn', + source: 'panel', + message: `搬迁 cc 会话 ${sid} 失败 (issue #${issueNumber}),worktree 清理仍继续`, + details: err instanceof Error ? err.message : String(err), + }) } - } - catch (err) { - // Non-fatal — worktree cleanup still proceeds. User can manually copy - // the jsonl later if needed. - const message = err instanceof Error ? err.message : String(err) - logger.add({ - level: 'warn', - source: 'panel', - message: `复制 cc session jsonl 失败 (issue #${issueNumber}),worktree 清理仍继续`, - details: message, - }) } }