ai-git-tools 2.0.68 → 2.0.70
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/bin/cli.js +14 -90
- package/package.json +1 -1
- package/src/commands/dev-from-issue.js +0 -4
- package/src/core/ai-client.js +1 -1
- package/src/pr-modules/ai/code-analyzer.js +42 -27
- package/src/pr-modules/core/workflow.js +54 -49
- package/src/commands/auto-dev.js +0 -256
- package/src/commands/generate-code.js +0 -115
- package/src/commands/plan-issue.js +0 -91
- package/src/commands/write-and-test.js +0 -469
- package/src/core/test-generator.js +0 -165
- package/src/core/test-runner.js +0 -132
package/src/commands/auto-dev.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* auto-dev 整合命令
|
|
3
|
-
* 將 plan-issue、generate-code、write-and-test 串連起來
|
|
4
|
-
* 支援全自動模式(--no-confirm)和分步互動模式
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { resolve } from 'path';
|
|
8
|
-
import inquirer from 'inquirer';
|
|
9
|
-
import { IssueReader } from '../core/issue-reader.js';
|
|
10
|
-
import { CodeGenerator } from '../core/code-generator.js';
|
|
11
|
-
import { AIClient } from '../core/ai-client.js';
|
|
12
|
-
import { writeAndTestCommand, TEST_TYPE_CHOICES, normalizeTestTypeSelection } from './write-and-test.js';
|
|
13
|
-
import { Logger } from '../utils/logger.js';
|
|
14
|
-
|
|
15
|
-
export async function autoDevCommand(options = {}) {
|
|
16
|
-
const logger = new Logger();
|
|
17
|
-
|
|
18
|
-
const issueNumber = options.issue;
|
|
19
|
-
if (!issueNumber) {
|
|
20
|
-
logger.error('請提供 Issue 編號(--issue <number>)');
|
|
21
|
-
throw new Error('缺少 Issue 編號');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const noConfirm = options.noConfirm;
|
|
25
|
-
let filePath = options.file;
|
|
26
|
-
|
|
27
|
-
logger.header('auto-dev 整合工作流');
|
|
28
|
-
if (noConfirm) {
|
|
29
|
-
console.log('模式:全自動(跳過所有確認)');
|
|
30
|
-
} else {
|
|
31
|
-
console.log('模式:分步互動(每步完成後詢問)');
|
|
32
|
-
}
|
|
33
|
-
console.log('');
|
|
34
|
-
|
|
35
|
-
// ============================================================
|
|
36
|
-
// 第一步:讀取 Issue
|
|
37
|
-
// ============================================================
|
|
38
|
-
logger.step(`正在讀取 Issue #${issueNumber}...`);
|
|
39
|
-
const issue = await IssueReader.readIssue(issueNumber);
|
|
40
|
-
logger.success(`Issue:${issue.title}`);
|
|
41
|
-
console.log(`作者:${issue.author} | URL:${issue.url}`);
|
|
42
|
-
console.log('');
|
|
43
|
-
|
|
44
|
-
// ============================================================
|
|
45
|
-
// 第二步:生成計畫
|
|
46
|
-
// ============================================================
|
|
47
|
-
logger.step('正在分析 Issue 並生成實現計畫...');
|
|
48
|
-
const planPrompt = buildPlanPrompt(issue);
|
|
49
|
-
const plan = await AIClient.sendAndWait(planPrompt, options.model);
|
|
50
|
-
logger.section('AI 生成的實現計畫');
|
|
51
|
-
console.log(plan);
|
|
52
|
-
console.log('');
|
|
53
|
-
|
|
54
|
-
// ============================================================
|
|
55
|
-
// 第三步:詢問是否繼續(若非全自動)
|
|
56
|
-
// ============================================================
|
|
57
|
-
if (!noConfirm) {
|
|
58
|
-
const { proceed } = await inquirer.prompt([{
|
|
59
|
-
type: 'confirm',
|
|
60
|
-
name: 'proceed',
|
|
61
|
-
message: '計畫確認無誤,是否繼續進行代碼生成?',
|
|
62
|
-
default: true,
|
|
63
|
-
}]);
|
|
64
|
-
|
|
65
|
-
if (!proceed) {
|
|
66
|
-
logger.info('已取消。');
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ============================================================
|
|
72
|
-
// 第四步:決定目標檔案路徑(優先自動推斷)
|
|
73
|
-
// ============================================================
|
|
74
|
-
if (!filePath) {
|
|
75
|
-
filePath = await inferTargetFilePath(issue, plan, options.model);
|
|
76
|
-
if (filePath) {
|
|
77
|
-
logger.info(`已自動推斷目標檔案:${filePath}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!filePath) {
|
|
82
|
-
if (noConfirm) {
|
|
83
|
-
logger.error('無法自動推斷目標檔案路徑,請改用 --file 明確指定。');
|
|
84
|
-
throw new Error('缺少可推斷的目標檔案路徑');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const { file } = await inquirer.prompt([{
|
|
88
|
-
type: 'input',
|
|
89
|
-
name: 'file',
|
|
90
|
-
message: '無法自動推斷,請輸入要生成的檔案路徑(例如:src/core/new-feature.js):',
|
|
91
|
-
validate: (input) => input.trim().length > 0 ? true : '路徑不能為空',
|
|
92
|
-
}]);
|
|
93
|
-
filePath = file;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const absoluteFilePath = resolve(process.cwd(), filePath);
|
|
97
|
-
console.log('');
|
|
98
|
-
|
|
99
|
-
// ============================================================
|
|
100
|
-
// 第五步:生成代碼
|
|
101
|
-
// ============================================================
|
|
102
|
-
logger.step(`正在生成代碼:${filePath}`);
|
|
103
|
-
let codeResult;
|
|
104
|
-
try {
|
|
105
|
-
codeResult = await CodeGenerator.generateFile(issue, absoluteFilePath, {
|
|
106
|
-
maxLines: parseInt(options.maxLines || '500', 10),
|
|
107
|
-
language: getLanguageFromFilePath(filePath),
|
|
108
|
-
extraContext: options.context || '',
|
|
109
|
-
model: options.model,
|
|
110
|
-
});
|
|
111
|
-
logger.success(`代碼已生成:${codeResult.linesCount} 行`);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
logger.error(`代碼生成失敗:${error.message}`);
|
|
114
|
-
throw error;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
console.log('');
|
|
118
|
-
|
|
119
|
-
const selectedTestType = await resolveTestTypeForAutoDev({
|
|
120
|
-
noConfirm,
|
|
121
|
-
requestedTestType: options.testType,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
console.log('');
|
|
125
|
-
|
|
126
|
-
// ============================================================
|
|
127
|
-
// 第六步:強制執行測試流程
|
|
128
|
-
// ============================================================
|
|
129
|
-
const testResult = await writeAndTestCommand({
|
|
130
|
-
file: filePath,
|
|
131
|
-
testType: selectedTestType,
|
|
132
|
-
maxFixes: options.maxFixes || '2',
|
|
133
|
-
model: options.model,
|
|
134
|
-
noConfirm: true,
|
|
135
|
-
skipCommit: true,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
if (!testResult?.success) {
|
|
139
|
-
logger.error('測試流程未完成,自動化工作流中止。');
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log('');
|
|
144
|
-
logger.section('✅ 自動化工作流完成');
|
|
145
|
-
console.log(`Issue #${issue.number}:${issue.title}`);
|
|
146
|
-
console.log(`生成檔案:${filePath}`);
|
|
147
|
-
testResult.testFilePaths.forEach((testFilePath) => {
|
|
148
|
-
console.log(`測試檔案:${testFilePath.replace(process.cwd(), '.')}`);
|
|
149
|
-
});
|
|
150
|
-
console.log(`測試類型:${testResult.testTypes.join('、')}`);
|
|
151
|
-
console.log('狀態:已完成代碼與測試流程,未自動 commit');
|
|
152
|
-
console.log(`合計行數:${codeResult.linesCount + ' (程式碼)'}`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* 建立計畫生成 prompt
|
|
157
|
-
*/
|
|
158
|
-
function buildPlanPrompt(issue) {
|
|
159
|
-
return `你是一位軟體架構師。請閱讀以下 GitHub Issue 並建立詳細的實現計畫。
|
|
160
|
-
|
|
161
|
-
## Issue #${issue.number}
|
|
162
|
-
標題:${issue.title}
|
|
163
|
-
|
|
164
|
-
描述:
|
|
165
|
-
${issue.body || '(無描述)'}
|
|
166
|
-
|
|
167
|
-
${issue.labels.length ? `標籤:${issue.labels.join(', ')}` : ''}
|
|
168
|
-
|
|
169
|
-
## 輸出要求
|
|
170
|
-
請輸出包含以下內容的實現計畫:
|
|
171
|
-
|
|
172
|
-
1. **摘要** - 一句話說明要做什麼
|
|
173
|
-
2. **需要新增/修改的檔案** - 列出所有相關檔案路徑和各自的職責
|
|
174
|
-
3. **實現步驟** - 有序的任務清單,說明每個步驟的目的
|
|
175
|
-
4. **注意事項** - 潛在風險或需要留意的事項(若有)
|
|
176
|
-
|
|
177
|
-
請使用繁體中文,格式清晰,簡潔有力。`.trim();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* 優先以規則與計畫內容推斷最可能的目標檔案
|
|
182
|
-
*/
|
|
183
|
-
async function inferTargetFilePath(issue, plan, model) {
|
|
184
|
-
const planCandidates = extractFileCandidates(plan);
|
|
185
|
-
if (planCandidates.length === 1) {
|
|
186
|
-
return planCandidates[0];
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (planCandidates.length > 1) {
|
|
190
|
-
const preferredCandidate = planCandidates.find((candidate) => candidate.startsWith('src/'));
|
|
191
|
-
if (preferredCandidate) {
|
|
192
|
-
return preferredCandidate;
|
|
193
|
-
}
|
|
194
|
-
return planCandidates[0];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const prompt = `請根據以下 GitHub Issue 與實作計畫,推斷「最主要的實作檔案路徑」。
|
|
198
|
-
|
|
199
|
-
## 規則
|
|
200
|
-
- 只回傳單一檔案路徑
|
|
201
|
-
- 優先回傳 src/ 底下的實作檔,不要回傳測試檔、文件檔、設定檔
|
|
202
|
-
- 副檔名限制為 .js、.ts、.jsx、.tsx、.mjs、.cjs
|
|
203
|
-
- 不要包含程式碼區塊、不要加說明
|
|
204
|
-
|
|
205
|
-
## Issue #${issue.number}
|
|
206
|
-
標題:${issue.title}
|
|
207
|
-
描述:
|
|
208
|
-
${issue.body || '(無描述)'}
|
|
209
|
-
|
|
210
|
-
## 實作計畫
|
|
211
|
-
${plan}`.trim();
|
|
212
|
-
|
|
213
|
-
const inferred = (await AIClient.sendAndWait(prompt, model)).trim().split(/\s+/)[0];
|
|
214
|
-
return isValidTargetPath(inferred) ? inferred : null;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function extractFileCandidates(plan) {
|
|
218
|
-
const matches = plan.match(/([A-Za-z0-9_./-]+\.(?:js|ts|jsx|tsx|mjs|cjs))/g) || [];
|
|
219
|
-
const uniqueMatches = [...new Set(matches.filter(isValidTargetPath))];
|
|
220
|
-
|
|
221
|
-
return uniqueMatches.filter((candidate) => {
|
|
222
|
-
const normalized = candidate.toLowerCase();
|
|
223
|
-
return !normalized.includes('__tests__/')
|
|
224
|
-
&& !normalized.includes('.test.')
|
|
225
|
-
&& !normalized.includes('.spec.')
|
|
226
|
-
&& !normalized.endsWith('.config.js');
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function isValidTargetPath(value) {
|
|
231
|
-
return typeof value === 'string'
|
|
232
|
-
&& /^[A-Za-z0-9_./-]+\.(js|ts|jsx|tsx|mjs|cjs)$/.test(value)
|
|
233
|
-
&& !value.startsWith('/');
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function getLanguageFromFilePath(filePath) {
|
|
237
|
-
return /\.(ts|tsx)$/.test(filePath) ? 'ts' : 'js';
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
async function resolveTestTypeForAutoDev({ noConfirm, requestedTestType }) {
|
|
241
|
-
const defaultTestType = normalizeTestTypeSelection(requestedTestType || 'auto')[0] || 'auto';
|
|
242
|
-
|
|
243
|
-
if (noConfirm) {
|
|
244
|
-
return requestedTestType || 'auto';
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const { testType } = await inquirer.prompt([{
|
|
248
|
-
type: 'list',
|
|
249
|
-
name: 'testType',
|
|
250
|
-
message: '請選擇這次要執行的測試方式:',
|
|
251
|
-
choices: TEST_TYPE_CHOICES,
|
|
252
|
-
default: defaultTestType === 'auto' ? 'both' : defaultTestType,
|
|
253
|
-
}]);
|
|
254
|
-
|
|
255
|
-
return testType;
|
|
256
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* generate-code 命令
|
|
3
|
-
* 讀取 GitHub Issue,依照指定路徑生成符合專案風格的代碼
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { readFileSync } from 'fs';
|
|
7
|
-
import { resolve } from 'path';
|
|
8
|
-
import inquirer from 'inquirer';
|
|
9
|
-
import { IssueReader } from '../core/issue-reader.js';
|
|
10
|
-
import { CodeGenerator } from '../core/code-generator.js';
|
|
11
|
-
import { writeAndTestCommand, TEST_TYPE_CHOICES, normalizeTestTypeSelection } from './write-and-test.js';
|
|
12
|
-
import { Logger } from '../utils/logger.js';
|
|
13
|
-
|
|
14
|
-
export async function generateCodeCommand(options = {}) {
|
|
15
|
-
const logger = new Logger();
|
|
16
|
-
|
|
17
|
-
// 驗證必要參數
|
|
18
|
-
const issueNumber = options.issue;
|
|
19
|
-
const filePath = options.file;
|
|
20
|
-
const extraContext = options.context || '';
|
|
21
|
-
const maxLines = parseInt(options.maxLines || '500', 10);
|
|
22
|
-
|
|
23
|
-
if (!issueNumber) {
|
|
24
|
-
logger.error('請提供 Issue 編號(--issue <number>)');
|
|
25
|
-
throw new Error('缺少 Issue 編號');
|
|
26
|
-
}
|
|
27
|
-
if (!filePath) {
|
|
28
|
-
logger.error('請提供目標檔案路徑(--file <path>)');
|
|
29
|
-
throw new Error('缺少目標檔案路徑');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const absolutePath = resolve(process.cwd(), filePath);
|
|
33
|
-
|
|
34
|
-
logger.header(`generate-code`);
|
|
35
|
-
console.log(`Issue:#${issueNumber}`);
|
|
36
|
-
console.log(`目標檔案:${absolutePath}`);
|
|
37
|
-
console.log(`最大行數:${maxLines}`);
|
|
38
|
-
console.log('');
|
|
39
|
-
|
|
40
|
-
// 1. 讀取 Issue
|
|
41
|
-
logger.step(`正在讀取 Issue #${issueNumber}...`);
|
|
42
|
-
const issue = await IssueReader.readIssue(issueNumber);
|
|
43
|
-
logger.info(`Issue:${issue.title}`);
|
|
44
|
-
|
|
45
|
-
// 2. 詢問確認後再生成
|
|
46
|
-
if (!options.noConfirm) {
|
|
47
|
-
const { confirmed } = await inquirer.prompt([{
|
|
48
|
-
type: 'confirm',
|
|
49
|
-
name: 'confirmed',
|
|
50
|
-
message: `確認為檔案 ${filePath} 生成代碼?`,
|
|
51
|
-
default: true,
|
|
52
|
-
}]);
|
|
53
|
-
|
|
54
|
-
if (!confirmed) {
|
|
55
|
-
logger.info('已取消。');
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// 3. 生成代碼
|
|
61
|
-
logger.step('正在生成代碼中,請稍候...\n');
|
|
62
|
-
|
|
63
|
-
const result = await CodeGenerator.generateFile(issue, absolutePath, {
|
|
64
|
-
maxLines,
|
|
65
|
-
language: /\.(ts|tsx)$/.test(absolutePath) ? 'ts' : 'js',
|
|
66
|
-
extraContext,
|
|
67
|
-
model: options.model,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// 4. 顯示結果
|
|
71
|
-
logger.section(`生成完成`);
|
|
72
|
-
logger.success(`檔案已寫入:${result.filePath}`);
|
|
73
|
-
logger.info(`共 ${result.linesCount} 行`);
|
|
74
|
-
|
|
75
|
-
// 5. 預覽前 20 行
|
|
76
|
-
try {
|
|
77
|
-
const preview = readFileSync(result.filePath, 'utf-8').split('\n').slice(0, 20).join('\n');
|
|
78
|
-
console.log('\n--- 預覽(前 20 行)---');
|
|
79
|
-
console.log(preview);
|
|
80
|
-
console.log('---');
|
|
81
|
-
} catch {
|
|
82
|
-
// 忽略預覽讀取失敗
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
console.log('\n💡 下一步:執行 write-and-test 為此檔案生成並執行測試');
|
|
86
|
-
console.log(` ai-git-tools write-and-test --file ${filePath}`);
|
|
87
|
-
|
|
88
|
-
if (!options.noConfirm) {
|
|
89
|
-
const { nextAction } = await inquirer.prompt([{
|
|
90
|
-
type: 'list',
|
|
91
|
-
name: 'nextAction',
|
|
92
|
-
message: '代碼已生成,接下來要如何處理測試?',
|
|
93
|
-
choices: [
|
|
94
|
-
...TEST_TYPE_CHOICES,
|
|
95
|
-
{
|
|
96
|
-
name: '先不執行測試',
|
|
97
|
-
value: 'skip',
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
default: 'both',
|
|
101
|
-
}]);
|
|
102
|
-
|
|
103
|
-
if (nextAction !== 'skip') {
|
|
104
|
-
await writeAndTestCommand({
|
|
105
|
-
file: filePath,
|
|
106
|
-
testType: normalizeTestTypeSelection(nextAction).join(','),
|
|
107
|
-
maxFixes: options.maxFixes || '2',
|
|
108
|
-
model: options.model,
|
|
109
|
-
noConfirm: true,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* plan-issue 命令
|
|
3
|
-
* 讀取 GitHub Issue,使用 AI 生成結構化的實現計畫
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import inquirer from 'inquirer';
|
|
7
|
-
import { IssueReader } from '../core/issue-reader.js';
|
|
8
|
-
import { AIClient } from '../core/ai-client.js';
|
|
9
|
-
import { Logger } from '../utils/logger.js';
|
|
10
|
-
|
|
11
|
-
export async function planIssueCommand(options = {}) {
|
|
12
|
-
const logger = new Logger();
|
|
13
|
-
|
|
14
|
-
const issueNumber = options.number || options.issue;
|
|
15
|
-
if (!issueNumber) {
|
|
16
|
-
logger.error('請提供 Issue 編號(--number <number>)');
|
|
17
|
-
throw new Error('缺少 Issue 編號');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
logger.header(`plan-issue #${issueNumber}`);
|
|
21
|
-
|
|
22
|
-
// 1. 讀取 Issue
|
|
23
|
-
logger.step(`正在讀取 Issue #${issueNumber}...`);
|
|
24
|
-
const issue = await IssueReader.readIssue(issueNumber);
|
|
25
|
-
|
|
26
|
-
logger.section(`Issue #${issue.number}:${issue.title}`);
|
|
27
|
-
if (options.verbose) {
|
|
28
|
-
console.log(`作者:${issue.author}`);
|
|
29
|
-
console.log(`標籤:${issue.labels.join(', ') || '(無)'}`);
|
|
30
|
-
console.log(`URL:${issue.url}`);
|
|
31
|
-
console.log(`\n描述:\n${issue.body || '(無描述)'}`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 2. 呼叫 AI 生成計畫
|
|
35
|
-
logger.step('正在分析 Issue 並生成實現計畫...\n');
|
|
36
|
-
const prompt = buildPlanPrompt(issue);
|
|
37
|
-
const plan = await AIClient.sendAndWait(prompt, options.model);
|
|
38
|
-
|
|
39
|
-
// 3. 顯示計畫
|
|
40
|
-
logger.section('AI 生成的實現計畫');
|
|
41
|
-
console.log(plan);
|
|
42
|
-
console.log('');
|
|
43
|
-
|
|
44
|
-
// 4. 詢問確認(除非 --no-confirm)
|
|
45
|
-
if (options.noConfirm) {
|
|
46
|
-
logger.success('自動模式:跳過確認,繼續進行代碼生成。');
|
|
47
|
-
return { issue, plan };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const { proceed } = await inquirer.prompt([{
|
|
51
|
-
type: 'confirm',
|
|
52
|
-
name: 'proceed',
|
|
53
|
-
message: '是否確認此計畫並繼續進行代碼生成?',
|
|
54
|
-
default: false,
|
|
55
|
-
}]);
|
|
56
|
-
|
|
57
|
-
if (proceed) {
|
|
58
|
-
logger.success('計畫已確認!可以使用 generate-code 命令開始生成代碼。');
|
|
59
|
-
console.log('');
|
|
60
|
-
console.log(` ai-git-tools generate-code --issue ${issue.number} --file <目標檔案路徑> --context <描述>`);
|
|
61
|
-
} else {
|
|
62
|
-
logger.info('已取消。請根據上方計畫手動進行後續操作。');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return { issue, plan };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 建立計畫生成 prompt
|
|
70
|
-
*/
|
|
71
|
-
function buildPlanPrompt(issue) {
|
|
72
|
-
return `你是一位軟體架構師。請閱讀以下 GitHub Issue 並建立詳細的實現計畫。
|
|
73
|
-
|
|
74
|
-
## Issue #${issue.number}
|
|
75
|
-
標題:${issue.title}
|
|
76
|
-
|
|
77
|
-
描述:
|
|
78
|
-
${issue.body || '(無描述)'}
|
|
79
|
-
|
|
80
|
-
${issue.labels.length ? `標籤:${issue.labels.join(', ')}` : ''}
|
|
81
|
-
|
|
82
|
-
## 輸出要求
|
|
83
|
-
請輸出包含以下內容的實現計畫:
|
|
84
|
-
|
|
85
|
-
1. **摘要** - 一句話說明要做什麼
|
|
86
|
-
2. **需要新增/修改的檔案** - 列出所有相關檔案路徑和各自的職責
|
|
87
|
-
3. **實現步驟** - 有序的任務清單,說明每個步驟的目的
|
|
88
|
-
4. **注意事項** - 潛在風險或需要留意的事項(若有)
|
|
89
|
-
|
|
90
|
-
請使用繁體中文,格式清晰,簡潔有力。`.trim();
|
|
91
|
-
}
|