From 491c170d366b162d758334732ff97fac5bc08b19 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 20 Jul 2026 16:37:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(AI=20=E5=A4=B1=E6=95=97=E8=A8=BA=E6=96=B7):?= =?UTF-8?q?=20=E5=A4=B1=E6=95=97=E6=99=82=E9=A0=90=E8=A8=AD=E4=BD=B5?= =?UTF-8?q?=E5=8D=B0=E9=81=AE=E7=BD=A9=E5=BE=8C=20stdout=EF=BC=88claude-co?= =?UTF-8?q?de=20=E9=8C=AF=E8=AA=A4=E5=AF=AB=E5=9C=A8=20stdout=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/review.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/lib/review.js b/src/lib/review.js index 6b45694..0125a22 100644 --- a/src/lib/review.js +++ b/src/lib/review.js @@ -41,10 +41,9 @@ function redactSecrets(text) { * * 安全考量:AI CLI 失敗時可能在 stderr/stdout 回顯提示內容、環境資訊、token、PII 或 * 原始碼祕密,這些會被長期保存並供多人讀取的 CI log 收錄。權衡「可除錯性」後:本函式 - * 於失敗時**預設**附上經 {@link redactSecrets} 遮罩且去除控制字元的 **stderr** 片段 - * (先截去過長輸入再取前 500 字)——只印 exit code 幾乎無從判斷 CLI - * 為何失敗;**另在明確開啟 Actions step debug**(環境變數 `ACTIONS_STEP_DEBUG=true`)時, - * 再附上同樣遮罩的 **stdout** 片段作為第二診斷來源。純函式、不拋例外。 + * 於失敗時**預設**附上經 {@link redactSecrets} 遮罩且去除控制字元的 **stderr 與 stdout** + * 片段(各先截去過長輸入再取前 500 字)——只印 exit code 幾乎無從判斷 CLI 為何失敗, + * 且部分 CLI(如 claude-code 的 `-p` 模式)將錯誤寫到 stdout 而非 stderr。純函式、不拋例外。 * * @param {{error: (Error & {code?: number|string, signal?: string, killed?: boolean})|null, stderr?: string, output?: string}} res * `runAgent` 的回傳物件。 @@ -66,17 +65,14 @@ function agentFailureDetail(res) { } // 先截去過長輸入再遮罩,避免對數 MB 的失敗輸出跑整份 O(k×n) 正規掃描; // 2000 字上限已足以涵蓋跨界機密樣式,最終仍截為 500 字。 - const DEBUG_INPUT_LIMIT = 2_000; - // 預設即附上「經 redactSecrets 遮罩+去控制字元+限長」的 stderr 片段——CLI 失敗時若只印 - // exit code 幾乎無從除錯(見 test-claude 秒失敗案例);遮罩為盡力防線,仍以此權衡可除錯性。 - const stderr = redactSecrets(String((res && res.stderr) || '').slice(0, DEBUG_INPUT_LIMIT)); + const INPUT_LIMIT = 2_000; + // 預設即附上「經 redactSecrets 遮罩+去控制字元+限長」的 stderr 與 stdout 片段——CLI 失敗時 + // 只印 exit code 幾乎無從除錯(見 test-claude 秒失敗案例);且部分 CLI(如 claude-code 的 + // -p 模式)會把錯誤寫到 stdout 而非 stderr,故兩者都輸出。redactSecrets 為盡力防線。 + const stderr = redactSecrets(String((res && res.stderr) || '').slice(0, INPUT_LIMIT)); if (stderr) parts.push(`stderr:${stderr.slice(0, 500)}`); - // 明確開啟 Actions step debug 時,再附上 stdout 片段作為第二診斷來源。 - const verbose = String(process.env.ACTIONS_STEP_DEBUG || '').trim().toLowerCase() === 'true'; - if (verbose) { - const stdout = redactSecrets(String((res && res.output) || '').slice(0, DEBUG_INPUT_LIMIT)); - if (stdout) parts.push(`stdout:${stdout.slice(0, 500)}`); - } + const stdout = redactSecrets(String((res && res.output) || '').slice(0, INPUT_LIMIT)); + if (stdout) parts.push(`stdout:${stdout.slice(0, 500)}`); if (parts.length === 0) { parts.push((err && err.message && redactSecrets(err.message)) || 'AI CLI 執行失敗(無診斷輸出)'); }