feat(vscode): 「改动」面板加审查勾 + deepseek 增量生成文件改动说明

右栏 diff 头部加一组按钮:
- 审查对勾:与左树同一状态源,勾上则文件路径标题置灰
-  一键调 deepseek 生成该文件「一句话改动目的」

增量复用会话:首个文件开新 cc 会话并把 sessionId 记到
.spx/pr-file-summaries.json,后续文件 --resume 接上去,省去每次重新
理解 PR 的开销;resume 失败则丢弃旧 id 重开一次。说明也落盘(跨 push
保留),重载后仍显示。

- spawnClaude 增 resumeSessionId(--resume)
- 新增 prFileSummaryStore;handler handleGeneratePrFileSummary
  用 jsdiff 拼 unified diff 喂模型
- 依赖 diff(jsdiff)
This commit is contained in:
2026-06-29 15:24:43 +08:00
parent fb505d59c5
commit 8c5cc90eda
11 changed files with 387 additions and 37 deletions
+31
View File
@@ -31,8 +31,13 @@ export interface UsePrFilesResult {
confirmed: string[]
/** key ∈ diffByPath 即「已请求/已到」;值为内容。仅 key 在但值 undefined 不会出现。 */
diffByPath: Record<string, FileDiff>
/** 路径 → 已生成的一句话改动说明(deepseek 增量生成、跨 push 保留)。 */
summariesByPath: Record<string, string>
/** 正在生成说明的文件路径;null 表示无生成中。 */
generatingPath: string | null
getFileDiff: (path: string, previousPath?: string) => void
setConfirmed: (paths: string[]) => void
generateSummary: (path: string, previousPath?: string) => void
}
export function usePrFiles(issueNumber: number | undefined): UsePrFilesResult {
@@ -42,6 +47,8 @@ export function usePrFiles(issueNumber: number | undefined): UsePrFilesResult {
const [loading, setLoading] = useState(false)
const [confirmed, setConfirmedState] = useState<string[]>([])
const [diffByPath, setDiffByPath] = useState<Record<string, FileDiff>>({})
const [summariesByPath, setSummariesByPath] = useState<Record<string, string>>({})
const [generatingPath, setGeneratingPath] = useState<string | null>(null)
// issueNumber / headSha 装进 ref,让订阅闭包与回调始终读到当前值。
const issueRef = useRef<number | undefined>(issueNumber)
@@ -60,10 +67,20 @@ export function usePrFiles(issueNumber: number | undefined): UsePrFilesResult {
setFiles(msg.files)
setHeadSha(msg.headSha)
setConfirmedState(msg.confirmed ?? [])
setSummariesByPath(msg.summaries ?? {})
setFilesError(msg.error)
setLoading(false)
return
}
if (msg.type === 'pr-file-summary/show') {
if (msg.issueNumber !== issueRef.current)
return
// 生成结束(成功带 summary / 失败带 error)都解除该文件的 loading;失败的 error 已由扩展侧 toast。
setGeneratingPath(p => (p === msg.path ? null : p))
if (msg.summary)
setSummariesByPath(prev => ({ ...prev, [msg.path]: msg.summary! }))
return
}
if (msg.type === 'pr-file-diff/show') {
if (msg.issueNumber !== issueRef.current)
return
@@ -89,6 +106,8 @@ export function usePrFiles(issueNumber: number | undefined): UsePrFilesResult {
setFilesError(undefined)
setConfirmedState([])
setDiffByPath({})
setSummariesByPath({})
setGeneratingPath(null)
requestedRef.current = new Set()
if (issueNumber === undefined) {
setLoading(false)
@@ -117,6 +136,15 @@ export function usePrFiles(issueNumber: number | undefined): UsePrFilesResult {
postMessage({ type: 'pr-review/set', issueNumber: num, headSha: headShaRef.current, confirmed: paths })
}, [])
// 触发 deepseek 增量生成该文件的改动说明;置 loading,结果经 pr-file-summary/show 回来。
const generateSummary = useCallback((path: string, previousPath?: string): void => {
const num = issueRef.current
if (num === undefined)
return
setGeneratingPath(path)
postMessage({ type: 'pr-file-summary/generate', issueNumber: num, path, previousPath })
}, [])
return {
files,
headSha,
@@ -124,7 +152,10 @@ export function usePrFiles(issueNumber: number | undefined): UsePrFilesResult {
loading,
confirmed,
diffByPath,
summariesByPath,
generatingPath,
getFileDiff,
setConfirmed,
generateSummary,
}
}