feat(ai-code-review): 建問題模式導向 issue,並整併流程調整、文件與 CI #14

Closed
opened 2026-07-20 09:17:27 +00:00 by admin · 20 comments
Owner

變更摘要

本 PR 將 ai-code-review action 分支的完整成果併入 develop,主要含四塊:

  1. 建問題模式重構(feat)create-issue: 'true' 時,審查留言(工具/diff/角色/嚴重問題/警告+建議)全部改發到追蹤 issue、不再張貼到 PR;不執行「舊留言標過時/resolve」;issue 延後到「確定有保留問題」才建立;無保留問題或無可審查變更則不建 issue、PR 也完全不留言(靜默通過);有問題時最後在 PR 回貼一則 issue 連結並補掛標籤,形成雙向關聯。
  2. 審查流程步驟調整(refactor):將「標記舊留言過時/resolve」提前到偵測 AI 工具之前,並依新順序重編所有步驟編號與說明。
  3. 修正(gitrepo):補抓淺層 checkout 的 base 歷史,避免 merge-base 計算失敗。
  4. 文件與 CI:補齊 action.ymlsrc 各模組文件、重建 readme.md,新增 .gitea/workflows/ci.yaml(多工具 code review 驗證)並啟用建問題模式。

影響範圍

範圍 說明
action 執行流程 src/index.js main() 依模式分流:留言去向、跳過 resolveOldComments、issue 延後建立、severe/others 導向 issue、有問題才在 PR 回貼連結
Gitea API src/lib/gitea.js 新增 addLabelsToIssue
留言模板 src/lib/templates.js 新增 issueLinkComment
審查核心 src/lib/review.js 新增 postSevereToIssue,移除 createIssueWithFindingssortFindingsForIssue
git base 解析 src/lib/gitrepo.js 補抓淺層 checkout 的 base 歷史
文件與 CI readme.mdaction.yml.gitea/workflows/ci.yaml.gitea/workflows/readme.md

風險與注意事項

  • 建問題模式行為明顯改變:啟用後 PR 上不再有審查留言(有問題時改為 issue + 一則連結留言;無問題時完全不留言),請確認團隊流程可接受。
  • 端對端行為需靠 CI 實測:本地僅完成語法與模組載入驗證,實際 issue/PR 互動需一次 CI 觸發確認。
  • readme.md 尚未反映「建問題模式導向 issue」的最新行為與新/移除的函式,建議後續以 doc-funcs 重建文件。
  • 各檔頭部「更新時間」時間戳仍為 2026/07/17 18:49:58,未刷新。

本問題由 AI Code Review 依 PR #6 的審查結果自動建立,問題明細見下方留言。

<!-- ai-code-review --> ## 變更摘要 本 PR 將 ai-code-review action 分支的完整成果併入 `develop`,主要含四塊: 1. **建問題模式重構(feat)**:`create-issue: 'true'` 時,審查留言(工具/diff/角色/嚴重問題/警告+建議)全部改發到追蹤 issue、不再張貼到 PR;不執行「舊留言標過時/resolve」;issue 延後到「確定有保留問題」才建立;**無保留問題或無可審查變更則不建 issue、PR 也完全不留言(靜默通過)**;有問題時最後在 PR 回貼一則 issue 連結並補掛標籤,形成雙向關聯。 2. **審查流程步驟調整(refactor)**:將「標記舊留言過時/resolve」提前到偵測 AI 工具之前,並依新順序重編所有步驟編號與說明。 3. **修正(gitrepo)**:補抓淺層 checkout 的 base 歷史,避免 merge-base 計算失敗。 4. **文件與 CI**:補齊 `action.yml`/`src` 各模組文件、重建 `readme.md`,新增 `.gitea/workflows/ci.yaml`(多工具 code review 驗證)並啟用建問題模式。 ## 影響範圍 | 範圍 | 說明 | | --- | --- | | action 執行流程 | `src/index.js` `main()` 依模式分流:留言去向、跳過 resolveOldComments、issue 延後建立、severe/others 導向 issue、有問題才在 PR 回貼連結 | | Gitea API | `src/lib/gitea.js` 新增 `addLabelsToIssue` | | 留言模板 | `src/lib/templates.js` 新增 `issueLinkComment` | | 審查核心 | `src/lib/review.js` 新增 `postSevereToIssue`,移除 `createIssueWithFindings`、`sortFindingsForIssue` | | git base 解析 | `src/lib/gitrepo.js` 補抓淺層 checkout 的 base 歷史 | | 文件與 CI | `readme.md`、`action.yml`、`.gitea/workflows/ci.yaml`、`.gitea/workflows/readme.md` | ## 風險與注意事項 - **建問題模式行為明顯改變**:啟用後 PR 上不再有審查留言(有問題時改為 issue + 一則連結留言;無問題時完全不留言),請確認團隊流程可接受。 - **端對端行為需靠 CI 實測**:本地僅完成語法與模組載入驗證,實際 issue/PR 互動需一次 CI 觸發確認。 - `readme.md` 尚未反映「建問題模式導向 issue」的最新行為與新/移除的函式,建議後續以 doc-funcs 重建文件。 - 各檔頭部「更新時間」時間戳仍為 `2026/07/17 18:49:58`,未刷新。 --- > 本問題由 AI Code Review 依 PR #6 的審查結果自動建立,問題明細見下方留言。
Author
Owner

🤖 AI Code Review|審查工具

項目 內容
工具 antigravity
版本 1.1.4
模型 gemini-3.5-flash
審查 commit 36bf2d8644d77876f3f1342fb4a5f74add273192
Run Job #31
flowchart LR
    A[整理 git diff] --> B[⚔️ 攻擊方找問題]
    B --> C[🛡️ 防守方裁決]
    C --> D[保存 findings]
    D --> E[留言到 PR]
<!-- ai-code-review --> ## 🤖 AI Code Review|審查工具 | 項目 | 內容 | | --- | --- | | 工具 | `antigravity` | | 版本 | `1.1.4` | | 模型 | `gemini-3.5-flash` | | 審查 commit | `36bf2d8644d77876f3f1342fb4a5f74add273192` | | Run Job | [#31](https://gitea.jsc.idv.tw/node-actions/ai-code-review/actions/runs/1600) | ```mermaid flowchart LR A[整理 git diff] --> B[⚔️ 攻擊方找問題] B --> C[🛡️ 防守方裁決] C --> D[保存 findings] D --> E[留言到 PR] ```
Author
Owner

📋 變更摘要(送審 git diff)

檔案 用途 git diff 長度 最後更新時間
action.yml 定義 Action 的輸入參數與執行進入點 95 行/4205 字元 2026/07/20 15:00:23
readme.md 專案的說明文件與使用指引 276 行/23829 字元(過長截斷送審) 2026/07/20 16:01:05
src/index.js Action 的執行入口與主流程控制 320 行/14204 字元 2026/07/20 15:00:15
src/lib/agents.js 偵測與執行 AI CLI 審查工具 14 行/503 字元 2026/07/20 09:46:12
src/lib/context.js 解析與管理 Action 的執行上下文 31 行/1398 字元 2026/07/20 15:00:23
src/lib/gitea.js 封裝與 Gitea API 互動的各類操作 121 行/5278 字元 2026/07/20 16:01:05
src/lib/gitrepo.js 處理 Git 指令與分支基準點解析 222 行/9110 字元 2026/07/20 16:01:05
src/lib/review.js 處理審查核心邏輯與診斷輸出遮罩 580 行/24901 字元(過長截斷送審) 2026/07/20 16:37:15
src/lib/roles.js 載入與管理 AI 審查角色的提示詞 14 行/586 字元 2026/07/20 09:46:12
src/lib/templates.js 定義 PR 留言與表格的 Markdown 模板 165 行/5949 字元 2026/07/20 15:00:32

共 10 個檔案納入審查;另有 7 個檔案依 .reviewignore 排除。

<!-- ai-code-review --> ## 📋 變更摘要(送審 git diff) | 檔案 | 用途 | git diff 長度 | 最後更新時間 | | --- | --- | --- | --- | | `action.yml` | 定義 Action 的輸入參數與執行進入點 | 95 行/4205 字元 | 2026/07/20 15:00:23 | | `readme.md` | 專案的說明文件與使用指引 | 276 行/23829 字元(過長截斷送審) | 2026/07/20 16:01:05 | | `src/index.js` | Action 的執行入口與主流程控制 | 320 行/14204 字元 | 2026/07/20 15:00:15 | | `src/lib/agents.js` | 偵測與執行 AI CLI 審查工具 | 14 行/503 字元 | 2026/07/20 09:46:12 | | `src/lib/context.js` | 解析與管理 Action 的執行上下文 | 31 行/1398 字元 | 2026/07/20 15:00:23 | | `src/lib/gitea.js` | 封裝與 Gitea API 互動的各類操作 | 121 行/5278 字元 | 2026/07/20 16:01:05 | | `src/lib/gitrepo.js` | 處理 Git 指令與分支基準點解析 | 222 行/9110 字元 | 2026/07/20 16:01:05 | | `src/lib/review.js` | 處理審查核心邏輯與診斷輸出遮罩 | 580 行/24901 字元(過長截斷送審) | 2026/07/20 16:37:15 | | `src/lib/roles.js` | 載入與管理 AI 審查角色的提示詞 | 14 行/586 字元 | 2026/07/20 09:46:12 | | `src/lib/templates.js` | 定義 PR 留言與表格的 Markdown 模板 | 165 行/5949 字元 | 2026/07/20 15:00:32 | > 共 10 個檔案納入審查;另有 7 個檔案依 `.reviewignore` 排除。
Author
Owner

⚔️ 攻擊方登場

角色 面向 個性
🗡️ Assassin 安全性(security) 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用
🎼 Bard 風格(style) 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版
🧰 Leo 可維護性(maintainability) 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來
🔮 Mage 邏輯(logic) 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」
🧪 Maya 測試(testing) 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑
Rogue 效率(efficiency) 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」
<!-- ai-code-review --> ## ⚔️ 攻擊方登場 | 角色 | 面向 | 個性 | | --- | --- | --- | | 🗡️ **Assassin** | 安全性(security) | 多疑偏執、以攻擊者視角看世界,假設每筆輸入都是惡意的,每個信任都會被濫用 | | 🎼 **Bard** | 風格(style) | 唯美龜毛、追求優雅,把可讀性與一致性當作旋律,最受不了走調的命名與排版 | | 🧰 **Leo** | 可維護性(maintainability) | 有遠見、重視長期維護成本,凡事先問「六個月後的自己還看得懂嗎?」,討厭把債留給未來 | | 🔮 **Mage** | 邏輯(logic) | 嚴謹冷靜、滴水不漏,凡事推演到最壞情況,深信「沒驗證過的假設都是 bug」 | | 🧪 **Maya** | 測試(testing) | 對測試覆蓋率有執念,深信「沒有測試的程式碼等於沒寫完」,溫和但堅持,最在意邊界與失敗路徑 | | ⚡ **Rogue** | 效率(efficiency) | 急性子、講求速度,最痛恨被浪費的 CPU 週期與記憶體,凡事先問「這能不能更快、更省」 |
Author
Owner

🛡️ 防守方登場

角色 面向 個性
🛡️ Paladin 裁決(verdict) 沉穩公正、就事論事,不護短也不冤枉,只依排除事項與原始碼脈絡裁定問題成立與否
<!-- ai-code-review --> ## 🛡️ 防守方登場 | 角色 | 面向 | 個性 | | --- | --- | --- | | 🛡️ **Paladin** | 裁決(verdict) | 沉穩公正、就事論事,不護短也不冤枉,只依排除事項與原始碼脈絡裁定問題成立與否 |
Author
Owner

🔴 嚴重| Rogue

位置src/index.js 第 216–218 行

問題描述

ensureIssueCreated 函式中,使用 for...of 迴圈搭配 await 來逐條對 Gitea API 發送留言請求。由於網路請求存在延遲(每次 RTT 約 100-300ms),在迴圈內阻塞式等待會導致整體執行時間隨留言數量線性增加,浪費大量 CPU 週期與網路連線資源。

修改建議

可以將 issueBuffer 中的所有情境留言合併為單一 Markdown 留言發送,僅需一次 API 呼叫;或者使用 Promise.all 將這些無相依性的留言請求並行化發送,大幅降低總延遲。

建議寫法

if (issueBuffer.length > 0) {
      const combinedBody = issueBuffer.join('\n\n---\n\n');
      await gitea.createCommentOnIssue(ctx, issue.number, combinedBody);
    }
    issueBuffer.length = 0;
<!-- ai-code-review --> ### 🔴 嚴重|⚡ Rogue **位置**:`src/index.js` 第 216–218 行 **問題描述** 在 `ensureIssueCreated` 函式中,使用 `for...of` 迴圈搭配 `await` 來逐條對 Gitea API 發送留言請求。由於網路請求存在延遲(每次 RTT 約 100-300ms),在迴圈內阻塞式等待會導致整體執行時間隨留言數量線性增加,浪費大量 CPU 週期與網路連線資源。 **修改建議** 可以將 `issueBuffer` 中的所有情境留言合併為單一 Markdown 留言發送,僅需一次 API 呼叫;或者使用 `Promise.all` 將這些無相依性的留言請求並行化發送,大幅降低總延遲。 **建議寫法** ``` if (issueBuffer.length > 0) { const combinedBody = issueBuffer.join('\n\n---\n\n'); await gitea.createCommentOnIssue(ctx, issue.number, combinedBody); } issueBuffer.length = 0; ```
Author
Owner

🔴 嚴重|🗡️ Assassin

位置src/lib/review.js 第 23–23 行

問題描述

redactSecrets 函式中,針對 Authorization 標頭的遮蔽正規表示式為 /(authorization\\s*[:=]\\s*)\\S+/gi。此規則僅會遮蔽 Authorization: 後方的第一個非空白字串。當使用常見的 Authorization: Bearer <token>Authorization: token <token> 格式時,僅有 Bearertoken 會被替換為 ***,而實際的敏感憑證(<token>)將會完整暴露並輸出至 CI 日誌中,造成憑證外洩風險。

修改建議

修正正規表示式,使其能同時匹配驗證機制名稱(如 Bearer、token、Basic)與隨後的憑證內容。可以使用分組同時捕捉機制與憑證字串來進行遮蔽。

建議寫法

.replace(/(authorization\\s*[:=]\\s*)(\\S+(?:\\s+\\S+)?)/gi, '$1***')
<!-- ai-code-review --> ### 🔴 嚴重|🗡️ Assassin **位置**:`src/lib/review.js` 第 23–23 行 **問題描述** 在 `redactSecrets` 函式中,針對 `Authorization` 標頭的遮蔽正規表示式為 `/(authorization\\s*[:=]\\s*)\\S+/gi`。此規則僅會遮蔽 `Authorization:` 後方的第一個非空白字串。當使用常見的 `Authorization: Bearer <token>` 或 `Authorization: token <token>` 格式時,僅有 `Bearer` 或 `token` 會被替換為 `***`,而實際的敏感憑證(`<token>`)將會完整暴露並輸出至 CI 日誌中,造成憑證外洩風險。 **修改建議** 修正正規表示式,使其能同時匹配驗證機制名稱(如 Bearer、token、Basic)與隨後的憑證內容。可以使用分組同時捕捉機制與憑證字串來進行遮蔽。 **建議寫法** ``` .replace(/(authorization\\s*[:=]\\s*)(\\S+(?:\\s+\\S+)?)/gi, '$1***') ```
Author
Owner

🔴 嚴重|🗡️ Assassin

位置src/lib/review.js 第 25–25 行

問題描述

redactSecrets 函式中,遮蔽 URL 內嵌帳密的正規表示式為 /(https?:\\/\\/)[^\\s/:@]+:[^\\s/@]+@/gi。此規則強制要求 URL 必須同時包含使用者名稱與密碼(以冒號 : 分隔,如 http://user:pass@host)。但在實際使用情境中,常會使用僅包含 Token 的 URL(如 https://<token>@gitea.com),此時該正規表示式將無法匹配,導致敏感的 Token 完整暴露在日誌中。

修改建議

建議簡化並強化正規表示式,直接遮蔽 https:// 與主機名之間的 @ 前的所有憑證字元,不論其是否包含冒號。

建議寫法

.replace(/(https?:\\/\\/)[^\\s/]+@/gi, '$1***@')
<!-- ai-code-review --> ### 🔴 嚴重|🗡️ Assassin **位置**:`src/lib/review.js` 第 25–25 行 **問題描述** 在 `redactSecrets` 函式中,遮蔽 URL 內嵌帳密的正規表示式為 `/(https?:\\/\\/)[^\\s/:@]+:[^\\s/@]+@/gi`。此規則強制要求 URL 必須同時包含使用者名稱與密碼(以冒號 `:` 分隔,如 `http://user:pass@host`)。但在實際使用情境中,常會使用僅包含 Token 的 URL(如 `https://<token>@gitea.com`),此時該正規表示式將無法匹配,導致敏感的 Token 完整暴露在日誌中。 **修改建議** 建議簡化並強化正規表示式,直接遮蔽 `https://` 與主機名之間的 `@` 前的所有憑證字元,不論其是否包含冒號。 **建議寫法** ``` .replace(/(https?:\\/\\/)[^\\s/]+@/gi, '$1***@') ```
Author
Owner

🟠 警告|🧰 Leo

位置src/index.js 第 186–225 行

問題描述

將 postComment 和 ensureIssueCreated 這類包含多角色審查與建問題模式核心業務邏輯的輔助函式直接內嵌於 main() 主流程函式中。這會導致這些函式因閉包而強耦合 main() 內部的局部變數(例如 issue, issueBuffer, currentRunCommentIds 等),未來若需要維護或擴充建問題邏輯,將大幅增加 main() 的認知複雜度,且無法對這些核心邏輯進行獨立的單元測試(Unit Test)。

修改建議

建議將這些輔助函式抽離到 main() 之外,定義為模組私有函式,並明確地將需要的依賴與狀態(如 ctx, issueBuffer)透過參數傳入,以提升程式碼的模組化與可測試性。

建議寫法

// 建議重構方向:將其移出 main() 函式外
async function postComment(ctx, body, state) {
  if (ctx.createIssue) {
    if (state.issue) {
      return gitea.createCommentOnIssue(ctx, state.issue.number, body);
    }
    state.issueBuffer.push(body);
    return null;
  }
  const created = await gitea.createIssueComment(ctx, body);
  state.currentRunCommentIds.add(created.id);
  return created;
}

async function ensureIssueCreated(ctx, labelIds = [], state) {
  state.issue = await gitea.createIssue(ctx, {
    title: ctx.prTitle || `AI Code Review:PR #${ctx.prNumber}`,
    body: templates.issueBody({ prNumber: ctx.prNumber, prBody: ctx.prBody }),
    labels: labelIds,
  });
  log('建問題', 'INF', `已建立追蹤 issue #${state.issue.number},寫入 ${state.issueBuffer.length} 則情境留言。`);
  for (const body of state.issueBuffer) {
    await gitea.createCommentOnIssue(ctx, state.issue.number, body);
  }
  state.issueBuffer.length = 0;
}
<!-- ai-code-review --> ### 🟠 警告|🧰 Leo **位置**:`src/index.js` 第 186–225 行 **問題描述** 將 postComment 和 ensureIssueCreated 這類包含多角色審查與建問題模式核心業務邏輯的輔助函式直接內嵌於 main() 主流程函式中。這會導致這些函式因閉包而強耦合 main() 內部的局部變數(例如 issue, issueBuffer, currentRunCommentIds 等),未來若需要維護或擴充建問題邏輯,將大幅增加 main() 的認知複雜度,且無法對這些核心邏輯進行獨立的單元測試(Unit Test)。 **修改建議** 建議將這些輔助函式抽離到 main() 之外,定義為模組私有函式,並明確地將需要的依賴與狀態(如 ctx, issueBuffer)透過參數傳入,以提升程式碼的模組化與可測試性。 **建議寫法** ``` // 建議重構方向:將其移出 main() 函式外 async function postComment(ctx, body, state) { if (ctx.createIssue) { if (state.issue) { return gitea.createCommentOnIssue(ctx, state.issue.number, body); } state.issueBuffer.push(body); return null; } const created = await gitea.createIssueComment(ctx, body); state.currentRunCommentIds.add(created.id); return created; } async function ensureIssueCreated(ctx, labelIds = [], state) { state.issue = await gitea.createIssue(ctx, { title: ctx.prTitle || `AI Code Review:PR #${ctx.prNumber}`, body: templates.issueBody({ prNumber: ctx.prNumber, prBody: ctx.prBody }), labels: labelIds, }); log('建問題', 'INF', `已建立追蹤 issue #${state.issue.number},寫入 ${state.issueBuffer.length} 則情境留言。`); for (const body of state.issueBuffer) { await gitea.createCommentOnIssue(ctx, state.issue.number, body); } state.issueBuffer.length = 0; } ```
Author
Owner

🟠 警告| Rogue

位置src/lib/gitrepo.js 第 134–134 行

問題描述

在檢查是否為淺層 repository (shallow repository) 時,呼叫了外部子行程執行 git rev-parse --is-shallow-repository。建立與啟動 OS 子行程是非常昂貴的操作,會白白浪費數十毫秒的 CPU 週期與系統資源。

修改建議

Git 在淺層 clone 時會在 .git 目錄下建立一個 shallow 檔案。我們可以使用 Node.js 內建的 fs.existsSync 進行本地檔案檢查,不需啟動額外的 Git 子行程,執行速度可快上百倍。

建議寫法

const fs = require('fs');
// ...
if (fs.existsSync(path.join(cwd, '.git', 'shallow'))) {
  strategies.push(['unshallow', 'fetch', '--no-tags', '--unshallow', 'origin']);
}
<!-- ai-code-review --> ### 🟠 警告|⚡ Rogue **位置**:`src/lib/gitrepo.js` 第 134–134 行 **問題描述** 在檢查是否為淺層 repository (shallow repository) 時,呼叫了外部子行程執行 `git rev-parse --is-shallow-repository`。建立與啟動 OS 子行程是非常昂貴的操作,會白白浪費數十毫秒的 CPU 週期與系統資源。 **修改建議** Git 在淺層 clone 時會在 `.git` 目錄下建立一個 `shallow` 檔案。我們可以使用 Node.js 內建的 `fs.existsSync` 進行本地檔案檢查,不需啟動額外的 Git 子行程,執行速度可快上百倍。 **建議寫法** ``` const fs = require('fs'); // ... if (fs.existsSync(path.join(cwd, '.git', 'shallow'))) { strategies.push(['unshallow', 'fetch', '--no-tags', '--unshallow', 'origin']); } ```
Author
Owner

🟠 警告| Rogue

位置src/lib/gitrepo.js 第 134–143 行

問題描述

在處理淺層歷史不足的救援策略時,將最沉重的 --unshallow(完整拉取整個存取庫歷史,對於大型專案會下載數 GB 的資料並導致嚴重的網路和 I/O 阻塞)放在第一順位,而較輕量的 --deepen 卻放在後面。這會導致絕大多數情況下直接執行最慢、最耗資源的完整拉取。

修改建議

應反轉策略順序,優先嘗試較輕量的 deepen。只有當 deepen 抓取後仍無法找出共同祖先時,才將 unshallow 作為最後的保底手段,以節省大量網路頻寬與時間。

建議寫法

const strategies = [];
  strategies.push([
    'deepen base',
    'fetch', '--no-tags', '--deepen=1000', 'origin', `+refs/heads/${baseRef}:refs/remotes/${remoteBase}`,
  ]);
  strategies.push(['deepen HEAD', 'fetch', '--no-tags', '--deepen=1000', 'origin', 'HEAD']);
  
  const fs = require('fs');
  if (fs.existsSync(path.join(cwd, '.git', 'shallow'))) {
    strategies.push(['unshallow', 'fetch', '--no-tags', '--unshallow', 'origin']);
  }
<!-- ai-code-review --> ### 🟠 警告|⚡ Rogue **位置**:`src/lib/gitrepo.js` 第 134–143 行 **問題描述** 在處理淺層歷史不足的救援策略時,將最沉重的 `--unshallow`(完整拉取整個存取庫歷史,對於大型專案會下載數 GB 的資料並導致嚴重的網路和 I/O 阻塞)放在第一順位,而較輕量的 `--deepen` 卻放在後面。這會導致絕大多數情況下直接執行最慢、最耗資源的完整拉取。 **修改建議** 應反轉策略順序,優先嘗試較輕量的 `deepen`。只有當 `deepen` 抓取後仍無法找出共同祖先時,才將 `unshallow` 作為最後的保底手段,以節省大量網路頻寬與時間。 **建議寫法** ``` const strategies = []; strategies.push([ 'deepen base', 'fetch', '--no-tags', '--deepen=1000', 'origin', `+refs/heads/${baseRef}:refs/remotes/${remoteBase}`, ]); strategies.push(['deepen HEAD', 'fetch', '--no-tags', '--deepen=1000', 'origin', 'HEAD']); const fs = require('fs'); if (fs.existsSync(path.join(cwd, '.git', 'shallow'))) { strategies.push(['unshallow', 'fetch', '--no-tags', '--unshallow', 'origin']); } ```
Author
Owner

🟠 警告|🧰 Leo

位置src/lib/gitrepo.js 第 293–305 行

問題描述

為了防止 Git 推送失敗時在例外訊息中回顯包含 Token 與遠端 URL 的命令列參數,pushWithCredential 的 catch 區塊直接拋出一個固定的 Error('推送審查結果 commit 失敗...')。但這樣一來,它完全吞掉了原始的錯誤(例如 non-fast-forward 非快轉、分支保護規則阻擋、或連線逾時),六個月後的維護者在 CI log 中看到此錯誤時,完全無從判斷失敗的原因。

修改建議

建議在保留安全遮罩的前提下,保留原始 exception 的排錯線索。例如可以檢查並安全地過濾 err.message 或 err.stderr 中所有的敏感字串(如 Token/URL),然後將其作為新錯誤的 cause 屬性或附加訊息傳遞下去。

建議寫法

} catch (err) {
    // 過濾敏感資訊後保留錯誤細節
    const safeMessage = err.message ? redactSecrets(err.message) : '未知錯誤';
    const error = new Error(`推送審查結果 commit 失敗(${safeMessage})。`);
    error.cause = err;
    throw error;
  }
<!-- ai-code-review --> ### 🟠 警告|🧰 Leo **位置**:`src/lib/gitrepo.js` 第 293–305 行 **問題描述** 為了防止 Git 推送失敗時在例外訊息中回顯包含 Token 與遠端 URL 的命令列參數,pushWithCredential 的 catch 區塊直接拋出一個固定的 Error('推送審查結果 commit 失敗...')。但這樣一來,它完全吞掉了原始的錯誤(例如 non-fast-forward 非快轉、分支保護規則阻擋、或連線逾時),六個月後的維護者在 CI log 中看到此錯誤時,完全無從判斷失敗的原因。 **修改建議** 建議在保留安全遮罩的前提下,保留原始 exception 的排錯線索。例如可以檢查並安全地過濾 err.message 或 err.stderr 中所有的敏感字串(如 Token/URL),然後將其作為新錯誤的 cause 屬性或附加訊息傳遞下去。 **建議寫法** ``` } catch (err) { // 過濾敏感資訊後保留錯誤細節 const safeMessage = err.message ? redactSecrets(err.message) : '未知錯誤'; const error = new Error(`推送審查結果 commit 失敗(${safeMessage})。`); error.cause = err; throw error; } ```
Author
Owner

🟠 警告|🗡️ Assassin

位置src/lib/gitrepo.js 第 299–299 行

問題描述

pushWithCredential 中,環境變數 GIT_CONFIG_KEY_0 被動態拼接為 http.${remoteUrl}.extraheader。如果 remoteUrl 來自外部或未經嚴格驗證的 context,且 URL 中包含特殊字元(如點號、路徑分隔符號或引號等),可能會導致 Git 配置解析錯誤,或在特定平台下引發 Git 配置參數注入風險。

修改建議

由於該執行程序僅為一次性的 git push 操作,可直接將該憑證應用於所有 HTTP 請求,將 GIT_CONFIG_KEY_0 設定為靜態的 http.extraheader,以避免動態拼接 URL 所帶來的注入風險。

建議寫法

GIT_CONFIG_KEY_0: 'http.extraheader',
<!-- ai-code-review --> ### 🟠 警告|🗡️ Assassin **位置**:`src/lib/gitrepo.js` 第 299–299 行 **問題描述** 在 `pushWithCredential` 中,環境變數 `GIT_CONFIG_KEY_0` 被動態拼接為 `http.${remoteUrl}.extraheader`。如果 `remoteUrl` 來自外部或未經嚴格驗證的 context,且 URL 中包含特殊字元(如點號、路徑分隔符號或引號等),可能會導致 Git 配置解析錯誤,或在特定平台下引發 Git 配置參數注入風險。 **修改建議** 由於該執行程序僅為一次性的 `git push` 操作,可直接將該憑證應用於所有 HTTP 請求,將 `GIT_CONFIG_KEY_0` 設定為靜態的 `http.extraheader`,以避免動態拼接 URL 所帶來的注入風險。 **建議寫法** ``` GIT_CONFIG_KEY_0: 'http.extraheader', ```
Author
Owner

🟠 警告|🧰 Leo

位置src/lib/review.js 第 28–38 行

問題描述

redactSecrets 使用的正則表達式 replace(/\b[A-Za-z0-9_-]{40,}\b/g, '***') 過於寬鬆。它會將任何長度大於或等於 40 的英數字/底線/減號字串(例如 Git 的 40 碼 Commit SHA 或某些合法的 hash 值)全數遮蔽為 ***。這會導致日誌中所有相關的 Commit SHA 被抹除,極大增加了排錯與回溯歷史的難度,是一項未來難以維護的技術債。

修改建議

遮罩機制應該針對特定且高信賴度的敏感模式(例如特定 token 前綴如 ghp_),或者建立一個明確的敏感詞清單(包含 ctx.token 與 ctx.pushToken 等),而非使用粗暴的長度匹配。

建議寫法

function redactSecrets(text, sensitiveValues = []) {
  let redacted = String(text ?? '').replace(/[\r\n\t\v\f\x00-\x1f\x7f]+/g, ' ');
  // 精確匹配已知敏感變數
  for (const value of sensitiveValues) {
    if (value && value.length > 5) {
      redacted = redacted.split(value).join('***');
    }
  }
  // 針對特定模式遮罩
  return redacted
    .replace(/(authorization\s*[:=]\s*)\S+/gi, '$1***')
    .replace(/((?:api[_-]?key|token|password|secret|bearer)\s*[:=]\s*)\S+/gi, '$1***')
    .replace(/(https?:\/\/)[^\s/:@]+:[^\s/@]+@/gi, '$1***:***@')
    .replace(/\bgh[pousr]_[A-Za-z0-9]{16,}\b/g, '***')
    .trim();
}
<!-- ai-code-review --> ### 🟠 警告|🧰 Leo **位置**:`src/lib/review.js` 第 28–38 行 **問題描述** redactSecrets 使用的正則表達式 replace(/\b[A-Za-z0-9_-]{40,}\b/g, '***') 過於寬鬆。它會將任何長度大於或等於 40 的英數字/底線/減號字串(例如 Git 的 40 碼 Commit SHA 或某些合法的 hash 值)全數遮蔽為 ***。這會導致日誌中所有相關的 Commit SHA 被抹除,極大增加了排錯與回溯歷史的難度,是一項未來難以維護的技術債。 **修改建議** 遮罩機制應該針對特定且高信賴度的敏感模式(例如特定 token 前綴如 ghp_),或者建立一個明確的敏感詞清單(包含 ctx.token 與 ctx.pushToken 等),而非使用粗暴的長度匹配。 **建議寫法** ``` function redactSecrets(text, sensitiveValues = []) { let redacted = String(text ?? '').replace(/[\r\n\t\v\f\x00-\x1f\x7f]+/g, ' '); // 精確匹配已知敏感變數 for (const value of sensitiveValues) { if (value && value.length > 5) { redacted = redacted.split(value).join('***'); } } // 針對特定模式遮罩 return redacted .replace(/(authorization\s*[:=]\s*)\S+/gi, '$1***') .replace(/((?:api[_-]?key|token|password|secret|bearer)\s*[:=]\s*)\S+/gi, '$1***') .replace(/(https?:\/\/)[^\s/:@]+:[^\s/@]+@/gi, '$1***:***@') .replace(/\bgh[pousr]_[A-Za-z0-9]{16,}\b/g, '***') .trim(); } ```
Author
Owner

🔵 建議|🧰 Leo

位置src/index.js 第 45–285 行

問題描述

程式碼中的註解(如 // ── 步驟 2:延後執行 ──)與日誌輸出(如 log('步驟3', ...)、log('步驟8', ...))強烈耦合了具體的數字編號。在此次變更中,因為步驟 2 被延後執行,導致後續所有步驟編號都必須在程式碼多處同步手動修改。這種硬編碼的步驟序號極易在未來的重構中遺漏修改,導致日誌順序編號與實際執行的步驟脫節,造成六個月後的自己除錯困難。

修改建議

建議移除日誌中寫死的數字步驟編號,改用描述性的階段名稱(例如 [DETECT_TOOL], [LOAD_DIFF], [SAVE_FINDINGS])來作為日誌範疇(Scope)標記,既保留流程脈絡,又不會引入多處同步修改的維護成本。

建議寫法

// 修改前
log('步驟3', 'ERR', '找不到可用的 AI 工具(antigravity/codex/claude)。');
// 修改後
log('DETECT_TOOL', 'ERR', '找不到可用的 AI 工具(antigravity/codex/claude)。');
<!-- ai-code-review --> ### 🔵 建議|🧰 Leo **位置**:`src/index.js` 第 45–285 行 **問題描述** 程式碼中的註解(如 // ── 步驟 2:延後執行 ──)與日誌輸出(如 log('步驟3', ...)、log('步驟8', ...))強烈耦合了具體的數字編號。在此次變更中,因為步驟 2 被延後執行,導致後續所有步驟編號都必須在程式碼多處同步手動修改。這種硬編碼的步驟序號極易在未來的重構中遺漏修改,導致日誌順序編號與實際執行的步驟脫節,造成六個月後的自己除錯困難。 **修改建議** 建議移除日誌中寫死的數字步驟編號,改用描述性的階段名稱(例如 [DETECT_TOOL], [LOAD_DIFF], [SAVE_FINDINGS])來作為日誌範疇(Scope)標記,既保留流程脈絡,又不會引入多處同步修改的維護成本。 **建議寫法** ``` // 修改前 log('步驟3', 'ERR', '找不到可用的 AI 工具(antigravity/codex/claude)。'); // 修改後 log('DETECT_TOOL', 'ERR', '找不到可用的 AI 工具(antigravity/codex/claude)。'); ```
Author
Owner

🔵 建議|🎼 Bard

位置src/index.js 第 308–368 行

問題描述

新增或修改的步驟分隔註解(如步驟 8 分組、步驟 2 延後、步驟 9、步驟 10、及建問題模式收束)其尾隨的水平分隔線(─)長度不一或僅存單一字元,破壞了專案既有程式碼中整齊劃一的長分隔線視覺排版,視覺上顯得雜亂、走調。

修改建議

補足尾隨的水平線 ─,使其與鄰近步驟分隔註解的長度(約 70~80 字元寬度)與視覺風格保持一致,維持排版的美觀。

建議寫法

// ── 步驟 8(分組):依嚴重等級分組(嚴重/警告+建議),組內已依檔案與行數排序 ────────────────
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/index.js` 第 308–368 行 **問題描述** 新增或修改的步驟分隔註解(如步驟 8 分組、步驟 2 延後、步驟 9、步驟 10、及建問題模式收束)其尾隨的水平分隔線(─)長度不一或僅存單一字元,破壞了專案既有程式碼中整齊劃一的長分隔線視覺排版,視覺上顯得雜亂、走調。 **修改建議** 補足尾隨的水平線 ─,使其與鄰近步驟分隔註解的長度(約 70~80 字元寬度)與視覺風格保持一致,維持排版的美觀。 **建議寫法** ``` // ── 步驟 8(分組):依嚴重等級分組(嚴重/警告+建議),組內已依檔案與行數排序 ──────────────── ```
Author
Owner

🔵 建議| Rogue

位置src/index.js 第 366–382 行

問題描述

在建問題模式收束時,先 await gitea.createIssueCommentawait gitea.addIssueDependency,這兩個 Gitea API 呼叫是獨立且無資料相依性的,卻以序列(Sequential)方式執行,白白浪費了一次網路往返(RTT)的等待時間。

修改建議

使用 Promise.all 同時發起這兩個請求,並行處理以減少整體 execution 的等待時間。

建議寫法

const commentPromise = gitea.createIssueComment(
      ctx,
      templates.issueLinkComment({
        issueNumber: issue.number,
        issueUrl: issue.html_url,
        severeCount: severe.length,
        otherCount: others.length,
      })
    );
    const dependencyPromise = gitea.addIssueDependency(ctx, ctx.prNumber, issue.number)
      .then(() => log('建問題', 'INF', `已將 PR #${ctx.prNumber} 設為相依於 issue #${issue.number}。`))
      .catch((err) => log('建問題', 'WRN', `設定 PR 相依失敗:${err.message}。`));
    
    await Promise.all([commentPromise, dependencyPromise]);
<!-- ai-code-review --> ### 🔵 建議|⚡ Rogue **位置**:`src/index.js` 第 366–382 行 **問題描述** 在建問題模式收束時,先 `await gitea.createIssueComment` 再 `await gitea.addIssueDependency`,這兩個 Gitea API 呼叫是獨立且無資料相依性的,卻以序列(Sequential)方式執行,白白浪費了一次網路往返(RTT)的等待時間。 **修改建議** 使用 `Promise.all` 同時發起這兩個請求,並行處理以減少整體 execution 的等待時間。 **建議寫法** ``` const commentPromise = gitea.createIssueComment( ctx, templates.issueLinkComment({ issueNumber: issue.number, issueUrl: issue.html_url, severeCount: severe.length, otherCount: others.length, }) ); const dependencyPromise = gitea.addIssueDependency(ctx, ctx.prNumber, issue.number) .then(() => log('建問題', 'INF', `已將 PR #${ctx.prNumber} 設為相依於 issue #${issue.number}。`)) .catch((err) => log('建問題', 'WRN', `設定 PR 相依失敗:${err.message}。`)); await Promise.all([commentPromise, dependencyPromise]); ```
Author
Owner

🔵 建議|🎼 Bard

位置src/lib/review.js 第 33–34 行

問題描述

在 redactSecrets 函式中,針對 authorization 以及其他憑證關鍵字(如 token、secret、password 等)的敏感資訊遮蔽,分別使用了兩條結構極為相似的正規表示式進行替換。這造成了重複的替換邏輯與額外的處理開銷,程式碼的旋律顯得不夠俐落。

修改建議

建議將這兩條正規表示式合併為單一表達式,消除重複的 replace 呼叫,使程式碼更加簡潔優雅且提升運行效率。

建議寫法

.replace(/((?:authorization|api[_-]?key|token|password|secret|bearer)\s*[:=]\s*)\S+/gi, '$1***')
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/lib/review.js` 第 33–34 行 **問題描述** 在 redactSecrets 函式中,針對 authorization 以及其他憑證關鍵字(如 token、secret、password 等)的敏感資訊遮蔽,分別使用了兩條結構極為相似的正規表示式進行替換。這造成了重複的替換邏輯與額外的處理開銷,程式碼的旋律顯得不夠俐落。 **修改建議** 建議將這兩條正規表示式合併為單一表達式,消除重複的 replace 呼叫,使程式碼更加簡潔優雅且提升運行效率。 **建議寫法** ``` .replace(/((?:authorization|api[_-]?key|token|password|secret|bearer)\s*[:=]\s*)\S+/gi, '$1***') ```
Author
Owner

🔵 建議| Rogue

位置src/lib/review.js 第 48–53 行

問題描述

agentFailureDetail 之中,進行 stderr 與 stdout 的遮罩處理時,是先截斷至 2,000 字元,然後執行多次複雜的 redactSecrets 正規表示式替換,最後再截斷至 500 字元輸出。這會造成 1,500 字元的複雜 regex 運算結果在下一步被直接丟棄,白白浪費了 CPU 進行字串比對與取代的週期。

修改建議

應在呼叫 redactSecrets 之前,就先將字串截斷至目標長度(500 字元),再進行遮罩,可大幅減少 regex 運算負擔。

建議寫法

const stderr = redactSecrets(String((res && res.stderr) || '').slice(0, 500));
  if (stderr) parts.push(`stderr:${stderr}`);
  const stdout = redactSecrets(String((res && res.output) || '').slice(0, 500));
  if (stdout) parts.push(`stdout:${stdout}`);
<!-- ai-code-review --> ### 🔵 建議|⚡ Rogue **位置**:`src/lib/review.js` 第 48–53 行 **問題描述** 在 `agentFailureDetail` 之中,進行 stderr 與 stdout 的遮罩處理時,是先截斷至 2,000 字元,然後執行多次複雜的 `redactSecrets` 正規表示式替換,最後再截斷至 500 字元輸出。這會造成 1,500 字元的複雜 regex 運算結果在下一步被直接丟棄,白白浪費了 CPU 進行字串比對與取代的週期。 **修改建議** 應在呼叫 `redactSecrets` 之前,就先將字串截斷至目標長度(500 字元),再進行遮罩,可大幅減少 regex 運算負擔。 **建議寫法** ``` const stderr = redactSecrets(String((res && res.stderr) || '').slice(0, 500)); if (stderr) parts.push(`stderr:${stderr}`); const stdout = redactSecrets(String((res && res.output) || '').slice(0, 500)); if (stdout) parts.push(`stdout:${stdout}`); ```
Author
Owner

🔵 建議|🎼 Bard

位置src/lib/templates.js 第 335–337 行

問題描述

issueFindingComment 函式的 @remarks 文件註解中,說明其使用情境為『建問題模式下 review.postSevereToIssue 把每條嚴重 finding... 作為問題明細的追蹤紀錄』。然而實際上,非嚴重的警告與建議(others)也會透過 review.postOthersToIssue 呼叫此模板進行發布,導致文件描述不夠完整。

修改建議

修正 @remarks 的使用情境說明,將 postOthersToIssue 亦併入描述中,使 JSDoc 文件能如實且精準地反映實際程式碼的呼叫情境。

建議寫法

* 使用情境:建問題模式下 `review.postSevereToIssue` 與 `review.postOthersToIssue`(src/lib/review.js)把保留的各級問題明細\n * 以本函式產生留言內容、經 `gitea.createCommentOnIssue` 發布到追蹤 issue 上,\n * 作為問題明細的追蹤紀錄。
<!-- ai-code-review --> ### 🔵 建議|🎼 Bard **位置**:`src/lib/templates.js` 第 335–337 行 **問題描述** issueFindingComment 函式的 @remarks 文件註解中,說明其使用情境為『建問題模式下 review.postSevereToIssue 把每條嚴重 finding... 作為問題明細的追蹤紀錄』。然而實際上,非嚴重的警告與建議(others)也會透過 review.postOthersToIssue 呼叫此模板進行發布,導致文件描述不夠完整。 **修改建議** 修正 @remarks 的使用情境說明,將 postOthersToIssue 亦併入描述中,使 JSDoc 文件能如實且精準地反映實際程式碼的呼叫情境。 **建議寫法** ``` * 使用情境:建問題模式下 `review.postSevereToIssue` 與 `review.postOthersToIssue`(src/lib/review.js)把保留的各級問題明細\n * 以本函式產生留言內容、經 `gitea.createCommentOnIssue` 發布到追蹤 issue 上,\n * 作為問題明細的追蹤紀錄。 ```
Member

🧩 code-review-resolve 處理進度

本議題為 AI Code Review 建問題模式的追蹤議題。以 --issue all 併同 .gitea/ai-review/findings/ 逐條處理後結果如下(對照目前程式碼與 exclusions.json):

# 等級 審查員 位置 處理結果 說明
1 🔴 嚴重 Rogue src/index.js 第 216–218 行 ⏭️待人工 issueBuffer 串行 await 屬效能取捨,skill 規範不得硬改,待人工評估。
2 🔴 嚴重 Assassin src/lib/review.js 第 23–23 行 🚫誤報 redactSecrets 遮罩 Authorization 不足致 token 外洩的安全疑慮已列入 exclusions 裁決為誤報。
3 🔴 嚴重 Assassin src/lib/review.js 第 25–25 行 🚫誤報 redactSecrets URL 內嵌帳密遮罩不足的安全疑慮已列入 exclusions 裁決為誤報。
4 🟠 警告 Leo src/index.js 第 186–225 行 🚫誤報 「main() 內閉包應抽出成模組私有 publisher」已列入 exclusions 裁決為誤報。
5 🟠 警告 Rogue src/lib/gitrepo.js 第 134–134 行 ⏭️待人工 以 rev-parse 子行程判斷淺層 repo 的成本屬效能取捨,不得硬改,待人工評估。
6 🟠 警告 Rogue src/lib/gitrepo.js 第 134–143 行 已解決 現行程式碼已改為 deepen base/PR HEAD 優先、--unshallow 僅在仍失敗且淺層時當最後手段。
7 🟠 警告 Leo src/lib/gitrepo.js 第 293–305 行 ⏭️待人工 pushWithCredential 刻意改拋固定訊息以免回顯 token/URL,屬安全設計取捨,待人工評估。
8 🟠 警告 Assassin src/lib/gitrepo.js 第 299–299 行 ⏭️待人工 GIT_CONFIG scope 須對齊 checkout 持久化的 extraheader 才能重置自動 token,屬安全邊界,待人工研判。
9 🟠 警告 Leo src/lib/review.js 第 28–38 行 🚫誤報 redactSecrets 40 碼長度遮罩過寬(抹除 SHA)的疑慮已列入 exclusions 裁決為誤報。
10 🔵 建議 Leo src/index.js 第 45–285 行 🚫誤報 步驟編號硬編碼/步驟 2 延後造成閱讀與同步負擔已列入 exclusions 裁決為誤報。
11 🔵 建議 Bard src/index.js 第 308–368 行 ⏭️待人工 分隔線長度一致性屬純排版風格慣例取捨,skill 規範不得硬改,待人工評估。
12 🔵 建議 Rogue src/index.js 第 366–382 行 ⏭️待人工 createIssueComment 與 addIssueDependency 可並行化屬效能取捨,待人工評估。
13 🔵 建議 Bard src/lib/review.js 第 33–34 行 ⏭️待人工 合併兩條相似 regex 屬風格/微效能建議,非誤報亦未修,待人工評估。
14 🔵 建議 Rogue src/lib/review.js 第 48–53 行 ⏭️待人工 agentFailureDetail 先截 2000 再遮罩為刻意設計(避免漏抓跨界機密),屬效能取捨,待人工評估。
15 🔵 建議 Bard src/lib/templates.js 第 335–337 行 ⏭️待人工 issueFindingComment 的 @remarks 用途描述過窄屬 JSDoc 風格取捨,待人工評估。

小計 已解決 1 條、🚫 誤報(已列入 exclusions)5 條、⏭️ 待人工處理 9 條。

⏭️ 待人工處理項目屬設計/效能/慣例取捨(skill 規範不得硬改),已將「只來自議題」的待人工問題(依主題去重)寫回 .gitea/ai-review/findings/2026-07-20-18:31:07.json 追蹤,關閉本議題不會遺失待辦。

  • 已解決:問題於目前程式碼已修復(如 resolveMergeBase 補抓策略調整、deepen PR HEAD 改用 head SHA、留言閉包改名、push-token input 移除等)。
  • 🚫 誤報:與 .gitea/ai-review/exclusions.json 既有裁決等價,不重複新增排除條目。

處理完成,依 code-review-resolve 流程關閉本議題。

<!-- code-review-resolve --> ## 🧩 code-review-resolve 處理進度 本議題為 AI Code Review 建問題模式的追蹤議題。以 `--issue all` 併同 `.gitea/ai-review/findings/` 逐條處理後結果如下(對照目前程式碼與 `exclusions.json`): | # | 等級 | 審查員 | 位置 | 處理結果 | 說明 | | --- | --- | --- | --- | --- | --- | | 1 | 🔴 嚴重 | Rogue | `src/index.js` 第 216–218 行 | ⏭️待人工 | issueBuffer 串行 await 屬效能取捨,skill 規範不得硬改,待人工評估。 | | 2 | 🔴 嚴重 | Assassin | `src/lib/review.js` 第 23–23 行 | 🚫誤報 | redactSecrets 遮罩 Authorization 不足致 token 外洩的安全疑慮已列入 exclusions 裁決為誤報。 | | 3 | 🔴 嚴重 | Assassin | `src/lib/review.js` 第 25–25 行 | 🚫誤報 | redactSecrets URL 內嵌帳密遮罩不足的安全疑慮已列入 exclusions 裁決為誤報。 | | 4 | 🟠 警告 | Leo | `src/index.js` 第 186–225 行 | 🚫誤報 | 「main() 內閉包應抽出成模組私有 publisher」已列入 exclusions 裁決為誤報。 | | 5 | 🟠 警告 | Rogue | `src/lib/gitrepo.js` 第 134–134 行 | ⏭️待人工 | 以 rev-parse 子行程判斷淺層 repo 的成本屬效能取捨,不得硬改,待人工評估。 | | 6 | 🟠 警告 | Rogue | `src/lib/gitrepo.js` 第 134–143 行 | ✅已解決 | 現行程式碼已改為 deepen base/PR HEAD 優先、--unshallow 僅在仍失敗且淺層時當最後手段。 | | 7 | 🟠 警告 | Leo | `src/lib/gitrepo.js` 第 293–305 行 | ⏭️待人工 | pushWithCredential 刻意改拋固定訊息以免回顯 token/URL,屬安全設計取捨,待人工評估。 | | 8 | 🟠 警告 | Assassin | `src/lib/gitrepo.js` 第 299–299 行 | ⏭️待人工 | GIT_CONFIG scope 須對齊 checkout 持久化的 extraheader 才能重置自動 token,屬安全邊界,待人工研判。 | | 9 | 🟠 警告 | Leo | `src/lib/review.js` 第 28–38 行 | 🚫誤報 | redactSecrets 40 碼長度遮罩過寬(抹除 SHA)的疑慮已列入 exclusions 裁決為誤報。 | | 10 | 🔵 建議 | Leo | `src/index.js` 第 45–285 行 | 🚫誤報 | 步驟編號硬編碼/步驟 2 延後造成閱讀與同步負擔已列入 exclusions 裁決為誤報。 | | 11 | 🔵 建議 | Bard | `src/index.js` 第 308–368 行 | ⏭️待人工 | 分隔線長度一致性屬純排版風格慣例取捨,skill 規範不得硬改,待人工評估。 | | 12 | 🔵 建議 | Rogue | `src/index.js` 第 366–382 行 | ⏭️待人工 | createIssueComment 與 addIssueDependency 可並行化屬效能取捨,待人工評估。 | | 13 | 🔵 建議 | Bard | `src/lib/review.js` 第 33–34 行 | ⏭️待人工 | 合併兩條相似 regex 屬風格/微效能建議,非誤報亦未修,待人工評估。 | | 14 | 🔵 建議 | Rogue | `src/lib/review.js` 第 48–53 行 | ⏭️待人工 | agentFailureDetail 先截 2000 再遮罩為刻意設計(避免漏抓跨界機密),屬效能取捨,待人工評估。 | | 15 | 🔵 建議 | Bard | `src/lib/templates.js` 第 335–337 行 | ⏭️待人工 | issueFindingComment 的 @remarks 用途描述過窄屬 JSDoc 風格取捨,待人工評估。 | **小計**:✅ 已解決 1 條、🚫 誤報(已列入 exclusions)5 條、⏭️ 待人工處理 9 條。 > ⏭️ 待人工處理項目屬設計/效能/慣例取捨(skill 規範不得硬改),已將「只來自議題」的待人工問題(依主題去重)寫回 `.gitea/ai-review/findings/2026-07-20-18:31:07.json` 追蹤,關閉本議題不會遺失待辦。 - ✅ 已解決:問題於目前程式碼已修復(如 `resolveMergeBase` 補抓策略調整、`deepen PR HEAD` 改用 head SHA、留言閉包改名、`push-token` input 移除等)。 - 🚫 誤報:與 `.gitea/ai-review/exclusions.json` 既有裁決等價,不重複新增排除條目。 處理完成,依 code-review-resolve 流程關閉本議題。
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Reference: node-actions/ai-code-review#14