From 2c0ac71c08835c0e29ea22f4f9dac071d7e5fee6 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Fri, 3 Jul 2026 11:40:18 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E5=AF=A9=E6=9F=A5=E6=B5=81=E7=A8=8B):=20?= =?UTF-8?q?=E4=BF=AE=E5=BE=A9=20AI=20=E5=8E=BB=E9=87=8D=E8=B6=85=E9=87=8F?= =?UTF-8?q?=E3=80=81clone=20=E5=A4=B1=E6=95=97=E8=AA=A4=E6=8C=81=E4=B9=85?= =?UTF-8?q?=E5=8C=96=E3=80=81=E7=95=99=E8=A8=80=E8=A1=8C=E8=99=9F=E6=BC=8F?= =?UTF-8?q?=20new=5Fposition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/findings.js | 17 +++++++++++------ src/main.js | 8 +++++++- src/resolve.js | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/findings.js b/src/findings.js index 3b51c9b..fb5598c 100644 --- a/src/findings.js +++ b/src/findings.js @@ -420,13 +420,18 @@ export async function deduplicateWithAI(findings) { try { const result = await chatJSON(systemPrompt, JSON.stringify(toAIPayload(findings))); - if (Array.isArray(result) && result.length > 0) { - ok(`AI 去重: ${findings.length} -> ${result.length} 筆`); - // 以 location+suggestion 為 key,將原始 findings 的完整欄位(含 is_new)補回 - const origMap = new Map(findings.map(f => [`${f.location}|${String(f.suggestion).slice(0, 50)}`, f])); - return result.map(r => origMap.get(`${r.location}|${String(r.suggestion).slice(0, 50)}`) ?? r); + // 去重結果數量不得超過輸入(避免 LLM 無中生有),且每筆都必須能對應回原始 finding。 + if (Array.isArray(result) && result.length > 0 && result.length <= findings.length) { + const keyOf = f => `${f.location}|${String(f.suggestion).slice(0, 50)}`; + const origMap = new Map(findings.map(f => [keyOf(f), f])); + // 只保留能對應回原始 finding 的項目,丟棄無法對應(可能為幻覺)的結果 + const mapped = result.map(r => origMap.get(keyOf(r))).filter(Boolean); + if (mapped.length > 0) { + ok(`AI 去重: ${findings.length} -> ${mapped.length} 筆`); + return mapped; + } } - throw new Error('AI 回傳空陣列'); + throw new Error('AI 去重結果異常(空、超量或無法對應原始 findings)'); } catch (e) { return fallback('AI 去重', findings, e); } diff --git a/src/main.js b/src/main.js index cc7e68f..78a046b 100644 --- a/src/main.js +++ b/src/main.js @@ -209,7 +209,13 @@ async function main() { step('Step10', '記憶區 Commit/Push'); const reviewOutcome = filtered.some(f => f.level === 'critical') ? 'failure' : 'success'; input(`review outcome=${reviewOutcome}`); - await commitAndPush(WORKSPACE, repoDir || WORKSPACE, undefined, undefined, reviewOutcome); + // clone 失敗(repoDir 為 undefined)時不可把 WORKSPACE(非來源分支 git repo)當 repoDir, + // 否則會在錯誤的工作目錄嘗試 commit/push,findings/exclusions 無法持久化到 PR 分支。 + if (!repoDir) { + warn('來源分支 clone 失敗,略過 findings/exclusions 持久化(不以 WORKSPACE 當 repoDir)'); + } else { + await commitAndPush(WORKSPACE, repoDir, undefined, undefined, reviewOutcome); + } // Step11 嚴重問題把關 step('Step11', '嚴重問題把關'); diff --git a/src/resolve.js b/src/resolve.js index 9303642..3e452d9 100644 --- a/src/resolve.js +++ b/src/resolve.js @@ -75,7 +75,7 @@ export function groupConversations(comments) { 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 lineNum = Number(c?.position) || Number(c?.new_position) || Number(c?.original_position) || 0; const key = `${filePath}|${lineNum}`; if (!groups.has(key)) { groups.set(key, { key, path: filePath, line: lineNum, commentIds: [], bodies: [], resolved: false, botFinding: null });