diff --git a/readme.md b/readme.md index 42b01e6..0c85410 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ | [formatFindingsStats](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L173) | [產生新舊問題依嚴重等級(嚴重/警告/建議/無法標示)分類統計的 Markdown 表格。](#formatfindingsstats) | | [formatFindingsStatsLine](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L194) | [產生與統計表相同內容的單行文字摘要,供 log 輸出使用。](#formatfindingsstatsline) | | [postFindingsReview](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L261) | [發布整批 findings 的 Gitea review(摘要+行內 comment),並提供多層降級機制。](#postfindingsreview) | -| [saveFindings](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L311) | [將 findings 陣列以 JSON 格式寫入 workspace(及可選的鏡像目錄)。](#savefindings) | +| [saveFindings](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L311) | [將 findings 包成新版 wrapper 後寫入 workspace(及可選的鏡像目錄)。](#savefindings) | | [postOldFindingsComment](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L335) | [發布所有舊有未解決問題的彙總 comment。](#postoldfindingscomment) | | [postNewNonCriticalComment](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L359) | [發布新問題中非 critical 等級者的彙總 comment。](#postnewnoncriticalcomment) | | [postNewCriticalComments](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/comments.js#L388) | [針對每個新的 critical 問題逐筆發布行內 comment,無法定位或失敗時降級為一般 comment。](#postnewcriticalcomments) | @@ -68,7 +68,7 @@ | [stripCodeFence](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/json.js#L17) | [移除文字外層的 markdown code fence 並清理前後空白。](#stripcodefence) | | [repairJSONArrayWithAI](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/json.js#L43) | [透過 LLM 將原始內容修復成可直接 JSON.parse 的 JSON 陣列字串。](#repairjsonarraywithai) | | [validateJSONArrayFile](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/json.js#L93) | [驗證 JSON 檔案是否合法,格式錯誤時嘗試以 AI 修復一次。](#validatejsonarrayfile) | -| [ensureJSONArrayFileExists](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/json.js#L137) | [確保指定路徑存在 JSON 檔案,不存在時建立空陣列檔。](#ensurejsonarrayfileexists) | +| [ensureJSONArrayFileExists](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/json.js#L137) | [確保指定路徑存在 JSON 檔案,不存在時建立空陣列或 findings wrapper。](#ensurejsonarrayfileexists) | | [mapWithConcurrency](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/llm.js#L26) | [以可控併發數並行處理陣列項目並保序回傳結果。](#mapwithconcurrency) | | [extractMeaningfulError](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/llm.js#L102) | [從 CLI/HTTP 原始輸出中擷取最有用的錯誤訊息片段。](#extractmeaningfulerror) | | [chat](https://gitea.jsc.idv.tw/actions/ai-code-review/src/branch/develop/src/llm.js#L209) | [呼叫 CLIProxyAPI 送出對話請求並回傳純文字回應。](#chat) | @@ -207,7 +207,7 @@ await postFindingsReview(findings, { usageSection: '## 使用量\n...' }); ### saveFindings -將 findings 陣列以 `JSON.stringify(findings, null, 2)` 序列化並補結尾換行後,寫入 `workspace/.gitea/ai-review/findings.json`;若提供且不同於 `workspace` 的 `mirrorDir`,會同時寫入該鏡像目錄的相同路徑。寫入前會建立必要的父目錄;本函式為同步阻塞呼叫且未做例外防護,`fs` 錯誤會直接向外拋出。 +將 findings 包成新版 wrapper 物件後,以 `JSON.stringify(wrapper, null, 2)` 序列化並補結尾換行,寫入 `workspace/.gitea/ai-review/findings.json`;wrapper 內含 `generatedAt`/`commitSha`/`prNumber`/`tool`/`findings`/`excluded`。若提供且不同於 `workspace` 的 `mirrorDir`,會同時寫入該鏡像目錄的相同路徑。寫入前會建立必要的父目錄;本函式為同步阻塞呼叫且未做例外防護,`fs` 錯誤會直接向外拋出。 - 參數:`workspace`(`string`)、`findings`(`Array`)、`mirrorDir`(`?string`,預設 `null`)。 - 回傳:`void`。 @@ -345,7 +345,7 @@ normalizeText(' 這裡有 SQL Injection!! '); ### loadOldFindings -讀取來源分支 clone 出的工作目錄下 `FINDINGS_PATH`(`.gitea/ai-review/findings.json`),每筆標記 `is_new: false`;並記錄檔案大小/修改時間等診斷日誌。檔案不存在或讀取失敗時視為空陣列,不拋例外。 +讀取來源分支 clone 出的工作目錄下 `FINDINGS_PATH`(`.gitea/ai-review/findings.json`),相容舊版頂層陣列與新版 wrapper 物件;每筆標記 `is_new: false`,並記錄檔案大小/修改時間等診斷日誌。檔案不存在或讀取失敗時視為空陣列,不拋例外。 - 參數:`workspace`(`string`)。 - 回傳:`Array`。 @@ -900,7 +900,7 @@ const repaired = await repairJSONArrayWithAI('/workspace/findings.json', 'findin ### validateJSONArrayFile -驗證指定路徑是否為合法的 JSON 檔案:檔案不存在回傳 `{ exists:false }`(交由呼叫端補檔);解析成功回傳 `{ exists:true, valid:true, repaired:false }`;解析失敗則呼叫 `repairer` 修復、覆寫檔案(確保以換行結尾)並再驗證一次,通過則回傳 `repaired:true`,仍失敗則拋出例外。僅嘗試修復一次。 +驗證指定路徑是否為合法的 JSON 檔案:檔案不存在回傳 `{ exists:false }`(交由呼叫端補檔);`exclusions.json` 仍以頂層陣列為準,而 `findings.json` 則接受新版 wrapper 物件,若讀到舊版 findings 陣列會自動正規化成 wrapper。解析失敗則呼叫 `repairer` 修復、覆寫檔案(確保以換行結尾)並再驗證一次,通過則回傳 `repaired:true`,仍失敗則拋出例外。僅嘗試修復一次。 - 參數:`fullPath`(`string`)、`label`(`string`)、`repairer`(`Function`,預設 `repairJSONArrayWithAI`)。 - 回傳:`Promise<{exists, valid, repaired}>`。 @@ -917,7 +917,7 @@ const result = await validateJSONArrayFile('/workspace/.gitea/ai-review/findings ### ensureJSONArrayFileExists -確保指定路徑存在一個 JSON 檔案;不存在則建立內容為 `"[]\n"` 的空陣列檔(會先建立父目錄)。若檔案已存在則原樣保留、不檢查內容是否合法。為同步函式。 +確保指定路徑存在一個 JSON 檔案;`exclusions.json` 不存在時建立內容為 `"[]\n"` 的空陣列檔,而 `findings.json` 不存在時建立空的新版 wrapper 物件(會先建立父目錄)。若檔案已存在則原樣保留、不檢查內容是否合法。為同步函式。 - 參數:`fullPath`(`string`)、`label`(`string`)。 - 回傳:`boolean`(是否為本次新建)。