Compare commits
9 Commits
v0.0.4-beta.6
...
v0.0.5
| Author | SHA1 | Date | |
|---|---|---|---|
| 46da713fa7 | |||
| 515ccb0509 | |||
| 69e3b33558 | |||
| c70a818986 | |||
| 684c35bc00 | |||
| 93c602b86a | |||
| b397b76a7a | |||
| c5c3f1d7e1 | |||
| fd49610838 |
@@ -1,14 +0,0 @@
|
|||||||
# Triage Findings
|
|
||||||
|
|
||||||
When the task is to triage review findings, follow this workflow:
|
|
||||||
|
|
||||||
1. Merge all findings into one list.
|
|
||||||
2. Remove duplicates.
|
|
||||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
|
||||||
4. Renumber from 1 after sorting.
|
|
||||||
5. Fix real issues with the smallest safe change.
|
|
||||||
6. Add false positives to `.gitea/ai-review/exclusions.json`.
|
|
||||||
7. Add or update tests when behavior changes.
|
|
||||||
8. Re-check the issue after each fix.
|
|
||||||
|
|
||||||
Use the repo-local `triage-findings` skill for the same workflow when running in Codex.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: triage-findings
|
|
||||||
description: Triage findings, fix real issues, and exclude false positives.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Triage Findings
|
|
||||||
|
|
||||||
## Use
|
|
||||||
|
|
||||||
直接輸入:`triage-findings 問題原始檔(文字或截圖)`
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
1. Merge all findings.
|
|
||||||
2. Sort by severity:
|
|
||||||
- critical
|
|
||||||
- warning
|
|
||||||
- info
|
|
||||||
3. Renumber from 1.
|
|
||||||
4. Fix real issues.
|
|
||||||
5. Put false positives into `.gitea/ai-review/exclusions.json`.
|
|
||||||
6. Add tests when behavior changes.
|
|
||||||
|
|
||||||
## Output Rules
|
|
||||||
|
|
||||||
- Keep the final list short.
|
|
||||||
- Keep numbering contiguous.
|
|
||||||
- Preserve file path, location, and fix.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: triage-findings
|
|
||||||
description: Triage findings, fix real issues, and exclude false positives.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Triage Findings
|
|
||||||
|
|
||||||
## Use
|
|
||||||
|
|
||||||
直接輸入:`triage-findings 問題原始檔(文字或截圖)`
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
1. Merge all findings.
|
|
||||||
2. Sort by severity:
|
|
||||||
- critical
|
|
||||||
- warning
|
|
||||||
- info
|
|
||||||
3. Renumber from 1.
|
|
||||||
4. Fix real issues.
|
|
||||||
5. Put false positives into `.gitea/ai-review/exclusions.json`.
|
|
||||||
6. Add tests when behavior changes.
|
|
||||||
|
|
||||||
## Output Rules
|
|
||||||
|
|
||||||
- Keep the final list short.
|
|
||||||
- Keep numbering contiguous.
|
|
||||||
- Preserve file path, location, and fix.
|
|
||||||
@@ -279,5 +279,33 @@
|
|||||||
{
|
{
|
||||||
"location": "app/json.js",
|
"location": "app/json.js",
|
||||||
"suggestion": "validateJSONArrayFile 只在 JSON 格式錯誤時才啟動 AI 修正,屬例外路徑;再加上檔案大小限制後,並不存在實際的無上限讀檔或資源消耗問題。"
|
"suggestion": "validateJSONArrayFile 只在 JSON 格式錯誤時才啟動 AI 修正,屬例外路徑;再加上檔案大小限制後,並不存在實際的無上限讀檔或資源消耗問題。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/json.test.js",
|
||||||
|
"suggestion": "邊界值測試已存在,`MAX_JSON_BYTES` 等於上限時可正常讀取,這不是未解決問題。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/gitea.test.js:64",
|
||||||
|
"suggestion": "`describe` 已改為同步 callback,`async` 不再出現在這個區塊。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/git.test.js:13",
|
||||||
|
"suggestion": "`makeTmpWorkspace` 已直接使用 `app/git.js` 匯出的 `SYNC_PATHS`,不再維護重複清單。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/gitea.js:32",
|
||||||
|
"suggestion": "`filterDiff` 內層縮排已符合專案的 2-space 風格,這是誤報。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/json.test.js:76",
|
||||||
|
"suggestion": "1MB 上限下的 JSON 讀取不需要改成串流解析;現有實作已先做大小檢查,這個建議屬過度設計。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/json.test.js:7",
|
||||||
|
"suggestion": "檔案大小限制已在 `readJSONText` / `validateJSONArrayFile` 中實作,這不是額外缺陷。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"location": "app/json.test.js:10",
|
||||||
|
"suggestion": "`MAX_JSON_BYTES` 是 `json.js` 的內部限制常數,不需要匯出成公開 API。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,30 +1 @@
|
|||||||
[
|
[]
|
||||||
{
|
|
||||||
"level": "warning",
|
|
||||||
"role": "Maya",
|
|
||||||
"location": "app/json.test.js",
|
|
||||||
"suggestion": "在 `readJSONText` 相關的測試中,除了測試檔案過大的情況,也建議增加一個測試案例,驗證當檔案大小剛好等於 `MAX_JSON_BYTES` 時,檔案能夠被成功讀取且不會拋出錯誤。這能確保邊界條件的處理是正確的。",
|
|
||||||
"is_new": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"level": "warning",
|
|
||||||
"role": "Aria",
|
|
||||||
"location": "app/gitea.test.js:64",
|
|
||||||
"suggestion": "`describe` 區塊的回呼函數不應使用 `async` 關鍵字。`describe` 區塊應同步執行,而異步操作應在 `it` 或 `beforeEach` 等鉤子函數中處理。",
|
|
||||||
"is_new": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"level": "warning",
|
|
||||||
"role": "Leo",
|
|
||||||
"location": "app/git.test.js:13",
|
|
||||||
"suggestion": "在 `makeTmpWorkspace` 函式中,`files` 陣列的內容與 `app/git.js` 中的 `SYNC_PATHS` 常數高度重複。為了避免未來修改 `SYNC_PATHS` 時遺漏更新測試檔案,建議將 `SYNC_PATHS` 從 `app/git.js` 匯出,並在測試中直接引用,以確保兩者保持同步。",
|
|
||||||
"is_new": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"level": "warning",
|
|
||||||
"role": "Aria",
|
|
||||||
"location": "app/gitea.js:32",
|
|
||||||
"suggestion": "在 `filterDiff` 函數中,`excludePrefixes.some` 回呼函數內的程式碼區塊(`const prefix`, `const singleFile`, `return` 語句)的縮排不正確。請將這些行相對於 `p => {` 縮排 2 個空格,以符合專案的 2-space 縮排規範。",
|
|
||||||
"is_new": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
# Triage Findings
|
|
||||||
|
|
||||||
When the task is to triage review findings, follow this workflow:
|
|
||||||
|
|
||||||
1. Merge all findings into one list.
|
|
||||||
2. Remove duplicates.
|
|
||||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
|
||||||
4. Renumber from 1 after sorting.
|
|
||||||
5. Fix real issues with the smallest safe change.
|
|
||||||
6. Add false positives to `.gitea/ai-review/exclusions.json`.
|
|
||||||
7. Add or update tests when behavior changes.
|
|
||||||
8. Re-check the issue after each fix.
|
|
||||||
|
|
||||||
Use the repo-local `triage-findings` skill for the same workflow when running in Codex.
|
|
||||||
|
|
||||||
Trigger it with `/triage-findings`.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
name: triage-findings
|
|
||||||
description: Triage findings, fix real issues, and exclude false positives.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Triage Findings
|
|
||||||
|
|
||||||
## Use
|
|
||||||
|
|
||||||
`triage-findings 問題原始檔(文字或截圖)`
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
1. Merge all findings.
|
|
||||||
2. Sort by severity:
|
|
||||||
- critical
|
|
||||||
- warning
|
|
||||||
- info
|
|
||||||
3. Renumber from 1.
|
|
||||||
4. Fix real issues.
|
|
||||||
5. Put false positives into `.gitea/ai-review/exclusions.json`.
|
|
||||||
6. Add tests when behavior changes.
|
|
||||||
|
|
||||||
## Output Rules
|
|
||||||
|
|
||||||
- Keep the final list short.
|
|
||||||
- Keep numbering contiguous.
|
|
||||||
- Preserve file path, location, and fix.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Triage Findings
|
|
||||||
|
|
||||||
Use the triage-finding workflow for review issue lists:
|
|
||||||
|
|
||||||
1. Merge findings into one list.
|
|
||||||
2. Remove duplicates.
|
|
||||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
|
||||||
4. Renumber from 1.
|
|
||||||
5. Fix real issues with the smallest safe change.
|
|
||||||
6. Put false positives into `.gitea/ai-review/exclusions.json`.
|
|
||||||
7. Add or update tests when behavior changes.
|
|
||||||
8. Re-check after each fix.
|
|
||||||
|
|
||||||
The full reusable skill lives in `.claude/skills/triage-findings/SKILL.md`.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Triage Findings
|
|
||||||
|
|
||||||
Use the triage-finding workflow for review issue lists:
|
|
||||||
|
|
||||||
1. Merge findings into one list.
|
|
||||||
2. Remove duplicates.
|
|
||||||
3. Sort by severity: `critical` -> `warning` -> `info`.
|
|
||||||
4. Renumber from 1.
|
|
||||||
5. Fix real issues with the smallest safe change.
|
|
||||||
6. Put false positives into `.gitea/ai-review/exclusions.json`.
|
|
||||||
7. Add or update tests when behavior changes.
|
|
||||||
8. Re-check after each fix.
|
|
||||||
|
|
||||||
The reusable skill lives in `.gemini/skills/triage-findings/SKILL.md`.
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
5. 從PR問題表格中取出所有舊問題,依照等級排序後 Comment 到 Push Request
|
5. 從PR問題表格中取出所有舊問題,依照等級排序後 Comment 到 Push Request
|
||||||
6. 從PR問題表格中取出所有新問題,排除嚴重等級的問題後 Comment 到 Push Request
|
6. 從PR問題表格中取出所有新問題,排除嚴重等級的問題後 Comment 到 Push Request
|
||||||
7. 從PR問題表格中取出所有新問題,將每個嚴重等級的問題 Comment 到 Push Request
|
7. 從PR問題表格中取出所有新問題,將每個嚴重等級的問題 Comment 到 Push Request
|
||||||
8. Commit 問題檔案
|
8. Commit 問題檔案,將 workspace 中實際存在的同步檔覆蓋到記憶區;workspace 不存在但記憶區已存在的同步檔則移除後再同步,避免 `git add` 因缺檔 pathspec 失敗
|
||||||
9. 如果PR問題表格中有嚴重問題,則不要讓 workflow 執行成功(exit 1)
|
9. 如果PR問題表格中有嚴重問題,則不要讓 workflow 執行成功(exit 1)
|
||||||
|
|
||||||
# 設計
|
# 設計
|
||||||
@@ -227,4 +227,4 @@ Amazon Q:直接輸入 `triage-findings 問題原始檔(文字或截圖)`
|
|||||||
|
|
||||||
### 版本包含
|
### 版本包含
|
||||||
|
|
||||||
提交時一併包含 `triage-findings` skill 與各平台入口檔;已存在檔案一律覆蓋,同步到最新內容。
|
提交時一併包含 `triage-findings` skill 與各平台入口檔;已存在檔案一律覆蓋,同步到最新內容;若 workspace 已移除某個同步檔,記憶區中的對應檔案也會一併刪除,讓 commit 結果與 workspace 保持一致。
|
||||||
|
|||||||
@@ -38,9 +38,9 @@
|
|||||||
- 已驗收:log 已明確顯示 `.gitea/ai-review/findings.json` 與 `.gitea/ai-review/exclusions.json` 都是 `JSON 格式正確`。
|
- 已驗收:log 已明確顯示 `.gitea/ai-review/findings.json` 與 `.gitea/ai-review/exclusions.json` 都是 `JSON 格式正確`。
|
||||||
|
|
||||||
## 階段八:記憶區 commit/push 與錯誤處理
|
## 階段八:記憶區 commit/push 與錯誤處理
|
||||||
- 目標:記憶區能成功 commit/push,且一併包含 `triage-findings` skill 與各平台入口檔;skill 檔案已存在時一律以來源覆蓋,達到同步效果;錯誤時有明確 log,流程結束有總結訊息。
|
- 目標:記憶區能成功 commit/push,且一併包含 `triage-findings` skill 與各平台入口檔;skill 檔案已存在時一律以來源覆蓋,缺少的同步檔則從記憶區刪除,達到鏡像同步效果;錯誤時有明確 log,流程結束有總結訊息。
|
||||||
- 驗收:log 有「persisted findings」、「commit=...」、「push=...」等訊息,且能看出 skill 相關檔案已一併提交並被覆蓋同步;錯誤時有「Runner failed: ...」等明確錯誤說明。
|
- 驗收:log 有「persisted findings」、「commit=...」、「push=...」等訊息,且能看出 skill 相關檔案已一併提交並被鏡像同步;當 workspace 不再包含某個同步檔時,記憶區中的對應檔案會被刪除且不再出現在 commit;錯誤時有「Runner failed: ...」等明確錯誤說明。
|
||||||
- 已驗收:log 已出現 `persisted findings commit=79506eb push=整理程式碼`,代表 commit/push 成功。
|
- 已驗收:log 已出現 `persisted findings commit=79506eb push=整理程式碼`,代表 commit/push 成功;本次已補上缺檔刪除的鏡像同步邏輯,相關單元測試也已覆蓋。
|
||||||
|
|
||||||
## 階段九:阻擋嚴重問題 PR(第 8 點)
|
## 階段九:阻擋嚴重問題 PR(第 8 點)
|
||||||
- 目標:如果 PR 問題表格中有嚴重(critical)問題,workflow 需直接 exit 1,不讓流程成功。
|
- 目標:如果 PR 問題表格中有嚴重(critical)問題,workflow 需直接 exit 1,不讓流程成功。
|
||||||
|
|||||||
+21
-5
@@ -65,16 +65,32 @@ export async function commitAndPush(workspace, repoDir, _spawnSync = spawnSync)
|
|||||||
run(['config', 'user.email', 'ai-review[bot]@gitea'], repoDir);
|
run(['config', 'user.email', 'ai-review[bot]@gitea'], repoDir);
|
||||||
run(['config', 'user.name', 'AI Review Bot'], repoDir);
|
run(['config', 'user.name', 'AI Review Bot'], repoDir);
|
||||||
|
|
||||||
// Always copy source files over the repo copy so skill files stay in sync.
|
const existingSyncPaths = [];
|
||||||
|
const missingSyncPaths = [];
|
||||||
|
|
||||||
|
// Mirror sync files from workspace into the repo copy.
|
||||||
for (const relPath of SYNC_PATHS) {
|
for (const relPath of SYNC_PATHS) {
|
||||||
const src = path.join(workspace, relPath);
|
const src = path.join(workspace, relPath);
|
||||||
const dest = path.join(repoDir, relPath);
|
const dest = path.join(repoDir, relPath);
|
||||||
if (!fs.existsSync(src)) continue;
|
if (fs.existsSync(src)) {
|
||||||
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
||||||
fs.copyFileSync(src, dest);
|
fs.copyFileSync(src, dest);
|
||||||
|
existingSyncPaths.push(relPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(dest)) {
|
||||||
|
fs.rmSync(dest, { force: true });
|
||||||
|
}
|
||||||
|
missingSyncPaths.push(relPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
run(['add', ...SYNC_PATHS], repoDir);
|
if (existingSyncPaths.length > 0) {
|
||||||
|
run(['add', ...existingSyncPaths], repoDir);
|
||||||
|
}
|
||||||
|
if (missingSyncPaths.length > 0) {
|
||||||
|
run(['rm', '--cached', '--ignore-unmatch', '--', ...missingSyncPaths], repoDir);
|
||||||
|
}
|
||||||
|
|
||||||
const status = run(['status', '--porcelain'], repoDir);
|
const status = run(['status', '--porcelain'], repoDir);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
|
|||||||
@@ -101,6 +101,20 @@ describe('commitAndPush', () => {
|
|||||||
assert.ok(!addCall.args.includes('README.md'));
|
assert.ok(!addCall.args.includes('README.md'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes missing sync paths from the repo copy', async () => {
|
||||||
|
const missingPath = path.join(workspace, '.amazonq/rules/triage-findings.md');
|
||||||
|
fs.rmSync(missingPath, { force: true });
|
||||||
|
fs.rmSync(path.join(workspace, 'repo', '.amazonq/rules/triage-findings.md'), { force: true });
|
||||||
|
const spawn = makeSpawn();
|
||||||
|
|
||||||
|
await commitAndPush(workspace, path.join(workspace, 'repo'), spawn);
|
||||||
|
|
||||||
|
const rmCall = spawn.calls.find(c => c.args[0] === 'rm');
|
||||||
|
assert.ok(rmCall, 'expected git rm to run');
|
||||||
|
assert.ok(rmCall.args.includes('.amazonq/rules/triage-findings.md'));
|
||||||
|
assert.equal(fs.existsSync(path.join(workspace, 'repo', '.amazonq/rules/triage-findings.md')), false);
|
||||||
|
});
|
||||||
|
|
||||||
it('overwrites existing repo copies with workspace files', async () => {
|
it('overwrites existing repo copies with workspace files', async () => {
|
||||||
const repoDir = path.join(workspace, 'repo');
|
const repoDir = path.join(workspace, 'repo');
|
||||||
fs.writeFileSync(path.join(repoDir, '.github/skills/triage-findings/SKILL.md'), 'stale');
|
fs.writeFileSync(path.join(repoDir, '.github/skills/triage-findings/SKILL.md'), 'stale');
|
||||||
|
|||||||
+2
-2
@@ -12,16 +12,16 @@ const api = (path) => `${GITEA_SERVER_URL.replace(/\/$/, '')}/api/v1${path}`;
|
|||||||
export async function getPRDiff() {
|
export async function getPRDiff() {
|
||||||
const resp = await axios.get(api(`/repos/${GITEA_REPOSITORY}/pulls/${PR_NUMBER}.diff`), { headers: headers(), timeout: 60000, httpsAgent });
|
const resp = await axios.get(api(`/repos/${GITEA_REPOSITORY}/pulls/${PR_NUMBER}.diff`), { headers: headers(), timeout: 60000, httpsAgent });
|
||||||
return filterDiff(resp.data, [
|
return filterDiff(resp.data, [
|
||||||
'.gitea/',
|
|
||||||
'.amazonq/',
|
'.amazonq/',
|
||||||
'.claude/',
|
'.claude/',
|
||||||
'.codex/',
|
'.codex/',
|
||||||
'.gemini/',
|
'.gemini/',
|
||||||
|
'.gitea/',
|
||||||
'.github/',
|
'.github/',
|
||||||
'CLAUDE.md',
|
'CLAUDE.md',
|
||||||
'GEMINI.md',
|
'GEMINI.md',
|
||||||
'TODO.md',
|
|
||||||
'README.md',
|
'README.md',
|
||||||
|
'TODO.md',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user