From 5bee498e4b5ccb7e2fde981c6a2cfb430144fba0 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 23 Jun 2026 11:30:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(ai-review=20=E5=B0=8D=E8=A9=B1=E6=94=B6?= =?UTF-8?q?=E6=96=82):=20=E4=B8=A6=E8=A1=8C=E5=8F=96=E6=AA=94=E8=88=87=20r?= =?UTF-8?q?esolve=E3=80=81=E8=99=95=E7=90=86=E5=96=AE=E6=AA=94=E5=A4=B1?= =?UTF-8?q?=E6=95=97=E8=88=87=E7=84=A1=E8=B7=AF=E5=BE=91=E7=95=99=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/resolve.js | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/app/resolve.js b/app/resolve.js index 43e1c7d..8076551 100644 --- a/app/resolve.js +++ b/app/resolve.js @@ -49,6 +49,7 @@ export function groupConversations(comments) { const groups = new Map(); for (const c of comments || []) { const filePath = typeof c?.path === 'string' ? c.path : ''; + if (!filePath) continue; // 無檔案路徑的留言無法定位,跳過以免併入共用群組 const lineNum = Number(c?.position) || Number(c?.original_position) || 0; const key = `${filePath}|${lineNum}`; if (!groups.has(key)) { @@ -129,10 +130,17 @@ export async function reconcileConversations(deps = {}) { line(`對話收斂: 對話總數=${conversations.length} 已解決/不可處理=${alreadyResolved} 待判斷=${open.length}`); if (open.length === 0) return { ...EMPTY }; + // 並行取得各檔案最新內容;單一檔案失敗時視為空字串,不中斷整體流程 const fileCache = new Map(); - for (const filePath of [...new Set(open.map(c => c.path).filter(Boolean))]) { - fileCache.set(filePath, await getFileContent(filePath)); - } + const filePaths = [...new Set(open.map(c => c.path).filter(Boolean))]; + await Promise.all(filePaths.map(async (filePath) => { + try { + fileCache.set(filePath, await getFileContent(filePath)); + } catch (e) { + warn(`取得檔案內容失敗(視為空): ${filePath} error=${e.message}`); + fileCache.set(filePath, ''); + } + })); const items = open.map((c, idx) => ({ idx, @@ -153,19 +161,29 @@ export async function reconcileConversations(deps = {}) { const resolvedFindings = []; const carriedFindings = []; + + // 並行 resolve 所有 AI 判定已解決的對話(allSettled:個別失敗不中斷其他) + const resolveTargets = open + .map((c, i) => ({ c, i })) + .filter(({ i }) => resolvedSet.has(i)); + const settled = await Promise.allSettled( + resolveTargets.map(({ c }) => resolveComment(c.commentIds[0])), + ); + const resolveOutcome = new Map(); + resolveTargets.forEach(({ i }, j) => resolveOutcome.set(i, settled[j])); + let resolvedCount = 0; for (let i = 0; i < open.length; i++) { const c = open[i]; - if (resolvedSet.has(i)) { - try { - await resolveComment(c.commentIds[0]); - resolvedCount += 1; - if (c.botFinding) resolvedFindings.push({ ...c.botFinding, is_new: false }); - ok(`對話已解決並 resolve: ${c.path}:${c.line}`); - continue; - } catch (e) { - warn(`resolve 對話失敗(保留為未解決): ${c.path}:${c.line} error=${e.message}`); - } + const outcome = resolveOutcome.get(i); + if (outcome?.status === 'fulfilled') { + resolvedCount += 1; + if (c.botFinding) resolvedFindings.push({ ...c.botFinding, is_new: false }); + ok(`對話已解決並 resolve: ${c.path}:${c.line}`); + continue; + } + if (outcome?.status === 'rejected') { + warn(`resolve 對話失敗(保留為未解決): ${c.path}:${c.line} error=${outcome.reason?.message}`); } pushCarried(carriedFindings, c); }