diff --git a/vscode/src/panel/handlers/issues.ts b/vscode/src/panel/handlers/issues.ts index 794f641..c88e21a 100644 --- a/vscode/src/panel/handlers/issues.ts +++ b/vscode/src/panel/handlers/issues.ts @@ -541,16 +541,16 @@ export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber: }) } - // 6. 全部成功 → 增量推 done + 清掉 worktreePath/branch + 标记 prMerged。 - // webview 端 `{ ...issue, ...patch }` spread 会把 worktreePath 覆盖成 - // undefined,详情面板的 worktree 链接行因此消失。 + // 6. 全部成功 → 增量推 done + 用 null 清空 worktreePath/branch(postMessage 会丢 undefined key) + // 并带 worktreeExists: false,详情「工作树」行即时变为只读/—。 panel.postMessage({ type: 'issue/patch', issueNumber, patch: { column: 'done', - worktreePath: undefined, - branch: undefined, + worktreePath: null, + branch: null, + worktreeExists: false, prMerged: true, prMergedAt: pullRequest.merged_at ?? new Date().toISOString(), }, diff --git a/vscode/src/panel/handlers/worktree.ts b/vscode/src/panel/handlers/worktree.ts index affeafb..f7ef9d3 100644 --- a/vscode/src/panel/handlers/worktree.ts +++ b/vscode/src/panel/handlers/worktree.ts @@ -144,12 +144,13 @@ export async function handleDeleteWorktree(panel: KanbanWebviewPanel, issueNumbe token, }) + // null 才能过 postMessage 序列化;undefined 会被丢掉,webview 合并不清字段 panel.postMessage({ type: 'issue/patch', issueNumber, patch: { - worktreePath: undefined, - branch: undefined, + worktreePath: null, + branch: null, worktreeExists: false, }, }) diff --git a/vscode/src/panel/messages.ts b/vscode/src/panel/messages.ts index 075a260..e48708c 100644 --- a/vscode/src/panel/messages.ts +++ b/vscode/src/panel/messages.ts @@ -42,7 +42,7 @@ export type ExtensionToWebview = | { type: 'issues/loading' } | { type: 'issues/update', issues: Issue[], 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, implementStatus?: 'running' | 'done' | 'failed', column?: IssueColumn, worktreePath?: string, prMerged?: boolean, prMergedAt?: string, branch?: string, 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, 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 } diff --git a/vscode/src/webhook/coordinator.ts b/vscode/src/webhook/coordinator.ts index 0a25e0b..41b7012 100644 --- a/vscode/src/webhook/coordinator.ts +++ b/vscode/src/webhook/coordinator.ts @@ -1062,7 +1062,8 @@ class WebhookCoordinator { this.activePanel.postMessage({ type: 'issue/patch', issueNumber: event.issueNumber, - patch: { pr: undefined }, + // null 才能过 postMessage;undefined 会被序列化丢掉 + patch: { pr: null }, }) } catch (err) { diff --git a/vscode/webview-ui/src/hooks/useIssues.ts b/vscode/webview-ui/src/hooks/useIssues.ts index 41b5360..7b891f3 100644 --- a/vscode/webview-ui/src/hooks/useIssues.ts +++ b/vscode/webview-ui/src/hooks/useIssues.ts @@ -23,6 +23,16 @@ import type { LogEntry } from '../lib/messages' import { compareIssuesInColumn } from '../lib/issueSort' import { onMessage, postMessage } from '../lib/vscode' +/** postMessage 用 null 清空 optional 字段;合并时 delete 还原 optional,避免残留 null */ +function applyIssuePatch(issue: Issue, patch: Record): Issue { + const next = { ...issue, ...patch } as Issue & Record + for (const [k, v] of Object.entries(patch)) { + if (v === null) + delete next[k] + } + return next as Issue +} + export interface SettingsValues { host: string token: string @@ -560,7 +570,7 @@ export function useIssues(): UseIssuesResult { return { status: 'ready', issues: prev.issues.map(i => - i.number === msg.issueNumber ? { ...i, ...msg.patch } : i, + i.number === msg.issueNumber ? applyIssuePatch(i, msg.patch) : i, ), } }) diff --git a/vscode/webview-ui/src/lib/messages.ts b/vscode/webview-ui/src/lib/messages.ts index f0c4419..05824b2 100644 --- a/vscode/webview-ui/src/lib/messages.ts +++ b/vscode/webview-ui/src/lib/messages.ts @@ -57,7 +57,7 @@ export type ExtensionToWebview = | { type: 'issues/loading' } | { type: 'issues/update', issues: Issue[], 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, implementStatus?: 'running' | 'done' | 'failed', column?: IssueColumn, worktreePath?: string, prMerged?: boolean, prMergedAt?: string, branch?: string, 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, 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 }