文件整理 #4

Merged
admin merged 12 commits from feat/文件整理 into develop 2026-08-07 16:49:29 +00:00
5 changed files with 17 additions and 39 deletions
Showing only changes of commit 409536b341 - Show all commits
+1 -4
View File
@@ -1,8 +1,5 @@
#!/bin/sh
# ============================================================================
# 用途:Docker 容器 action 的進入點腳本,於容器啟動時執行 Node 主程式並轉傳所有參數。
# 更新時間:2026/08/07 13:51:53
# ============================================================================
# Docker 容器 action 的進入點腳本,於容器啟動時執行 Node 主程式並轉傳所有參數。
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級:🟡 警告
審查員:Bard
問題:進入點腳本一開頭就塞入固定更新時間與裝飾性框線,資訊價值很低,卻會讓每次重生產都留下無意義的 diff 雜訊。
建議:移除這種會過期的時間戳註解,只保留真正需要提醒讀者的簡短說明即可。

**嚴重等級**:🟡 警告 **審查員**:Bard **問題**:進入點腳本一開頭就塞入固定更新時間與裝飾性框線,資訊價值很低,卻會讓每次重生產都留下無意義的 diff 雜訊。 **建議**:移除這種會過期的時間戳註解,只保留真正需要提醒讀者的簡短說明即可。
# 遇到任何指令執行失敗時立即中止腳本,避免錯誤被吞掉而繼續往下執行
set -e
+9 -21
View File
2
@@ -235,28 +235,16 @@ function toReviewComment(f) {
}
admin marked this conversation as resolved
Review

嚴重等級:🟡 警告
審查員:Bard
問題:postFindingsReview 這段 JSDoc 太像流程筆記,不像 API 說明。@param、@remarks、使用情境 與多層降級敘事一路堆疊,重點被枝節埋掉,閱讀節奏很不乾淨。
建議:把註解壓縮回最必要的契約說明:用途、參數、回傳與例外即可;降級順序和測試注入細節留給實作內的短註解。

**嚴重等級**:🟡 警告 **審查員**:Bard **問題**:`postFindingsReview` 這段 JSDoc 太像流程筆記,不像 API 說明。`@param`、`@remarks`、`使用情境` 與多層降級敘事一路堆疊,重點被枝節埋掉,閱讀節奏很不乾淨。 **建議**:把註解壓縮回最必要的契約說明:用途、參數、回傳與例外即可;降級順序和測試注入細節留給實作內的短註解。
/**
* 發布單一 Gitea review:一次性送出「統計摘要 + 逐筆行內 review comment」,並提供多層降級機制。
*
* @param {Array<object>} findings 本次審查的完整 findings 陣列;當 `deps.summaryFindings` 或
* `deps.commentFindings` 未提供時,兩者皆預設使用此參數。
* @param {object} [deps={}] 可覆寫的相依注入物件(主要供測試替換,正常情境可省略)。
* @param {Function} [deps.postReview=postPullReview] 發布整批 review(含 body 與 comments)的函式。
* @param {Function} [deps.postInline=postPullReviewComment] 發布單筆行內 review comment 的函式。
* @param {Function} [deps.postIssue=postComment] 發布一般(非 review)comment 的函式,作為最終降級手段。
* @param {Array<object>} [deps.summaryFindings=findings] 用於統計本文數字(含新舊問題)的 findings 子集合。
* @param {Array<object>} [deps.commentFindings=findings] 用於產生 review comments 的 findings 子集合;
* 會先依 {@link bySeverity} 排序,僅新問題(`is_new !== false`)會被轉成行內 comment,
* 舊問題只計入統計、不再重複標註檔案與行數。
* @param {string} [deps.usageSection=''] 附加在統計表之後的用量/token 統計區塊;空字串時不附加。
* 發布單一 Gitea review,必要時會先降級成 summary review,再降級成一般 comment。
* @param {Array<object>} findings 審查 findings。
* @param {object} [deps={}] 可注入的相依物件。
* @param {Function} [deps.postReview=postPullReview] 發布整批 review 的函式。
* @param {Function} [deps.postInline=postPullReviewComment] 發布單筆行內 comment 的函式。
* @param {Function} [deps.postIssue=postComment] 發布一般 comment 的降級函式。
* @param {Array<object>} [deps.summaryFindings=findings] 用於統計的 findings 子集合。
* @param {Array<object>} [deps.commentFindings=findings] 用於建立 review comments 的 findings 子集合。
* @param {string} [deps.usageSection=''] 附加的使用量區塊。
* @returns {Promise<void>} 無回傳值。
* @remarks
* 降級順序:① 整批 `postReview`(含 comments)→ 失敗則 ② 僅 body 的 `postReview`
* (comments 為空陣列)→ 失敗則 ③ `postIssue(body)`。**注意:③ 未包在 try/catch 中**,
* 若 `postIssue` 本身失敗,例外會直接從本函式往外拋出(reject),呼叫端須自行 catch。
* 無論走到哪一步,只要走完 ①~③ 中任一步不再往下失敗,後續都會逐筆嘗試 `postInline` 補發
* 行內 comment,每筆各自失敗僅記錄 warn 並略過,不影響其他筆。
* 使用情境:CI 流程完成一輪 AI Code Review 後,呼叫一次本函式即可把整批結果發布到 Gitea PR;
* 單元測試時可透過 `deps` 注入假的 `postReview`/`postInline`/`postIssue` 以驗證各降級分支。
*/
export async function postFindingsReview(findings, deps = {}) {
const {
1
+6 -10
View File
2
@@ -411,16 +411,12 @@ function extractFileDiff(diff, file) {
}
/**
admin marked this conversation as resolved
Review

嚴重等級:🟡 警告
審查員:Bard
問題:resolveMissingLineNumbers 的註解把行為、邊界條件、併發設定與人工備註全揉成一段,語氣也從說明一路滑到審查心得,讀起來有點散、有點吵。
建議:把說明拆短,保留輸入、輸出與副作用三件事即可;如果某些設計值得提醒,也應縮成一句附註,不要塞進主體敘述。

**嚴重等級**:🟡 警告 **審查員**:Bard **問題**:`resolveMissingLineNumbers` 的註解把行為、邊界條件、併發設定與人工備註全揉成一段,語氣也從說明一路滑到審查心得,讀起來有點散、有點吵。 **建議**:把說明拆短,保留輸入、輸出與副作用三件事即可;如果某些設計值得提醒,也應縮成一句附註,不要塞進主體敘述。
* 對「只有檔名、缺行號」的 findings,反問原角色依該檔 diff 找出行號,
* 重複嘗試直到取得有效行號(每條最多 maxAttempts 次,避免無限迴圈);
* 成功則直接修改(mutate)該 finding 的 location 為 `檔案:行號`,否則保留原檔名不變。
* 各條 finding 以獨立 LLM 呼叫並行定位,併發上限見 concurrency。
*
* @param {Array<object>} findings - findings 陣列;缺行號且有檔名者會被就地修改 location(mutate),其餘不受影響。
* @param {string} diff - 完整 unified diff,用於擷取各檔案對應區段作為定位依據。
* @param {{chatFn?: Function, getRole?: Function, maxAttempts?: number, concurrency?: number}} [deps] - 依賴注入(利於測試):
* chatFn 預設 chatJSON;getRole 預設 loadRole;maxAttempts 預設 3(MAX_LOCATE_ATTEMPTS);concurrency 預設 LLM_CONCURRENCY。
* @returns {Promise<Array<object>>} 與傳入 findings 相同參照的陣列(部分項目的 location 已被就地修改)。
* 對缺行號的 findings 重新詢問原角色補上行號,成功時會就地更新 `location`。
* @param {Array<object>} findings findings 陣列。
* @param {string} diff 完整 unified diff。
* @param {{chatFn?: Function, getRole?: Function, maxAttempts?: number, concurrency?: number}} [deps]
* 測試用依賴注入。
* @returns {Promise<Array<object>>} 與傳入相同參照的 findings 陣列。
*/
export async function resolveMissingLineNumbers(findings, diff, deps = {}) {
const { chatFn = chatJSON, getRole = loadRole, maxAttempts = MAX_LOCATE_ATTEMPTS, concurrency = LLM_CONCURRENCY } = deps;
1
+1 -1
View File
@@ -6,7 +6,7 @@
* @returns {string} 例如 `2026/08/07 12:39:43`。
*/
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級:🟡 警告
審查員:Rogue
問題:formatTimestamp() 每次調用都新建 Intl.DateTimeFormat 實例,加上 formatToParts() 與 Object.fromEntries() 轉換,高頻日誌場景下重複成本大;而日誌函式會在 section/step/line/input/output/result/ok/warn/error 等多處調用,累積開銷明顯
建議:將 Intl.DateTimeFormat 快取為模組層級單例(const formatter = new Intl.DateTimeFormat(...)),或改用更輕量的時間格式化方式(例如直接用 Date 方法),避免每條日誌都重複實例化

**嚴重等級**:🟡 警告 **審查員**:Rogue **問題**:formatTimestamp() 每次調用都新建 Intl.DateTimeFormat 實例,加上 formatToParts() 與 Object.fromEntries() 轉換,高頻日誌場景下重複成本大;而日誌函式會在 section/step/line/input/output/result/ok/warn/error 等多處調用,累積開銷明顯 **建議**:將 Intl.DateTimeFormat 快取為模組層級單例(const formatter = new Intl.DateTimeFormat(...)),或改用更輕量的時間格式化方式(例如直接用 Date 方法),避免每條日誌都重複實例化
function formatTimestamp(date = new Date()) {
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級:🔵 建議
審查員:Bard
問題:這裡用 en-CA 來拼台灣時區時間字串,技法不算錯,但對讀者很不直觀。看到 Asia/Taipei 卻搭配 en-CA,第一眼會先懷疑這是不是某種繞路寫法。
建議:改用更直白的格式化方式,例如手動補零組字串,或至少把這個 locale 選擇的用意明講,讓 helper 的意圖一眼可懂。

**嚴重等級**:🔵 建議 **審查員**:Bard **問題**:這裡用 `en-CA` 來拼台灣時區時間字串,技法不算錯,但對讀者很不直觀。看到 `Asia/Taipei` 卻搭配 `en-CA`,第一眼會先懷疑這是不是某種繞路寫法。 **建議**:改用更直白的格式化方式,例如手動補零組字串,或至少把這個 locale 選擇的用意明講,讓 helper 的意圖一眼可懂。
const parts = new Intl.DateTimeFormat('en-CA', {
const parts = new Intl.DateTimeFormat('zh-TW', {
timeZone: 'Asia/Taipei',
year: 'numeric',
month: '2-digit',
2
-3
View File
@@ -53,9 +53,6 @@ const WORKSPACE = process.env.GITHUB_WORKSPACE || '/workspace';
* 降級處理:Step4 對話收斂、Step5 角色介紹 comment 與個別角色分析、Step6 clone repo、
* Step8 Review 發布等非致命步驟失敗時,僅 `warn` 後繼續執行。
*
* 目前程式碼中有 3 個 exit 1 呼叫點(未設定 CLIProxyAPI、取 diff 失敗、所有角色分析皆失敗)
* 退出前未呼叫 `section('Pipeline 結束')`,與其餘 exit 點不一致,會少一行收尾分隔線,
* 是否為刻意設計尚需人工確認。
*/
export async function main() {
section('AI Code Review Pipeline');
1