ai-git-tools 2.0.74 → 2.0.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -2,6 +2,9 @@ import { CopilotClient, approveAll } from '@github/copilot-sdk';
|
|
|
2
2
|
import { CONSTANTS, PROJECT_SKILLS_CONTEXT } from '../utils/constants.js';
|
|
3
3
|
import { getSkillsSummaryForPrompt, log } from '../utils/helpers.js';
|
|
4
4
|
|
|
5
|
+
// 讓 CopilotClient 啟動的 Node 子程序繼承此設定,靜音 SQLite ExperimentalWarning
|
|
6
|
+
process.env.NODE_NO_WARNINGS = '1';
|
|
7
|
+
|
|
5
8
|
// CopilotClient 子程序啟動 + AI 模型回應可能共需 60-120s,設為 150s 保留足夠緩衝
|
|
6
9
|
const AI_TIMEOUT_MS = 150000;
|
|
7
10
|
|
|
@@ -35,6 +38,14 @@ export class AIAnalyzer {
|
|
|
35
38
|
});
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
/**
|
|
42
|
+
* 預熱 CopilotClient — 在 workflow 開始時盡早呼叫,
|
|
43
|
+
* 讓 subprocess 在 git 操作期間並行啟動,避免 session.idle timeout
|
|
44
|
+
*/
|
|
45
|
+
async warmup() {
|
|
46
|
+
await this._getOrCreateClient();
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
/**
|
|
39
50
|
* 釋放 CopilotClient 子程序資源
|
|
40
51
|
*/
|
|
@@ -51,28 +62,47 @@ export class AIAnalyzer {
|
|
|
51
62
|
}
|
|
52
63
|
|
|
53
64
|
/**
|
|
54
|
-
* 生成 PR
|
|
65
|
+
* 生成 PR 內容(失敗時自動重建 client 重試一次)
|
|
55
66
|
*/
|
|
56
67
|
async generatePRContent(commits, diff) {
|
|
57
68
|
const skillsSummary = getSkillsSummaryForPrompt(PROJECT_SKILLS_CONTEXT);
|
|
58
69
|
const prompt = this.buildPRPrompt(commits, diff, skillsSummary);
|
|
59
70
|
|
|
60
|
-
|
|
71
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
72
|
+
try {
|
|
73
|
+
if (attempt === 2) {
|
|
74
|
+
log.info(' 重試 AI 請求(重建 session)...\n');
|
|
75
|
+
await this.close(); // 釋放舊 client,下一次 _createSession 會建新的
|
|
76
|
+
}
|
|
61
77
|
|
|
62
|
-
|
|
63
|
-
const responsePromise = session.sendAndWait({ prompt });
|
|
64
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
65
|
-
setTimeout(() => reject(new Error(`AI 請求超時 (${AI_TIMEOUT_MS / 1000} 秒)`)), AI_TIMEOUT_MS);
|
|
66
|
-
});
|
|
78
|
+
const session = await this._createSession();
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
const responsePromise = session.sendAndWait({ prompt });
|
|
81
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
82
|
+
setTimeout(() => reject(new Error(`AI 請求超時 (${AI_TIMEOUT_MS / 1000} 秒)`)), AI_TIMEOUT_MS);
|
|
83
|
+
});
|
|
70
84
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
const response = await Promise.race([responsePromise, timeoutPromise]);
|
|
86
|
+
const prContent = response?.data.content?.trim() || '';
|
|
87
|
+
|
|
88
|
+
if (!prContent) {
|
|
89
|
+
throw new Error('AI 未能生成 PR 內容');
|
|
90
|
+
}
|
|
74
91
|
|
|
75
|
-
|
|
92
|
+
return this.parsePRContent(prContent);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// SDK 內部 session.idle timeout(hardcoded 60s)→ 重試一次
|
|
95
|
+
const isSessionIdleTimeout =
|
|
96
|
+
error.message?.includes('session.idle') || error.message?.includes('Timeout after');
|
|
97
|
+
if (attempt === 1 && isSessionIdleTimeout) {
|
|
98
|
+
log.warning(` AI session 超時,即將重試...\n`);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// unreachable,但保留讓 linter 滿意
|
|
105
|
+
throw new Error('AI 未能生成 PR 內容');
|
|
76
106
|
// 注意:不在此 stop() client,改由 close() 統一清理以便複用
|
|
77
107
|
}
|
|
78
108
|
|