feat(ai-review 對話收斂): 讀 PR review 留言判斷解決狀態並收斂 findings #45

Merged
admin merged 69 commits from develop into master 2026-06-23 08:30:28 +00:00
3 changed files with 18 additions and 11 deletions
Showing only changes of commit 55bd14e480 - Show all commits
+6 -6
View File
@@ -104,21 +104,21 @@ describe('formatFindingsStats', () => {
{ level: 'custom', is_new: true }, { level: 'custom', is_new: true },
]; ];
it('formats old and new findings by severity', () => { it('formats old and new findings by severity with an unclassified column', () => {
const stats = formatFindingsStats(statsFindings); const stats = formatFindingsStats(statsFindings);
assert.equal(stats, [ assert.equal(stats, [
'| 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 |', '| 類型 | 🔴 嚴重 | 🟡 警告 | 🔵 建議 | ⚪ 無法標示 |',
'| --- | --- | --- | --- |', '| --- | --- | --- | --- | --- |',
'| 問題 | 1 筆 | 0 筆 | 0 筆 |', '| 問題 | 0 筆 | 1 筆 | 1 筆 | 1 筆 |',
'| 問題 | 0 筆 | 1 筆 | 1 筆 |', '| 問題 | 1 筆 | 0 筆 | 0 筆 | 0 筆 |',
].join('\n')); ].join('\n'));
}); });
it('formats compact one-line stats for action logs', () => { it('formats compact one-line stats for action logs', () => {
assert.equal( assert.equal(
formatFindingsStatsLine(statsFindings), formatFindingsStatsLine(statsFindings),
': 嚴重1 / 警告0 / 建議0;新: 嚴重0 / 警告1 / 建議1', ': 嚴重0 / 警告1 / 建議1 / 無法標示1;舊: 嚴重1 / 警告0 / 建議0 / 無法標示0',
); );
}); });
}); });
+7
View File
@@ -86,6 +86,13 @@ describe('codeWindow', () => {
it('returns empty string for empty content', () => { it('returns empty string for empty content', () => {
assert.equal(codeWindow('', 10), ''); assert.equal(codeWindow('', 10), '');
}); });
it('handles out-of-range line numbers without throwing', () => {
const content = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n');
assert.doesNotThrow(() => codeWindow(content, -5, 2));
assert.equal(codeWindow(content, 0, 1), '1: line1\n2: line2'); // 非正數行號 → 從開頭取窗
assert.equal(codeWindow(content, 9999, 2), ''); // 超過檔尾 → 空字串,不丟錯
});
}); });
describe('judgeConversationsResolved', () => { describe('judgeConversationsResolved', () => {
+5 -5
View File
@@ -100,11 +100,11 @@ describe('fetchAccountQuota', () => {
} }
}); });
it('accepts a real openrouter subdomain', async () => { it('only accepts the exact openrouter.ai apex host (subdomains are not OpenRouter)', async () => {
const get = async () => ({ data: { data: { usage: 1, limit: 10, limit_remaining: 9 } } }); const get = async () => { throw new Error('should not be called for non-apex host'); };
const q = await fetchAccountQuota('openai', { apiKeys: ['k'], baseURL: 'https://api.openrouter.ai/api/v1' }, { get }); const q = await fetchAccountQuota('openai', { apiKeys: ['sk-secret'], baseURL: 'https://api.openrouter.ai/api/v1' }, { get });
assert.equal(q.available, true); assert.equal(q.available, false);
assert.equal(q.source, 'openrouter'); assert.match(q.reason, /API key 無法取得/);
}); });
it('reports 不適用 for local platforms', async () => { it('reports 不適用 for local platforms', async () => {