🐛 fix(vscode): 恢复实施会话改按显式角色命名,worktree 清理后不再误标为规划
Claude-Session: https://claude.ai/code/session_012YFEAU7RsuCdinUNMS9tzv
This commit is contained in:
1 parent
1fee0f2630
commit
e8963ac2a2
11 files changed
+116
-61
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import type { Terminal } from 'vscode'
|
||||
import type { KanbanWebviewPanel } from '../KanbanPanel'
|
||||
import type { ResumeKind } from './resumeTarget'
|
||||
import { execFile } from 'node:child_process'
|
||||
import * as fs from 'node:fs'
|
||||
import { promises as fsp } from 'node:fs'
|
||||
@@ -25,13 +26,10 @@ import { decideAutoReviewPath } from '../autoReviewDecision'
|
||||
import { pickBrainstormContinuePath } from '../brainstormContinue'
|
||||
import { makeNonce } from '../KanbanPanel'
|
||||
import { cleanupFeatureBranch } from './branchCleanup'
|
||||
import { planResumeCwd, resumeTerminalName } from './resumeTarget'
|
||||
import { submitToSessionTerminal } from './terminals'
|
||||
|
||||
export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId: string, profilePath?: string, relCwd?: string, issueNumber?: number): Promise<void> {
|
||||
// kind 跟着 sessionRole 提前判定(原来散落在方法中部,提到入口是为了构造
|
||||
// resumeInFlight 锁 key)。relCwd 在则是实施 resume,否则视为规划/讨论。
|
||||
const sessionKind: 'implement' | 'brainstorm' = relCwd ? 'implement' : 'brainstorm'
|
||||
|
||||
export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId: string, sessionKind: ResumeKind, profilePath?: string, relCwd?: string, issueNumber?: number): Promise<void> {
|
||||
// In-flight 锁:防 impl-tab-pre-create 钩子 await(pgrep pycharm 最多 15s)
|
||||
// 期间用户重复点同一会话 id 触发重复 createTerminal。issueNumber 为空时
|
||||
// (legacy session)跳过锁,直接走原路径。
|
||||
@@ -91,45 +89,25 @@ export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId:
|
||||
return
|
||||
}
|
||||
const workspaceRoot = workspace.workspaceFolders?.[0]?.uri.fsPath
|
||||
// Implementation sessions live in a worktree; `relCwd` may be absolute /
|
||||
// `~/...` / workspace-relative — must go through resolveWorktreePath
|
||||
// (path.join(workspaceRoot, abs) would mangle absolute paths).
|
||||
// If the worktree has since been cleaned up (typical: drop card to
|
||||
// "完成" → auto `git worktree remove`), fall back to the workspace
|
||||
// root instead of pointing the terminal at a missing directory.
|
||||
let effectiveCwd: string | undefined = workspaceRoot
|
||||
let cwdFallback = false
|
||||
if (relCwd && workspaceRoot) {
|
||||
const resolved = resolveWorktreePath(relCwd, workspaceRoot)
|
||||
if (fs.existsSync(resolved)) {
|
||||
effectiveCwd = resolved
|
||||
}
|
||||
else {
|
||||
cwdFallback = true
|
||||
effectiveCwd = workspaceRoot
|
||||
logger.add({
|
||||
level: 'warn',
|
||||
source: 'panel',
|
||||
message: `worktree 不存在,退回工作区根目录 (#${issueNumber ?? '?'}): ${relCwd}`,
|
||||
})
|
||||
}
|
||||
// 实施会话住在 worktree 里;relCwd 可能是绝对路径 / `~/...` / 工作区相对
|
||||
// 路径,统一走 resolveWorktreePath。worktree 已被清理(典型:卡片拖到
|
||||
// 「完成」→ 自动 `git worktree remove`,工单里 worktreePath 随之清空)
|
||||
// 时退回工作区根目录;角色只看 sessionKind,不受 cwd 有无影响。
|
||||
const worktreeAbs = relCwd && workspaceRoot ? resolveWorktreePath(relCwd, workspaceRoot) : undefined
|
||||
const plan = workspaceRoot
|
||||
? planResumeCwd({ kind: sessionKind, workspaceRoot, worktreeAbs, worktreeExists: !!worktreeAbs && fs.existsSync(worktreeAbs) })
|
||||
: undefined
|
||||
const effectiveCwd = plan?.cwd
|
||||
const worktreeMissing = plan?.worktreeMissing ?? false
|
||||
if (worktreeMissing) {
|
||||
logger.add({
|
||||
level: 'warn',
|
||||
source: 'panel',
|
||||
message: `worktree 不存在,退回工作区根目录 (#${issueNumber ?? '?'}): ${relCwd ?? '(工单未记录 worktreePath)'}`,
|
||||
})
|
||||
}
|
||||
// Open the terminal as an editor tab beside the kanban (not in the
|
||||
// bottom panel), so the user can see both side-by-side. `Beside` opens
|
||||
// in a new editor group when needed.
|
||||
// Name reflects which of the three session roles this is:
|
||||
// relCwd present → 实施 session (resumed inside the worktree)
|
||||
// relCwd absent → 规划 / discussion session (workspace root)
|
||||
// Fall back to the legacy id-suffixed name if we somehow lack issueNumber.
|
||||
const sessionRole = relCwd ? '实施' : '规划'
|
||||
// 注:sessionKind 已在方法入口处判定(用于 resumeInFlight 锁 key)。
|
||||
// 原来两条 trackSessionTerminal 路径都硬写 'brainstorm',导致实施 resume
|
||||
// 后 terminalOrigin map 里 kind 错,onDidCloseTerminal 里的
|
||||
// `kind === 'implement'` 判断永远不命中,impl-tab-post-close 钩子(关
|
||||
// pycharm)不会执行。
|
||||
const terminalName = issueNumber !== undefined
|
||||
? `issue-${issueNumber}-${sessionRole}`
|
||||
: `Claude · ${sessionId.slice(0, 8)}`
|
||||
// 终端开成编辑区 tab(不在底部面板),和看板并排。
|
||||
const terminalName = resumeTerminalName(sessionKind, sessionId, issueNumber)
|
||||
// Scan live terminals before creating a new one — survives panel
|
||||
// reload / webview rebuild where `this.terminals` got wiped but the
|
||||
// tab is still open. Refresh the Map too so subsequent lookups (and
|
||||
@@ -142,12 +120,12 @@ export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId:
|
||||
existingByName.show(false)
|
||||
return
|
||||
}
|
||||
// 实施 resume 走新建 terminal 路径时(且 worktree 还在)需触发
|
||||
// impl-tab-pre-create 钩子(启动 pycharm 等)。existingByName fast path
|
||||
// 不调钩子——pycharm 应该已经在跑,重复启会冲突;cwdFallback=true 时
|
||||
// worktree 已清理,pycharm 不该指向 workspace root;legacy session
|
||||
// (issueNumber === undefined) 钩子签名要 issueNumber,也跳过。
|
||||
if (sessionRole === '实施' && !cwdFallback && issueNumber !== undefined && workspaceRoot) {
|
||||
// 实施 resume 走新建 terminal 路径且 worktree 还在时触发 impl-tab-pre-create
|
||||
// 钩子(启动 pycharm 等)。existingByName fast path 不调——pycharm 应该已
|
||||
// 在跑,重复启会冲突;worktree 没了也不调——钩子拿 WORKTREE_PATH 开
|
||||
// pycharm,指向工作区根目录会把主仓库窗口拉起来;legacy session
|
||||
// (issueNumber === undefined) 钩子签名要 issueNumber,同样跳过。
|
||||
if (sessionKind === 'implement' && !worktreeMissing && issueNumber !== undefined && workspaceRoot) {
|
||||
const settingsForHook = getSettings(panel.context)
|
||||
// 从 state JSON 读 branch;任何一步读不到就用空字符串(脚本里
|
||||
// BRANCH env 仍能传,只是为空),不阻塞 resume 主流程。
|
||||
@@ -205,7 +183,7 @@ export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId:
|
||||
})
|
||||
// Worktree 已清理时给用户一个明确提示,避免他们误以为 cc 在原
|
||||
// worktree 路径里跑。toast 上 dismissOnTimer 5s 自动消失。
|
||||
if (cwdFallback) {
|
||||
if (worktreeMissing) {
|
||||
panel.postMessage({
|
||||
type: 'toast/show',
|
||||
id: makeNonce(),
|
||||
|
||||
Reference in new issue
Block a user