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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-git-tools",
3
- "version": "2.0.74",
3
+ "version": "2.0.75",
4
4
  "description": "AI-powered Git automation tools for commit messages and PR generation",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -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
- const session = await this._createSession();
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
- // 使用超時保護(150 秒,含子程序啟動 + AI 回應)
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
- const response = await Promise.race([responsePromise, timeoutPromise]);
69
- const prContent = response?.data.content?.trim() || '';
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
- if (!prContent) {
72
- throw new Error('AI 未能生成 PR 內容');
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
- return this.parsePRContent(prContent);
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
 
@@ -42,6 +42,9 @@ export class PRWorkflow {
42
42
  }
43
43
  }
44
44
 
45
+ // 0.5 提前預熱 AI client(異步非阻塞),讓 subprocess 在 git 操作期間並行啟動
46
+ this.ai.warmup().catch(() => {});
47
+
45
48
  // 1. 驗證環境和分支
46
49
  const { baseBranch, headBranch } = await this.detectAndValidateBranches();
47
50