@icode-js/icode 3.0.2
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/README.md +346 -0
- package/bin/icode.js +6 -0
- package/package.json +34 -0
- package/src/cli.js +131 -0
- package/src/commands/ai.js +287 -0
- package/src/commands/checkout.js +59 -0
- package/src/commands/clean.js +65 -0
- package/src/commands/codereview.js +52 -0
- package/src/commands/config.js +513 -0
- package/src/commands/explain.js +80 -0
- package/src/commands/help.js +49 -0
- package/src/commands/info.js +57 -0
- package/src/commands/migrate.js +86 -0
- package/src/commands/push.js +125 -0
- package/src/commands/sync.js +74 -0
- package/src/commands/tag.js +53 -0
- package/src/commands/undo.js +66 -0
- package/src/core/ai-client.js +1125 -0
- package/src/core/ai-commit-summary.js +18 -0
- package/src/core/ai-config.js +342 -0
- package/src/core/ai-diff-range.js +117 -0
- package/src/core/args.js +47 -0
- package/src/core/commit-conventions.js +169 -0
- package/src/core/config-store.js +194 -0
- package/src/core/errors.js +25 -0
- package/src/core/git-context.js +105 -0
- package/src/core/git-service.js +428 -0
- package/src/core/hook-diagnostics.js +23 -0
- package/src/core/loading.js +36 -0
- package/src/core/logger.js +55 -0
- package/src/core/prompts.js +152 -0
- package/src/core/shell.js +77 -0
- package/src/workflows/ai-codereview-workflow.js +126 -0
- package/src/workflows/ai-commit-workflow.js +128 -0
- package/src/workflows/ai-conflict-workflow.js +102 -0
- package/src/workflows/ai-explain-workflow.js +116 -0
- package/src/workflows/ai-risk-review-workflow.js +49 -0
- package/src/workflows/checkout-workflow.js +85 -0
- package/src/workflows/clean-workflow.js +131 -0
- package/src/workflows/info-workflow.js +30 -0
- package/src/workflows/migrate-workflow.js +449 -0
- package/src/workflows/push-workflow.js +276 -0
- package/src/workflows/rollback-workflow.js +84 -0
- package/src/workflows/sync-workflow.js +141 -0
- package/src/workflows/tag-workflow.js +64 -0
- package/src/workflows/undo-workflow.js +328 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
+
import { getAiCommandOptions } from '../core/ai-config.js'
|
|
4
|
+
import { formatAiCommitSummary } from '../core/ai-commit-summary.js'
|
|
5
|
+
import { IcodeError } from '../core/errors.js'
|
|
6
|
+
import { logger } from '../core/logger.js'
|
|
7
|
+
import { runAiCodeReviewWorkflow } from '../workflows/ai-codereview-workflow.js'
|
|
8
|
+
import { runAiCommitWorkflow } from '../workflows/ai-commit-workflow.js'
|
|
9
|
+
import { runAiConflictWorkflow } from '../workflows/ai-conflict-workflow.js'
|
|
10
|
+
import { runAiExplainWorkflow } from '../workflows/ai-explain-workflow.js'
|
|
11
|
+
|
|
12
|
+
function printMainHelp() {
|
|
13
|
+
process.stdout.write(`
|
|
14
|
+
Usage:
|
|
15
|
+
icode ai <subcommand> [options]
|
|
16
|
+
|
|
17
|
+
Subcommands:
|
|
18
|
+
commit AI 生成提交信息(会参考本地 hook/commitlint 规范)
|
|
19
|
+
conflict AI 冲突解决建议
|
|
20
|
+
codereview AI 代码评审
|
|
21
|
+
explain AI 解释 Git diff
|
|
22
|
+
|
|
23
|
+
Tips:
|
|
24
|
+
icode ai <subcommand> -h 查看子命令参数说明
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
icode ai commit --apply -y
|
|
28
|
+
icode ai conflict
|
|
29
|
+
icode ai codereview --base origin/main --head HEAD
|
|
30
|
+
icode ai explain --base origin/main --head HEAD
|
|
31
|
+
`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function printCommitHelp() {
|
|
35
|
+
process.stdout.write(`
|
|
36
|
+
Usage:
|
|
37
|
+
icode ai commit [options]
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
--apply 直接使用 AI 信息执行 commit
|
|
41
|
+
--lang <zh|en> 输出语言,默认 zh
|
|
42
|
+
--profile <name> 指定 AI profile
|
|
43
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
44
|
+
--no-verify commit 时跳过 hook/husky 校验
|
|
45
|
+
-y, --yes 自动确认(跳过确认提示)
|
|
46
|
+
-h, --help 查看帮助
|
|
47
|
+
`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printConflictHelp() {
|
|
51
|
+
process.stdout.write(`
|
|
52
|
+
Usage:
|
|
53
|
+
icode ai conflict [options]
|
|
54
|
+
|
|
55
|
+
Options:
|
|
56
|
+
--profile <name> 指定 AI profile
|
|
57
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
58
|
+
-h, --help 查看帮助
|
|
59
|
+
`)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function printCodeReviewHelp() {
|
|
63
|
+
process.stdout.write(`
|
|
64
|
+
Usage:
|
|
65
|
+
icode ai codereview [options]
|
|
66
|
+
|
|
67
|
+
Options:
|
|
68
|
+
--base <ref> 指定分支 diff 基线;未传时默认评审暂存区 + 工作区改动
|
|
69
|
+
--head <ref> 指定分支 diff 终点,默认 HEAD
|
|
70
|
+
--focus <text> 评审重点(安全/性能/测试等)
|
|
71
|
+
--profile <name> 指定 AI profile
|
|
72
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
73
|
+
--dump-response 输出 AI 原始响应(调试数据格式)
|
|
74
|
+
-h, --help 查看帮助
|
|
75
|
+
`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function printExplainHelp() {
|
|
79
|
+
process.stdout.write(`
|
|
80
|
+
Usage:
|
|
81
|
+
icode ai explain [options]
|
|
82
|
+
|
|
83
|
+
Options:
|
|
84
|
+
--base <ref> diff 基线,默认 origin/<defaultBranch>;不可用时回退到本地默认分支
|
|
85
|
+
--head <ref> diff 终点,默认 HEAD
|
|
86
|
+
--profile <name> 指定 AI profile
|
|
87
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
88
|
+
--dump-response 输出 AI 原始响应(调试数据格式)
|
|
89
|
+
-h, --help 查看帮助
|
|
90
|
+
`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function resolveBooleanOption(cliValue, configValue, fallback = false) {
|
|
94
|
+
if (typeof cliValue === 'boolean') {
|
|
95
|
+
return cliValue
|
|
96
|
+
}
|
|
97
|
+
if (typeof configValue === 'boolean') {
|
|
98
|
+
return configValue
|
|
99
|
+
}
|
|
100
|
+
if (typeof configValue === 'string') {
|
|
101
|
+
const normalized = configValue.trim().toLowerCase()
|
|
102
|
+
if (['true', '1', 'yes', 'y', 'on'].includes(normalized)) {
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
if (['false', '0', 'no', 'n', 'off'].includes(normalized)) {
|
|
106
|
+
return false
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return fallback
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function resolveStringOption(cliValue, configValue, fallback = '') {
|
|
113
|
+
if (typeof cliValue === 'string' && cliValue.trim()) {
|
|
114
|
+
return cliValue
|
|
115
|
+
}
|
|
116
|
+
if (typeof configValue === 'string' && configValue.trim()) {
|
|
117
|
+
return configValue
|
|
118
|
+
}
|
|
119
|
+
return fallback
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Execute `icode ai commit` and surface the full applied commit message in logs.
|
|
123
|
+
async function runCommitSubcommand(rawArgs) {
|
|
124
|
+
const scopedOptions = getAiCommandOptions('commit')
|
|
125
|
+
const parsed = parseArgs({
|
|
126
|
+
args: rawArgs,
|
|
127
|
+
allowPositionals: true,
|
|
128
|
+
options: {
|
|
129
|
+
apply: { type: 'boolean' },
|
|
130
|
+
lang: { type: 'string' },
|
|
131
|
+
profile: { type: 'string' },
|
|
132
|
+
'repo-mode': { type: 'string' },
|
|
133
|
+
'no-verify': { type: 'boolean' },
|
|
134
|
+
yes: { type: 'boolean', short: 'y' },
|
|
135
|
+
help: { type: 'boolean', short: 'h' }
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
if (parsed.values.help) {
|
|
140
|
+
printCommitHelp()
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = await runAiCommitWorkflow({
|
|
145
|
+
apply: resolveBooleanOption(parsed.values.apply, scopedOptions.apply, false),
|
|
146
|
+
lang: resolveStringOption(parsed.values.lang, scopedOptions.lang, 'zh'),
|
|
147
|
+
profile: resolveStringOption(parsed.values.profile, scopedOptions.profile, ''),
|
|
148
|
+
repoMode: resolveStringOption(parsed.values['repo-mode'], scopedOptions.repoMode, 'auto'),
|
|
149
|
+
noVerify: resolveBooleanOption(parsed.values['no-verify'], scopedOptions.noVerify, false),
|
|
150
|
+
yes: resolveBooleanOption(parsed.values.yes, scopedOptions.yes, false)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
if (result.canceled) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (result.applied) {
|
|
158
|
+
logger.success(`AI commit 已应用:\n${formatAiCommitSummary(result.commitId, result.commitMessage)}`)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function runConflictSubcommand(rawArgs) {
|
|
163
|
+
const scopedOptions = getAiCommandOptions('conflict')
|
|
164
|
+
const parsed = parseArgs({
|
|
165
|
+
args: rawArgs,
|
|
166
|
+
allowPositionals: true,
|
|
167
|
+
options: {
|
|
168
|
+
profile: { type: 'string' },
|
|
169
|
+
'repo-mode': { type: 'string' },
|
|
170
|
+
help: { type: 'boolean', short: 'h' }
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
if (parsed.values.help) {
|
|
175
|
+
printConflictHelp()
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const result = await runAiConflictWorkflow({
|
|
180
|
+
profile: resolveStringOption(parsed.values.profile, scopedOptions.profile, ''),
|
|
181
|
+
repoMode: resolveStringOption(parsed.values['repo-mode'], scopedOptions.repoMode, 'auto')
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
logger.info(`冲突文件: ${result.conflictedFiles.join(', ')}`)
|
|
185
|
+
process.stdout.write(`\n${result.suggestion}\n`)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function runCodeReviewSubcommand(rawArgs) {
|
|
189
|
+
const parsed = parseArgs({
|
|
190
|
+
args: rawArgs,
|
|
191
|
+
allowPositionals: true,
|
|
192
|
+
options: {
|
|
193
|
+
base: { type: 'string' },
|
|
194
|
+
head: { type: 'string' },
|
|
195
|
+
focus: { type: 'string' },
|
|
196
|
+
profile: { type: 'string' },
|
|
197
|
+
'repo-mode': { type: 'string' },
|
|
198
|
+
'dump-response': { type: 'boolean' },
|
|
199
|
+
help: { type: 'boolean', short: 'h' }
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
if (parsed.values.help) {
|
|
204
|
+
printCodeReviewHelp()
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const result = await runAiCodeReviewWorkflow({
|
|
209
|
+
baseRef: resolveStringOption(parsed.values.base, '', ''),
|
|
210
|
+
headRef: resolveStringOption(parsed.values.head, '', ''),
|
|
211
|
+
focus: resolveStringOption(parsed.values.focus, '', ''),
|
|
212
|
+
profile: resolveStringOption(parsed.values.profile, '', ''),
|
|
213
|
+
repoMode: resolveStringOption(parsed.values['repo-mode'], '', 'auto'),
|
|
214
|
+
dumpResponse: resolveBooleanOption(parsed.values['dump-response'], undefined, false)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
logger.info(`Code Review 范围: ${result.rangeSpec}`)
|
|
218
|
+
process.stdout.write(`\n${result.review}\n`)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function runExplainSubcommand(rawArgs) {
|
|
222
|
+
const scopedOptions = getAiCommandOptions('explain')
|
|
223
|
+
const parsed = parseArgs({
|
|
224
|
+
args: rawArgs,
|
|
225
|
+
allowPositionals: true,
|
|
226
|
+
options: {
|
|
227
|
+
base: { type: 'string' },
|
|
228
|
+
head: { type: 'string' },
|
|
229
|
+
profile: { type: 'string' },
|
|
230
|
+
'repo-mode': { type: 'string' },
|
|
231
|
+
'dump-response': { type: 'boolean' },
|
|
232
|
+
help: { type: 'boolean', short: 'h' }
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
if (parsed.values.help) {
|
|
237
|
+
printExplainHelp()
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const result = await runAiExplainWorkflow({
|
|
242
|
+
baseRef: resolveStringOption(parsed.values.base, scopedOptions.base, ''),
|
|
243
|
+
headRef: resolveStringOption(parsed.values.head, scopedOptions.head, ''),
|
|
244
|
+
profile: resolveStringOption(parsed.values.profile, scopedOptions.profile, ''),
|
|
245
|
+
repoMode: resolveStringOption(parsed.values['repo-mode'], scopedOptions.repoMode, 'auto'),
|
|
246
|
+
dumpResponse: resolveBooleanOption(parsed.values['dump-response'], scopedOptions.dumpResponse, false)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
logger.info(`Explain 范围: ${result.rangeSpec}`)
|
|
250
|
+
process.stdout.write(`\n${result.explanation}\n`)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export async function runAiCommand(rawArgs) {
|
|
254
|
+
const args = normalizeLegacyArgs(rawArgs)
|
|
255
|
+
|
|
256
|
+
if (!args.length || args[0] === '--help' || args[0] === '-h') {
|
|
257
|
+
printMainHelp()
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const [subcommand, ...subcommandArgs] = args
|
|
262
|
+
|
|
263
|
+
if (subcommand === 'commit') {
|
|
264
|
+
await runCommitSubcommand(subcommandArgs)
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (subcommand === 'conflict') {
|
|
269
|
+
await runConflictSubcommand(subcommandArgs)
|
|
270
|
+
return
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (subcommand === 'codereview' || subcommand === 'review') {
|
|
274
|
+
await runCodeReviewSubcommand(subcommandArgs)
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (subcommand === 'explain') {
|
|
279
|
+
await runExplainSubcommand(subcommandArgs)
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
throw new IcodeError(`未知 ai 子命令: ${subcommand}`, {
|
|
284
|
+
code: 'AI_SUBCOMMAND_UNKNOWN',
|
|
285
|
+
exitCode: 2
|
|
286
|
+
})
|
|
287
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
+
import { logger } from '../core/logger.js'
|
|
4
|
+
import { runCheckoutWorkflow } from '../workflows/checkout-workflow.js'
|
|
5
|
+
|
|
6
|
+
function printHelp() {
|
|
7
|
+
process.stdout.write(`
|
|
8
|
+
Usage:
|
|
9
|
+
icode checkout <branch> [base] [options]
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
<branch> 目标分支名(必填)
|
|
13
|
+
[base] 新建分支基线,默认主分支
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-y, --yes 自动确认(跳过交互提示)
|
|
17
|
+
--push-origin 新建分支后立即推送到 origin
|
|
18
|
+
--pull-main 切换后同步主分支到当前分支
|
|
19
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
20
|
+
--no-verify 跳过 hook/husky 校验
|
|
21
|
+
-h, --help 查看帮助
|
|
22
|
+
|
|
23
|
+
Notes:
|
|
24
|
+
若本地与远程都不存在,会从基线分支创建。
|
|
25
|
+
`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function runCheckoutCommand(rawArgs) {
|
|
29
|
+
const args = normalizeLegacyArgs(rawArgs)
|
|
30
|
+
const parsed = parseArgs({
|
|
31
|
+
args,
|
|
32
|
+
allowPositionals: true,
|
|
33
|
+
options: {
|
|
34
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
35
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
36
|
+
'push-origin': { type: 'boolean', default: false },
|
|
37
|
+
'pull-main': { type: 'boolean', default: false },
|
|
38
|
+
'repo-mode': { type: 'string', default: 'auto' },
|
|
39
|
+
'no-verify': { type: 'boolean', default: false }
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
if (parsed.values.help || parsed.positionals.length < 1) {
|
|
44
|
+
printHelp()
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const [branchName, baseBranchName] = parsed.positionals
|
|
49
|
+
const result = await runCheckoutWorkflow({
|
|
50
|
+
branchName,
|
|
51
|
+
baseBranchName,
|
|
52
|
+
pushOrigin: parsed.values['push-origin'],
|
|
53
|
+
pullMain: parsed.values['pull-main'],
|
|
54
|
+
repoMode: parsed.values['repo-mode'],
|
|
55
|
+
noVerify: parsed.values['no-verify']
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
logger.success(`checkout 完成: ${result.branchName}`)
|
|
59
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { logger } from '../core/logger.js'
|
|
3
|
+
import { runCleanWorkflow } from '../workflows/clean-workflow.js'
|
|
4
|
+
|
|
5
|
+
function printHelp() {
|
|
6
|
+
process.stdout.write(`
|
|
7
|
+
Usage:
|
|
8
|
+
icode clean [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--merged-target <branch> 基于该分支判断“已合并”状态,默认主分支
|
|
12
|
+
--keep <branch|csv> 额外保留分支,可重复使用或逗号分隔
|
|
13
|
+
--remote 同时删除远程分支
|
|
14
|
+
--force 强制删除本地分支(-D)
|
|
15
|
+
-y, --yes 自动确认(跳过确认提示)
|
|
16
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
17
|
+
-h, --help 查看帮助
|
|
18
|
+
|
|
19
|
+
Notes:
|
|
20
|
+
默认保护当前分支/主分支/受保护分支。
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
icode clean
|
|
24
|
+
icode clean --merged-target main --keep release,hotfix
|
|
25
|
+
icode clean --remote --force -y
|
|
26
|
+
`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runCleanCommand(rawArgs) {
|
|
30
|
+
const parsed = parseArgs({
|
|
31
|
+
args: rawArgs,
|
|
32
|
+
allowPositionals: true,
|
|
33
|
+
options: {
|
|
34
|
+
'merged-target': { type: 'string' },
|
|
35
|
+
keep: { type: 'string', multiple: true, default: [] },
|
|
36
|
+
remote: { type: 'boolean', default: false },
|
|
37
|
+
force: { type: 'boolean', default: false },
|
|
38
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
39
|
+
'repo-mode': { type: 'string', default: 'auto' },
|
|
40
|
+
help: { type: 'boolean', short: 'h', default: false }
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
if (parsed.values.help) {
|
|
45
|
+
printHelp()
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const result = await runCleanWorkflow({
|
|
50
|
+
mergedTarget: parsed.values['merged-target'],
|
|
51
|
+
keep: parsed.values.keep,
|
|
52
|
+
remote: parsed.values.remote,
|
|
53
|
+
force: parsed.values.force,
|
|
54
|
+
yes: parsed.values.yes,
|
|
55
|
+
repoMode: parsed.values['repo-mode']
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (result.canceled) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
logger.success(
|
|
63
|
+
`clean 完成: 本地删除 ${result.deletedLocal.length} 个, 远程删除 ${result.deletedRemote.length} 个`
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { logger } from '../core/logger.js'
|
|
3
|
+
import { runAiCodeReviewWorkflow } from '../workflows/ai-codereview-workflow.js'
|
|
4
|
+
|
|
5
|
+
function printHelp() {
|
|
6
|
+
process.stdout.write(`
|
|
7
|
+
Usage:
|
|
8
|
+
icode codereview [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--base <ref> 指定分支 diff 基线;未传时默认评审暂存区 + 工作区改动
|
|
12
|
+
--head <ref> 指定分支 diff 终点,默认 HEAD
|
|
13
|
+
--focus <text> 评审重点(安全/性能/测试等)
|
|
14
|
+
--profile <name> 指定 AI profile
|
|
15
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
16
|
+
--dump-response 输出 AI 原始响应(调试数据格式)
|
|
17
|
+
-h, --help 查看帮助
|
|
18
|
+
`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function runCodeReviewCommand(rawArgs) {
|
|
22
|
+
const parsed = parseArgs({
|
|
23
|
+
args: rawArgs,
|
|
24
|
+
allowPositionals: true,
|
|
25
|
+
options: {
|
|
26
|
+
base: { type: 'string' },
|
|
27
|
+
head: { type: 'string' },
|
|
28
|
+
focus: { type: 'string' },
|
|
29
|
+
profile: { type: 'string' },
|
|
30
|
+
'repo-mode': { type: 'string' },
|
|
31
|
+
'dump-response': { type: 'boolean' },
|
|
32
|
+
help: { type: 'boolean', short: 'h' }
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
if (parsed.values.help) {
|
|
37
|
+
printHelp()
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = await runAiCodeReviewWorkflow({
|
|
42
|
+
baseRef: typeof parsed.values.base === 'string' ? parsed.values.base : '',
|
|
43
|
+
headRef: typeof parsed.values.head === 'string' ? parsed.values.head : '',
|
|
44
|
+
focus: typeof parsed.values.focus === 'string' ? parsed.values.focus : '',
|
|
45
|
+
profile: typeof parsed.values.profile === 'string' ? parsed.values.profile : '',
|
|
46
|
+
repoMode: typeof parsed.values['repo-mode'] === 'string' ? parsed.values['repo-mode'] : 'auto',
|
|
47
|
+
dumpResponse: parsed.values['dump-response'] === true
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
logger.info(`Code Review 范围: ${result.rangeSpec}`)
|
|
51
|
+
process.stdout.write(`\n${result.review}\n`)
|
|
52
|
+
}
|