✨ feat(vscode): 审查会话链接按本机 codex 会话文件存在判定,不再绑 worktree
This commit is contained in:
@@ -21,6 +21,7 @@ import { loadIssues } from '../gitea/issueLoader'
|
||||
import { overlayLocalIssueState } from '../issues/localState'
|
||||
import { closeIssueByRef, mergeIssueState, readIssueState } from '../issues/stateRouter'
|
||||
import { logger } from '../logging/logger'
|
||||
import { annotateReviewSessionFileExists } from '../sessions/codexSessions'
|
||||
import { getEffectiveCommitProfilePath, getSettings } from '../settings/store'
|
||||
import { webhookCoordinator } from '../webhook/coordinator'
|
||||
import { loadYouTrackIssues } from '../youtrack/issueLoader'
|
||||
@@ -899,9 +900,12 @@ export class KanbanWebviewPanel {
|
||||
dismissOnTimer: 6000,
|
||||
})
|
||||
}
|
||||
// 本机记录(会话 id / worktree 等)叠加在共享状态之上,再补 live terminal 态。
|
||||
// 本机记录(会话 id / worktree 等)叠加在共享状态之上,附加本机 codex
|
||||
// 会话文件存在性,再补 live terminal 态。
|
||||
const issues = this.withLiveTerminalTabState(
|
||||
overlayLocalIssueState(this.context, [...giteaIssues, ...youtrackList], workspaceRoot),
|
||||
await annotateReviewSessionFileExists(
|
||||
overlayLocalIssueState(this.context, [...giteaIssues, ...youtrackList], workspaceRoot),
|
||||
),
|
||||
)
|
||||
this.issueRefs = new Map(
|
||||
issues.map(i => [i.number, { source: i.source ?? 'gitea', externalId: i.externalId }] as const),
|
||||
|
||||
@@ -238,8 +238,7 @@ export async function handleResumeReviewSession(panel: KanbanWebviewPanel, sessi
|
||||
try {
|
||||
// Server-side prerequisite gate — consistent with handleResumeSession /
|
||||
// handleImplement. In practice review sessions imply the issue has
|
||||
// moved past todo (a worktree must exist), but enforcing here keeps
|
||||
// the contract uniform.
|
||||
// moved past todo, but enforcing here keeps the contract uniform.
|
||||
const lockCheck = await panel.resolveLockedReason(issueNumber)
|
||||
if (lockCheck.locked) {
|
||||
logger.add({
|
||||
@@ -257,15 +256,31 @@ export async function handleResumeReviewSession(panel: KanbanWebviewPanel, sessi
|
||||
existing.show(false)
|
||||
return
|
||||
}
|
||||
// codex resume 只依赖 ~/.codex/sessions 下的 rollout 文件,与 worktree
|
||||
// 无关:worktree 在则用它当 cwd,否则退回工作区根目录(与
|
||||
// handleResumeSession 同款回退)。
|
||||
const workspaceRoot = workspace.workspaceFolders?.[0]?.uri.fsPath
|
||||
if (!relCwd || !workspaceRoot) {
|
||||
void window.showErrorMessage(`审查会话无法恢复 #${issueNumber}:worktree 路径未记录`)
|
||||
if (!workspaceRoot) {
|
||||
void window.showErrorMessage(`审查会话无法恢复 #${issueNumber}:未打开工作区`)
|
||||
return
|
||||
}
|
||||
const worktreeAbs = resolveWorktreePath(relCwd, workspaceRoot)
|
||||
if (!fs.existsSync(worktreeAbs)) {
|
||||
void window.showErrorMessage(`审查会话无法恢复 #${issueNumber}:worktree 不存在 ${worktreeAbs}`)
|
||||
return
|
||||
let effectiveCwd = workspaceRoot
|
||||
let cwdFallback = true
|
||||
if (relCwd) {
|
||||
const worktreeAbs = resolveWorktreePath(relCwd, workspaceRoot)
|
||||
if (fs.existsSync(worktreeAbs)) {
|
||||
effectiveCwd = worktreeAbs
|
||||
cwdFallback = false
|
||||
}
|
||||
}
|
||||
if (cwdFallback) {
|
||||
panel.postMessage({
|
||||
type: 'toast/show',
|
||||
id: makeNonce(),
|
||||
level: 'info',
|
||||
message: `工单 #${issueNumber} 的 worktree 不可用,审查会话将在工作区根目录恢复`,
|
||||
dismissOnTimer: 5000,
|
||||
})
|
||||
}
|
||||
// Scan live terminals before creating a new one — survives panel
|
||||
// reload / webview rebuild where `this.reviewTerminals` got wiped but
|
||||
@@ -284,7 +299,7 @@ export async function handleResumeReviewSession(panel: KanbanWebviewPanel, sessi
|
||||
const { themeColor, iconUri } = await panel.resolveIssueIcon(issueNumber)
|
||||
const terminal = window.createTerminal({
|
||||
name: reviewTerminalName,
|
||||
cwd: worktreeAbs,
|
||||
cwd: effectiveCwd,
|
||||
location: panel.resolveTerminalLocation(false),
|
||||
iconPath: iconUri,
|
||||
color: themeColor,
|
||||
@@ -302,7 +317,7 @@ export async function handleResumeReviewSession(panel: KanbanWebviewPanel, sessi
|
||||
logger.add({
|
||||
level: 'info',
|
||||
source: 'terminal',
|
||||
message: `已创建审查会话终端 #${issueNumber} cwd=${worktreeAbs}`,
|
||||
message: `已创建审查会话终端 #${issueNumber} cwd=${effectiveCwd}`,
|
||||
})
|
||||
}
|
||||
finally {
|
||||
@@ -590,10 +605,12 @@ async function triggerAutoReviewTabUnlocked(panel: KanbanWebviewPanel, opts: {
|
||||
if (!token)
|
||||
return
|
||||
await panel.mergeIssueState(opts.issueNumber, { reviewSessionId: threadId })
|
||||
// reviewSessionFileExists 是计算字段不持久化;rollout 文件刚在本机
|
||||
// 落盘,patch 里直接置 true 让 resume 链接立即可点。
|
||||
panel.postMessage({
|
||||
type: 'issue/patch',
|
||||
issueNumber: opts.issueNumber,
|
||||
patch: { reviewSessionId: threadId },
|
||||
patch: { reviewSessionId: threadId, reviewSessionFileExists: true },
|
||||
})
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
@@ -42,7 +42,7 @@ export type ExtensionToWebview
|
||||
= | { type: 'issues/loading' }
|
||||
| { type: 'issues/update', issues: Issue[], scope: 'mine' | 'all', globalAutoReview: boolean, youtrackConfigured: boolean }
|
||||
| { type: 'issues/error', message: string }
|
||||
| { type: 'issue/patch', issueNumber: number, patch: { autoReview?: boolean, specFile?: string, planFile?: string, prDiffFile?: string, sessionId?: string, implementSessionId?: string, reviewSessionId?: string, testSessionId?: string, pr?: string | null, implementStatus?: 'running' | 'done' | 'failed', column?: IssueColumn, worktreePath?: string | null, prMerged?: boolean, prMergedAt?: string, branch?: string | null, color?: string, worktreeExists?: boolean, brainstormTabOpen?: boolean, implementTabOpen?: boolean, reviewTabOpen?: boolean, testTabOpen?: boolean, profilePath?: string, brainstormProfilePath?: string, testProfilePath?: string } }
|
||||
| { type: 'issue/patch', issueNumber: number, patch: { autoReview?: boolean, specFile?: string, planFile?: string, prDiffFile?: string, sessionId?: string, implementSessionId?: string, reviewSessionId?: string, reviewSessionFileExists?: boolean, testSessionId?: string, pr?: string | null, implementStatus?: 'running' | 'done' | 'failed', column?: IssueColumn, worktreePath?: string | null, prMerged?: boolean, prMergedAt?: string, branch?: string | null, color?: string, worktreeExists?: boolean, brainstormTabOpen?: boolean, implementTabOpen?: boolean, reviewTabOpen?: boolean, testTabOpen?: boolean, profilePath?: string, brainstormProfilePath?: string, testProfilePath?: string } }
|
||||
| { type: 'issue/pr-diff-summary-done', issueNumber: number }
|
||||
| { type: 'issue/append', issue: Issue, select?: boolean }
|
||||
| { type: 'issue/select-by-number', issueNumber: number }
|
||||
|
||||
Reference in New Issue
Block a user