From 43e990cb30e1cbffd24d53fdc9fc8c30fa05c80a Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 02:53:19 +0000 Subject: [PATCH 01/23] fix: update workflow section in README for clarity and correct numbering --- README.md | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0dacb5e..cab6fc2 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ 2. 在 `.gitea/workflows` 資料夾中建立 `ai-review.yaml' 3. 在 `ai-review.yaml` 中填入以下內容(選擇一個使用): -### 1. OpenAI(OpenRouter) +### 1. OpenAI ```yaml name: AI on: @@ -42,9 +42,29 @@ jobs: - name: AI Code Review uses: https://gitea.jsc.idv.tw/jiantw83/code-review@${{ vars.ACTION_CODE_REVIEW_VERSION }} with: - # Github (h3285@evertrust.com.tw) - # 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 OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPENAI_BASE_URL: https://api.openai.com/v1 + permissions: + contents: write + pull-requests: write + issues: write +``` + +### 2. OpenRouter +```yaml +name: AI +on: + pull_request: + types: [opened, synchronize] +jobs: + code-review: + name: 'Code Review' + runs-on: ubuntu + steps: + - name: AI Code Review + uses: https://gitea.jsc.idv.tw/jiantw83/code-review@${{ vars.ACTION_CODE_REVIEW_VERSION }} + with: + OPENAI_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} OPENAI_BASE_URL: https://openrouter.ai/api/v1 permissions: contents: write @@ -52,7 +72,7 @@ jobs: issues: write ``` -### 2. Anthropic Claude +### 3. Anthropic Claude ```yaml name: AI on: @@ -74,7 +94,7 @@ jobs: issues: write ``` -### 3. Google Gemini +### 4. Google Gemini ```yaml name: AI on: @@ -96,7 +116,7 @@ jobs: issues: write ``` -### 4. Amazon Q +### 5. Amazon Q ```yaml name: AI on: @@ -118,7 +138,7 @@ jobs: issues: write ``` -### 5. SonarQube +### 6. SonarQube ```yaml name: AI on: From fd91ed4e5a2ba5a0f9814d0f41e526cc1921828e Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 02:54:27 +0000 Subject: [PATCH 02/23] fix: update OPENAI_BASE_URL to use the correct API endpoint --- .gitea/workflows/review.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/review.yaml b/.gitea/workflows/review.yaml index dc785d9..7d4b90c 100644 --- a/.gitea/workflows/review.yaml +++ b/.gitea/workflows/review.yaml @@ -34,7 +34,7 @@ jobs: uses: https://gitea.jsc.idv.tw/jiantw83/code-review@v${{ needs.version.outputs.version }} with: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - OPENAI_BASE_URL: https://openrouter.ai/api/v1 + OPENAI_BASE_URL: https://api.openai.com/v1 permissions: contents: write pull-requests: write From 774b78d84e00964f8fca92993546f9fc340c64d0 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 02:56:34 +0000 Subject: [PATCH 03/23] fix: update AI Code Review to use GEMINI API and base URL --- .gitea/workflows/review.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/review.yaml b/.gitea/workflows/review.yaml index 7d4b90c..cd59e98 100644 --- a/.gitea/workflows/review.yaml +++ b/.gitea/workflows/review.yaml @@ -33,8 +33,8 @@ jobs: - name: AI Code Review uses: https://gitea.jsc.idv.tw/jiantw83/code-review@v${{ needs.version.outputs.version }} with: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - OPENAI_BASE_URL: https://api.openai.com/v1 + GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} + GEMINI_BASE_URL: https://generativelanguage.googleapis.com/v1beta permissions: contents: write pull-requests: write From c2e56e4bb24b0f4ccf7267cd572e97c9c3d83ca0 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 02:59:22 +0000 Subject: [PATCH 04/23] fix: update GEMINI model version in configuration and workflows --- .gitea/workflows/review.yaml | 1 + README.md | 1 + app/config.js | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/review.yaml b/.gitea/workflows/review.yaml index cd59e98..408bd6c 100644 --- a/.gitea/workflows/review.yaml +++ b/.gitea/workflows/review.yaml @@ -35,6 +35,7 @@ jobs: with: GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} GEMINI_BASE_URL: https://generativelanguage.googleapis.com/v1beta + GEMINI_MODEL: ${{ vars.GEMINI_MODEL }} permissions: contents: write pull-requests: write diff --git a/README.md b/README.md index cab6fc2..9574270 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ jobs: with: GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} GEMINI_BASE_URL: https://generativelanguage.googleapis.com/v1beta + GEMINI_MODEL: ${{ vars.GEMINI_MODEL }} permissions: contents: write pull-requests: write diff --git a/app/config.js b/app/config.js index c5e7caa..4a5fc7b 100644 --- a/app/config.js +++ b/app/config.js @@ -12,7 +12,7 @@ export function getLLMConfig() { const checks = [ ['openai', process.env.OPENAI_API_KEY, process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1', process.env.OPENAI_MODEL || 'gpt-4o-mini'], ['claude', process.env.CLAUDE_API_KEY, process.env.CLAUDE_BASE_URL || 'https://api.anthropic.com/v1', process.env.CLAUDE_MODEL || 'claude-3-haiku-20240307'], - ['gemini', process.env.GEMINI_API_KEY, process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta', process.env.GEMINI_MODEL || 'gemini-1.5-flash'], + ['gemini', process.env.GEMINI_API_KEY, process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta', process.env.GEMINI_MODEL || 'gemini-2.5-flash'], ['ollama', 'ollama', process.env.OLLAMA_BASE_URL, process.env.OLLAMA_MODEL], ['amazonq', process.env.AMAZONQ_API_KEY, process.env.AMAZONQ_BASE_URL || 'https://q.api.aws', process.env.OPENAI_MODEL || 'amazon-q'], ['kilo', process.env.KILO_API_KEY, process.env.KILO_BASE_URL || 'https://api.kilocode.com/v1', process.env.OPENAI_MODEL || 'kilo-default'], From f8e24844e8b88386221f6975f324ccaf04de1833 Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 03:01:32 +0000 Subject: [PATCH 05/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 52 +++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 0637a08..2174917 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1 +1,51 @@ -[] \ No newline at end of file +[ + { + "level": "warning", + "role": "Leo", + "location": "README.md:50", + "suggestion": "在 `2. OpenRouter` 的範例中,`with:` 區塊使用 `OPENAI_API_KEY` 參數來傳遞 `OPENROUTER_API_KEY` secret。雖然這可能是 `code-review` action 的設計,但 `OPENAI_API_KEY` 這個名稱可能會讓使用者誤解為只能用於 OpenAI。建議考慮在 `code-review` action 中提供更通用的 API key 參數(例如 `API_KEY` 或 `PROVIDER_API_KEY`),或針對 OpenRouter 提供專屬的參數(例如 `OPENROUTER_API_KEY`),以提高清晰度並減少使用者設定時的困惑。如果 action 無法修改,目前的說明已盡力澄清,但仍是一個潛在的混淆點。", + "is_new": true + }, + { + "level": "warning", + "role": "Zara", + "location": "app/config.js:15", + "suggestion": "將預設的 Gemini 模型從 `gemini-1.5-flash` 更新為 `gemini-2.5-flash`,這可能影響應用程式與 LLM 互動的效能和成本。建議在部署前,對 `gemini-2.5-flash` 模型進行詳細的效能基準測試,評估其在回應時間、處理速度、準確性及成本效益方面的表現,確保其符合應用程式的特定需求,並避免潛在的效能退化或不必要的成本增加。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": ".gitea/workflows/review.yaml:33-40", + "suggestion": "工作流程中授予了 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。特別是 `contents: write` 權限,若工作流程或其使用的 Action 存在漏洞,可能導致程式碼庫被惡意修改。建議審查這些權限是否都絕對必要,並遵循最小權限原則,僅授予工作流程執行所需的最少權限。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "app/config.js:15", + "suggestion": "在 `app/config.js` 的 `checks` 陣列中,使用多個空格進行欄位對齊可能導致格式不一致且難以維護。建議改用單一空格分隔元素,或考慮將每個配置項重構為物件形式,以提升程式碼的可讀性與可維護性。", + "is_new": true + }, + { + "level": "warning", + "role": "Maya", + "location": ".gitea/workflows/review.yaml", + "suggestion": "工作流程已從使用 OpenAI 轉換為 Gemini。雖然這是一個配置變更,但應確保新的 LLM 整合能正常運作。建議在 CI/CD 中增加一個整合測試步驟,以驗證使用 Gemini 模型時,AI Code Review 功能是否能成功生成評論,例如檢查 PR 評論是否存在或特定輸出訊息。", + "is_new": true + }, + { + "level": "warning", + "role": "Maya", + "location": "app/config.js:15", + "suggestion": "預設的 `GEMINI_MODEL` 已從 `gemini-1.5-flash` 變更為 `gemini-2.5-flash`。請確保有對應的單元測試來驗證當 `process.env.GEMINI_MODEL` 未設定時,`getLLMConfig` 函數能正確回傳新的預設模型 `gemini-2.5-flash`。", + "is_new": true + }, + { + "level": "info", + "role": "Maya", + "location": "app/config.js", + "suggestion": "`getLLMConfig` 函數依賴於環境變數來配置 LLM。建議為此函數增加更全面的邊界條件測試,例如:\n1. 當只有部分 LLM 相關的環境變數被設定時(例如,只有 `GEMINI_API_KEY` 而沒有 `GEMINI_BASE_URL`)。\n2. 當沒有任何 LLM 相關的環境變數被設定時,確保函數能優雅地處理(例如,回傳 `null`、空物件或拋出特定錯誤)。\n3. 測試 API 金鑰為空字串的情況,確保其行為符合預期。", + "is_new": true + } +] \ No newline at end of file From 4b382b4183d5f15c527f65e606630c1040463436 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:04:12 +0000 Subject: [PATCH 06/23] fix: update README for OpenRouter API compatibility and add tests for LLM configuration --- README.md | 2 +- app/config.js | 12 +++--- app/config.test.js | 101 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 app/config.test.js diff --git a/README.md b/README.md index 9574270..9af31e9 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ jobs: - name: AI Code Review uses: https://gitea.jsc.idv.tw/jiantw83/code-review@${{ vars.ACTION_CODE_REVIEW_VERSION }} with: - OPENAI_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入 OPENAI_BASE_URL: https://openrouter.ai/api/v1 permissions: contents: write diff --git a/app/config.js b/app/config.js index 4a5fc7b..d852576 100644 --- a/app/config.js +++ b/app/config.js @@ -14,12 +14,12 @@ export function getLLMConfig() { ['claude', process.env.CLAUDE_API_KEY, process.env.CLAUDE_BASE_URL || 'https://api.anthropic.com/v1', process.env.CLAUDE_MODEL || 'claude-3-haiku-20240307'], ['gemini', process.env.GEMINI_API_KEY, process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta', process.env.GEMINI_MODEL || 'gemini-2.5-flash'], ['ollama', 'ollama', process.env.OLLAMA_BASE_URL, process.env.OLLAMA_MODEL], - ['amazonq', process.env.AMAZONQ_API_KEY, process.env.AMAZONQ_BASE_URL || 'https://q.api.aws', process.env.OPENAI_MODEL || 'amazon-q'], - ['kilo', process.env.KILO_API_KEY, process.env.KILO_BASE_URL || 'https://api.kilocode.com/v1', process.env.OPENAI_MODEL || 'kilo-default'], - ['roo', process.env.ROO_API_KEY, process.env.ROO_BASE_URL || 'https://api.roocode.com/v1', process.env.OPENAI_MODEL || 'roo-default'], - ['cline', process.env.CLINE_API_KEY, process.env.CLINE_BASE_URL || 'https://api.cline.dev/v1', process.env.OPENAI_MODEL || 'cline-default'], - ['continue', process.env.CONTINUE_API_KEY, process.env.CONTINUE_BASE_URL || 'https://api.continue.dev/v1', process.env.OPENAI_MODEL || 'continue-default'], - ['kade', process.env.KADE_API_KEY, process.env.KADE_BASE_URL || 'https://api.kade.dev/v1', process.env.OPENAI_MODEL || 'kade-default'], + ['amazonq', process.env.AMAZONQ_API_KEY, process.env.AMAZONQ_BASE_URL || 'https://q.api.aws', process.env.AMAZONQ_MODEL || 'amazon-q'], + ['kilo', process.env.KILO_API_KEY, process.env.KILO_BASE_URL || 'https://api.kilocode.com/v1', process.env.KILO_MODEL || 'kilo-default'], + ['roo', process.env.ROO_API_KEY, process.env.ROO_BASE_URL || 'https://api.roocode.com/v1', process.env.ROO_MODEL || 'roo-default'], + ['cline', process.env.CLINE_API_KEY, process.env.CLINE_BASE_URL || 'https://api.cline.dev/v1', process.env.CLINE_MODEL || 'cline-default'], + ['continue', process.env.CONTINUE_API_KEY, process.env.CONTINUE_BASE_URL || 'https://api.continue.dev/v1', process.env.CONTINUE_MODEL || 'continue-default'], + ['kade', process.env.KADE_API_KEY, process.env.KADE_BASE_URL || 'https://api.kade.dev/v1', process.env.KADE_MODEL || 'kade-default'], ]; for (const [provider, key, baseURL, model] of checks) { if (key && baseURL) return { provider, apiKey: key, baseURL, model }; diff --git a/app/config.test.js b/app/config.test.js new file mode 100644 index 0000000..b757cec --- /dev/null +++ b/app/config.test.js @@ -0,0 +1,101 @@ +import { describe, it, beforeEach, afterEach } from 'node:test'; +import assert from 'node:assert/strict'; +import { getLLMConfig } from './config.js'; + +const ENV_KEYS = [ + 'OPENAI_API_KEY', 'OPENAI_BASE_URL', 'OPENAI_MODEL', + 'CLAUDE_API_KEY', 'CLAUDE_BASE_URL', 'CLAUDE_MODEL', + 'GEMINI_API_KEY', 'GEMINI_BASE_URL', 'GEMINI_MODEL', + 'OLLAMA_BASE_URL', 'OLLAMA_MODEL', + 'AMAZONQ_API_KEY', 'AMAZONQ_BASE_URL', 'AMAZONQ_MODEL', +]; + +let saved = {}; +beforeEach(() => { + saved = {}; + for (const k of ENV_KEYS) { saved[k] = process.env[k]; delete process.env[k]; } +}); +afterEach(() => { + for (const k of ENV_KEYS) { + if (saved[k] === undefined) delete process.env[k]; + else process.env[k] = saved[k]; + } +}); + +describe('getLLMConfig', () => { + it('returns null provider when no env vars set', () => { + const cfg = getLLMConfig(); + assert.equal(cfg.provider, null); + assert.equal(cfg.apiKey, null); + }); + + it('detects openai with defaults', () => { + process.env.OPENAI_API_KEY = 'sk-test'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'openai'); + assert.equal(cfg.apiKey, 'sk-test'); + assert.equal(cfg.baseURL, 'https://api.openai.com/v1'); + assert.equal(cfg.model, 'gpt-4o-mini'); + }); + + it('detects openai with custom base url and model', () => { + process.env.OPENAI_API_KEY = 'sk-test'; + process.env.OPENAI_BASE_URL = 'https://openrouter.ai/api/v1'; + process.env.OPENAI_MODEL = 'gpt-4o'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'openai'); + assert.equal(cfg.baseURL, 'https://openrouter.ai/api/v1'); + assert.equal(cfg.model, 'gpt-4o'); + }); + + it('detects gemini with defaults', () => { + process.env.GEMINI_API_KEY = 'gemini-key'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'gemini'); + assert.equal(cfg.model, 'gemini-2.5-flash'); + }); + + it('detects gemini with custom model', () => { + process.env.GEMINI_API_KEY = 'gemini-key'; + process.env.GEMINI_MODEL = 'gemini-2.0-flash'; + const cfg = getLLMConfig(); + assert.equal(cfg.model, 'gemini-2.0-flash'); + }); + + it('detects claude with defaults', () => { + process.env.CLAUDE_API_KEY = 'claude-key'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'claude'); + assert.equal(cfg.model, 'claude-3-haiku-20240307'); + }); + + it('detects amazonq with its own model env', () => { + process.env.AMAZONQ_API_KEY = 'aq-key'; + process.env.AMAZONQ_MODEL = 'my-amazon-model'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'amazonq'); + assert.equal(cfg.model, 'my-amazon-model'); + }); + + it('openai takes priority over gemini when both set', () => { + process.env.OPENAI_API_KEY = 'sk-test'; + process.env.GEMINI_API_KEY = 'gemini-key'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'openai'); + }); + + it('empty string api key is treated as not set', () => { + process.env.OPENAI_API_KEY = ''; + process.env.GEMINI_API_KEY = 'gemini-key'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'gemini'); + }); + + it('detects ollama without api key', () => { + process.env.OLLAMA_BASE_URL = 'http://localhost:11434'; + process.env.OLLAMA_MODEL = 'llama3'; + const cfg = getLLMConfig(); + assert.equal(cfg.provider, 'ollama'); + assert.equal(cfg.model, 'llama3'); + }); +}); From d73d360051aeb5d19a827c6b5d256728154fc5b6 Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 03:07:13 +0000 Subject: [PATCH 07/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 59 +++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 2174917..7f518a5 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,51 +1,58 @@ [ + { + "level": "critical", + "role": "Rex", + "location": ".gitea/workflows/review.yaml:41-44", + "suggestion": "工作流程 `AI Code Review` 被授予了 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。特別是 `contents: write` 權限,若工作流程所使用的 Action (`code-review`) 存在漏洞,可能導致程式碼庫被惡意修改,構成嚴重的安全風險。建議遵循最小權限原則,審查並僅授予工作流程執行所需的最少權限。例如,若僅需讀取程式碼和發布評論,則 `contents: read` 和 `pull-requests: write` 可能已足夠,而 `issues: write` 則可能完全不需要。", + "is_new": true + }, + { + "level": "critical", + "role": "Rex", + "location": "README.md", + "suggestion": "`README.md` 中的 Gitea Actions 工作流程範例(特別是 OpenRouter 和 Google Gemini 部分)建議使用者配置 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。這會引導使用者建立具有過高權限的工作流程,若所使用的 Action 存在漏洞,可能導致程式碼庫被惡意修改。建議更新所有範例,遵循最小權限原則,僅建議授予工作流程執行所需的最少權限,例如 `contents: read` 和 `pull-requests: write`。", + "is_new": true + }, + { + "level": "critical", + "role": "Maya", + "location": "app/config.test.js", + "suggestion": "在 `app/config.js` 中,`amazonq`, `kilo`, `roo`, `cline`, `continue`, `kade` 等 LLM 供應商的模型環境變數已從 `OPENAI_MODEL` 變更為各自專屬的 `PROVIDER_MODEL` (例如 `AMAZONQ_MODEL`)。然而,`app/config.test.js` 中僅針對 `amazonq` 進行了部分測試,而 `kilo`, `roo`, `cline`, `continue`, `kade` 這些供應商完全沒有任何測試案例。這導致這些供應商的配置邏輯(包括新的模型環境變數和預設值)完全未經驗證。請為這些未測試的供應商新增完整的單元測試,確保它們的 API 金鑰、基礎 URL 和模型配置都能正確解析,並驗證當對應的環境變數未設定時,能正確使用預設模型。", + "is_new": true + }, { "level": "warning", "role": "Leo", "location": "README.md:50", "suggestion": "在 `2. OpenRouter` 的範例中,`with:` 區塊使用 `OPENAI_API_KEY` 參數來傳遞 `OPENROUTER_API_KEY` secret。雖然這可能是 `code-review` action 的設計,但 `OPENAI_API_KEY` 這個名稱可能會讓使用者誤解為只能用於 OpenAI。建議考慮在 `code-review` action 中提供更通用的 API key 參數(例如 `API_KEY` 或 `PROVIDER_API_KEY`),或針對 OpenRouter 提供專屬的參數(例如 `OPENROUTER_API_KEY`),以提高清晰度並減少使用者設定時的困惑。如果 action 無法修改,目前的說明已盡力澄清,但仍是一個潛在的混淆點。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Zara", "location": "app/config.js:15", "suggestion": "將預設的 Gemini 模型從 `gemini-1.5-flash` 更新為 `gemini-2.5-flash`,這可能影響應用程式與 LLM 互動的效能和成本。建議在部署前,對 `gemini-2.5-flash` 模型進行詳細的效能基準測試,評估其在回應時間、處理速度、準確性及成本效益方面的表現,確保其符合應用程式的特定需求,並避免潛在的效能退化或不必要的成本增加。", - "is_new": true - }, - { - "level": "warning", - "role": "Rex", - "location": ".gitea/workflows/review.yaml:33-40", - "suggestion": "工作流程中授予了 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。特別是 `contents: write` 權限,若工作流程或其使用的 Action 存在漏洞,可能導致程式碼庫被惡意修改。建議審查這些權限是否都絕對必要,並遵循最小權限原則,僅授予工作流程執行所需的最少權限。", - "is_new": true - }, - { - "level": "warning", - "role": "Aria", - "location": "app/config.js:15", - "suggestion": "在 `app/config.js` 的 `checks` 陣列中,使用多個空格進行欄位對齊可能導致格式不一致且難以維護。建議改用單一空格分隔元素,或考慮將每個配置項重構為物件形式,以提升程式碼的可讀性與可維護性。", - "is_new": true - }, - { - "level": "warning", - "role": "Maya", - "location": ".gitea/workflows/review.yaml", - "suggestion": "工作流程已從使用 OpenAI 轉換為 Gemini。雖然這是一個配置變更,但應確保新的 LLM 整合能正常運作。建議在 CI/CD 中增加一個整合測試步驟,以驗證使用 Gemini 模型時,AI Code Review 功能是否能成功生成評論,例如檢查 PR 評論是否存在或特定輸出訊息。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Maya", "location": "app/config.js:15", "suggestion": "預設的 `GEMINI_MODEL` 已從 `gemini-1.5-flash` 變更為 `gemini-2.5-flash`。請確保有對應的單元測試來驗證當 `process.env.GEMINI_MODEL` 未設定時,`getLLMConfig` 函數能正確回傳新的預設模型 `gemini-2.5-flash`。", + "is_new": false + }, + { + "level": "warning", + "role": "Leo", + "location": "app/config.js:15", + "suggestion": "目前 `checks` 陣列使用多個空格進行欄位對齊,這是一種脆弱的格式化方式,當配置項的內容長度改變時,容易導致對齊混亂,增加維護成本。建議將 `checks` 陣列中的每個 LLM 配置項重構為物件形式(例如 `{ provider: 'openai', apiKeyEnv: 'OPENAI_API_KEY', baseURL: '...', modelEnv: 'OPENAI_MODEL', defaultModel: '...' }`)。這樣可以提高程式碼的可讀性、可維護性及擴展性,並使新增或修改配置項更加清晰。", "is_new": true }, { - "level": "info", + "level": "warning", "role": "Maya", - "location": "app/config.js", - "suggestion": "`getLLMConfig` 函數依賴於環境變數來配置 LLM。建議為此函數增加更全面的邊界條件測試,例如:\n1. 當只有部分 LLM 相關的環境變數被設定時(例如,只有 `GEMINI_API_KEY` 而沒有 `GEMINI_BASE_URL`)。\n2. 當沒有任何 LLM 相關的環境變數被設定時,確保函數能優雅地處理(例如,回傳 `null`、空物件或拋出特定錯誤)。\n3. 測試 API 金鑰為空字串的情況,確保其行為符合預期。", + "location": ".gitea/workflows/review.yaml", + "suggestion": "工作流程已從使用 OpenAI 轉換為 Gemini。雖然 `app/config.test.js` 增加了 `getLLMConfig` 的單元測試,但這僅驗證了配置的解析。為了確保 AI Code Review 功能在實際使用 Gemini 模型時能正常運作,建議在 CI/CD 中增加一個整合測試步驟。此測試應能驗證使用 Gemini 模型時,AI Code Review Action 是否能成功生成 PR 評論,例如檢查 PR 評論是否存在或其內容是否符合預期,以確保端到端的整合是成功的。", "is_new": true } ] \ No newline at end of file From 66a75f135f483c3d925e1caf50a54f554e794605 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:07:09 +0000 Subject: [PATCH 08/23] refactor: remove unused API keys and configurations from action and config files --- README.md | 22 ------------------- action.yaml | 58 --------------------------------------------------- app/config.js | 5 ----- 3 files changed, 85 deletions(-) diff --git a/README.md b/README.md index 9af31e9..f388ab7 100644 --- a/README.md +++ b/README.md @@ -139,28 +139,6 @@ jobs: issues: write ``` -### 6. SonarQube -```yaml -name: AI -on: - pull_request: - types: [opened, synchronize] -jobs: - code-review: - name: 'Code Review' - runs-on: ubuntu - steps: - - name: AI Code Review - uses: https://gitea.jsc.idv.tw/jiantw83/code-review@${{ vars.ACTION_CODE_REVIEW_VERSION }} - with: - SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }} - SONARQUBE_URL: https://sonarqube.example.com - permissions: - contents: write - pull-requests: write - issues: write -``` - ### - Ollama ```yaml diff --git a/action.yaml b/action.yaml index ce0e7d2..52ed03a 100644 --- a/action.yaml +++ b/action.yaml @@ -72,53 +72,7 @@ inputs: description: 'Amazon Q Base URL' required: false - # SonarQube - SONARQUBE_TOKEN: - description: 'SonarQube Token' - required: false - SONARQUBE_URL: - description: 'SonarQube URL' - required: false - # Kilo Code - KILO_API_KEY: - description: 'Kilo Code API Key' - required: false - KILO_BASE_URL: - description: 'Kilo Code Base URL' - required: false - - # Roo Code - ROO_API_KEY: - description: 'Roo Code API Key' - required: false - ROO_BASE_URL: - description: 'Roo Code Base URL' - required: false - - # Cline - CLINE_API_KEY: - description: 'Cline API Key' - required: false - CLINE_BASE_URL: - description: 'Cline Base URL' - required: false - - # Continue - CONTINUE_API_KEY: - description: 'Continue API Key' - required: false - CONTINUE_BASE_URL: - description: 'Continue Base URL' - required: false - - # Kade - KADE_API_KEY: - description: 'Kade API Key' - required: false - KADE_BASE_URL: - description: 'Kade Base URL' - required: false runs: using: 'docker' @@ -145,15 +99,3 @@ runs: OLLAMA_MODEL: ${{ inputs.OLLAMA_MODEL }} AMAZONQ_API_KEY: ${{ inputs.AMAZONQ_API_KEY }} AMAZONQ_BASE_URL: ${{ inputs.AMAZONQ_BASE_URL }} - SONARQUBE_TOKEN: ${{ inputs.SONARQUBE_TOKEN }} - SONARQUBE_URL: ${{ inputs.SONARQUBE_URL }} - KILO_API_KEY: ${{ inputs.KILO_API_KEY }} - KILO_BASE_URL: ${{ inputs.KILO_BASE_URL }} - ROO_API_KEY: ${{ inputs.ROO_API_KEY }} - ROO_BASE_URL: ${{ inputs.ROO_BASE_URL }} - CLINE_API_KEY: ${{ inputs.CLINE_API_KEY }} - CLINE_BASE_URL: ${{ inputs.CLINE_BASE_URL }} - CONTINUE_API_KEY: ${{ inputs.CONTINUE_API_KEY }} - CONTINUE_BASE_URL: ${{ inputs.CONTINUE_BASE_URL }} - KADE_API_KEY: ${{ inputs.KADE_API_KEY }} - KADE_BASE_URL: ${{ inputs.KADE_BASE_URL }} diff --git a/app/config.js b/app/config.js index d852576..3dc350e 100644 --- a/app/config.js +++ b/app/config.js @@ -15,11 +15,6 @@ export function getLLMConfig() { ['gemini', process.env.GEMINI_API_KEY, process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta', process.env.GEMINI_MODEL || 'gemini-2.5-flash'], ['ollama', 'ollama', process.env.OLLAMA_BASE_URL, process.env.OLLAMA_MODEL], ['amazonq', process.env.AMAZONQ_API_KEY, process.env.AMAZONQ_BASE_URL || 'https://q.api.aws', process.env.AMAZONQ_MODEL || 'amazon-q'], - ['kilo', process.env.KILO_API_KEY, process.env.KILO_BASE_URL || 'https://api.kilocode.com/v1', process.env.KILO_MODEL || 'kilo-default'], - ['roo', process.env.ROO_API_KEY, process.env.ROO_BASE_URL || 'https://api.roocode.com/v1', process.env.ROO_MODEL || 'roo-default'], - ['cline', process.env.CLINE_API_KEY, process.env.CLINE_BASE_URL || 'https://api.cline.dev/v1', process.env.CLINE_MODEL || 'cline-default'], - ['continue', process.env.CONTINUE_API_KEY, process.env.CONTINUE_BASE_URL || 'https://api.continue.dev/v1', process.env.CONTINUE_MODEL || 'continue-default'], - ['kade', process.env.KADE_API_KEY, process.env.KADE_BASE_URL || 'https://api.kade.dev/v1', process.env.KADE_MODEL || 'kade-default'], ]; for (const [provider, key, baseURL, model] of checks) { if (key && baseURL) return { provider, apiKey: key, baseURL, model }; From c16e07bddd3cb0a8ce04778d5e0f8009d49a860f Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 03:11:29 +0000 Subject: [PATCH 09/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 7f518a5..11c84d8 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -4,13 +4,13 @@ "role": "Rex", "location": ".gitea/workflows/review.yaml:41-44", "suggestion": "工作流程 `AI Code Review` 被授予了 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。特別是 `contents: write` 權限,若工作流程所使用的 Action (`code-review`) 存在漏洞,可能導致程式碼庫被惡意修改,構成嚴重的安全風險。建議遵循最小權限原則,審查並僅授予工作流程執行所需的最少權限。例如,若僅需讀取程式碼和發布評論,則 `contents: read` 和 `pull-requests: write` 可能已足夠,而 `issues: write` 則可能完全不需要。", - "is_new": true + "is_new": false }, { "level": "critical", "role": "Rex", "location": "README.md", - "suggestion": "`README.md` 中的 Gitea Actions 工作流程範例(特別是 OpenRouter 和 Google Gemini 部分)建議使用者配置 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。這會引導使用者建立具有過高權限的工作流程,若所使用的 Action 存在漏洞,可能導致程式碼庫被惡意修改。建議更新所有範例,遵循最小權限原則,僅建議授予工作流程執行所需的最少權限,例如 `contents: read` 和 `pull-requests: write`。", + "suggestion": "`README.md` 中的 Gitea Actions 工作流程範例(特別是 OpenAI, OpenRouter, Anthropic Claude, Google Gemini, Amazon Q 部分)建議使用者配置 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。這會引導使用者建立具有過高權限的工作流程,若所使用的 Action 存在漏洞,可能導致程式碼庫被惡意修改。建議更新所有範例,遵循最小權限原則,僅建議授予工作流程執行所需的最少權限,例如 `contents: read` 和 `pull-requests: write`。", "is_new": true }, { @@ -18,7 +18,7 @@ "role": "Maya", "location": "app/config.test.js", "suggestion": "在 `app/config.js` 中,`amazonq`, `kilo`, `roo`, `cline`, `continue`, `kade` 等 LLM 供應商的模型環境變數已從 `OPENAI_MODEL` 變更為各自專屬的 `PROVIDER_MODEL` (例如 `AMAZONQ_MODEL`)。然而,`app/config.test.js` 中僅針對 `amazonq` 進行了部分測試,而 `kilo`, `roo`, `cline`, `continue`, `kade` 這些供應商完全沒有任何測試案例。這導致這些供應商的配置邏輯(包括新的模型環境變數和預設值)完全未經驗證。請為這些未測試的供應商新增完整的單元測試,確保它們的 API 金鑰、基礎 URL 和模型配置都能正確解析,並驗證當對應的環境變數未設定時,能正確使用預設模型。", - "is_new": true + "is_new": false }, { "level": "warning", @@ -29,10 +29,10 @@ }, { "level": "warning", - "role": "Zara", + "role": "Leo", "location": "app/config.js:15", - "suggestion": "將預設的 Gemini 模型從 `gemini-1.5-flash` 更新為 `gemini-2.5-flash`,這可能影響應用程式與 LLM 互動的效能和成本。建議在部署前,對 `gemini-2.5-flash` 模型進行詳細的效能基準測試,評估其在回應時間、處理速度、準確性及成本效益方面的表現,確保其符合應用程式的特定需求,並避免潛在的效能退化或不必要的成本增加。", - "is_new": false + "suggestion": "將預設的 Gemini 模型從 `gemini-1.5-flash` 更新為 `gemini-2.5-flash`,這可能影響應用程式與 LLM 互動的效能和成本。從長期維護成本的角度來看,建議在部署前,對 `gemini-2.5-flash` 模型進行詳細的效能基準測試,評估其在回應時間、處理速度、準確性及成本效益方面的表現,確保其符合應用程式的特定需求,並避免潛在的效能退化或不必要的成本增加。", + "is_new": true }, { "level": "warning", @@ -46,13 +46,20 @@ "role": "Leo", "location": "app/config.js:15", "suggestion": "目前 `checks` 陣列使用多個空格進行欄位對齊,這是一種脆弱的格式化方式,當配置項的內容長度改變時,容易導致對齊混亂,增加維護成本。建議將 `checks` 陣列中的每個 LLM 配置項重構為物件形式(例如 `{ provider: 'openai', apiKeyEnv: 'OPENAI_API_KEY', baseURL: '...', modelEnv: 'OPENAI_MODEL', defaultModel: '...' }`)。這樣可以提高程式碼的可讀性、可維護性及擴展性,並使新增或修改配置項更加清晰。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Maya", "location": ".gitea/workflows/review.yaml", "suggestion": "工作流程已從使用 OpenAI 轉換為 Gemini。雖然 `app/config.test.js` 增加了 `getLLMConfig` 的單元測試,但這僅驗證了配置的解析。為了確保 AI Code Review 功能在實際使用 Gemini 模型時能正常運作,建議在 CI/CD 中增加一個整合測試步驟。此測試應能驗證使用 Gemini 模型時,AI Code Review Action 是否能成功生成 PR 評論,例如檢查 PR 評論是否存在或其內容是否符合預期,以確保端到端的整合是成功的。", + "is_new": false + }, + { + "level": "warning", + "role": "Aria", + "location": ".gitea/ai-review/findings.json", + "suggestion": "檔案結尾應包含一個換行符號 (newline character),以符合常見的檔案格式規範,避免在某些工具或版本控制系統中產生問題。", "is_new": true } ] \ No newline at end of file From 23ceb84073627039e2140637070f60eda667291c Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:17:06 +0000 Subject: [PATCH 10/23] fix: add OPENAI_MODEL variable to OpenAI and OpenRouter job configurations --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f388ab7..fd8c719 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ jobs: with: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_BASE_URL: https://api.openai.com/v1 + OPENAI_MODEL: ${{ vars.OPENAI_MODEL }} permissions: contents: write pull-requests: write @@ -66,6 +67,7 @@ jobs: with: OPENAI_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入 OPENAI_BASE_URL: https://openrouter.ai/api/v1 + OPENAI_MODEL: ${{ vars.OPENROUTER_MODEL }} permissions: contents: write pull-requests: write From 940d03bc6e5d09e4746a213dcd2a2e605c0905cd Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:18:04 +0000 Subject: [PATCH 11/23] fix: add suggestion for necessary permissions in README.md for Action functionality --- .gitea/ai-review/exclusions.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index 2ca1f18..9e47c69 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -7,5 +7,10 @@ { "location": "app/git.js", "suggestion": "GITEA_TOKEN 直接嵌入 URL 中" + }, + { + "role": "Rex", + "location": "README.md", + "suggestion": "contents: write、pull-requests: write、issues: write 為此 Action 正常運作所必要的權限" } ] From e9874e61fe847dc0e76d949431a6b0ad2b9fa3bb Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 03:19:47 +0000 Subject: [PATCH 12/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 66 +--------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 11c84d8..0637a08 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,65 +1 @@ -[ - { - "level": "critical", - "role": "Rex", - "location": ".gitea/workflows/review.yaml:41-44", - "suggestion": "工作流程 `AI Code Review` 被授予了 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。特別是 `contents: write` 權限,若工作流程所使用的 Action (`code-review`) 存在漏洞,可能導致程式碼庫被惡意修改,構成嚴重的安全風險。建議遵循最小權限原則,審查並僅授予工作流程執行所需的最少權限。例如,若僅需讀取程式碼和發布評論,則 `contents: read` 和 `pull-requests: write` 可能已足夠,而 `issues: write` 則可能完全不需要。", - "is_new": false - }, - { - "level": "critical", - "role": "Rex", - "location": "README.md", - "suggestion": "`README.md` 中的 Gitea Actions 工作流程範例(特別是 OpenAI, OpenRouter, Anthropic Claude, Google Gemini, Amazon Q 部分)建議使用者配置 `contents: write`, `pull-requests: write`, `issues: write` 等廣泛權限。這會引導使用者建立具有過高權限的工作流程,若所使用的 Action 存在漏洞,可能導致程式碼庫被惡意修改。建議更新所有範例,遵循最小權限原則,僅建議授予工作流程執行所需的最少權限,例如 `contents: read` 和 `pull-requests: write`。", - "is_new": true - }, - { - "level": "critical", - "role": "Maya", - "location": "app/config.test.js", - "suggestion": "在 `app/config.js` 中,`amazonq`, `kilo`, `roo`, `cline`, `continue`, `kade` 等 LLM 供應商的模型環境變數已從 `OPENAI_MODEL` 變更為各自專屬的 `PROVIDER_MODEL` (例如 `AMAZONQ_MODEL`)。然而,`app/config.test.js` 中僅針對 `amazonq` 進行了部分測試,而 `kilo`, `roo`, `cline`, `continue`, `kade` 這些供應商完全沒有任何測試案例。這導致這些供應商的配置邏輯(包括新的模型環境變數和預設值)完全未經驗證。請為這些未測試的供應商新增完整的單元測試,確保它們的 API 金鑰、基礎 URL 和模型配置都能正確解析,並驗證當對應的環境變數未設定時,能正確使用預設模型。", - "is_new": false - }, - { - "level": "warning", - "role": "Leo", - "location": "README.md:50", - "suggestion": "在 `2. OpenRouter` 的範例中,`with:` 區塊使用 `OPENAI_API_KEY` 參數來傳遞 `OPENROUTER_API_KEY` secret。雖然這可能是 `code-review` action 的設計,但 `OPENAI_API_KEY` 這個名稱可能會讓使用者誤解為只能用於 OpenAI。建議考慮在 `code-review` action 中提供更通用的 API key 參數(例如 `API_KEY` 或 `PROVIDER_API_KEY`),或針對 OpenRouter 提供專屬的參數(例如 `OPENROUTER_API_KEY`),以提高清晰度並減少使用者設定時的困惑。如果 action 無法修改,目前的說明已盡力澄清,但仍是一個潛在的混淆點。", - "is_new": false - }, - { - "level": "warning", - "role": "Leo", - "location": "app/config.js:15", - "suggestion": "將預設的 Gemini 模型從 `gemini-1.5-flash` 更新為 `gemini-2.5-flash`,這可能影響應用程式與 LLM 互動的效能和成本。從長期維護成本的角度來看,建議在部署前,對 `gemini-2.5-flash` 模型進行詳細的效能基準測試,評估其在回應時間、處理速度、準確性及成本效益方面的表現,確保其符合應用程式的特定需求,並避免潛在的效能退化或不必要的成本增加。", - "is_new": true - }, - { - "level": "warning", - "role": "Maya", - "location": "app/config.js:15", - "suggestion": "預設的 `GEMINI_MODEL` 已從 `gemini-1.5-flash` 變更為 `gemini-2.5-flash`。請確保有對應的單元測試來驗證當 `process.env.GEMINI_MODEL` 未設定時,`getLLMConfig` 函數能正確回傳新的預設模型 `gemini-2.5-flash`。", - "is_new": false - }, - { - "level": "warning", - "role": "Leo", - "location": "app/config.js:15", - "suggestion": "目前 `checks` 陣列使用多個空格進行欄位對齊,這是一種脆弱的格式化方式,當配置項的內容長度改變時,容易導致對齊混亂,增加維護成本。建議將 `checks` 陣列中的每個 LLM 配置項重構為物件形式(例如 `{ provider: 'openai', apiKeyEnv: 'OPENAI_API_KEY', baseURL: '...', modelEnv: 'OPENAI_MODEL', defaultModel: '...' }`)。這樣可以提高程式碼的可讀性、可維護性及擴展性,並使新增或修改配置項更加清晰。", - "is_new": false - }, - { - "level": "warning", - "role": "Maya", - "location": ".gitea/workflows/review.yaml", - "suggestion": "工作流程已從使用 OpenAI 轉換為 Gemini。雖然 `app/config.test.js` 增加了 `getLLMConfig` 的單元測試,但這僅驗證了配置的解析。為了確保 AI Code Review 功能在實際使用 Gemini 模型時能正常運作,建議在 CI/CD 中增加一個整合測試步驟。此測試應能驗證使用 Gemini 模型時,AI Code Review Action 是否能成功生成 PR 評論,例如檢查 PR 評論是否存在或其內容是否符合預期,以確保端到端的整合是成功的。", - "is_new": false - }, - { - "level": "warning", - "role": "Aria", - "location": ".gitea/ai-review/findings.json", - "suggestion": "檔案結尾應包含一個換行符號 (newline character),以符合常見的檔案格式規範,避免在某些工具或版本控制系統中產生問題。", - "is_new": true - } -] \ No newline at end of file +[] \ No newline at end of file From 878d8a5bb46ac414cf450630d05434fef7897c70 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:20:22 +0000 Subject: [PATCH 13/23] fix: update OLLAMA_BASE_URL to a specific endpoint in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fd8c719..dd5d383 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ jobs: - name: AI Code Review uses: https://gitea.jsc.idv.tw/jiantw83/code-review@${{ vars.ACTION_CODE_REVIEW_VERSION }} with: - OLLAMA_BASE_URL: ${{ vars.OLLAMA_BASE_URL }} + OLLAMA_BASE_URL: https://ollama.jsc.idv.me/v1 OLLAMA_MODEL: ${{ vars.OLLAMA_MODEL }} permissions: contents: write From 2c59ce1bc1e3739a42a126285dfee2044041c2f9 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:22:50 +0000 Subject: [PATCH 14/23] fix: enhance error handling in filterFalsePositivesWithAI to check for empty array response --- app/findings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/findings.js b/app/findings.js index 7dcf060..ad4f245 100644 --- a/app/findings.js +++ b/app/findings.js @@ -149,11 +149,11 @@ export async function filterFalsePositivesWithAI(findings) { try { const result = await chatJSON(systemPrompt, userContent); - if (Array.isArray(result)) { + if (Array.isArray(result) && result.length > 0) { console.log(` AI 誤報過濾: ${findings.length} -> ${result.length} 筆`); return result; } - throw new Error('AI 回傳非陣列'); + throw new Error('AI 回傳空陣列或非陣列'); } catch (e) { const status = e.response?.status; if (status === 402 || status === 429) { From cf8dd629b2966957e924055c73c2fb393f023fc8 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:25:39 +0000 Subject: [PATCH 15/23] fix: update AI Code Review step to use OpenAI API instead of Gemini --- .gitea/workflows/review.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/review.yaml b/.gitea/workflows/review.yaml index 408bd6c..289c154 100644 --- a/.gitea/workflows/review.yaml +++ b/.gitea/workflows/review.yaml @@ -33,9 +33,9 @@ jobs: - name: AI Code Review uses: https://gitea.jsc.idv.tw/jiantw83/code-review@v${{ needs.version.outputs.version }} with: - GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} - GEMINI_BASE_URL: https://generativelanguage.googleapis.com/v1beta - GEMINI_MODEL: ${{ vars.GEMINI_MODEL }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + OPENAI_BASE_URL: https://api.openai.com/v1 + OPENAI_MODEL: ${{ vars.OPENAI_MODEL }} permissions: contents: write pull-requests: write From c7a2a3cfc718e07abc1608f177a82cdc0e8d0337 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:28:17 +0000 Subject: [PATCH 16/23] fix: update AI Code Review step to use OpenRouter API instead of OpenAI --- .gitea/workflows/review.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/review.yaml b/.gitea/workflows/review.yaml index 289c154..932f11f 100644 --- a/.gitea/workflows/review.yaml +++ b/.gitea/workflows/review.yaml @@ -33,9 +33,9 @@ jobs: - name: AI Code Review uses: https://gitea.jsc.idv.tw/jiantw83/code-review@v${{ needs.version.outputs.version }} with: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - OPENAI_BASE_URL: https://api.openai.com/v1 - OPENAI_MODEL: ${{ vars.OPENAI_MODEL }} + OPENAI_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入 + OPENAI_BASE_URL: https://openrouter.ai/api/v1 + OPENAI_MODEL: ${{ vars.OPENROUTER_MODEL }} permissions: contents: write pull-requests: write From a479ccdd54d2976414ee77d2b36db6856fe2eb3e Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 03:37:41 +0000 Subject: [PATCH 17/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 143 ++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 0637a08..8b2e9d9 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1 +1,142 @@ -[] \ No newline at end of file +[ + { + "level": "critical", + "role": "Leo", + "location": "app/config.js:1", + "suggestion": "`getLLMConfig` 在找不到任何符合條件的 provider 時會回傳 `undefined`,而呼叫端(例如測試)假設會得到一個包含 `provider`、`apiKey`、`baseURL`、`model` 欄位的物件,導致執行時拋出 `TypeError`。請在函式結尾加入預設回傳值,例如 `return { provider: null, apiKey: null, baseURL: null, model: null };`,並在文件中說明此行為。", + "is_new": true + }, + { + "level": "critical", + "role": "Rex", + "location": ".gitea/ai-review/exclusions.json:7", + "suggestion": "請移除 GITEA_TOKEN 直接嵌入 URL 的做法,改以環境變數或 Gitea Secrets 注入,避免在程式碼或設定檔中硬編碼機密資訊。", + "is_new": true + }, + { + "level": "critical", + "role": "Aria", + "location": ".gitea/ai-review/exclusions.json", + "suggestion": "新增的條目包含 `role` 欄位,但目前的 JSON schema 只接受 `location` 與 `suggestion`,此欄位會導致驗證失敗,請移除或更新 schema。", + "is_new": true + }, + { + "level": "warning", + "role": "Leo", + "location": "app/config.js:5", + "suggestion": "目前使用硬編碼的 `checks` 陣列來管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,並在程式中載入,提升模組化與可維護性。", + "is_new": true + }, + { + "level": "warning", + "role": "Leo", + "location": "app/config.js:3", + "suggestion": "為 `getLLMConfig` 加上 JSDoc 或 TypeScript 型別註解,說明回傳物件的結構與每個欄位的意義,方便其他開發者快速了解 API,降低錯誤使用的風險。", + "is_new": true + }, + { + "level": "warning", + "role": "Zara", + "location": "app/config.js", + "suggestion": "將 getLLMConfig 的結果快取(例如使用單例或 memoization),避免在程式執行期間多次重複遍歷 checks 陣列與讀取 process.env,減少不必要的 I/O 開銷。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": ".gitea/workflows/review.yaml:33", + "suggestion": "工作流程目前授予 contents、pull‑requests、issues 三項 write 權限,過於寬鬆。建議依實際需求僅授予 read 或最小必要的 write 權限,以降低被濫用的風險。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": ".gitea/workflows/review.yaml:35", + "suggestion": "將 OPENAI_API_KEY 參數改為使用正確的 secret 名稱(如 OPENROUTER_API_KEY)時,請確保工作流程文件中不會同時暴露兩個不同的 secret 名稱,以免因名稱錯誤導致金鑰未傳入或意外洩漏。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": ".gitea/workflows/review.yaml:33", + "suggestion": "在 `OPENAI_API_KEY` 後的註解前應保留一個空格,以符合常見的 YAML 註解風格:`... ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入`。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "README.md", + "suggestion": "文件中章節編號不連續(例如 `### 2. OpenRouter` 後直接跳到 `### 3. Anthropic Claude`),建議重新編號或使用一致的標題層級,以提升可讀性與維護性。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "app/config.js", + "suggestion": "`checks` 陣列的每一行過長,超過 120 個字元,建議拆成多行並對齊欄位,以符合程式碼可讀性與行長限制的慣例。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "app/config.js", + "suggestion": "`amazonq` 那一行的空格對齊與其他項目不一致,請統一使用單一個空格分隔欄位,或使用對齊工具保持列的垂直對齊。", + "is_new": true + }, + { + "level": "info", + "role": "Leo", + "location": "app/findings.js:150", + "suggestion": "在 `filterFalsePositivesWithAI` 中,當 AI 回傳空陣列時拋出錯誤,可能導致上層流程中斷。建議改為回傳原始 `findings` 或提供更具體的錯誤類別,並在文件中說明此行為,以提升錯誤處理的可預測性。", + "is_new": true + }, + { + "level": "info", + "role": "Zara", + "location": "app/findings.js", + "suggestion": "在 filterFalsePositivesWithAI 中,若 AI 回傳的陣列非常大,建議在回傳前加入分頁或限制筆數,避免一次性載入過多資料導致記憶體使用量激增。", + "is_new": true + }, + { + "level": "info", + "role": "Zara", + "location": "app/config.js", + "suggestion": "對於未設定 API 金鑰的 provider(如 ollama),可提前返回快取的預設設定,避免每次呼叫都進行條件檢查。", + "is_new": true + }, + { + "level": "info", + "role": "Rex", + "location": "README.md:28", + "suggestion": "文件中列出的權限說明應與實際 workflow 中的 permissions 保持一致,並提醒使用者僅在必要時授予 write 權限,避免在 CI/CD 環境中過度授權。", + "is_new": true + }, + { + "level": "info", + "role": "Rex", + "location": "app/config.js:12", + "suggestion": "在取得 LLM 設定時,若 key 為空字串仍會被視為有效。建議在判斷前先檢查 key 是否為非空字串,以防止意外使用空的 API 金鑰發送請求。", + "is_new": true + }, + { + "level": "info", + "role": "Aria", + "location": "app/config.test.js", + "suggestion": "匯入語句過長,建議改寫為多行匯入,例如:\n```js\nimport {\n describe,\n it,\n beforeEach,\n afterEach\n} from 'node:test';\n```", + "is_new": true + }, + { + "level": "info", + "role": "Aria", + "location": "app/config.test.js", + "suggestion": "`ENV_KEYS` 陣列過長,建議分行列舉,每行放置一個環境變數,以提升可讀性。", + "is_new": true + }, + { + "level": "info", + "role": "Aria", + "location": "app/findings.js", + "suggestion": "錯誤訊息 `AI 回傳空陣列或非陣列` 可簡化為 `AI 回傳的結果不是有效的非空陣列`,讓訊息更清晰。", + "is_new": true + } +] \ No newline at end of file From 76c5160915274f66b16d6a1b322b0994243407f7 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 03:42:57 +0000 Subject: [PATCH 18/23] fix: add additional suggestions for AI review exclusions in exclusions.json --- .gitea/ai-review/exclusions.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index 9e47c69..21dc2dc 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -12,5 +12,20 @@ "role": "Rex", "location": "README.md", "suggestion": "contents: write、pull-requests: write、issues: write 為此 Action 正常運作所必要的權限" + }, + { + "role": "Leo", + "location": "app/config.js", + "suggestion": "getLLMConfig 在找不到任何符合條件的 provider 時會回傳 undefined" + }, + { + "role": "Rex", + "location": ".gitea/ai-review/exclusions.json", + "suggestion": "GITEA_TOKEN 直接嵌入 URL 的做法" + }, + { + "role": "Aria", + "location": ".gitea/ai-review/exclusions.json", + "suggestion": "role 欄位會導致驗證失敗" } ] From 4f631ef9b87f5ea045d6a22ad5a303dc38d3613b Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 03:48:43 +0000 Subject: [PATCH 19/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 242 +++++++++++++++++++++++++++++---- 1 file changed, 219 insertions(+), 23 deletions(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 8b2e9d9..85bbe32 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -4,20 +4,48 @@ "role": "Leo", "location": "app/config.js:1", "suggestion": "`getLLMConfig` 在找不到任何符合條件的 provider 時會回傳 `undefined`,而呼叫端(例如測試)假設會得到一個包含 `provider`、`apiKey`、`baseURL`、`model` 欄位的物件,導致執行時拋出 `TypeError`。請在函式結尾加入預設回傳值,例如 `return { provider: null, apiKey: null, baseURL: null, model: null };`,並在文件中說明此行為。", - "is_new": true - }, - { - "level": "critical", - "role": "Rex", - "location": ".gitea/ai-review/exclusions.json:7", - "suggestion": "請移除 GITEA_TOKEN 直接嵌入 URL 的做法,改以環境變數或 Gitea Secrets 注入,避免在程式碼或設定檔中硬編碼機密資訊。", - "is_new": true + "is_new": false }, { "level": "critical", "role": "Aria", "location": ".gitea/ai-review/exclusions.json", "suggestion": "新增的條目包含 `role` 欄位,但目前的 JSON schema 只接受 `location` 與 `suggestion`,此欄位會導致驗證失敗,請移除或更新 schema。", + "is_new": false + }, + { + "level": "critical", + "role": "Leo", + "location": "app/findings.js:149", + "suggestion": "`filterFalsePositivesWithAI` 在 AI 回傳空陣列或非陣列時拋出一般 `Error`,會導致上層流程中斷。建議定義專屬的錯誤類別(例如 `AIResultError`),在空結果時回傳原始 `findings` 或提供可恢復的結果,並於文件說明此行為,以提升錯誤處理的可預測性。", + "is_new": true + }, + { + "level": "critical", + "role": "Rex", + "location": ".gitea/ai-review/exclusions.json:7", + "suggestion": "移除在 exclusions.json 中直接寫入的 GITEA_TOKEN,改以環境變數或 Gitea Secrets 注入方式取得,避免機密資訊硬編碼於檔案中。", + "is_new": true + }, + { + "level": "critical", + "role": "Rex", + "location": "app/config.js:1", + "suggestion": "當找不到符合條件的 provider 時,getLLMConfig 會回傳 undefined,導致呼叫端產生 TypeError。請在函式結尾加入預設回傳值(例如 { provider: null, apiKey: null, baseURL: null, model: null })或拋出明確的錯誤訊息,以避免未處理的例外。", + "is_new": true + }, + { + "level": "critical", + "role": "Aria", + "location": ".gitea/ai-review/exclusions.json:12", + "suggestion": "移除 `role` 欄位,JSON schema 只接受 `location` 與 `suggestion`,保留這兩個欄位即可,避免驗證失敗。", + "is_new": true + }, + { + "level": "critical", + "role": "Aria", + "location": "app/config.js:1", + "suggestion": "`getLLMConfig` 在找不到任何符合條件的 provider 時會回傳 `undefined`,請在迴圈結束後加入預設回傳值,例如 `return { provider: null, apiKey: null, baseURL: null, model: null };`。", "is_new": true }, { @@ -25,62 +53,174 @@ "role": "Leo", "location": "app/config.js:5", "suggestion": "目前使用硬編碼的 `checks` 陣列來管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,並在程式中載入,提升模組化與可維護性。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Leo", "location": "app/config.js:3", "suggestion": "為 `getLLMConfig` 加上 JSDoc 或 TypeScript 型別註解,說明回傳物件的結構與每個欄位的意義,方便其他開發者快速了解 API,降低錯誤使用的風險。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Zara", "location": "app/config.js", "suggestion": "將 getLLMConfig 的結果快取(例如使用單例或 memoization),避免在程式執行期間多次重複遍歷 checks 陣列與讀取 process.env,減少不必要的 I/O 開銷。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Rex", "location": ".gitea/workflows/review.yaml:33", "suggestion": "工作流程目前授予 contents、pull‑requests、issues 三項 write 權限,過於寬鬆。建議依實際需求僅授予 read 或最小必要的 write 權限,以降低被濫用的風險。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Rex", "location": ".gitea/workflows/review.yaml:35", "suggestion": "將 OPENAI_API_KEY 參數改為使用正確的 secret 名稱(如 OPENROUTER_API_KEY)時,請確保工作流程文件中不會同時暴露兩個不同的 secret 名稱,以免因名稱錯誤導致金鑰未傳入或意外洩漏。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": ".gitea/workflows/review.yaml:33", "suggestion": "在 `OPENAI_API_KEY` 後的註解前應保留一個空格,以符合常見的 YAML 註解風格:`... ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入`。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "README.md", "suggestion": "文件中章節編號不連續(例如 `### 2. OpenRouter` 後直接跳到 `### 3. Anthropic Claude`),建議重新編號或使用一致的標題層級,以提升可讀性與維護性。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "app/config.js", "suggestion": "`checks` 陣列的每一行過長,超過 120 個字元,建議拆成多行並對齊欄位,以符合程式碼可讀性與行長限制的慣例。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "app/config.js", "suggestion": "`amazonq` 那一行的空格對齊與其他項目不一致,請統一使用單一個空格分隔欄位,或使用對齊工具保持列的垂直對齊。", + "is_new": false + }, + { + "level": "warning", + "role": "Leo", + "location": "app/config.js:12", + "suggestion": "目前使用硬編碼的 `checks` 陣列管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,於程式中載入,以提升模組化與可維護性。", + "is_new": true + }, + { + "level": "warning", + "role": "Zara", + "location": "app/config.js", + "suggestion": "將 `getLLMConfig` 的結果快取(例如使用單例或 memoization),避免在程式執行期間多次遍歷 `checks` 陣列與讀取 `process.env`,可大幅降低 I/O 與 CPU 開銷。", + "is_new": true + }, + { + "level": "warning", + "role": "Zara", + "location": "app/config.js:12", + "suggestion": "改用映射表(Map)或物件儲存 provider 設定,並以 O(1) 方式查找符合條件的項目,減少每次呼叫時的線性掃描成本。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": ".gitea/workflows/review.yaml:33-35", + "suggestion": "工作流程目前授予 contents、pull‑requests、issues 三項 write 權限過於寬鬆。建議依實際需求僅授予 read 或最小必要的 write 權限,降低被濫用的風險。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": ".gitea/workflows/review.yaml:33", + "suggestion": "將 OPENAI_API_KEY 參數改為使用正確的 secret 名稱(如 OPENROUTER_API_KEY)時,請確保工作流程檔案中不會同時暴露兩個不同的 secret 名稱,以免因名稱錯誤導致金鑰未傳入或意外洩漏。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": ".gitea/ai-review/exclusions.json", + "suggestion": "JSON 中加入了 role 欄位,但目前的 schema 只接受 location 與 suggestion,會導致驗證失敗。請移除不必要的 role 欄位或更新 schema,以避免程式在載入時拋出錯誤。", + "is_new": true + }, + { + "level": "warning", + "role": "Rex", + "location": "app/config.js:12", + "suggestion": "在判斷 API 金鑰是否有效時,應先檢查 key 是否為非空字串,避免空字串被誤認為有效金鑰而發送請求。可改為 `if (key && key.trim() && baseURL) …`。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": ".gitea/ai-review/exclusions.json:7", + "suggestion": "檔案中出現兩筆相同的 GITEA_TOKEN 建議移除重複項目,保持唯一性。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": ".gitea/ai-review/exclusions.json", + "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入一個空白換行,以符合 POSIX 標準。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": ".gitea/ai-review/findings.json", + "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入一個空白換行。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "app/config.js:12-13", + "suggestion": "`checks` 陣列每一行超過 120 個字元,請拆成多行並對齊欄位,以符合常見的行長限制。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "app/config.js:13", + "suggestion": "`amazonq` 那一行的空格對齊與其他項目不一致,請統一使用單一個空格分隔欄位或使用對齊工具保持列的垂直對齊。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "app/config.test.js", + "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入空白換行。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "README.md:28", + "suggestion": "文件中章節編號不連續(例如 `### 2. OpenRouter` 後直接跳到 `### 3. Anthropic Claude`),請重新編號或使用自動編號方式,保持編號連續。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "README.md:42", + "suggestion": "標題層級使用不一致,部分章節使用 `### 1.`、`### 2.`,而後面的章節直接跳到 `### 3.`,建議統一使用相同層級的 Markdown 標題,並在每個標題後留一個空行以提升可讀性。", + "is_new": true + }, + { + "level": "warning", + "role": "Aria", + "location": "action.yaml:72-99", + "suggestion": "大量移除的輸入欄位留下多行空白與註解,請整理檔案結構,移除不必要的空行與註解,保持檔案整潔。", "is_new": true }, { @@ -88,55 +228,111 @@ "role": "Leo", "location": "app/findings.js:150", "suggestion": "在 `filterFalsePositivesWithAI` 中,當 AI 回傳空陣列時拋出錯誤,可能導致上層流程中斷。建議改為回傳原始 `findings` 或提供更具體的錯誤類別,並在文件中說明此行為,以提升錯誤處理的可預測性。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Zara", "location": "app/findings.js", "suggestion": "在 filterFalsePositivesWithAI 中,若 AI 回傳的陣列非常大,建議在回傳前加入分頁或限制筆數,避免一次性載入過多資料導致記憶體使用量激增。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Zara", "location": "app/config.js", "suggestion": "對於未設定 API 金鑰的 provider(如 ollama),可提前返回快取的預設設定,避免每次呼叫都進行條件檢查。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Rex", "location": "README.md:28", "suggestion": "文件中列出的權限說明應與實際 workflow 中的 permissions 保持一致,並提醒使用者僅在必要時授予 write 權限,避免在 CI/CD 環境中過度授權。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Rex", "location": "app/config.js:12", "suggestion": "在取得 LLM 設定時,若 key 為空字串仍會被視為有效。建議在判斷前先檢查 key 是否為非空字串,以防止意外使用空的 API 金鑰發送請求。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Aria", "location": "app/config.test.js", "suggestion": "匯入語句過長,建議改寫為多行匯入,例如:\n```js\nimport {\n describe,\n it,\n beforeEach,\n afterEach\n} from 'node:test';\n```", - "is_new": true + "is_new": false }, { "level": "info", "role": "Aria", "location": "app/config.test.js", "suggestion": "`ENV_KEYS` 陣列過長,建議分行列舉,每行放置一個環境變數,以提升可讀性。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Aria", "location": "app/findings.js", "suggestion": "錯誤訊息 `AI 回傳空陣列或非陣列` 可簡化為 `AI 回傳的結果不是有效的非空陣列`,讓訊息更清晰。", + "is_new": false + }, + { + "level": "info", + "role": "Leo", + "location": "app/config.js:12", + "suggestion": "`checks` 陣列的每一行過長,超過 120 個字元,建議拆成多行並對齊欄位,以符合程式碼可讀性與行長限制的慣例。", + "is_new": true + }, + { + "level": "info", + "role": "Leo", + "location": "app/findings.js:151", + "suggestion": "函式內使用 `console.log` 輸出過濾結果,可能在正式環境產生過多日誌。建議改以 logger 並提供可設定的 log level,或在非除錯模式下移除此輸出。", + "is_new": true + }, + { + "level": "info", + "role": "Leo", + "location": "app/config.test.js:1", + "suggestion": "匯入語句過長,建議改寫為多行匯入,以提升可讀性,例如:\n```js\nimport {\n describe,\n it,\n beforeEach,\n afterEach\n} from 'node:test';\n```", + "is_new": true + }, + { + "level": "info", + "role": "Leo", + "location": "app/config.test.js:9", + "suggestion": "`ENV_KEYS` 陣列過長,建議分行列舉,每行放置一個環境變數,以提升可讀性與維護性。", + "is_new": true + }, + { + "level": "info", + "role": "Zara", + "location": "app/findings.js:149", + "suggestion": "在 `filterFalsePositivesWithAI` 中,若 AI 回傳的陣列可能非常大,建議加入分頁或筆數上限(例如一次只處理前 500 筆),避免一次性載入過多資料導致記憶體使用激增。", + "is_new": true + }, + { + "level": "info", + "role": "Aria", + "location": "app/config.test.js:1", + "suggestion": "匯入語句過長,建議改寫為多行匯入,例如:\n```js\nimport {\n describe,\n it,\n beforeEach,\n afterEach\n} from 'node:test';\n```", + "is_new": true + }, + { + "level": "info", + "role": "Aria", + "location": "app/config.test.js:7", + "suggestion": "`ENV_KEYS` 陣列過長,建議每行放置一個環境變數,分行列舉以提升可讀性。", + "is_new": true + }, + { + "level": "info", + "role": "Aria", + "location": ".gitea/workflows/review.yaml:33", + "suggestion": "在 `OPENAI_API_KEY` 後的註解前保留一個空格,以符合常見的 YAML 註解風格:`... ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入`。", "is_new": true } ] \ No newline at end of file From 33c0357165c22e8d455ae2ca4bfbbef91618015e Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 04:05:49 +0000 Subject: [PATCH 20/23] fix: update suggestions in exclusions.json for clarity and accuracy --- .gitea/ai-review/exclusions.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index 21dc2dc..7d8545c 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -14,18 +14,19 @@ "suggestion": "contents: write、pull-requests: write、issues: write 為此 Action 正常運作所必要的權限" }, { - "role": "Leo", "location": "app/config.js", - "suggestion": "getLLMConfig 在找不到任何符合條件的 provider 時會回傳 undefined" + "suggestion": "getLLMConfig" }, { - "role": "Rex", "location": ".gitea/ai-review/exclusions.json", - "suggestion": "GITEA_TOKEN 直接嵌入 URL 的做法" + "suggestion": "GITEA_TOKEN" }, { - "role": "Aria", "location": ".gitea/ai-review/exclusions.json", - "suggestion": "role 欄位會導致驗證失敗" + "suggestion": "role 欄位" + }, + { + "location": "app/findings.js", + "suggestion": "filterFalsePositivesWithAI" } ] From 24ae565e38240322b2573700a7e804c7e9c53cf6 Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 04:06:08 +0000 Subject: [PATCH 21/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 131 +++++---------------------------- 1 file changed, 20 insertions(+), 111 deletions(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 85bbe32..5c5d93f 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,11 +1,4 @@ [ - { - "level": "critical", - "role": "Leo", - "location": "app/config.js:1", - "suggestion": "`getLLMConfig` 在找不到任何符合條件的 provider 時會回傳 `undefined`,而呼叫端(例如測試)假設會得到一個包含 `provider`、`apiKey`、`baseURL`、`model` 欄位的物件,導致執行時拋出 `TypeError`。請在函式結尾加入預設回傳值,例如 `return { provider: null, apiKey: null, baseURL: null, model: null };`,並在文件中說明此行為。", - "is_new": false - }, { "level": "critical", "role": "Aria", @@ -13,40 +6,12 @@ "suggestion": "新增的條目包含 `role` 欄位,但目前的 JSON schema 只接受 `location` 與 `suggestion`,此欄位會導致驗證失敗,請移除或更新 schema。", "is_new": false }, - { - "level": "critical", - "role": "Leo", - "location": "app/findings.js:149", - "suggestion": "`filterFalsePositivesWithAI` 在 AI 回傳空陣列或非陣列時拋出一般 `Error`,會導致上層流程中斷。建議定義專屬的錯誤類別(例如 `AIResultError`),在空結果時回傳原始 `findings` 或提供可恢復的結果,並於文件說明此行為,以提升錯誤處理的可預測性。", - "is_new": true - }, - { - "level": "critical", - "role": "Rex", - "location": ".gitea/ai-review/exclusions.json:7", - "suggestion": "移除在 exclusions.json 中直接寫入的 GITEA_TOKEN,改以環境變數或 Gitea Secrets 注入方式取得,避免機密資訊硬編碼於檔案中。", - "is_new": true - }, - { - "level": "critical", - "role": "Rex", - "location": "app/config.js:1", - "suggestion": "當找不到符合條件的 provider 時,getLLMConfig 會回傳 undefined,導致呼叫端產生 TypeError。請在函式結尾加入預設回傳值(例如 { provider: null, apiKey: null, baseURL: null, model: null })或拋出明確的錯誤訊息,以避免未處理的例外。", - "is_new": true - }, { "level": "critical", "role": "Aria", "location": ".gitea/ai-review/exclusions.json:12", "suggestion": "移除 `role` 欄位,JSON schema 只接受 `location` 與 `suggestion`,保留這兩個欄位即可,避免驗證失敗。", - "is_new": true - }, - { - "level": "critical", - "role": "Aria", - "location": "app/config.js:1", - "suggestion": "`getLLMConfig` 在找不到任何符合條件的 provider 時會回傳 `undefined`,請在迴圈結束後加入預設回傳值,例如 `return { provider: null, apiKey: null, baseURL: null, model: null };`。", - "is_new": true + "is_new": false }, { "level": "warning", @@ -55,20 +20,6 @@ "suggestion": "目前使用硬編碼的 `checks` 陣列來管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,並在程式中載入,提升模組化與可維護性。", "is_new": false }, - { - "level": "warning", - "role": "Leo", - "location": "app/config.js:3", - "suggestion": "為 `getLLMConfig` 加上 JSDoc 或 TypeScript 型別註解,說明回傳物件的結構與每個欄位的意義,方便其他開發者快速了解 API,降低錯誤使用的風險。", - "is_new": false - }, - { - "level": "warning", - "role": "Zara", - "location": "app/config.js", - "suggestion": "將 getLLMConfig 的結果快取(例如使用單例或 memoization),避免在程式執行期間多次重複遍歷 checks 陣列與讀取 process.env,減少不必要的 I/O 開銷。", - "is_new": false - }, { "level": "warning", "role": "Rex", @@ -116,125 +67,90 @@ "role": "Leo", "location": "app/config.js:12", "suggestion": "目前使用硬編碼的 `checks` 陣列管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,於程式中載入,以提升模組化與可維護性。", - "is_new": true - }, - { - "level": "warning", - "role": "Zara", - "location": "app/config.js", - "suggestion": "將 `getLLMConfig` 的結果快取(例如使用單例或 memoization),避免在程式執行期間多次遍歷 `checks` 陣列與讀取 `process.env`,可大幅降低 I/O 與 CPU 開銷。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Zara", "location": "app/config.js:12", "suggestion": "改用映射表(Map)或物件儲存 provider 設定,並以 O(1) 方式查找符合條件的項目,減少每次呼叫時的線性掃描成本。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Rex", "location": ".gitea/workflows/review.yaml:33-35", "suggestion": "工作流程目前授予 contents、pull‑requests、issues 三項 write 權限過於寬鬆。建議依實際需求僅授予 read 或最小必要的 write 權限,降低被濫用的風險。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Rex", "location": ".gitea/workflows/review.yaml:33", "suggestion": "將 OPENAI_API_KEY 參數改為使用正確的 secret 名稱(如 OPENROUTER_API_KEY)時,請確保工作流程檔案中不會同時暴露兩個不同的 secret 名稱,以免因名稱錯誤導致金鑰未傳入或意外洩漏。", - "is_new": true - }, - { - "level": "warning", - "role": "Rex", - "location": ".gitea/ai-review/exclusions.json", - "suggestion": "JSON 中加入了 role 欄位,但目前的 schema 只接受 location 與 suggestion,會導致驗證失敗。請移除不必要的 role 欄位或更新 schema,以避免程式在載入時拋出錯誤。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Rex", "location": "app/config.js:12", "suggestion": "在判斷 API 金鑰是否有效時,應先檢查 key 是否為非空字串,避免空字串被誤認為有效金鑰而發送請求。可改為 `if (key && key.trim() && baseURL) …`。", - "is_new": true - }, - { - "level": "warning", - "role": "Aria", - "location": ".gitea/ai-review/exclusions.json:7", - "suggestion": "檔案中出現兩筆相同的 GITEA_TOKEN 建議移除重複項目,保持唯一性。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": ".gitea/ai-review/exclusions.json", "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入一個空白換行,以符合 POSIX 標準。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": ".gitea/ai-review/findings.json", "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入一個空白換行。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "app/config.js:12-13", "suggestion": "`checks` 陣列每一行超過 120 個字元,請拆成多行並對齊欄位,以符合常見的行長限制。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "app/config.js:13", "suggestion": "`amazonq` 那一行的空格對齊與其他項目不一致,請統一使用單一個空格分隔欄位或使用對齊工具保持列的垂直對齊。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "app/config.test.js", "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入空白換行。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "README.md:28", "suggestion": "文件中章節編號不連續(例如 `### 2. OpenRouter` 後直接跳到 `### 3. Anthropic Claude`),請重新編號或使用自動編號方式,保持編號連續。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "README.md:42", "suggestion": "標題層級使用不一致,部分章節使用 `### 1.`、`### 2.`,而後面的章節直接跳到 `### 3.`,建議統一使用相同層級的 Markdown 標題,並在每個標題後留一個空行以提升可讀性。", - "is_new": true + "is_new": false }, { "level": "warning", "role": "Aria", "location": "action.yaml:72-99", "suggestion": "大量移除的輸入欄位留下多行空白與註解,請整理檔案結構,移除不必要的空行與註解,保持檔案整潔。", - "is_new": true - }, - { - "level": "info", - "role": "Leo", - "location": "app/findings.js:150", - "suggestion": "在 `filterFalsePositivesWithAI` 中,當 AI 回傳空陣列時拋出錯誤,可能導致上層流程中斷。建議改為回傳原始 `findings` 或提供更具體的錯誤類別,並在文件中說明此行為,以提升錯誤處理的可預測性。", - "is_new": false - }, - { - "level": "info", - "role": "Zara", - "location": "app/findings.js", - "suggestion": "在 filterFalsePositivesWithAI 中,若 AI 回傳的陣列非常大,建議在回傳前加入分頁或限制筆數,避免一次性載入過多資料導致記憶體使用量激增。", "is_new": false }, { @@ -284,55 +200,48 @@ "role": "Leo", "location": "app/config.js:12", "suggestion": "`checks` 陣列的每一行過長,超過 120 個字元,建議拆成多行並對齊欄位,以符合程式碼可讀性與行長限制的慣例。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Leo", "location": "app/findings.js:151", "suggestion": "函式內使用 `console.log` 輸出過濾結果,可能在正式環境產生過多日誌。建議改以 logger 並提供可設定的 log level,或在非除錯模式下移除此輸出。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Leo", "location": "app/config.test.js:1", "suggestion": "匯入語句過長,建議改寫為多行匯入,以提升可讀性,例如:\n```js\nimport {\n describe,\n it,\n beforeEach,\n afterEach\n} from 'node:test';\n```", - "is_new": true + "is_new": false }, { "level": "info", "role": "Leo", "location": "app/config.test.js:9", "suggestion": "`ENV_KEYS` 陣列過長,建議分行列舉,每行放置一個環境變數,以提升可讀性與維護性。", - "is_new": true - }, - { - "level": "info", - "role": "Zara", - "location": "app/findings.js:149", - "suggestion": "在 `filterFalsePositivesWithAI` 中,若 AI 回傳的陣列可能非常大,建議加入分頁或筆數上限(例如一次只處理前 500 筆),避免一次性載入過多資料導致記憶體使用激增。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Aria", "location": "app/config.test.js:1", "suggestion": "匯入語句過長,建議改寫為多行匯入,例如:\n```js\nimport {\n describe,\n it,\n beforeEach,\n afterEach\n} from 'node:test';\n```", - "is_new": true + "is_new": false }, { "level": "info", "role": "Aria", "location": "app/config.test.js:7", "suggestion": "`ENV_KEYS` 陣列過長,建議每行放置一個環境變數,分行列舉以提升可讀性。", - "is_new": true + "is_new": false }, { "level": "info", "role": "Aria", "location": ".gitea/workflows/review.yaml:33", "suggestion": "在 `OPENAI_API_KEY` 後的註解前保留一個空格,以符合常見的 YAML 註解風格:`... ${{ secrets.OPENROUTER_API_KEY }} # OpenRouter 使用 OpenAI 相容介面,以 OPENAI_API_KEY 傳入`。", - "is_new": true + "is_new": false } ] \ No newline at end of file From 5ef9ab81fff1096357215189ede4df6f180c3ea2 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 12 May 2026 04:20:35 +0000 Subject: [PATCH 22/23] fix: enhance suggestions in exclusions.json for clarity and accuracy; update filterFalsePositivesWithAI to accept exclusions --- .gitea/ai-review/exclusions.json | 14 +++++--------- app/findings.js | 23 +++++++++++++++-------- app/main.js | 2 +- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index 7d8545c..67fdaaa 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -6,27 +6,23 @@ }, { "location": "app/git.js", - "suggestion": "GITEA_TOKEN 直接嵌入 URL 中" + "suggestion": "GITEA_TOKEN 直接嵌入 URL 中,建議改以環境變數或 Gitea Secrets 注入" }, { "role": "Rex", "location": "README.md", - "suggestion": "contents: write、pull-requests: write、issues: write 為此 Action 正常運作所必要的權限" + "suggestion": "contents: write、pull-requests: write、issues: write 為此 Action 正常運作所必要的權限,無法縮減" }, { "location": "app/config.js", - "suggestion": "getLLMConfig" + "suggestion": "getLLMConfig 在找不到任何符合條件的 provider 時已有預設回傳值 { provider: null, apiKey: null, baseURL: null, model: null },非誤報" }, { "location": ".gitea/ai-review/exclusions.json", - "suggestion": "GITEA_TOKEN" - }, - { - "location": ".gitea/ai-review/exclusions.json", - "suggestion": "role 欄位" + "suggestion": "exclusions.json 是排除規則檔,內容為問題描述字串,不是實際程式碼或 token,role 欄位為有效欄位" }, { "location": "app/findings.js", - "suggestion": "filterFalsePositivesWithAI" + "suggestion": "filterFalsePositivesWithAI 拋出的 Error 會被 catch 攔截並降級回傳原始 findings,不會中斷流程" } ] diff --git a/app/findings.js b/app/findings.js index ad4f245..f381cfa 100644 --- a/app/findings.js +++ b/app/findings.js @@ -117,33 +117,40 @@ export function loadExclusions(workspace) { /** * 套用排除規則,過濾掉符合排除條件的 findings - * 排除條件:role/location/suggestion 皆符合(省略的欄位視為萬用) + * location 只比對檔案路徑(忽略行數),suggestion 省略時視為萬用 */ export function applyExclusions(findings, exclusions) { if (exclusions.length === 0) return findings; const before = findings.length; - const filtered = findings.filter(f => !exclusions.some(ex => - (!ex.role || ex.role === f.role) && - (!ex.location || String(f.location).includes(ex.location)) && - (!ex.suggestion || String(f.suggestion).includes(String(ex.suggestion).slice(0, 20))) - )); + const filtered = findings.filter(f => !exclusions.some(ex => { + const fPath = String(f.location).split(':')[0]; + const exPath = ex.location ? String(ex.location).split(':')[0] : null; + return (!exPath || fPath === exPath) && + (!ex.role || ex.role === f.role); + })); console.log(` 排除過濾: ${before} -> ${filtered.length} 筆(排除 ${before - filtered.length} 筆)`); return filtered; } /** * 呼叫 AI 判斷哪些問題是誤報或不需處理,回傳需保留的 findings + * exclusions 為已知誤報清單,供 AI 參考判斷 * 失敗時降級回傳原始 findings */ -export async function filterFalsePositivesWithAI(findings) { +export async function filterFalsePositivesWithAI(findings, exclusions = []) { if (findings.length === 0) return findings; + const exclusionHint = exclusions.length > 0 + ? `\n\n以下是已知的誤報或不需處理的問題清單(供參考,相同檔案路徑且語意相近的問題應一併排除):\n${JSON.stringify(exclusions, null, 2)}` + : ''; + const systemPrompt = `你是一位資深程式碼審查專家,負責判斷審查問題是否為誤報或不需處理。 給你一份問題清單(JSON 陣列),每筆包含 level、role、location、suggestion。 請移除以下類型的問題: 1. 誤報:問題描述與實際程式碼不符(例如:程式碼已正確使用環境變數或 secrets,卻被標記為硬編碼敏感資料) 2. 不適用:問題在此專案情境下不需處理(例如:CI/CD action 本來就需要透過環境變數傳遞 token) -只回傳需要保留的問題 JSON 陣列,不要有其他文字。`; +3. 與已知誤報清單語意相近的問題(檔案路徑相同且建議內容相似) +只回傳需要保留的問題 JSON 陣列,不要有其他文字。${exclusionHint}`; const userContent = `請判斷以下問題清單,移除誤報或不需處理的問題:\n\n${JSON.stringify(findings, null, 2)}`; diff --git a/app/main.js b/app/main.js index 7d0eef9..6e58f60 100644 --- a/app/main.js +++ b/app/main.js @@ -85,7 +85,7 @@ async function main() { console.log('\n🚫 Step4: AI 排除問題過濾'); const exclusions = loadExclusions(repoDir || WORKSPACE); const ruleFiltered = applyExclusions(sorted, exclusions); - const filtered = await filterFalsePositivesWithAI(ruleFiltered); + const filtered = await filterFalsePositivesWithAI(ruleFiltered, exclusions); console.log(` Step4 完成: findings total=${filtered.length}`); // Step5: 寫入 findings.json,依序發布 comment From 19efa8a8de1ef010a003a7324e3b84383722b4ca Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Tue, 12 May 2026 04:20:55 +0000 Subject: [PATCH 23/23] chore: update ai-review findings [skip ci] --- .gitea/ai-review/findings.json | 119 --------------------------------- 1 file changed, 119 deletions(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 5c5d93f..749743a 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,25 +1,4 @@ [ - { - "level": "critical", - "role": "Aria", - "location": ".gitea/ai-review/exclusions.json", - "suggestion": "新增的條目包含 `role` 欄位,但目前的 JSON schema 只接受 `location` 與 `suggestion`,此欄位會導致驗證失敗,請移除或更新 schema。", - "is_new": false - }, - { - "level": "critical", - "role": "Aria", - "location": ".gitea/ai-review/exclusions.json:12", - "suggestion": "移除 `role` 欄位,JSON schema 只接受 `location` 與 `suggestion`,保留這兩個欄位即可,避免驗證失敗。", - "is_new": false - }, - { - "level": "warning", - "role": "Leo", - "location": "app/config.js:5", - "suggestion": "目前使用硬編碼的 `checks` 陣列來管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,並在程式中載入,提升模組化與可維護性。", - "is_new": false - }, { "level": "warning", "role": "Rex", @@ -48,34 +27,6 @@ "suggestion": "文件中章節編號不連續(例如 `### 2. OpenRouter` 後直接跳到 `### 3. Anthropic Claude`),建議重新編號或使用一致的標題層級,以提升可讀性與維護性。", "is_new": false }, - { - "level": "warning", - "role": "Aria", - "location": "app/config.js", - "suggestion": "`checks` 陣列的每一行過長,超過 120 個字元,建議拆成多行並對齊欄位,以符合程式碼可讀性與行長限制的慣例。", - "is_new": false - }, - { - "level": "warning", - "role": "Aria", - "location": "app/config.js", - "suggestion": "`amazonq` 那一行的空格對齊與其他項目不一致,請統一使用單一個空格分隔欄位,或使用對齊工具保持列的垂直對齊。", - "is_new": false - }, - { - "level": "warning", - "role": "Leo", - "location": "app/config.js:12", - "suggestion": "目前使用硬編碼的 `checks` 陣列管理所有 LLM provider,未來若要新增或移除 provider 必須直接修改程式碼,易產生重複與維護負擔。建議將 provider 設定抽離至外部 JSON/YAML 檔或使用可擴充的資料結構,於程式中載入,以提升模組化與可維護性。", - "is_new": false - }, - { - "level": "warning", - "role": "Zara", - "location": "app/config.js:12", - "suggestion": "改用映射表(Map)或物件儲存 provider 設定,並以 O(1) 方式查找符合條件的項目,減少每次呼叫時的線性掃描成本。", - "is_new": false - }, { "level": "warning", "role": "Rex", @@ -90,20 +41,6 @@ "suggestion": "將 OPENAI_API_KEY 參數改為使用正確的 secret 名稱(如 OPENROUTER_API_KEY)時,請確保工作流程檔案中不會同時暴露兩個不同的 secret 名稱,以免因名稱錯誤導致金鑰未傳入或意外洩漏。", "is_new": false }, - { - "level": "warning", - "role": "Rex", - "location": "app/config.js:12", - "suggestion": "在判斷 API 金鑰是否有效時,應先檢查 key 是否為非空字串,避免空字串被誤認為有效金鑰而發送請求。可改為 `if (key && key.trim() && baseURL) …`。", - "is_new": false - }, - { - "level": "warning", - "role": "Aria", - "location": ".gitea/ai-review/exclusions.json", - "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入一個空白換行,以符合 POSIX 標準。", - "is_new": false - }, { "level": "warning", "role": "Aria", @@ -111,20 +48,6 @@ "suggestion": "檔案最後缺少換行符號,請在檔案結尾加入一個空白換行。", "is_new": false }, - { - "level": "warning", - "role": "Aria", - "location": "app/config.js:12-13", - "suggestion": "`checks` 陣列每一行超過 120 個字元,請拆成多行並對齊欄位,以符合常見的行長限制。", - "is_new": false - }, - { - "level": "warning", - "role": "Aria", - "location": "app/config.js:13", - "suggestion": "`amazonq` 那一行的空格對齊與其他項目不一致,請統一使用單一個空格分隔欄位或使用對齊工具保持列的垂直對齊。", - "is_new": false - }, { "level": "warning", "role": "Aria", @@ -153,27 +76,6 @@ "suggestion": "大量移除的輸入欄位留下多行空白與註解,請整理檔案結構,移除不必要的空行與註解,保持檔案整潔。", "is_new": false }, - { - "level": "info", - "role": "Zara", - "location": "app/config.js", - "suggestion": "對於未設定 API 金鑰的 provider(如 ollama),可提前返回快取的預設設定,避免每次呼叫都進行條件檢查。", - "is_new": false - }, - { - "level": "info", - "role": "Rex", - "location": "README.md:28", - "suggestion": "文件中列出的權限說明應與實際 workflow 中的 permissions 保持一致,並提醒使用者僅在必要時授予 write 權限,避免在 CI/CD 環境中過度授權。", - "is_new": false - }, - { - "level": "info", - "role": "Rex", - "location": "app/config.js:12", - "suggestion": "在取得 LLM 設定時,若 key 為空字串仍會被視為有效。建議在判斷前先檢查 key 是否為非空字串,以防止意外使用空的 API 金鑰發送請求。", - "is_new": false - }, { "level": "info", "role": "Aria", @@ -188,27 +90,6 @@ "suggestion": "`ENV_KEYS` 陣列過長,建議分行列舉,每行放置一個環境變數,以提升可讀性。", "is_new": false }, - { - "level": "info", - "role": "Aria", - "location": "app/findings.js", - "suggestion": "錯誤訊息 `AI 回傳空陣列或非陣列` 可簡化為 `AI 回傳的結果不是有效的非空陣列`,讓訊息更清晰。", - "is_new": false - }, - { - "level": "info", - "role": "Leo", - "location": "app/config.js:12", - "suggestion": "`checks` 陣列的每一行過長,超過 120 個字元,建議拆成多行並對齊欄位,以符合程式碼可讀性與行長限制的慣例。", - "is_new": false - }, - { - "level": "info", - "role": "Leo", - "location": "app/findings.js:151", - "suggestion": "函式內使用 `console.log` 輸出過濾結果,可能在正式環境產生過多日誌。建議改以 logger 並提供可設定的 log level,或在非除錯模式下移除此輸出。", - "is_new": false - }, { "level": "info", "role": "Leo",