@icode-js/icode 3.0.3 → 3.1.0
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/LICENSE +21 -0
- package/README.md +40 -3
- package/bin/icode.js +4 -4
- package/package.json +1 -1
- package/src/cli.js +54 -23
- package/src/commands/ai.js +4 -4
- package/src/commands/checkout.js +2 -2
- package/src/commands/clean.js +1 -1
- package/src/commands/codereview.js +1 -1
- package/src/commands/completion.js +90 -0
- package/src/commands/config.js +117 -7
- package/src/commands/explain.js +2 -2
- package/src/commands/help.js +7 -0
- package/src/commands/info.js +1 -1
- package/src/commands/migrate.js +2 -2
- package/src/commands/push.js +29 -8
- package/src/commands/sync.js +2 -2
- package/src/commands/tag.js +2 -2
- package/src/commands/undo.js +60 -9
- package/src/core/{ai-client.js → ai/client.js} +3 -3
- package/src/core/{ai-config.js → ai/config.js} +2 -2
- package/src/core/{ai-diff-range.js → ai/diff-range.js} +2 -2
- package/src/core/cli/completion.js +687 -0
- package/src/core/cli/update-notifier.js +138 -0
- package/src/core/{shell.js → commands/shell.js} +13 -1
- package/src/core/{config-store.js → config/store.js} +55 -3
- package/src/core/{git-context.js → git/context.js} +25 -10
- package/src/core/{git-service.js → git/service.js} +78 -6
- package/src/core/remote-merge/client.js +42 -0
- package/src/core/remote-merge/providers/gitlab.js +537 -0
- package/src/core/remote-merge/shared.js +49 -0
- package/src/core/{prompts.js → tools/interactive.js} +46 -5
- package/src/workflows/ai-codereview-workflow.js +4 -4
- package/src/workflows/ai-commit-workflow.js +30 -15
- package/src/workflows/ai-conflict-workflow.js +4 -4
- package/src/workflows/ai-explain-workflow.js +4 -4
- package/src/workflows/ai-risk-review-workflow.js +1 -1
- package/src/workflows/checkout-workflow.js +3 -3
- package/src/workflows/clean-workflow.js +5 -5
- package/src/workflows/info-workflow.js +4 -4
- package/src/workflows/migrate-workflow.js +4 -4
- package/src/workflows/push-workflow.js +259 -24
- package/src/workflows/rollback-workflow.js +4 -4
- package/src/workflows/sync-workflow.js +4 -4
- package/src/workflows/tag-workflow.js +4 -4
- package/src/workflows/undo-workflow.js +12 -5
- /package/src/core/{ai-commit-summary.js → ai/commit-summary.js} +0 -0
- /package/src/core/{args.js → cli/args.js} +0 -0
- /package/src/core/{commit-conventions.js → git/commit-conventions.js} +0 -0
- /package/src/core/{hook-diagnostics.js → git/hook-diagnostics.js} +0 -0
- /package/src/core/{loading.js → tools/loading.js} +0 -0
- /package/src/core/{logger.js → tools/logger.js} +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 C
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -23,6 +23,26 @@ icode info
|
|
|
23
23
|
icode config ai list
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Shell Tab 补全
|
|
27
|
+
|
|
28
|
+
`icode` 现在支持生成 `bash` / `zsh` 的 tab 补全脚本。
|
|
29
|
+
|
|
30
|
+
临时启用:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
source <(icode completion bash)
|
|
34
|
+
source <(icode completion zsh)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
持久启用可以把对应命令追加到 `~/.bashrc` 或 `~/.zshrc`。
|
|
38
|
+
|
|
39
|
+
补全范围包括:
|
|
40
|
+
|
|
41
|
+
- 顶层命令和嵌套子命令
|
|
42
|
+
- 已知参数开关与枚举值
|
|
43
|
+
- 常见 Git 分支 / ref
|
|
44
|
+
- `icode config ai ...` 下已配置的 profile 名称
|
|
45
|
+
|
|
26
46
|
## 全局参数
|
|
27
47
|
|
|
28
48
|
- `-h, --help`:查看帮助(也可 `icode <command> -h` 查看子命令参数)
|
|
@@ -105,7 +125,7 @@ icode checkout <branch> [base] [--push-origin] [--pull-main] [--repo-mode auto|s
|
|
|
105
125
|
### push
|
|
106
126
|
|
|
107
127
|
```bash
|
|
108
|
-
icode push [targetBranch...] [-m "commit message"] [--ai-commit] [--pull-main] [--not-push-current]
|
|
128
|
+
icode push [targetBranch...] [-m "commit message"] [--ai-commit] [--pull-main] [--not-push-current] [--remote-merge]
|
|
109
129
|
```
|
|
110
130
|
|
|
111
131
|
示例:
|
|
@@ -120,6 +140,7 @@ icode push release test -m "feat: batch publish" -y # 默认本地 merge 推送
|
|
|
120
140
|
- 若仓库存在 husky/hooks/commitlint 规则,AI commit 会先扫描本地规范再生成提交信息
|
|
121
141
|
- 支持把当前分支合并到多个目标分支
|
|
122
142
|
- 默认使用本地 merge 模式(会生成 merge commit)
|
|
143
|
+
- 支持远程 PR/MR API 模式(需配置平台密钥)
|
|
123
144
|
- 支持受保护分支策略(通过 `icode config protect ...` 管理)
|
|
124
145
|
|
|
125
146
|
参数说明:
|
|
@@ -128,6 +149,7 @@ icode push release test -m "feat: batch publish" -y # 默认本地 merge 推送
|
|
|
128
149
|
- `-m, --message <msg>`:提交信息(未填会提示输入)
|
|
129
150
|
- `-y, --yes`:自动确认(跳过确认提示)
|
|
130
151
|
- `--local-merge`:显式声明使用本地 merge 模式(当前为默认行为,会切换分支并生成 merge commit)
|
|
152
|
+
- `--remote-merge`:改为远程 PR/MR 模式;会先推送源分支,再通过 API 创建合并请求;若发生冲突会暂停,并输出明确失败原因
|
|
131
153
|
- `--ai-commit`:push 前自动执行 AI commit
|
|
132
154
|
- `--ai-profile <name>`:指定 AI profile(用于 `--ai-commit`)
|
|
133
155
|
- `--pull-main`:提交前同步主分支到当前分支
|
|
@@ -140,6 +162,19 @@ icode push release test -m "feat: batch publish" -y # 默认本地 merge 推送
|
|
|
140
162
|
说明:
|
|
141
163
|
- `push` 的布尔开关(如 `--ai-commit`、`--pull-main`、`--no-verify`、`-y`)仅在命令行显式传入时生效。
|
|
142
164
|
|
|
165
|
+
远程合并配置示例:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
icode config platform remote-merge set --provider gitlab --api-key rm_xxx
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
建议:
|
|
172
|
+
- 密钥按平台维度管理,例如 GitLab / GitHub / 自建平台。
|
|
173
|
+
- GitLab API 地址固定为仓库 `origin` 对应站点的 `/api/v4`,无需再单独配置服务地址。
|
|
174
|
+
- 项目/仓库默认启用远程合并;如个别仓库不希望启用,可显式设置 `repositories.<repo>.remoteMerge.enabled=false`。
|
|
175
|
+
- 远程合并会直接根据 `origin` 自动提取 GitLab 项目地址;若无法识别,会提示你修正仓库 remote 配置。
|
|
176
|
+
- 这样更符合密钥复用与安全边界,避免多个仓库重复维护同一平台 API 地址。
|
|
177
|
+
|
|
143
178
|
### ai
|
|
144
179
|
|
|
145
180
|
```bash
|
|
@@ -239,18 +274,20 @@ icode tag [--name <tag>] [--message <msg>] [--from <ref>]
|
|
|
239
274
|
### undo
|
|
240
275
|
|
|
241
276
|
```bash
|
|
242
|
-
icode undo [--mode revert|soft|mixed|hard] [--ref <ref>] [--recover continue|abort|keep]
|
|
277
|
+
icode undo [ref] [--mode revert|soft|mixed|hard] [--ref <ref>] [--hash <hash>] [--recover continue|abort|keep]
|
|
243
278
|
```
|
|
244
279
|
|
|
245
280
|
- 向导式撤销命令(交互选择回滚策略)
|
|
246
281
|
- 适合新人或低频 Git 操作场景
|
|
247
|
-
- 也支持非交互参数:`--mode` + `--ref`
|
|
282
|
+
- 也支持非交互参数:`--mode` + `--ref` / `--hash`
|
|
283
|
+
- 支持用位置参数指定 commit hash,例如:`icode undo a1b2c3d --mode revert -y`
|
|
248
284
|
- 检测到 revert/cherry-pick 冲突时,会提示继续或中止
|
|
249
285
|
|
|
250
286
|
参数说明:
|
|
251
287
|
|
|
252
288
|
- `--mode <mode>`:回滚模式(`revert|soft|mixed|hard`)
|
|
253
289
|
- `--ref <ref>`:回滚目标,默认按 mode 自动给出
|
|
290
|
+
- `--hash <hash>`:按 commit hash 指定回滚目标(等同 `--ref`)
|
|
254
291
|
- `--recover <action>`:冲突恢复策略(`continue|abort|keep`)
|
|
255
292
|
- `-y, --yes`:自动确认(跳过确认提示)
|
|
256
293
|
- `--repo-mode auto|strict`:仓库模式(自动继承父仓库/禁止继承)
|
package/bin/icode.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { handleCliError, main } from '../src/cli.js'
|
|
3
|
+
|
|
4
|
+
main().catch((error) => {
|
|
5
|
+
handleCliError(error)
|
|
6
6
|
})
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { runAiCommand } from './commands/ai.js'
|
|
2
2
|
import { runCleanCommand } from './commands/clean.js'
|
|
3
3
|
import { runCodeReviewCommand } from './commands/codereview.js'
|
|
4
|
+
import { runCompletionCommand, runHiddenCompletionCommand } from './commands/completion.js'
|
|
4
5
|
import { runCheckoutCommand } from './commands/checkout.js'
|
|
5
6
|
import { runConfigCommand } from './commands/config.js'
|
|
6
7
|
import { runExplainCommand } from './commands/explain.js'
|
|
@@ -12,8 +13,9 @@ import { runSyncCommand } from './commands/sync.js'
|
|
|
12
13
|
import { runTagCommand } from './commands/tag.js'
|
|
13
14
|
import { runUndoCommand } from './commands/undo.js'
|
|
14
15
|
import { asIcodeError } from './core/errors.js'
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
16
|
+
import { normalizeLegacyArgs } from './core/cli/args.js'
|
|
17
|
+
import { notifyIfCliUpdateAvailable } from './core/cli/update-notifier.js'
|
|
18
|
+
import { logger } from './core/tools/logger.js'
|
|
17
19
|
|
|
18
20
|
function isTruthy(value) {
|
|
19
21
|
const normalized = String(value || '').trim().toLowerCase()
|
|
@@ -31,6 +33,7 @@ function serializeErrorMeta(meta) {
|
|
|
31
33
|
const COMMANDS = {
|
|
32
34
|
ai: runAiCommand,
|
|
33
35
|
codereview: runCodeReviewCommand,
|
|
36
|
+
completion: runCompletionCommand,
|
|
34
37
|
checkout: runCheckoutCommand,
|
|
35
38
|
push: runPushCommand,
|
|
36
39
|
sync: runSyncCommand,
|
|
@@ -43,7 +46,44 @@ const COMMANDS = {
|
|
|
43
46
|
info: runInfoCommand,
|
|
44
47
|
help: async () => {
|
|
45
48
|
printMainHelp()
|
|
49
|
+
},
|
|
50
|
+
__complete: runHiddenCompletionCommand
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const NO_UPDATE_NOTIFICATION_COMMANDS = new Set(['help', 'completion', '__complete'])
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 执行 CLI 主流程并在命令成功后触发升级提示检查。
|
|
57
|
+
* 输入为命令行参数与可注入依赖,输出为建议的退出码。
|
|
58
|
+
*/
|
|
59
|
+
export async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
60
|
+
const commands = dependencies.commands || COMMANDS
|
|
61
|
+
const printHelp = dependencies.printMainHelp || printMainHelp
|
|
62
|
+
const notifyUpdate = dependencies.notifyIfCliUpdateAvailable || notifyIfCliUpdateAvailable
|
|
63
|
+
const { globalArgs, commandName, commandArgs } = parseEntryArgs(argv)
|
|
64
|
+
const globalResult = applyGlobalFlags(globalArgs)
|
|
65
|
+
|
|
66
|
+
if (globalResult.shouldExit) {
|
|
67
|
+
return globalResult.exitCode
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!commandName) {
|
|
71
|
+
printHelp()
|
|
72
|
+
return 0
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const command = commands[commandName]
|
|
76
|
+
if (!command) {
|
|
77
|
+
throw new Error(`未知命令: ${commandName}`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await command(commandArgs)
|
|
81
|
+
|
|
82
|
+
if (!NO_UPDATE_NOTIFICATION_COMMANDS.has(commandName)) {
|
|
83
|
+
await notifyUpdate()
|
|
46
84
|
}
|
|
85
|
+
|
|
86
|
+
return 0
|
|
47
87
|
}
|
|
48
88
|
|
|
49
89
|
function parseEntryArgs(argv) {
|
|
@@ -86,28 +126,19 @@ function applyGlobalFlags(globalArgs) {
|
|
|
86
126
|
}
|
|
87
127
|
}
|
|
88
128
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!commandName) {
|
|
98
|
-
printMainHelp()
|
|
99
|
-
process.exit(0)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const command = COMMANDS[commandName]
|
|
103
|
-
if (!command) {
|
|
104
|
-
throw new Error(`未知命令: ${commandName}`)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
await command(commandArgs)
|
|
129
|
+
/**
|
|
130
|
+
* 启动 CLI 入口,复用 runCli 处理参数与命令调度。
|
|
131
|
+
* 输入为可选 argv 与依赖注入,输出为退出码。
|
|
132
|
+
*/
|
|
133
|
+
export async function main(argv = process.argv.slice(2), dependencies = {}) {
|
|
134
|
+
return runCli(argv, dependencies)
|
|
108
135
|
}
|
|
109
136
|
|
|
110
|
-
|
|
137
|
+
/**
|
|
138
|
+
* 统一处理 CLI 异常并输出对用户可读的错误信息。
|
|
139
|
+
* 输入为任意异常对象,输出为进程退出。
|
|
140
|
+
*/
|
|
141
|
+
export function handleCliError(error) {
|
|
111
142
|
const normalized = asIcodeError(error)
|
|
112
143
|
logger.error(normalized.message)
|
|
113
144
|
|
|
@@ -128,4 +159,4 @@ main().catch((error) => {
|
|
|
128
159
|
}
|
|
129
160
|
|
|
130
161
|
process.exit(normalized.exitCode || 1)
|
|
131
|
-
}
|
|
162
|
+
}
|
package/src/commands/ai.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util'
|
|
2
|
-
import {
|
|
3
|
-
import { getAiCommandOptions } from '../core/ai
|
|
4
|
-
import {
|
|
2
|
+
import { formatAiCommitSummary } from '../core/ai/commit-summary.js'
|
|
3
|
+
import { getAiCommandOptions } from '../core/ai/config.js'
|
|
4
|
+
import { normalizeLegacyArgs } from '../core/cli/args.js'
|
|
5
5
|
import { IcodeError } from '../core/errors.js'
|
|
6
|
-
import { logger } from '../core/logger.js'
|
|
6
|
+
import { logger } from '../core/tools/logger.js'
|
|
7
7
|
import { runAiCodeReviewWorkflow } from '../workflows/ai-codereview-workflow.js'
|
|
8
8
|
import { runAiCommitWorkflow } from '../workflows/ai-commit-workflow.js'
|
|
9
9
|
import { runAiConflictWorkflow } from '../workflows/ai-conflict-workflow.js'
|
package/src/commands/checkout.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util'
|
|
2
|
-
import { normalizeLegacyArgs } from '../core/args.js'
|
|
3
|
-
import { logger } from '../core/logger.js'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/cli/args.js'
|
|
3
|
+
import { logger } from '../core/tools/logger.js'
|
|
4
4
|
import { runCheckoutWorkflow } from '../workflows/checkout-workflow.js'
|
|
5
5
|
|
|
6
6
|
function printHelp() {
|
package/src/commands/clean.js
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { IcodeError } from '../core/errors.js'
|
|
3
|
+
import { getCompletionCandidates, renderCompletionScript } from '../core/cli/completion.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 输出 completion 命令帮助,说明支持的 shell 与安装方式。
|
|
7
|
+
* 输入为空,输出为标准输出文本。
|
|
8
|
+
*/
|
|
9
|
+
function printHelp() {
|
|
10
|
+
process.stdout.write(`
|
|
11
|
+
Usage:
|
|
12
|
+
icode completion <bash|zsh>
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-h, --help 查看帮助
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
source <(icode completion bash)
|
|
19
|
+
source <(icode completion zsh)
|
|
20
|
+
`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 解析隐藏补全命令参数,提取当前词与已确认参数列表。
|
|
25
|
+
* 输入为隐藏命令的原始参数数组,输出为 current 和 previousWords。
|
|
26
|
+
*/
|
|
27
|
+
function parseHiddenCompletionArgs(rawArgs) {
|
|
28
|
+
let current = ''
|
|
29
|
+
let separatorIndex = rawArgs.indexOf('--')
|
|
30
|
+
|
|
31
|
+
if (separatorIndex === -1) {
|
|
32
|
+
separatorIndex = rawArgs.length
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for (let index = 0; index < separatorIndex; index += 1) {
|
|
36
|
+
const token = rawArgs[index]
|
|
37
|
+
if (token === '--current') {
|
|
38
|
+
current = rawArgs[index + 1] || ''
|
|
39
|
+
index += 1
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
current,
|
|
45
|
+
previousWords: rawArgs.slice(separatorIndex + 1)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 执行公开的 completion 命令,输出对应 shell 的补全脚本。
|
|
51
|
+
* 输入为命令行参数数组,输出为脚本文本到标准输出。
|
|
52
|
+
*/
|
|
53
|
+
export async function runCompletionCommand(rawArgs) {
|
|
54
|
+
const parsed = parseArgs({
|
|
55
|
+
args: rawArgs,
|
|
56
|
+
allowPositionals: true,
|
|
57
|
+
options: {
|
|
58
|
+
help: { type: 'boolean', short: 'h', default: false }
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
if (parsed.values.help || parsed.positionals.length === 0) {
|
|
63
|
+
printHelp()
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const [shellName] = parsed.positionals
|
|
68
|
+
const normalizedShell = shellName.trim().toLowerCase()
|
|
69
|
+
if (!['bash', 'zsh'].includes(normalizedShell)) {
|
|
70
|
+
throw new IcodeError(`completion 仅支持 bash|zsh,当前输入: ${shellName}`, {
|
|
71
|
+
code: 'COMPLETION_SHELL_INVALID',
|
|
72
|
+
exitCode: 2
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
process.stdout.write(renderCompletionScript(normalizedShell))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 执行隐藏补全命令,只输出候选项,避免污染 shell 的补全结果。
|
|
81
|
+
* 输入为隐藏命令参数数组,输出为逐行候选项到标准输出。
|
|
82
|
+
*/
|
|
83
|
+
export async function runHiddenCompletionCommand(rawArgs) {
|
|
84
|
+
const { current, previousWords } = parseHiddenCompletionArgs(rawArgs)
|
|
85
|
+
const candidates = getCompletionCandidates(previousWords, current)
|
|
86
|
+
|
|
87
|
+
if (candidates.length > 0) {
|
|
88
|
+
process.stdout.write(`${candidates.join('\n')}\n`)
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/commands/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { parseArgs } from 'node:util'
|
|
3
|
-
import { askAi } from '../core/ai
|
|
3
|
+
import { askAi } from '../core/ai/client.js'
|
|
4
4
|
import {
|
|
5
5
|
getAiCommandOptions,
|
|
6
6
|
getAiProfileForDisplay,
|
|
@@ -11,28 +11,31 @@ import {
|
|
|
11
11
|
upsertAiCommandOptions,
|
|
12
12
|
upsertAiProfile,
|
|
13
13
|
useAiProfile
|
|
14
|
-
} from '../core/ai
|
|
14
|
+
} from '../core/ai/config.js'
|
|
15
15
|
import {
|
|
16
16
|
deleteValue,
|
|
17
17
|
getConfigFilePath,
|
|
18
|
+
getPlatformConfig,
|
|
18
19
|
getRepoPolicy,
|
|
19
20
|
getValue,
|
|
20
21
|
readConfig,
|
|
22
|
+
setPlatformConfig,
|
|
21
23
|
setRepoPolicy,
|
|
22
24
|
setValue
|
|
23
|
-
} from '../core/config
|
|
24
|
-
import { parseConfigValue } from '../core/args.js'
|
|
25
|
+
} from '../core/config/store.js'
|
|
26
|
+
import { parseConfigValue } from '../core/cli/args.js'
|
|
25
27
|
import { IcodeError } from '../core/errors.js'
|
|
26
|
-
import { resolveGitContext } from '../core/git
|
|
27
|
-
import { logger } from '../core/logger.js'
|
|
28
|
+
import { resolveGitContext } from '../core/git/context.js'
|
|
29
|
+
import { logger } from '../core/tools/logger.js'
|
|
28
30
|
|
|
31
|
+
// 输出 config 命令帮助,并展示当前支持的远程合并配置方式。
|
|
29
32
|
function printHelp() {
|
|
30
33
|
process.stdout.write(`
|
|
31
34
|
Usage:
|
|
32
35
|
icode config <command> [...args]
|
|
33
36
|
|
|
34
37
|
Arguments:
|
|
35
|
-
<command> 子命令(list/get/set/delete/ai/protect)
|
|
38
|
+
<command> 子命令(list/get/set/delete/ai/protect/platform)
|
|
36
39
|
|
|
37
40
|
Commands:
|
|
38
41
|
list 查看全部配置
|
|
@@ -43,6 +46,7 @@ Commands:
|
|
|
43
46
|
protect list 查看受保护分支
|
|
44
47
|
protect add <branch...> 添加受保护分支
|
|
45
48
|
protect remove <branch...> 移除受保护分支
|
|
49
|
+
platform <subcommand> 平台级配置(如远程合并密钥)
|
|
46
50
|
|
|
47
51
|
Options:
|
|
48
52
|
--repo-mode <mode> 仓库模式: auto(自动继承父仓库) | strict(禁止继承),仅影响 protect
|
|
@@ -52,11 +56,112 @@ Examples:
|
|
|
52
56
|
icode config set defaults.repoMode strict
|
|
53
57
|
icode config get defaults.repoMode
|
|
54
58
|
icode config protect add main release
|
|
59
|
+
icode config platform remote-merge set --provider gitlab --api-key rm_xxx
|
|
55
60
|
icode config ai set openai --format openai --base-url https://api.openai.com/v1 --api-key sk-xxx --model gpt-4o-mini --activate
|
|
56
61
|
icode config ai set ollama --format ollama --base-url http://127.0.0.1:11434 --model qwen2.5:7b --activate
|
|
57
62
|
`)
|
|
58
63
|
}
|
|
59
64
|
|
|
65
|
+
function maskSecret(secret) {
|
|
66
|
+
const raw = String(secret || '').trim()
|
|
67
|
+
if (!raw) {
|
|
68
|
+
return ''
|
|
69
|
+
}
|
|
70
|
+
if (raw.length <= 8) {
|
|
71
|
+
return `${raw.slice(0, 2)}****${raw.slice(-1)}`
|
|
72
|
+
}
|
|
73
|
+
return `${raw.slice(0, 4)}****${raw.slice(-4)}`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 输出 platform 子命令帮助,明确 remote-merge 仅需平台名与密钥。
|
|
77
|
+
function printPlatformHelp() {
|
|
78
|
+
process.stdout.write(`
|
|
79
|
+
Usage:
|
|
80
|
+
icode config platform <subcommand> [options]
|
|
81
|
+
|
|
82
|
+
Subcommands:
|
|
83
|
+
remote-merge show
|
|
84
|
+
remote-merge set --provider gitlab --api-key <key>
|
|
85
|
+
|
|
86
|
+
Examples:
|
|
87
|
+
icode config platform remote-merge show
|
|
88
|
+
icode config platform remote-merge set --provider gitlab --api-key rm_xxx
|
|
89
|
+
`)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 处理平台级远程合并配置,当前只接受 GitLab 平台密钥写入。
|
|
93
|
+
async function runPlatformConfigCommand(args) {
|
|
94
|
+
if (!args.length || args[0] === '-h' || args[0] === '--help') {
|
|
95
|
+
printPlatformHelp()
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const [domain, action, ...rest] = args
|
|
100
|
+
if (domain !== 'remote-merge') {
|
|
101
|
+
throw new IcodeError(`未知 platform 子命令: ${domain}`, {
|
|
102
|
+
code: 'CONFIG_PLATFORM_UNKNOWN_SUBCOMMAND',
|
|
103
|
+
exitCode: 2
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (action === 'show') {
|
|
108
|
+
const config = getPlatformConfig('remoteMerge')
|
|
109
|
+
process.stdout.write(`${JSON.stringify({
|
|
110
|
+
provider: config.provider || '',
|
|
111
|
+
hasApiKey: Boolean(config.apiKey),
|
|
112
|
+
apiKeyMasked: maskSecret(config.apiKey)
|
|
113
|
+
}, null, 2)}\n`)
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (action === 'set') {
|
|
118
|
+
const parsed = parseArgs({
|
|
119
|
+
args: rest,
|
|
120
|
+
allowPositionals: true,
|
|
121
|
+
options: {
|
|
122
|
+
provider: { type: 'string' },
|
|
123
|
+
'api-key': { type: 'string' }
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const provider = String(parsed.values.provider || '').trim()
|
|
128
|
+
const apiKey = String(parsed.values['api-key'] || '').trim()
|
|
129
|
+
|
|
130
|
+
if (!provider) {
|
|
131
|
+
throw new IcodeError('缺少 --provider,示例: icode config platform remote-merge set --provider gitlab --api-key xxx', {
|
|
132
|
+
code: 'CONFIG_PLATFORM_PROVIDER_REQUIRED',
|
|
133
|
+
exitCode: 2
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!apiKey) {
|
|
138
|
+
throw new IcodeError('缺少 --api-key,示例: icode config platform remote-merge set --provider gitlab --api-key xxx', {
|
|
139
|
+
code: 'CONFIG_PLATFORM_API_KEY_REQUIRED',
|
|
140
|
+
exitCode: 2
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (provider !== 'gitlab') {
|
|
145
|
+
throw new IcodeError(`platform remote-merge 当前仅支持 gitlab,收到 provider=${provider}`, {
|
|
146
|
+
code: 'CONFIG_PLATFORM_PROVIDER_UNSUPPORTED',
|
|
147
|
+
exitCode: 2
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
setPlatformConfig('remoteMerge', {
|
|
152
|
+
provider,
|
|
153
|
+
apiKey
|
|
154
|
+
})
|
|
155
|
+
logger.success(`平台远程合并密钥已写入: ${provider}`)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
throw new IcodeError('platform remote-merge 仅支持: show | set', {
|
|
160
|
+
code: 'CONFIG_PLATFORM_INVALID_ACTION',
|
|
161
|
+
exitCode: 2
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
60
165
|
function printAiHelp() {
|
|
61
166
|
process.stdout.write(`
|
|
62
167
|
Usage:
|
|
@@ -386,6 +491,11 @@ export async function runConfigCommand(rawArgs) {
|
|
|
386
491
|
return
|
|
387
492
|
}
|
|
388
493
|
|
|
494
|
+
if (rawArgs[0] === 'platform') {
|
|
495
|
+
await runPlatformConfigCommand(rawArgs.slice(1))
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
|
|
389
499
|
const parsed = parseArgs({
|
|
390
500
|
args: rawArgs,
|
|
391
501
|
allowPositionals: true,
|
package/src/commands/explain.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util'
|
|
2
|
-
import { getAiCommandOptions } from '../core/ai
|
|
3
|
-
import { logger } from '../core/logger.js'
|
|
2
|
+
import { getAiCommandOptions } from '../core/ai/config.js'
|
|
3
|
+
import { logger } from '../core/tools/logger.js'
|
|
4
4
|
import { runAiExplainWorkflow } from '../workflows/ai-explain-workflow.js'
|
|
5
5
|
|
|
6
6
|
function printHelp() {
|
package/src/commands/help.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 输出主帮助文本,集中展示命令总览与常用示例。
|
|
3
|
+
* 输入为空,输出为标准输出文本。
|
|
4
|
+
*/
|
|
1
5
|
export function printMainHelp() {
|
|
2
6
|
process.stdout.write(`
|
|
3
7
|
icode v3 - Git workflow CLI
|
|
@@ -18,6 +22,7 @@ Commands:
|
|
|
18
22
|
config 查看和修改本地配置(含 AI profile)
|
|
19
23
|
explain AI 解释 Git diff(自然语言)
|
|
20
24
|
info 查看当前 git 与配置环境
|
|
25
|
+
completion 生成 bash/zsh tab 补全脚本
|
|
21
26
|
help 查看帮助(命令总览)
|
|
22
27
|
|
|
23
28
|
Global options:
|
|
@@ -38,12 +43,14 @@ Examples:
|
|
|
38
43
|
icode push release test -m "feat: keep merge commit" --local-merge -y
|
|
39
44
|
icode sync --all-local --merge-main
|
|
40
45
|
icode clean --remote --force -y
|
|
46
|
+
icode undo a1b2c3d --mode revert -y
|
|
41
47
|
icode undo --mode revert --ref HEAD~1 -y
|
|
42
48
|
icode undo --recover abort
|
|
43
49
|
icode migrate feature/login release --push -y
|
|
44
50
|
icode migrate --interactive
|
|
45
51
|
icode push --no-verify -m "chore: bypass hooks"
|
|
46
52
|
icode config protect add main release
|
|
53
|
+
source <(icode completion zsh)
|
|
47
54
|
icode info
|
|
48
55
|
`)
|
|
49
56
|
}
|
package/src/commands/info.js
CHANGED
package/src/commands/migrate.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parseArgs } from 'node:util'
|
|
2
|
-
import { normalizeLegacyArgs } from '../core/args.js'
|
|
2
|
+
import { normalizeLegacyArgs } from '../core/cli/args.js'
|
|
3
3
|
import { IcodeError } from '../core/errors.js'
|
|
4
|
-
import { logger } from '../core/logger.js'
|
|
4
|
+
import { logger } from '../core/tools/logger.js'
|
|
5
5
|
import { runMigrateWorkflow } from '../workflows/migrate-workflow.js'
|
|
6
6
|
|
|
7
7
|
function printHelp() {
|