@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,86 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
+
import { IcodeError } from '../core/errors.js'
|
|
4
|
+
import { logger } from '../core/logger.js'
|
|
5
|
+
import { runMigrateWorkflow } from '../workflows/migrate-workflow.js'
|
|
6
|
+
|
|
7
|
+
function printHelp() {
|
|
8
|
+
process.stdout.write(`
|
|
9
|
+
Usage:
|
|
10
|
+
icode migrate <sourceBranch> <targetBranch> [options]
|
|
11
|
+
icode migrate --interactive
|
|
12
|
+
|
|
13
|
+
Arguments:
|
|
14
|
+
<sourceBranch> 迁移来源分支(交互模式可省略)
|
|
15
|
+
<targetBranch> 迁移目标分支(交互模式可省略)
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
-i, --interactive 交互模式(单选/多选 source/target 与迁移范围)
|
|
19
|
+
--range <spec> 指定提交范围,例如 main..feature-x(交互模式下若提供则直接使用)
|
|
20
|
+
--push 迁移后自动推送 target 分支
|
|
21
|
+
-y, --yes 自动确认(跳过确认提示)
|
|
22
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
23
|
+
--no-verify 推送时跳过 hook/husky 校验
|
|
24
|
+
-h, --help 查看帮助
|
|
25
|
+
|
|
26
|
+
Notes:
|
|
27
|
+
默认迁移 target..source 的增量提交。
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
icode migrate feature/login release
|
|
31
|
+
icode migrate --interactive
|
|
32
|
+
icode migrate feature/login release --range HEAD~3..feature/login
|
|
33
|
+
icode migrate feature/login release --push -y
|
|
34
|
+
`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function runMigrateCommand(rawArgs) {
|
|
38
|
+
const args = normalizeLegacyArgs(rawArgs)
|
|
39
|
+
const parsed = parseArgs({
|
|
40
|
+
args,
|
|
41
|
+
allowPositionals: true,
|
|
42
|
+
options: {
|
|
43
|
+
interactive: { type: 'boolean', short: 'i', default: false },
|
|
44
|
+
range: { type: 'string' },
|
|
45
|
+
push: { type: 'boolean', default: false },
|
|
46
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
47
|
+
'repo-mode': { type: 'string', default: 'auto' },
|
|
48
|
+
'no-verify': { type: 'boolean', default: false },
|
|
49
|
+
help: { type: 'boolean', short: 'h', default: false }
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (parsed.values.help) {
|
|
54
|
+
printHelp()
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (parsed.positionals.length > 2) {
|
|
59
|
+
throw new IcodeError('参数过多: icode migrate 最多接收两个分支参数', {
|
|
60
|
+
code: 'MIGRATE_ARGS_TOO_MANY',
|
|
61
|
+
exitCode: 2
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const [sourceBranch = '', targetBranch = ''] = parsed.positionals
|
|
66
|
+
const interactive = parsed.values.interactive || parsed.positionals.length < 2
|
|
67
|
+
|
|
68
|
+
const result = await runMigrateWorkflow({
|
|
69
|
+
sourceBranch,
|
|
70
|
+
targetBranch,
|
|
71
|
+
interactive,
|
|
72
|
+
range: parsed.values.range,
|
|
73
|
+
push: parsed.values.push,
|
|
74
|
+
yes: parsed.values.yes,
|
|
75
|
+
repoMode: parsed.values['repo-mode'],
|
|
76
|
+
noVerify: parsed.values['no-verify']
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if (result.canceled) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
logger.success(
|
|
84
|
+
`migrate 完成: ${result.sourceBranch} -> ${result.targetBranch}, commits=${result.migratedCommits}, mode=${result.rangeMode || 'range'}`
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
+
import { getAiCommandOptions } from '../core/ai-config.js'
|
|
4
|
+
import { logger } from '../core/logger.js'
|
|
5
|
+
import { runPushWorkflow } from '../workflows/push-workflow.js'
|
|
6
|
+
|
|
7
|
+
function formatBranchStatus(status) {
|
|
8
|
+
const map = {
|
|
9
|
+
pushed: '已推送',
|
|
10
|
+
'merged-and-pushed': '已合并并推送',
|
|
11
|
+
'skipped-protected': '已跳过(受保护)',
|
|
12
|
+
'skipped-missing-remote': '已跳过(远程分支不存在)'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return map[status] || status
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function printHelp() {
|
|
19
|
+
process.stdout.write(`
|
|
20
|
+
Usage:
|
|
21
|
+
icode push [targetBranch...] [options]
|
|
22
|
+
|
|
23
|
+
Arguments:
|
|
24
|
+
[targetBranch...] 目标分支列表(可多个,空则默认当前分支)
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
-m, --message <msg> 提交信息(未填会提示输入)
|
|
28
|
+
-y, --yes 自动确认(跳过确认提示)
|
|
29
|
+
--local-merge 使用本地 merge 模式(默认,会切换分支并生成 merge commit)
|
|
30
|
+
--ai-commit push 前自动执行 AI commit(会参考本地 hook/commitlint 规范)
|
|
31
|
+
--ai-profile <name> 指定 AI profile(用于 --ai-commit)
|
|
32
|
+
--pull-main 提交前将主分支同步到当前分支
|
|
33
|
+
--not-push-current 不推送当前分支,只处理目标分支
|
|
34
|
+
--force-protected 强制处理配置里的受保护分支
|
|
35
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
36
|
+
--no-verify 跳过 hook/husky 校验
|
|
37
|
+
-h, --help 查看帮助
|
|
38
|
+
|
|
39
|
+
Notes:
|
|
40
|
+
默认使用本地 merge 模式。
|
|
41
|
+
未指定 target 时默认处理当前分支。
|
|
42
|
+
布尔开关仅在命令行显式传入时生效(如 --ai-commit / --pull-main / --no-verify / -y)。
|
|
43
|
+
`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function resolveBooleanOption(cliValue, fallback = false) {
|
|
47
|
+
if (typeof cliValue === 'boolean') {
|
|
48
|
+
return cliValue
|
|
49
|
+
}
|
|
50
|
+
if (typeof cliValue === 'string') {
|
|
51
|
+
const normalized = cliValue.trim().toLowerCase()
|
|
52
|
+
if (['true', '1', 'yes', 'y', 'on'].includes(normalized)) {
|
|
53
|
+
return true
|
|
54
|
+
}
|
|
55
|
+
if (['false', '0', 'no', 'n', 'off'].includes(normalized)) {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return fallback
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveStringOption(cliValue, configValue, fallback = '') {
|
|
63
|
+
if (typeof cliValue === 'string' && cliValue.trim()) {
|
|
64
|
+
return cliValue
|
|
65
|
+
}
|
|
66
|
+
if (typeof configValue === 'string' && configValue.trim()) {
|
|
67
|
+
return configValue
|
|
68
|
+
}
|
|
69
|
+
return fallback
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function resolvePushWorkflowOptions(parsedValues, parsedPositionals, scopedOptions = {}) {
|
|
73
|
+
return {
|
|
74
|
+
targetBranches: parsedPositionals,
|
|
75
|
+
message: parsedValues.message,
|
|
76
|
+
// 显式传入开关才生效,避免配置项隐式开启 push 行为。
|
|
77
|
+
yes: resolveBooleanOption(parsedValues.yes, false),
|
|
78
|
+
aiCommit: resolveBooleanOption(parsedValues['ai-commit'], false),
|
|
79
|
+
aiCommitLang: resolveStringOption(undefined, scopedOptions.aiCommitLang, 'zh'),
|
|
80
|
+
aiProfile: resolveStringOption(parsedValues['ai-profile'], scopedOptions.aiProfile, ''),
|
|
81
|
+
pullMain: resolveBooleanOption(parsedValues['pull-main'], false),
|
|
82
|
+
notPushCurrent: resolveBooleanOption(parsedValues['not-push-current'], false),
|
|
83
|
+
forceProtected: resolveBooleanOption(parsedValues['force-protected'], false),
|
|
84
|
+
repoMode: resolveStringOption(parsedValues['repo-mode'], undefined, 'auto'),
|
|
85
|
+
noVerify: resolveBooleanOption(parsedValues['no-verify'], false)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function runPushCommand(rawArgs) {
|
|
90
|
+
const args = normalizeLegacyArgs(rawArgs)
|
|
91
|
+
const scopedOptions = getAiCommandOptions('push')
|
|
92
|
+
const parsed = parseArgs({
|
|
93
|
+
args,
|
|
94
|
+
allowPositionals: true,
|
|
95
|
+
options: {
|
|
96
|
+
message: { type: 'string', short: 'm' },
|
|
97
|
+
yes: { type: 'boolean', short: 'y' },
|
|
98
|
+
'local-merge': { type: 'boolean' },
|
|
99
|
+
'ai-commit': { type: 'boolean' },
|
|
100
|
+
'ai-profile': { type: 'string' },
|
|
101
|
+
help: { type: 'boolean', short: 'h' },
|
|
102
|
+
'pull-main': { type: 'boolean' },
|
|
103
|
+
'not-push-current': { type: 'boolean' },
|
|
104
|
+
'force-protected': { type: 'boolean' },
|
|
105
|
+
'repo-mode': { type: 'string' },
|
|
106
|
+
'no-verify': { type: 'boolean' }
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
if (parsed.values.help) {
|
|
111
|
+
printHelp()
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const result = await runPushWorkflow(resolvePushWorkflowOptions(parsed.values, parsed.positionals, scopedOptions))
|
|
116
|
+
|
|
117
|
+
if (result.canceled) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
result.summary.forEach((item) => {
|
|
122
|
+
logger.info(`[结果] ${item.branch}: ${formatBranchStatus(item.status)}`)
|
|
123
|
+
})
|
|
124
|
+
logger.success(`push 完成,共处理 ${result.summary.length} 个分支。`)
|
|
125
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
+
import { logger } from '../core/logger.js'
|
|
4
|
+
import { runSyncWorkflow } from '../workflows/sync-workflow.js'
|
|
5
|
+
|
|
6
|
+
function printHelp() {
|
|
7
|
+
process.stdout.write(`
|
|
8
|
+
Usage:
|
|
9
|
+
icode sync [branch...] [options]
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
[branch...] 需要同步的分支列表(可多个)
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--all-local 自动同步全部本地分支
|
|
16
|
+
--merge-main 同步后把主分支 merge 到目标分支
|
|
17
|
+
--rebase pull 时使用 rebase
|
|
18
|
+
--push 同步后自动 push
|
|
19
|
+
-y, --yes 自动确认(跳过确认提示)
|
|
20
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
21
|
+
--no-verify push 时跳过 hook/husky 校验
|
|
22
|
+
-h, --help 查看帮助
|
|
23
|
+
|
|
24
|
+
Notes:
|
|
25
|
+
未传分支时默认同步当前分支与主分支。
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
icode sync
|
|
29
|
+
icode sync --all-local
|
|
30
|
+
icode sync develop test --merge-main
|
|
31
|
+
icode sync release --push -y
|
|
32
|
+
`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function runSyncCommand(rawArgs) {
|
|
36
|
+
const args = normalizeLegacyArgs(rawArgs)
|
|
37
|
+
const parsed = parseArgs({
|
|
38
|
+
args,
|
|
39
|
+
allowPositionals: true,
|
|
40
|
+
options: {
|
|
41
|
+
'all-local': { type: 'boolean', default: false },
|
|
42
|
+
'merge-main': { type: 'boolean', default: false },
|
|
43
|
+
rebase: { type: 'boolean', default: false },
|
|
44
|
+
push: { type: 'boolean', default: false },
|
|
45
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
46
|
+
'repo-mode': { type: 'string', default: 'auto' },
|
|
47
|
+
'no-verify': { type: 'boolean', default: false },
|
|
48
|
+
help: { type: 'boolean', short: 'h', default: false }
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (parsed.values.help) {
|
|
53
|
+
printHelp()
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const result = await runSyncWorkflow({
|
|
58
|
+
branches: parsed.positionals,
|
|
59
|
+
allLocal: parsed.values['all-local'],
|
|
60
|
+
mergeMain: parsed.values['merge-main'],
|
|
61
|
+
rebase: parsed.values.rebase,
|
|
62
|
+
push: parsed.values.push,
|
|
63
|
+
yes: parsed.values.yes,
|
|
64
|
+
repoMode: parsed.values['repo-mode'],
|
|
65
|
+
noVerify: parsed.values['no-verify']
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
if (result.canceled) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const summaryText = result.summary.map((item) => `${item.branch}:${item.status}`).join(', ')
|
|
73
|
+
logger.success(`sync 完成: ${summaryText}`)
|
|
74
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
+
import { logger } from '../core/logger.js'
|
|
4
|
+
import { runTagWorkflow } from '../workflows/tag-workflow.js'
|
|
5
|
+
|
|
6
|
+
function printHelp() {
|
|
7
|
+
process.stdout.write(`
|
|
8
|
+
Usage:
|
|
9
|
+
icode tag [options]
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-n, --name <tag> 指定 tag 名(默认 vYYYYMMDD_NN)
|
|
13
|
+
-m, --message <msg> tag 备注
|
|
14
|
+
--from <ref> 从指定分支/commit 创建 tag
|
|
15
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
16
|
+
--no-verify 跳过 hook/husky 校验
|
|
17
|
+
-h, --help 查看帮助
|
|
18
|
+
|
|
19
|
+
Notes:
|
|
20
|
+
默认 tag 规则: vYYYYMMDD_NN(例如 v20260309_01)。
|
|
21
|
+
`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function runTagCommand(rawArgs) {
|
|
25
|
+
const args = normalizeLegacyArgs(rawArgs)
|
|
26
|
+
const parsed = parseArgs({
|
|
27
|
+
args,
|
|
28
|
+
allowPositionals: true,
|
|
29
|
+
options: {
|
|
30
|
+
name: { type: 'string', short: 'n' },
|
|
31
|
+
message: { type: 'string', short: 'm' },
|
|
32
|
+
from: { type: 'string' },
|
|
33
|
+
'repo-mode': { type: 'string', default: 'auto' },
|
|
34
|
+
'no-verify': { type: 'boolean', default: false },
|
|
35
|
+
help: { type: 'boolean', short: 'h', default: false }
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
if (parsed.values.help) {
|
|
40
|
+
printHelp()
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const result = await runTagWorkflow({
|
|
45
|
+
tagName: parsed.values.name,
|
|
46
|
+
message: parsed.values.message,
|
|
47
|
+
fromRef: parsed.values.from,
|
|
48
|
+
repoMode: parsed.values['repo-mode'],
|
|
49
|
+
noVerify: parsed.values['no-verify']
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
logger.success(`tag 完成: ${result.tagName}`)
|
|
53
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { logger } from '../core/logger.js'
|
|
3
|
+
import { runUndoWorkflow } from '../workflows/undo-workflow.js'
|
|
4
|
+
|
|
5
|
+
function printHelp() {
|
|
6
|
+
process.stdout.write(`
|
|
7
|
+
Usage:
|
|
8
|
+
icode undo [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--mode <mode> 回滚模式: revert | soft | mixed | hard
|
|
12
|
+
--ref <ref> 回滚目标,默认按 mode 自动给出
|
|
13
|
+
--recover <action> 冲突恢复策略: continue | abort | keep
|
|
14
|
+
-y, --yes 自动确认(跳过确认提示)
|
|
15
|
+
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承)
|
|
16
|
+
-h, --help 查看帮助
|
|
17
|
+
|
|
18
|
+
Notes:
|
|
19
|
+
revert 模式会生成新提交;reset 模式会移动 HEAD。
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
icode undo
|
|
23
|
+
icode undo --mode revert --ref HEAD~2
|
|
24
|
+
icode undo --recover abort
|
|
25
|
+
icode undo --mode hard --ref HEAD~1 -y
|
|
26
|
+
`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runUndoCommand(rawArgs) {
|
|
30
|
+
const parsed = parseArgs({
|
|
31
|
+
args: rawArgs,
|
|
32
|
+
allowPositionals: true,
|
|
33
|
+
options: {
|
|
34
|
+
mode: { type: 'string' },
|
|
35
|
+
ref: { type: 'string' },
|
|
36
|
+
recover: { type: 'string' },
|
|
37
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
38
|
+
'repo-mode': { type: 'string', default: 'auto' },
|
|
39
|
+
help: { type: 'boolean', short: 'h', default: false }
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
if (parsed.values.help) {
|
|
44
|
+
printHelp()
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await runUndoWorkflow({
|
|
49
|
+
mode: parsed.values.mode,
|
|
50
|
+
ref: parsed.values.ref,
|
|
51
|
+
recover: parsed.values.recover,
|
|
52
|
+
yes: parsed.values.yes,
|
|
53
|
+
repoMode: parsed.values['repo-mode']
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if (result.canceled) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (result.resolvedOperation) {
|
|
61
|
+
logger.success(`undo 已处理未完成操作: ${result.resolvedOperation} -> ${result.recoverAction}`)
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
logger.success(`undo 完成: mode=${result.mode}, ref=${result.ref}`)
|
|
66
|
+
}
|